]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/rgw_lua_request.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / rgw / rgw_lua_request.cc
CommitLineData
f67539c2
TL
1#include <sstream>
2#include <stdexcept>
3#include <lua.hpp>
4#include "common/dout.h"
5#include "services/svc_zone.h"
6#include "rgw_lua_utils.h"
7#include "rgw_lua.h"
8#include "rgw_common.h"
9#include "rgw_log.h"
1e59de90
TL
10#include "rgw_op.h"
11#include "rgw_process_env.h"
f67539c2
TL
12#include "rgw_zone.h"
13#include "rgw_acl.h"
14#include "rgw_sal_rados.h"
1e59de90
TL
15#include "rgw_lua_background.h"
16#include "rgw_perf_counters.h"
f67539c2
TL
17
18#define dout_subsys ceph_subsys_rgw
19
20namespace rgw::lua::request {
21
22// closure that perform ops log action
23// e.g.
24// Request.Log()
25//
26constexpr const char* RequestLogAction{"Log"};
27
28int RequestLog(lua_State* L)
29{
1e59de90
TL
30 const auto rest = reinterpret_cast<RGWREST*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
31 const auto olog = reinterpret_cast<OpsLogSink*>(lua_touserdata(L, lua_upvalueindex(SECOND_UPVAL)));
32 const auto s = reinterpret_cast<req_state*>(lua_touserdata(L, lua_upvalueindex(THIRD_UPVAL)));
33 const auto op(reinterpret_cast<RGWOp*>(lua_touserdata(L, lua_upvalueindex(FOURTH_UPVAL))));
a4b75251 34 if (s) {
39ae355f 35 const auto rc = rgw_log_op(rest, s, op, olog);
f67539c2
TL
36 lua_pushinteger(L, rc);
37 } else {
a4b75251 38 ldpp_dout(s, 1) << "Lua ERROR: missing request state, cannot use ops log" << dendl;
f67539c2
TL
39 lua_pushinteger(L, -EINVAL);
40 }
41
42 return ONE_RETURNVAL;
43}
44
1e59de90
TL
45int SetAttribute(lua_State* L) {
46 auto s = reinterpret_cast<req_state*>(lua_touserdata(L, lua_upvalueindex(1)));
47
48 if (!s->trace || !s->trace->IsRecording()) {
49 return 0;
50 }
51
52 auto key = luaL_checkstring(L, 1);
53 int value_type = lua_type(L, 2);
54
55 switch (value_type) {
56 case LUA_TSTRING:
57 s->trace->SetAttribute(key, lua_tostring(L, 2));
58 break;
59
60 case LUA_TNUMBER:
61 if (lua_isinteger(L, 2)) {
62 s->trace->SetAttribute(key, static_cast<int64_t>(lua_tointeger(L, 2)));
63 } else {
64 s->trace->SetAttribute(key, static_cast<double>(lua_tonumber(L, 2)));
65 }
66 break;
67
68 default:
69 luaL_error(L, "unsupported value type for SetAttribute");
70 }
71 return 0;
72}
73
74int AddEvent(lua_State* L) {
75 auto s = reinterpret_cast<req_state*>(lua_touserdata(L, lua_upvalueindex(1)));
76
77 if (!s->trace || !s->trace->IsRecording()) {
78 return 0;
79 }
80
81 int args = lua_gettop(L);
82 if (args == 1) {
83 auto log = luaL_checkstring(L, 1);
84 s->trace->AddEvent(log);
85 } else if(args == 2) {
86 auto event_name = luaL_checkstring(L, 1);
87 std::unordered_map<const char*, jspan_attribute> event_values;
88 lua_pushnil(L);
89 while (lua_next(L, 2) != 0) {
90 if (lua_type(L, -2) != LUA_TSTRING) {
91 // skip pair if key is not a string
92 lua_pop(L, 1);
93 continue;
94 }
95
96 auto key = luaL_checkstring(L, -2);
97 int value_type = lua_type(L, -1);
98 switch (value_type) {
99 case LUA_TSTRING:
100 event_values.emplace(key, lua_tostring(L, -1));
101 break;
102
103 case LUA_TNUMBER:
104 if (lua_isinteger(L, -1)) {
105 event_values.emplace(key, static_cast<int64_t>(lua_tointeger(L, -1)));
106 } else {
107 event_values.emplace(key, static_cast<double>(lua_tonumber(L, -1)));
108 }
109 break;
110 }
111 lua_pop(L, 1);
112 }
113 lua_pop(L, 1);
114 s->trace->AddEvent(event_name, event_values);
115 }
116 return 0;
117}
118
f67539c2
TL
119struct ResponseMetaTable : public EmptyMetaTable {
120 static std::string TableName() {return "Response";}
121 static std::string Name() {return TableName() + "Meta";}
122
123 static int IndexClosure(lua_State* L) {
1e59de90 124 const auto err = reinterpret_cast<const rgw_err*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
f67539c2
TL
125
126 const char* index = luaL_checkstring(L, 2);
127
128 if (strcasecmp(index, "HTTPStatusCode") == 0) {
129 lua_pushinteger(L, err->http_ret);
130 } else if (strcasecmp(index, "RGWCode") == 0) {
131 lua_pushinteger(L, err->ret);
132 } else if (strcasecmp(index, "HTTPStatus") == 0) {
133 pushstring(L, err->err_code);
134 } else if (strcasecmp(index, "Message") == 0) {
135 pushstring(L, err->message);
136 } else {
20effc67 137 return error_unknown_field(L, index, TableName());
f67539c2
TL
138 }
139 return ONE_RETURNVAL;
140 }
141
142 static int NewIndexClosure(lua_State* L) {
1e59de90 143 auto err = reinterpret_cast<rgw_err*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
f67539c2
TL
144
145 const char* index = luaL_checkstring(L, 2);
146
147 if (strcasecmp(index, "HTTPStatusCode") == 0) {
148 err->http_ret = luaL_checkinteger(L, 3);
149 } else if (strcasecmp(index, "RGWCode") == 0) {
150 err->ret = luaL_checkinteger(L, 3);
151 } else if (strcasecmp(index, "HTTPStatus") == 0) {
152 err->err_code.assign(luaL_checkstring(L, 3));
153 } else if (strcasecmp(index, "Message") == 0) {
154 err->message.assign(luaL_checkstring(L, 3));
155 } else {
20effc67 156 return error_unknown_field(L, index, TableName());
f67539c2
TL
157 }
158 return NO_RETURNVAL;
159 }
160};
161
162struct QuotaMetaTable : public EmptyMetaTable {
163 static std::string TableName() {return "Quota";}
164 static std::string Name() {return TableName() + "Meta";}
165
166 static int IndexClosure(lua_State* L) {
1e59de90 167 const auto info = reinterpret_cast<RGWQuotaInfo*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
f67539c2
TL
168
169 const char* index = luaL_checkstring(L, 2);
170
171 if (strcasecmp(index, "MaxSize") == 0) {
172 lua_pushinteger(L, info->max_size);
173 } else if (strcasecmp(index, "MaxObjects") == 0) {
174 lua_pushinteger(L, info->max_objects);
175 } else if (strcasecmp(index, "Enabled") == 0) {
176 lua_pushboolean(L, info->enabled);
177 } else if (strcasecmp(index, "Rounded") == 0) {
178 lua_pushboolean(L, !info->check_on_raw);
179 } else {
20effc67 180 return error_unknown_field(L, index, TableName());
f67539c2
TL
181 }
182 return ONE_RETURNVAL;
183 }
184};
185
186struct PlacementRuleMetaTable : public EmptyMetaTable {
187 static std::string TableName() {return "PlacementRule";}
188 static std::string Name() {return TableName() + "Meta";}
189
190 static int IndexClosure(lua_State* L) {
1e59de90 191 const auto rule = reinterpret_cast<rgw_placement_rule*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
f67539c2
TL
192
193 const char* index = luaL_checkstring(L, 2);
194
195 if (strcasecmp(index, "Name") == 0) {
196 pushstring(L, rule->name);
197 } else if (strcasecmp(index, "StorageClass") == 0) {
198 pushstring(L, rule->storage_class);
199 } else {
20effc67 200 return error_unknown_field(L, index, TableName());
f67539c2
TL
201 }
202 return ONE_RETURNVAL;
203 }
204};
205
206struct UserMetaTable : public EmptyMetaTable {
207 static std::string TableName() {return "User";}
208 static std::string Name() {return TableName() + "Meta";}
209
210 static int IndexClosure(lua_State* L) {
1e59de90 211 const auto user = reinterpret_cast<const rgw_user*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
f67539c2
TL
212
213 const char* index = luaL_checkstring(L, 2);
214
215 if (strcasecmp(index, "Tenant") == 0) {
216 pushstring(L, user->tenant);
217 } else if (strcasecmp(index, "Id") == 0) {
218 pushstring(L, user->id);
219 } else {
20effc67 220 return error_unknown_field(L, index, TableName());
f67539c2
TL
221 }
222 return ONE_RETURNVAL;
223 }
224};
225
1e59de90
TL
226struct TraceMetaTable : public EmptyMetaTable {
227 static std::string TableName() {return "Trace";}
228 static std::string Name() {return TableName() + "Meta";}
229
230 static int IndexClosure(lua_State* L) {
231 const auto s = reinterpret_cast<req_state*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
232
233 const char* index = luaL_checkstring(L, 2);
234
235 if (strcasecmp(index, "Enable") == 0) {
236 lua_pushboolean(L, s->trace_enabled);
237 } else if(strcasecmp(index, "SetAttribute") == 0) {
238 lua_pushlightuserdata(L, s);
239 lua_pushcclosure(L, SetAttribute, ONE_UPVAL);
240 } else if(strcasecmp(index, "AddEvent") == 0) {
241 lua_pushlightuserdata(L, s);
242 lua_pushcclosure(L, AddEvent, ONE_UPVAL);
243 } else {
244 return error_unknown_field(L, index, TableName());
245 }
246 return ONE_RETURNVAL;
247 }
248
249 static int NewIndexClosure(lua_State* L) {
250 const auto s = reinterpret_cast<req_state*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
251
252 const char* index = luaL_checkstring(L, 2);
253
254 if (strcasecmp(index, "Enable") == 0) {
255 s->trace_enabled = lua_toboolean(L, 3);
256 } else {
257 return error_unknown_field(L, index, TableName());
258 }
259 return NO_RETURNVAL;
260 }
261};
262
f67539c2
TL
263struct OwnerMetaTable : public EmptyMetaTable {
264 static std::string TableName() {return "Owner";}
265 static std::string Name() {return TableName() + "Meta";}
266
267 static int IndexClosure(lua_State* L) {
1e59de90 268 const auto owner = reinterpret_cast<ACLOwner*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
f67539c2
TL
269
270 const char* index = luaL_checkstring(L, 2);
271
272 if (strcasecmp(index, "DisplayName") == 0) {
273 pushstring(L, owner->get_display_name());
274 } else if (strcasecmp(index, "User") == 0) {
275 create_metatable<UserMetaTable>(L, false, &(owner->get_id()));
276 } else {
20effc67 277 return error_unknown_field(L, index, TableName());
f67539c2
TL
278 }
279 return ONE_RETURNVAL;
280 }
281};
282
283struct BucketMetaTable : public EmptyMetaTable {
284 static std::string TableName() {return "Bucket";}
285 static std::string Name() {return TableName() + "Meta";}
286
f67539c2 287 static int IndexClosure(lua_State* L) {
1e59de90
TL
288 const auto s = reinterpret_cast<req_state*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
289 const auto bucket = s->bucket.get();
f67539c2
TL
290
291 const char* index = luaL_checkstring(L, 2);
292
1e59de90
TL
293 if (rgw::sal::Bucket::empty(bucket)) {
294 if (strcasecmp(index, "Name") == 0) {
295 pushstring(L, s->init_state.url_bucket);
296 } else {
297 lua_pushnil(L);
298 }
299 } else if (strcasecmp(index, "Tenant") == 0) {
f67539c2
TL
300 pushstring(L, bucket->get_tenant());
301 } else if (strcasecmp(index, "Name") == 0) {
302 pushstring(L, bucket->get_name());
303 } else if (strcasecmp(index, "Marker") == 0) {
304 pushstring(L, bucket->get_marker());
305 } else if (strcasecmp(index, "Id") == 0) {
306 pushstring(L, bucket->get_bucket_id());
307 } else if (strcasecmp(index, "Count") == 0) {
308 lua_pushinteger(L, bucket->get_count());
309 } else if (strcasecmp(index, "Size") == 0) {
310 lua_pushinteger(L, bucket->get_size());
311 } else if (strcasecmp(index, "ZoneGroupId") == 0) {
312 pushstring(L, bucket->get_info().zonegroup);
313 } else if (strcasecmp(index, "CreationTime") == 0) {
314 pushtime(L, bucket->get_creation_time());
315 } else if (strcasecmp(index, "MTime") == 0) {
316 pushtime(L, bucket->get_modification_time());
317 } else if (strcasecmp(index, "Quota") == 0) {
318 create_metatable<QuotaMetaTable>(L, false, &(bucket->get_info().quota));
319 } else if (strcasecmp(index, "PlacementRule") == 0) {
320 create_metatable<PlacementRuleMetaTable>(L, false, &(bucket->get_info().placement_rule));
321 } else if (strcasecmp(index, "User") == 0) {
322 create_metatable<UserMetaTable>(L, false, &(bucket->get_info().owner));
323 } else {
20effc67 324 return error_unknown_field(L, index, TableName());
f67539c2
TL
325 }
326 return ONE_RETURNVAL;
327 }
1e59de90
TL
328
329 static int NewIndexClosure(lua_State* L) {
330 const auto s = reinterpret_cast<req_state*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
331 const auto bucket = s->bucket.get();
332
333 const char* index = luaL_checkstring(L, 2);
334
335 if (rgw::sal::Bucket::empty(bucket)) {
336 if (strcasecmp(index, "Name") == 0) {
337 s->init_state.url_bucket = luaL_checkstring(L, 3);
338 return NO_RETURNVAL;
339 }
340 }
341 return error_unknown_field(L, index, TableName());
342 }
f67539c2
TL
343};
344
345struct ObjectMetaTable : public EmptyMetaTable {
346 static const std::string TableName() {return "Object";}
347 static std::string Name() {return TableName() + "Meta";}
348
20effc67 349 using Type = rgw::sal::Object;
f67539c2
TL
350
351 static int IndexClosure(lua_State* L) {
1e59de90 352 const auto obj = reinterpret_cast<const Type*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
f67539c2
TL
353
354 const char* index = luaL_checkstring(L, 2);
355
356 if (strcasecmp(index, "Name") == 0) {
357 pushstring(L, obj->get_name());
358 } else if (strcasecmp(index, "Instance") == 0) {
359 pushstring(L, obj->get_instance());
360 } else if (strcasecmp(index, "Id") == 0) {
361 pushstring(L, obj->get_oid());
362 } else if (strcasecmp(index, "Size") == 0) {
363 lua_pushinteger(L, obj->get_obj_size());
364 } else if (strcasecmp(index, "MTime") == 0) {
365 pushtime(L, obj->get_mtime());
366 } else {
20effc67 367 return error_unknown_field(L, index, TableName());
f67539c2
TL
368 }
369 return ONE_RETURNVAL;
370 }
371};
372
f67539c2
TL
373struct GrantMetaTable : public EmptyMetaTable {
374 static std::string TableName() {return "Grant";}
375 static std::string Name() {return TableName() + "Meta";}
376
377 static int IndexClosure(lua_State* L) {
1e59de90 378 const auto grant = reinterpret_cast<ACLGrant*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
f67539c2
TL
379
380 const char* index = luaL_checkstring(L, 2);
381
382 if (strcasecmp(index, "Type") == 0) {
383 lua_pushinteger(L, grant->get_type().get_type());
384 } else if (strcasecmp(index, "User") == 0) {
385 const auto id_ptr = grant->get_id();
386 if (id_ptr) {
387 create_metatable<UserMetaTable>(L, false, const_cast<rgw_user*>(id_ptr));
388 } else {
389 lua_pushnil(L);
390 }
391 } else if (strcasecmp(index, "Permission") == 0) {
392 lua_pushinteger(L, grant->get_permission().get_permissions());
393 } else if (strcasecmp(index, "GroupType") == 0) {
394 lua_pushinteger(L, grant->get_group());
395 } else if (strcasecmp(index, "Referer") == 0) {
396 pushstring(L, grant->get_referer());
397 } else {
20effc67 398 return error_unknown_field(L, index, TableName());
f67539c2
TL
399 }
400 return ONE_RETURNVAL;
401 }
402};
403
404struct GrantsMetaTable : public EmptyMetaTable {
405 static std::string TableName() {return "Grants";}
406 static std::string Name() {return TableName() + "Meta";}
407
408 static int IndexClosure(lua_State* L) {
1e59de90 409 const auto map = reinterpret_cast<ACLGrantMap*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
f67539c2
TL
410
411 const char* index = luaL_checkstring(L, 2);
412
413 const auto it = map->find(std::string(index));
414 if (it == map->end()) {
415 lua_pushnil(L);
416 } else {
417 create_metatable<GrantMetaTable>(L, false, &(it->second));
418 }
419 return ONE_RETURNVAL;
420 }
421
422 static int PairsClosure(lua_State* L) {
1e59de90 423 auto map = reinterpret_cast<ACLGrantMap*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
f67539c2
TL
424 ceph_assert(map);
425 lua_pushlightuserdata(L, map);
426 lua_pushcclosure(L, stateless_iter, ONE_UPVAL); // push the stateless iterator function
427 lua_pushnil(L); // indicate this is the first call
428 // return stateless_iter, nil
429
430 return TWO_RETURNVALS;
431 }
432
433 static int stateless_iter(lua_State* L) {
434 // based on: http://lua-users.org/wiki/GeneralizedPairsAndIpairs
1e59de90 435 auto map = reinterpret_cast<ACLGrantMap*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
f67539c2
TL
436 ACLGrantMap::iterator next_it;
437 if (lua_isnil(L, -1)) {
438 next_it = map->begin();
439 } else {
440 const char* index = luaL_checkstring(L, 2);
441 const auto it = map->find(std::string(index));
442 ceph_assert(it != map->end());
443 next_it = std::next(it);
444 }
445
446 if (next_it == map->end()) {
447 // index of the last element was provided
448 lua_pushnil(L);
449 lua_pushnil(L);
450 return TWO_RETURNVALS;
451 // return nil, nil
452 }
453
454 while (next_it->first.empty()) {
455 // this is a multimap and the next element does not have a unique key
456 ++next_it;
457 if (next_it == map->end()) {
458 // index of the last element was provided
459 lua_pushnil(L);
460 lua_pushnil(L);
461 return TWO_RETURNVALS;
462 // return nil, nil
463 }
464 }
465
466 pushstring(L, next_it->first);
467 create_metatable<GrantMetaTable>(L, false, &(next_it->second));
468 // return key, value
469
470 return TWO_RETURNVALS;
471 }
472
473 static int LenClosure(lua_State* L) {
1e59de90 474 const auto map = reinterpret_cast<ACLGrantMap*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
f67539c2
TL
475
476 lua_pushinteger(L, map->size());
477
478 return ONE_RETURNVAL;
479 }
480};
481
482struct ACLMetaTable : public EmptyMetaTable {
483 static std::string TableName() {return "ACL";}
484 static std::string Name() {return TableName() + "Meta";}
485
486 using Type = RGWAccessControlPolicy;
487
488 static int IndexClosure(lua_State* L) {
1e59de90 489 const auto acl = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
f67539c2
TL
490
491 const char* index = luaL_checkstring(L, 2);
492
493 if (strcasecmp(index, "Owner") == 0) {
494 create_metatable<OwnerMetaTable>(L, false, &(acl->get_owner()));
495 } else if (strcasecmp(index, "Grants") == 0) {
496 create_metatable<GrantsMetaTable>(L, false, &(acl->get_acl().get_grant_map()));
497 } else {
20effc67 498 return error_unknown_field(L, index, TableName());
f67539c2
TL
499 }
500 return ONE_RETURNVAL;
501 }
502};
503
504struct StatementsMetaTable : public EmptyMetaTable {
505 static std::string TableName() {return "Statements";}
506 static std::string Name() {return TableName() + "Meta";}
507
508 using Type = std::vector<rgw::IAM::Statement>;
509
510 static std::string statement_to_string(const rgw::IAM::Statement& statement) {
511 std::stringstream ss;
512 ss << statement;
513 return ss.str();
514 }
515
516 static int IndexClosure(lua_State* L) {
1e59de90 517 const auto statements = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
f67539c2
TL
518
519 const auto index = luaL_checkinteger(L, 2);
520
521 if (index >= (int)statements->size() || index < 0) {
522 lua_pushnil(L);
523 } else {
524 // TODO: policy language could be interpreted to lua and executed as such
525 pushstring(L, statement_to_string((*statements)[index]));
526 }
527 return ONE_RETURNVAL;
528 }
529
530 static int PairsClosure(lua_State* L) {
1e59de90 531 auto statements = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
f67539c2
TL
532 ceph_assert(statements);
533 lua_pushlightuserdata(L, statements);
534 lua_pushcclosure(L, stateless_iter, ONE_UPVAL); // push the stateless iterator function
535 lua_pushnil(L); // indicate this is the first call
536 // return stateless_iter, nil
537
538 return TWO_RETURNVALS;
539 }
540
541 static int stateless_iter(lua_State* L) {
1e59de90 542 auto statements = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
f67539c2
TL
543 size_t next_it;
544 if (lua_isnil(L, -1)) {
545 next_it = 0;
546 } else {
547 const auto it = luaL_checkinteger(L, -1);
548 next_it = it+1;
549 }
550
551 if (next_it >= statements->size()) {
552 // index of the last element was provided
553 lua_pushnil(L);
554 lua_pushnil(L);
555 // return nil, nil
556 } else {
557 lua_pushinteger(L, next_it);
558 pushstring(L, statement_to_string((*statements)[next_it]));
559 // return key, value
560 }
561
562 return TWO_RETURNVALS;
563 }
564
565 static int LenClosure(lua_State* L) {
1e59de90 566 const auto statements = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
f67539c2
TL
567
568 lua_pushinteger(L, statements->size());
569
570 return ONE_RETURNVAL;
571 }
572};
573
574struct PolicyMetaTable : public EmptyMetaTable {
575 static std::string TableName() {return "Policy";}
576 static std::string Name() {return TableName() + "Meta";}
577
578 static int IndexClosure(lua_State* L) {
1e59de90 579 const auto policy = reinterpret_cast<rgw::IAM::Policy*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
f67539c2
TL
580
581 const char* index = luaL_checkstring(L, 2);
582
583 if (strcasecmp(index, "Text") == 0) {
584 pushstring(L, policy->text);
585 } else if (strcasecmp(index, "Id") == 0) {
586 // TODO create pushstring for std::unique_ptr
587 if (!policy->id) {
588 lua_pushnil(L);
589 } else {
590 pushstring(L, policy->id.get());
591 }
592 } else if (strcasecmp(index, "Statements") == 0) {
1e59de90 593 create_metatable<StatementsMetaTable>(L, false, &(policy->statements));
f67539c2 594 } else {
20effc67 595 return error_unknown_field(L, index, TableName());
f67539c2
TL
596 }
597 return ONE_RETURNVAL;
598 }
599};
600
601struct PoliciesMetaTable : public EmptyMetaTable {
602 static std::string TableName() {return "Policies";}
603 static std::string Name() {return TableName() + "Meta";}
604
605 using Type = std::vector<rgw::IAM::Policy>;
606
607 static int IndexClosure(lua_State* L) {
1e59de90 608 const auto policies = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
f67539c2
TL
609
610 const auto index = luaL_checkinteger(L, 2);
611
612 if (index >= (int)policies->size() || index < 0) {
613 lua_pushnil(L);
614 } else {
615 create_metatable<PolicyMetaTable>(L, false, &((*policies)[index]));
616 }
617 return ONE_RETURNVAL;
618 }
619
620 static int PairsClosure(lua_State* L) {
1e59de90 621 auto policies = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
f67539c2
TL
622 ceph_assert(policies);
623 lua_pushlightuserdata(L, policies);
624 lua_pushcclosure(L, stateless_iter, ONE_UPVAL); // push the stateless iterator function
625 lua_pushnil(L); // indicate this is the first call
626 // return stateless_iter, nil
627
628 return TWO_RETURNVALS;
629 }
630
631 static int stateless_iter(lua_State* L) {
1e59de90 632 auto policies = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
f67539c2
TL
633 size_t next_it;
634 if (lua_isnil(L, -1)) {
635 next_it = 0;
636 } else {
637 ceph_assert(lua_isinteger(L, -1));
638 const auto it = luaL_checkinteger(L, -1);
639 next_it = it+1;
640 }
641
642 if (next_it >= policies->size()) {
643 // index of the last element was provided
644 lua_pushnil(L);
645 lua_pushnil(L);
646 // return nil, nil
647 } else {
648 lua_pushinteger(L, next_it);
649 create_metatable<PolicyMetaTable>(L, false, &((*policies)[next_it]));
650 // return key, value
651 }
652
653 return TWO_RETURNVALS;
654 }
655
656 static int LenClosure(lua_State* L) {
1e59de90 657 const auto policies = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
f67539c2
TL
658
659 lua_pushinteger(L, policies->size());
660
661 return ONE_RETURNVAL;
662 }
663};
664
665struct HTTPMetaTable : public EmptyMetaTable {
666 static std::string TableName() {return "HTTP";}
667 static std::string Name() {return TableName() + "Meta";}
668
669 static int IndexClosure(lua_State* L) {
1e59de90 670 const auto info = reinterpret_cast<req_info*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
f67539c2
TL
671
672 const char* index = luaL_checkstring(L, 2);
673
674 if (strcasecmp(index, "Parameters") == 0) {
675 create_metatable<StringMapMetaTable<>>(L, false, &(info->args.get_params()));
676 } else if (strcasecmp(index, "Resources") == 0) {
677 // TODO: add non-const api to get resources
678 create_metatable<StringMapMetaTable<>>(L, false,
679 const_cast<std::map<std::string, std::string>*>(&(info->args.get_sub_resources())));
680 } else if (strcasecmp(index, "Metadata") == 0) {
681 create_metatable<StringMapMetaTable<meta_map_t, StringMapWriteableNewIndex<meta_map_t>>>(L, false, &(info->x_meta_map));
682 } else if (strcasecmp(index, "Host") == 0) {
683 pushstring(L, info->host);
684 } else if (strcasecmp(index, "Method") == 0) {
685 pushstring(L, info->method);
686 } else if (strcasecmp(index, "URI") == 0) {
687 pushstring(L, info->request_uri);
688 } else if (strcasecmp(index, "QueryString") == 0) {
689 pushstring(L, info->request_params);
690 } else if (strcasecmp(index, "Domain") == 0) {
691 pushstring(L, info->domain);
20effc67
TL
692 } else if (strcasecmp(index, "StorageClass") == 0) {
693 pushstring(L, info->storage_class);
f67539c2 694 } else {
20effc67 695 return error_unknown_field(L, index, TableName());
f67539c2
TL
696 }
697 return ONE_RETURNVAL;
698 }
20effc67
TL
699
700 static int NewIndexClosure(lua_State* L) {
1e59de90 701 auto info = reinterpret_cast<req_info*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
20effc67
TL
702
703 const char* index = luaL_checkstring(L, 2);
704
705 if (strcasecmp(index, "StorageClass") == 0) {
706 info->storage_class = luaL_checkstring(L, 3);
707 } else {
708 return error_unknown_field(L, index, TableName());
709 }
710 return NO_RETURNVAL;
711 }
f67539c2
TL
712};
713
714struct CopyFromMetaTable : public EmptyMetaTable {
715 static std::string TableName() {return "CopyFrom";}
716 static std::string Name() {return TableName() + "Meta";}
717
718 static int IndexClosure(lua_State* L) {
1e59de90 719 const auto s = reinterpret_cast<req_state*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
f67539c2
TL
720
721 const char* index = luaL_checkstring(L, 2);
722
723 if (strcasecmp(index, "Tenant") == 0) {
724 pushstring(L, s->src_tenant_name);
725 } else if (strcasecmp(index, "Bucket") == 0) {
726 pushstring(L, s->src_bucket_name);
727 } else if (strcasecmp(index, "Object") == 0) {
728 create_metatable<ObjectMetaTable>(L, false, s->src_object);
729 } else {
20effc67 730 return error_unknown_field(L, index, TableName());
f67539c2
TL
731 }
732 return ONE_RETURNVAL;
733 }
734};
735
736struct ZoneGroupMetaTable : public EmptyMetaTable {
737 static std::string TableName() {return "ZoneGroup";}
738 static std::string Name() {return TableName() + "Meta";}
739
740 static int IndexClosure(lua_State* L) {
1e59de90 741 const auto s = reinterpret_cast<req_state*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
f67539c2
TL
742
743 const char* index = luaL_checkstring(L, 2);
744
745 if (strcasecmp(index, "Name") == 0) {
746 pushstring(L, s->zonegroup_name);
747 } else if (strcasecmp(index, "Endpoint") == 0) {
748 pushstring(L, s->zonegroup_endpoint);
749 } else {
20effc67 750 return error_unknown_field(L, index, TableName());
f67539c2
TL
751 }
752 return ONE_RETURNVAL;
753 }
754};
755
756struct RequestMetaTable : public EmptyMetaTable {
757 static std::string TableName() {return "Request";}
758 static std::string Name() {return TableName() + "Meta";}
759
760 // __index closure that expect req_state to be captured
761 static int IndexClosure(lua_State* L) {
1e59de90
TL
762 const auto s = reinterpret_cast<req_state*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
763 const auto op_name = reinterpret_cast<const char*>(lua_touserdata(L, lua_upvalueindex(SECOND_UPVAL)));
f67539c2
TL
764
765 const char* index = luaL_checkstring(L, 2);
766
767 if (strcasecmp(index, "RGWOp") == 0) {
768 pushstring(L, op_name);
769 } else if (strcasecmp(index, "DecodedURI") == 0) {
770 pushstring(L, s->decoded_uri);
771 } else if (strcasecmp(index, "ContentLength") == 0) {
772 lua_pushinteger(L, s->content_length);
773 } else if (strcasecmp(index, "GenericAttributes") == 0) {
774 create_metatable<StringMapMetaTable<>>(L, false, &(s->generic_attrs));
775 } else if (strcasecmp(index, "Response") == 0) {
776 create_metatable<ResponseMetaTable>(L, false, &(s->err));
777 } else if (strcasecmp(index, "SwiftAccountName") == 0) {
778 if (s->dialect == "swift") {
779 pushstring(L, s->account_name);
780 } else {
781 lua_pushnil(L);
782 }
783 } else if (strcasecmp(index, "Bucket") == 0) {
1e59de90 784 create_metatable<BucketMetaTable>(L, false, s);
f67539c2
TL
785 } else if (strcasecmp(index, "Object") == 0) {
786 create_metatable<ObjectMetaTable>(L, false, s->object);
787 } else if (strcasecmp(index, "CopyFrom") == 0) {
788 if (s->op_type == RGW_OP_COPY_OBJ) {
789 create_metatable<CopyFromMetaTable>(L, s);
790 } else {
791 lua_pushnil(L);
792 }
793 } else if (strcasecmp(index, "ObjectOwner") == 0) {
794 create_metatable<OwnerMetaTable>(L, false, &(s->owner));
795 } else if (strcasecmp(index, "ZoneGroup") == 0) {
796 create_metatable<ZoneGroupMetaTable>(L, false, s);
797 } else if (strcasecmp(index, "UserACL") == 0) {
798 create_metatable<ACLMetaTable>(L, false, s->user_acl);
799 } else if (strcasecmp(index, "BucketACL") == 0) {
800 create_metatable<ACLMetaTable>(L, false, s->bucket_acl);
801 } else if (strcasecmp(index, "ObjectACL") == 0) {
802 create_metatable<ACLMetaTable>(L, false, s->object_acl);
803 } else if (strcasecmp(index, "Environment") == 0) {
804 create_metatable<StringMapMetaTable<rgw::IAM::Environment>>(L, false, &(s->env));
805 } else if (strcasecmp(index, "Policy") == 0) {
806 // TODO: create a wrapper to std::optional
807 if (!s->iam_policy) {
808 lua_pushnil(L);
809 } else {
810 create_metatable<PolicyMetaTable>(L, false, s->iam_policy.get_ptr());
811 }
812 } else if (strcasecmp(index, "UserPolicies") == 0) {
813 create_metatable<PoliciesMetaTable>(L, false, &(s->iam_user_policies));
814 } else if (strcasecmp(index, "RGWId") == 0) {
815 pushstring(L, s->host_id);
816 } else if (strcasecmp(index, "HTTP") == 0) {
817 create_metatable<HTTPMetaTable>(L, false, &(s->info));
818 } else if (strcasecmp(index, "Time") == 0) {
819 pushtime(L, s->time);
820 } else if (strcasecmp(index, "Dialect") == 0) {
821 pushstring(L, s->dialect);
822 } else if (strcasecmp(index, "Id") == 0) {
823 pushstring(L, s->req_id);
824 } else if (strcasecmp(index, "TransactionId") == 0) {
825 pushstring(L, s->trans_id);
826 } else if (strcasecmp(index, "Tags") == 0) {
827 create_metatable<StringMapMetaTable<RGWObjTags::tag_map_t>>(L, false, &(s->tagset.get_tags()));
20effc67
TL
828 } else if (strcasecmp(index, "User") == 0) {
829 if (!s->user) {
830 lua_pushnil(L);
831 } else {
832 create_metatable<UserMetaTable>(L, false, const_cast<rgw_user*>(&(s->user->get_id())));
833 }
1e59de90
TL
834 } else if (strcasecmp(index, "Trace") == 0) {
835 create_metatable<TraceMetaTable>(L, false, s);
f67539c2 836 } else {
20effc67 837 return error_unknown_field(L, index, TableName());
f67539c2
TL
838 }
839 return ONE_RETURNVAL;
840 }
841};
842
1e59de90
TL
843void create_top_metatable(lua_State* L, req_state* s, const char* op_name) {
844 create_metatable<RequestMetaTable>(L, true, s, const_cast<char*>(op_name));
845 lua_getglobal(L, RequestMetaTable::TableName().c_str());
846 ceph_assert(lua_istable(L, -1));
847}
848
f67539c2 849int execute(
1e59de90 850 rgw::sal::Driver* driver,
f67539c2 851 RGWREST* rest,
a4b75251 852 OpsLogSink* olog,
f67539c2 853 req_state* s,
39ae355f 854 RGWOp* op,
f67539c2 855 const std::string& script)
f67539c2
TL
856{
857 auto L = luaL_newstate();
39ae355f 858 const char* op_name = op ? op->name() : "Unknown";
f67539c2
TL
859 lua_state_guard lguard(L);
860
861 open_standard_libs(L);
1e59de90 862 set_package_path(L, s->penv.lua.luarocks_path);
f67539c2
TL
863
864 create_debug_action(L, s->cct);
f67539c2 865
1e59de90
TL
866 create_metatable<RequestMetaTable>(L, true, s, const_cast<char*>(op_name));
867
f67539c2
TL
868 lua_getglobal(L, RequestMetaTable::TableName().c_str());
869 ceph_assert(lua_istable(L, -1));
1e59de90
TL
870
871 // add the ops log action
f67539c2 872 pushstring(L, RequestLogAction);
f67539c2
TL
873 lua_pushlightuserdata(L, rest);
874 lua_pushlightuserdata(L, olog);
875 lua_pushlightuserdata(L, s);
39ae355f 876 lua_pushlightuserdata(L, op);
a4b75251 877 lua_pushcclosure(L, RequestLog, FOUR_UPVALS);
f67539c2 878 lua_rawset(L, -3);
1e59de90
TL
879
880 if (s->penv.lua.background) {
881 s->penv.lua.background->create_background_metatable(L);
882 lua_getglobal(L, rgw::lua::RGWTable::TableName().c_str());
883 ceph_assert(lua_istable(L, -1));
884 }
f67539c2 885
1e59de90 886 int rc = 0;
f67539c2
TL
887 try {
888 // execute the lua script
889 if (luaL_dostring(L, script.c_str()) != LUA_OK) {
890 const std::string err(lua_tostring(L, -1));
b3b6e05e 891 ldpp_dout(s, 1) << "Lua ERROR: " << err << dendl;
1e59de90 892 rc = -1;
f67539c2
TL
893 }
894 } catch (const std::runtime_error& e) {
b3b6e05e 895 ldpp_dout(s, 1) << "Lua ERROR: " << e.what() << dendl;
1e59de90
TL
896 rc = -1;
897 }
898 if (perfcounter) {
899 perfcounter->inc((rc == -1 ? l_rgw_lua_script_fail : l_rgw_lua_script_ok), 1);
f67539c2
TL
900 }
901
1e59de90 902 return rc;
f67539c2
TL
903}
904
1e59de90
TL
905} // namespace rgw::lua::request
906