1 #include <gtest/gtest.h>
2 #include "common/ceph_context.h"
3 #include "rgw/rgw_common.h"
4 #include "rgw/rgw_process.h"
5 #include "rgw/rgw_sal_rados.h"
6 #include "rgw/rgw_lua_request.h"
13 CctCleaner(CephContext
* _cct
) : cct(_cct
) {}
23 class TestRGWUser
: public sal::RGWUser
{
25 virtual int list_buckets(const string
&, const string
&, uint64_t, bool, sal::RGWBucketList
&, optional_yield y
) override
{
29 virtual sal::RGWBucket
* create_bucket(rgw_bucket
& bucket
, ceph::real_time creation_time
) override
{
33 virtual int load_by_id(optional_yield y
) override
{
37 virtual ~TestRGWUser() = default;
40 class TestAccounter
: public io::Accounter
, public io::BasicClient
{
44 virtual int init_env(CephContext
*cct
) override
{
49 ~TestAccounter() = default;
51 virtual void set_account(bool enabled
) override
{
54 virtual uint64_t get_bytes_sent() const override
{
58 virtual uint64_t get_bytes_received() const override
{
62 virtual RGWEnv
& get_env() noexcept override
{
66 virtual size_t complete_request() override
{
71 auto cct
= new CephContext(CEPH_ENTITY_TYPE_CLIENT
);
73 CctCleaner
cleaner(cct
);
75 TEST(TestRGWLua
, EmptyScript
)
77 const std::string script
;
81 req_state
s(cct
, &e
, id
);
83 const auto rc
= lua::request::execute(nullptr, nullptr, nullptr, &s
, "", script
);
87 #define DEFINE_REQ_STATE RGWEnv e; req_state s(cct, &e, 0);
89 TEST(TestRGWLua
, SyntaxError
)
91 const std::string script
= R
"(
93 RGWDebugLog("missing
'end'")
98 const auto rc
= lua::request::execute(nullptr, nullptr, nullptr, &s
, "", script
);
102 TEST(TestRGWLua
, Hello
)
104 const std::string script
= R
"(
105 RGWDebugLog("hello from lua
")
110 const auto rc
= lua::request::execute(nullptr, nullptr, nullptr, &s
, "", script
);
114 TEST(TestRGWLua
, RGWDebugLogNumber
)
116 const std::string script
= R
"(
117 RGWDebugLog(1234567890)
122 const auto rc
= lua::request::execute(nullptr, nullptr, nullptr, &s
, "", script
);
126 TEST(TestRGWLua
, RGWDebugNil
)
128 const std::string script
= R
"(
134 const auto rc
= lua::request::execute(nullptr, nullptr, nullptr, &s
, "", script
);
138 TEST(TestRGWLua
, URI
)
140 const std::string script
= R
"(
141 RGWDebugLog(Request.DecodedURI)
142 assert(Request.DecodedURI == "http
://hello.world/")
146 s.decoded_uri = "http
://hello.world/";
148 const auto rc
= lua::request::execute(nullptr, nullptr, nullptr, &s
, "", script
);
152 TEST(TestRGWLua
, Response
)
154 const std::string script
= R
"(
155 assert(Request.Response.Message == "This is a bad request
")
156 assert(Request.Response.HTTPStatus == "Bad Request
")
157 assert(Request.Response.RGWCode == 4000)
158 assert(Request.Response.HTTPStatusCode == 400)
162 s
.err
.http_ret
= 400;
164 s
.err
.err_code
= "Bad Request";
165 s
.err
.message
= "This is a bad request";
167 const auto rc
= lua::request::execute(nullptr, nullptr, nullptr, &s
, "put_obj", script
);
171 TEST(TestRGWLua
, SetResponse
)
173 const std::string script
= R
"(
174 assert(Request.Response.Message == "this is a bad request
")
175 Request.Response.Message = "this is a good request
"
176 assert(Request.Response.Message == "this is a good request
")
180 s
.err
.message
= "this is a bad request";
182 const auto rc
= lua::request::execute(nullptr, nullptr, nullptr, &s
, "put_obj", script
);
186 TEST(TestRGWLua
, SetRGWId
)
188 const std::string script
= R
"(
189 assert(Request.RGWId == "foo
")
190 Request.RGWId = "bar
"
196 const auto rc
= lua::request::execute(nullptr, nullptr, nullptr, &s
, "put_obj", script
);
200 TEST(TestRGWLua
, InvalidField
)
202 const std::string script
= R
"(
203 RGWDebugLog(Request.Kaboom)
209 const auto rc
= lua::request::execute(nullptr, nullptr, nullptr, &s
, "kaboom", script
);
213 TEST(TestRGWLua
, InvalidSubField
)
215 const std::string script
= R
"(
216 RGWDebugLog(Request.Error.Kaboom)
221 const auto rc
= lua::request::execute(nullptr, nullptr, nullptr, &s
, "kaboom", script
);
225 TEST(TestRGWLua
, Bucket
)
227 const std::string script
= R
"(
228 assert(Request.Bucket)
229 RGWDebugLog("Bucket Id
: " .. Request.Bucket.Id)
230 assert(Request.Bucket.Marker == "mymarker
")
231 assert(Request.Bucket.Name == "myname
")
232 assert(Request.Bucket.Tenant == "mytenant
")
233 assert(Request.Bucket.Count == 0)
234 assert(Request.Bucket.Size == 0)
235 assert(Request.Bucket.ZoneGroupId)
236 assert(Request.Bucket.CreationTime)
237 assert(Request.Bucket.MTime)
238 assert(Request.Bucket.Quota.MaxSize == -1)
239 assert(Request.Bucket.Quota.MaxObjects == -1)
240 assert(tostring(Request.Bucket.Quota.Enabled))
241 assert(tostring(Request.Bucket.Quota.Rounded))
242 assert(Request.Bucket.User.Id)
243 assert(Request.Bucket.User.Tenant)
249 b
.tenant
= "mytenant";
251 b
.marker
= "mymarker";
252 b
.bucket_id
= "myid";
253 s
.bucket
.reset(new sal::RGWRadosBucket(nullptr, b
));
255 const auto rc
= lua::request::execute(nullptr, nullptr, nullptr, &s
, "put_obj", script
);
259 TEST(TestRGWLua
, GenericAttributes
)
261 const std::string script
= R
"(
262 assert(Request.GenericAttributes["hello
"] == "world
")
263 assert(Request.GenericAttributes["foo
"] == "bar
")
264 assert(Request.GenericAttributes["kaboom
"] == nil)
265 assert(#Request.GenericAttributes == 4)
266 for k, v in pairs(Request.GenericAttributes) do
273 s
.generic_attrs
["hello"] = "world";
274 s
.generic_attrs
["foo"] = "bar";
275 s
.generic_attrs
["goodbye"] = "cruel world";
276 s
.generic_attrs
["ka"] = "boom";
278 const auto rc
= lua::request::execute(nullptr, nullptr, nullptr, &s
, "put_obj", script
);
282 TEST(TestRGWLua
, Environment
)
284 const std::string script
= R
"(
285 assert(Request.Environment[""] == "bar
")
286 assert(Request.Environment["goodbye
"] == "cruel world
")
287 assert(Request.Environment["ka
"] == "boom
")
288 assert(#Request.Environment == 3, #Request.Environment)
289 for k, v in pairs(Request.Environment) do
298 s
.env
["goodbye"] = "cruel world";
299 s
.env
["ka"] = "boom";
301 const auto rc
= lua::request::execute(nullptr, nullptr, nullptr, &s
, "put_obj", script
);
305 TEST(TestRGWLua
, Tags
)
307 const std::string script
= R
"(
308 assert(#Request.Tags == 4)
309 assert(Request.Tags["foo
"] == "bar
")
310 for k, v in pairs(Request.Tags) do
317 s
.tagset
.add_tag("hello", "world");
318 s
.tagset
.add_tag("foo", "bar");
319 s
.tagset
.add_tag("goodbye", "cruel world");
320 s
.tagset
.add_tag("ka", "boom");
322 const auto rc
= lua::request::execute(nullptr, nullptr, nullptr, &s
, "put_obj", script
);
326 TEST(TestRGWLua
, TagsNotWriteable
)
328 const std::string script
= R
"(
329 Request.Tags["hello
"] = "goodbye
"
333 s
.tagset
.add_tag("hello", "world");
335 const auto rc
= lua::request::execute(nullptr, nullptr, nullptr, &s
, "put_obj", script
);
339 TEST(TestRGWLua
, Metadata
)
341 const std::string script
= R
"(
342 assert(#Request.HTTP.Metadata == 3)
343 for k, v in pairs(Request.HTTP.Metadata) do
347 assert(Request.HTTP.Metadata["hello
"] == "world
")
348 assert(Request.HTTP.Metadata["kaboom
"] == nil)
349 Request.HTTP.Metadata["hello
"] = "goodbye
"
350 Request.HTTP.Metadata["kaboom
"] = "boom
"
351 assert(#Request.HTTP.Metadata == 4)
352 assert(Request.HTTP.Metadata["hello
"] == "goodbye
")
353 assert(Request.HTTP.Metadata["kaboom
"] == "boom
")
357 s
.info
.x_meta_map
["hello"] = "world";
358 s
.info
.x_meta_map
["foo"] = "bar";
359 s
.info
.x_meta_map
["ka"] = "boom";
361 const auto rc
= lua::request::execute(nullptr, nullptr, nullptr, &s
, "put_obj", script
);
365 TEST(TestRGWLua
, Acl
)
367 const std::string script
= R
"(
368 function print_grant(g)
369 print("Grant Type
: " .. g.Type)
370 print("Grant Group Type
: " .. g.GroupType)
371 print("Grant Referer
: " .. g.Referer)
373 print("Grant User
.Tenant
: " .. g.User.Tenant)
374 print("Grant User
.Id
: " .. g.User.Id)
378 assert(Request.UserAcl.Owner.DisplayName == "jack black
", Request.UserAcl.Owner.DisplayName)
379 assert(Request.UserAcl.Owner.User.Id == "black
", Request.UserAcl.Owner.User.Id)
380 assert(Request.UserAcl.Owner.User.Tenant == "jack
", Request.UserAcl.Owner.User.Tenant)
381 assert(#Request.UserAcl.Grants == 5)
382 print_grant(Request.UserAcl.Grants[""])
383 for k, v in pairs(Request.UserAcl.Grants) do
385 if k == "john$doe
" then
386 assert(v.Permission == 4)
387 elseif k == "jane$doe
" then
388 assert(v.Permission == 1)
397 owner
.set_id(rgw_user("jack", "black"));
398 owner
.set_name("jack black");
399 s
.user_acl
.reset(new RGWAccessControlPolicy(cct
));
400 s
.user_acl
->set_owner(owner
);
401 ACLGrant grant1
, grant2
, grant3
, grant4
, grant5
;
402 grant1
.set_canon(rgw_user("jane", "doe"), "her grant", 1);
403 grant2
.set_group(ACL_GROUP_ALL_USERS
,2);
404 grant3
.set_referer("http://localhost/ref2", 3);
405 grant4
.set_canon(rgw_user("john", "doe"), "his grant", 4);
406 grant5
.set_group(ACL_GROUP_AUTHENTICATED_USERS
, 5);
407 s
.user_acl
->get_acl().add_grant(&grant1
);
408 s
.user_acl
->get_acl().add_grant(&grant2
);
409 s
.user_acl
->get_acl().add_grant(&grant3
);
410 s
.user_acl
->get_acl().add_grant(&grant4
);
411 s
.user_acl
->get_acl().add_grant(&grant5
);
412 const auto rc
= lua::request::execute(nullptr, nullptr, nullptr, &s
, "put_obj", script
);
416 TEST(TestRGWLua
, UseFunction
)
418 const std::string script
= R
"(
419 function print_owner(owner)
420 print("Owner Dispaly Name
: " .. owner.DisplayName)
421 print("Owner Id
: " .. owner.User.Id)
422 print("Owner Tenanet
: " .. owner.User.Tenant)
425 print_owner(Request.ObjectOwner)
427 function print_acl(acl_type)
428 index = acl_type .. "ACL
"
431 print(acl_type .. "ACL Owner
")
432 print_owner(acl.Owner)
434 print("no
" .. acl_type .. " ACL in request
: " .. Request.Id)
444 s
.owner
.set_name("user two");
445 s
.owner
.set_id(rgw_user("tenant2", "user2"));
446 s
.user_acl
.reset(new RGWAccessControlPolicy());
447 s
.user_acl
->get_owner().set_name("user three");
448 s
.user_acl
->get_owner().set_id(rgw_user("tenant3", "user3"));
449 s
.bucket_acl
.reset(new RGWAccessControlPolicy());
450 s
.bucket_acl
->get_owner().set_name("user four");
451 s
.bucket_acl
->get_owner().set_id(rgw_user("tenant4", "user4"));
452 s
.object_acl
.reset(new RGWAccessControlPolicy());
453 s
.object_acl
->get_owner().set_name("user five");
454 s
.object_acl
->get_owner().set_id(rgw_user("tenant5", "user5"));
456 const auto rc
= lua::request::execute(nullptr, nullptr, nullptr, &s
, "put_obj", script
);
460 TEST(TestRGWLua
, WithLib
)
462 const std::string script
= R
"(
463 expected_result = {"my
", "bucket
", "name
", "is
", "fish
"}
465 for p in string.gmatch(Request.Bucket.Name, "%a
+") do
466 assert(p == expected_result[i])
474 b
.name
= "my-bucket-name-is-fish";
475 s
.bucket
.reset(new sal::RGWRadosBucket(nullptr, b
));
477 const auto rc
= lua::request::execute(nullptr, nullptr, nullptr, &s
, "put_obj", script
);
481 TEST(TestRGWLua
, NotAllowedInLib
)
483 const std::string script
= R
"(
484 os.clock() -- this should be ok
485 os.exit() -- this should fail (os.exit() is removed)
490 const auto rc
= lua::request::execute(nullptr, nullptr, nullptr, &s
, "put_obj", script
);
493 #include <sys/socket.h>
496 bool unix_socket_client_ended_ok
= false;
498 void unix_socket_client(const std::string
& path
) {
501 if ((fd
= socket(AF_UNIX
, SOCK_STREAM
, 0)) == -1) {
502 std::cout
<< "unix socket error: " << errno
<< std::endl
;
506 struct sockaddr_un addr
;
507 memset(&addr
, 0, sizeof(addr
));
508 addr
.sun_family
= AF_UNIX
;
509 strncpy(addr
.sun_path
, path
.c_str(), sizeof(addr
.sun_path
)-1);
511 // let the socket be created by the "rgw" side
512 std::this_thread::sleep_for(std::chrono::seconds(2));
513 if (connect(fd
, (struct sockaddr
*)&addr
, sizeof(addr
)) == -1) {
514 std::cout
<< "unix socket connect error: " << errno
<< std::endl
;
520 while((rc
=read(fd
, buff
, sizeof(buff
))) > 0) {
521 std::cout
<< std::string(buff
, rc
);
522 unix_socket_client_ended_ok
= true;
526 TEST(TestRGWLua
, OpsLog
)
528 const std::string unix_socket_path
= "./aSocket.sock";
529 unlink(unix_socket_path
.c_str());
531 std::thread
unix_socket_thread(unix_socket_client
, unix_socket_path
);
533 const std::string script
= R
"(
534 if Request.Response.HTTPStatusCode == 200 then
535 assert(Request.Response.Message == "Life is great
")
537 assert(Request.Bucket)
538 assert(Request.Log() == 0)
542 auto store
= std::unique_ptr
<sal::RGWRadosStore
>(new sal::RGWRadosStore
);
543 store
->setRados(new RGWRados
);
544 auto olog
= std::unique_ptr
<OpsLogSocket
>(new OpsLogSocket(cct
, 1024));
545 ASSERT_TRUE(olog
->init(unix_socket_path
));
548 s
.err
.http_ret
= 200;
550 s
.err
.err_code
= "200OK";
551 s
.err
.message
= "Life is great";
557 s
.bucket
.reset(new sal::RGWRadosBucket(nullptr, b
));
558 s
.bucket_name
= "name";
559 s
.enable_ops_log
= true;
560 s
.enable_usage_log
= false;
561 s
.user
.reset(new TestRGWUser());
564 s
.cct
->_conf
->rgw_ops_log_rados
= false;
566 auto rc
= lua::request::execute(store
.get(), nullptr, olog
.get(), &s
, "put_obj", script
);
569 s
.err
.http_ret
= 400;
570 rc
= lua::request::execute(store
.get(), nullptr, olog
.get(), &s
, "put_obj", script
);
573 // give the socket client time to read
574 std::this_thread::sleep_for(std::chrono::seconds(5));
575 unix_socket_thread
.detach(); // read is stuck there, so we cannot join
576 EXPECT_TRUE(unix_socket_client_ended_ok
);