]> git.proxmox.com Git - ceph.git/blob - ceph/src/rgw/rgw_admin.cc
update ceph source to reef 18.2.1
[ceph.git] / ceph / src / rgw / rgw_admin.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
3
4 #include <errno.h>
5 #include <iostream>
6 #include <sstream>
7 #include <string>
8
9 #include <boost/asio.hpp>
10 #include <boost/optional.hpp>
11
12 extern "C" {
13 #include <liboath/oath.h>
14 }
15
16 #include <fmt/format.h>
17
18 #include "auth/Crypto.h"
19 #include "compressor/Compressor.h"
20
21 #include "common/armor.h"
22 #include "common/ceph_json.h"
23 #include "common/config.h"
24 #include "common/ceph_argparse.h"
25 #include "common/Formatter.h"
26 #include "common/errno.h"
27 #include "common/safe_io.h"
28 #include "common/fault_injector.h"
29
30 #include "include/util.h"
31
32 #include "cls/rgw/cls_rgw_types.h"
33 #include "cls/rgw/cls_rgw_client.h"
34
35 #include "include/utime.h"
36 #include "include/str_list.h"
37
38 #include "rgw_user.h"
39 #include "rgw_otp.h"
40 #include "rgw_rados.h"
41 #include "rgw_acl.h"
42 #include "rgw_acl_s3.h"
43 #include "rgw_datalog.h"
44 #include "rgw_lc.h"
45 #include "rgw_log.h"
46 #include "rgw_formats.h"
47 #include "rgw_usage.h"
48 #include "rgw_orphan.h"
49 #include "rgw_sync.h"
50 #include "rgw_trim_bilog.h"
51 #include "rgw_trim_datalog.h"
52 #include "rgw_trim_mdlog.h"
53 #include "rgw_data_sync.h"
54 #include "rgw_rest_conn.h"
55 #include "rgw_realm_watcher.h"
56 #include "rgw_role.h"
57 #include "rgw_reshard.h"
58 #include "rgw_http_client_curl.h"
59 #include "rgw_zone.h"
60 #include "rgw_pubsub.h"
61 #include "rgw_bucket_sync.h"
62 #include "rgw_sync_checkpoint.h"
63 #include "rgw_lua.h"
64 #include "rgw_sal.h"
65 #include "rgw_sal_config.h"
66
67 #include "services/svc_sync_modules.h"
68 #include "services/svc_cls.h"
69 #include "services/svc_bilog_rados.h"
70 #include "services/svc_mdlog.h"
71 #include "services/svc_meta_be_otp.h"
72 #include "services/svc_user.h"
73 #include "services/svc_zone.h"
74
75 #include "driver/rados/rgw_bucket.h"
76 #include "driver/rados/rgw_sal_rados.h"
77
78 #define dout_context g_ceph_context
79
80 #define SECRET_KEY_LEN 40
81 #define PUBLIC_ID_LEN 20
82
83 using namespace std;
84
85 static rgw::sal::Driver* driver = NULL;
86 static constexpr auto dout_subsys = ceph_subsys_rgw;
87
88
89 static const DoutPrefixProvider* dpp() {
90 struct GlobalPrefix : public DoutPrefixProvider {
91 CephContext *get_cct() const override { return dout_context; }
92 unsigned get_subsys() const override { return dout_subsys; }
93 std::ostream& gen_prefix(std::ostream& out) const override { return out; }
94 };
95 static GlobalPrefix global_dpp;
96 return &global_dpp;
97 }
98
99 #define CHECK_TRUE(x, msg, err) \
100 do { \
101 if (!x) { \
102 cerr << msg << std::endl; \
103 return err; \
104 } \
105 } while (0)
106
107 #define CHECK_SUCCESS(x, msg) \
108 do { \
109 int _x_val = (x); \
110 if (_x_val < 0) { \
111 cerr << msg << ": " << cpp_strerror(-_x_val) << std::endl; \
112 return _x_val; \
113 } \
114 } while (0)
115
116 static inline int posix_errortrans(int r)
117 {
118 switch(r) {
119 case ERR_NO_SUCH_BUCKET:
120 r = ENOENT;
121 break;
122 default:
123 break;
124 }
125 return r;
126 }
127
128
129 static const std::string LUA_CONTEXT_LIST("prerequest, postrequest, background, getdata, putdata");
130
131 void usage()
132 {
133 cout << "usage: radosgw-admin <cmd> [options...]" << std::endl;
134 cout << "commands:\n";
135 cout << " user create create a new user\n" ;
136 cout << " user modify modify user\n";
137 cout << " user info get user info\n";
138 cout << " user rename rename user\n";
139 cout << " user rm remove user\n";
140 cout << " user suspend suspend a user\n";
141 cout << " user enable re-enable user after suspension\n";
142 cout << " user check check user info\n";
143 cout << " user stats show user stats as accounted by quota subsystem\n";
144 cout << " user list list users\n";
145 cout << " caps add add user capabilities\n";
146 cout << " caps rm remove user capabilities\n";
147 cout << " subuser create create a new subuser\n" ;
148 cout << " subuser modify modify subuser\n";
149 cout << " subuser rm remove subuser\n";
150 cout << " key create create access key\n";
151 cout << " key rm remove access key\n";
152 cout << " bucket list list buckets (specify --allow-unordered for\n";
153 cout << " faster, unsorted listing)\n";
154 cout << " bucket limit check show bucket sharding stats\n";
155 cout << " bucket link link bucket to specified user\n";
156 cout << " bucket unlink unlink bucket from specified user\n";
157 cout << " bucket stats returns bucket statistics\n";
158 cout << " bucket rm remove bucket\n";
159 cout << " bucket check check bucket index by verifying size and object count stats\n";
160 cout << " bucket check olh check for olh index entries and objects that are pending removal\n";
161 cout << " bucket check unlinked check for object versions that are not visible in a bucket listing \n";
162 cout << " bucket chown link bucket to specified user and update its object ACLs\n";
163 cout << " bucket reshard reshard bucket\n";
164 cout << " bucket rewrite rewrite all objects in the specified bucket\n";
165 cout << " bucket sync checkpoint poll a bucket's sync status until it catches up to its remote\n";
166 cout << " bucket sync disable disable bucket sync\n";
167 cout << " bucket sync enable enable bucket sync\n";
168 cout << " bucket radoslist list rados objects backing bucket's objects\n";
169 cout << " bi get retrieve bucket index object entries\n";
170 cout << " bi put store bucket index object entries\n";
171 cout << " bi list list raw bucket index entries\n";
172 cout << " bi purge purge bucket index entries\n";
173 cout << " object rm remove object\n";
174 cout << " object put put object\n";
175 cout << " object stat stat an object for its metadata\n";
176 cout << " object unlink unlink object from bucket index\n";
177 cout << " object rewrite rewrite the specified object\n";
178 cout << " object reindex reindex the object(s) indicated by --bucket and either --object or --objects-file\n";
179 cout << " objects expire run expired objects cleanup\n";
180 cout << " objects expire-stale list list stale expired objects (caused by reshard)\n";
181 cout << " objects expire-stale rm remove stale expired objects\n";
182 cout << " period rm remove a period\n";
183 cout << " period get get period info\n";
184 cout << " period get-current get current period info\n";
185 cout << " period pull pull a period\n";
186 cout << " period push push a period\n";
187 cout << " period list list all periods\n";
188 cout << " period update update the staging period\n";
189 cout << " period commit commit the staging period\n";
190 cout << " quota set set quota params\n";
191 cout << " quota enable enable quota\n";
192 cout << " quota disable disable quota\n";
193 cout << " ratelimit get get ratelimit params\n";
194 cout << " ratelimit set set ratelimit params\n";
195 cout << " ratelimit enable enable ratelimit\n";
196 cout << " ratelimit disable disable ratelimit\n";
197 cout << " global quota get view global quota params\n";
198 cout << " global quota set set global quota params\n";
199 cout << " global quota enable enable a global quota\n";
200 cout << " global quota disable disable a global quota\n";
201 cout << " global ratelimit get view global ratelimit params\n";
202 cout << " global ratelimit set set global ratelimit params\n";
203 cout << " global ratelimit enable enable a ratelimit quota\n";
204 cout << " global ratelimit disable disable a ratelimit quota\n";
205 cout << " realm create create a new realm\n";
206 cout << " realm rm remove a realm\n";
207 cout << " realm get show realm info\n";
208 cout << " realm get-default get default realm name\n";
209 cout << " realm list list realms\n";
210 cout << " realm list-periods list all realm periods\n";
211 cout << " realm rename rename a realm\n";
212 cout << " realm set set realm info (requires infile)\n";
213 cout << " realm default set realm as default\n";
214 cout << " realm pull pull a realm and its current period\n";
215 cout << " zonegroup add add a zone to a zonegroup\n";
216 cout << " zonegroup create create a new zone group info\n";
217 cout << " zonegroup default set default zone group\n";
218 cout << " zonegroup delete delete a zone group info\n";
219 cout << " zonegroup get show zone group info\n";
220 cout << " zonegroup modify modify an existing zonegroup\n";
221 cout << " zonegroup set set zone group info (requires infile)\n";
222 cout << " zonegroup rm remove a zone from a zonegroup\n";
223 cout << " zonegroup rename rename a zone group\n";
224 cout << " zonegroup list list all zone groups set on this cluster\n";
225 cout << " zonegroup placement list list zonegroup's placement targets\n";
226 cout << " zonegroup placement get get a placement target of a specific zonegroup\n";
227 cout << " zonegroup placement add add a placement target id to a zonegroup\n";
228 cout << " zonegroup placement modify modify a placement target of a specific zonegroup\n";
229 cout << " zonegroup placement rm remove a placement target from a zonegroup\n";
230 cout << " zonegroup placement default set a zonegroup's default placement target\n";
231 cout << " zone create create a new zone\n";
232 cout << " zone rm remove a zone\n";
233 cout << " zone get show zone cluster params\n";
234 cout << " zone modify modify an existing zone\n";
235 cout << " zone set set zone cluster params (requires infile)\n";
236 cout << " zone list list all zones set on this cluster\n";
237 cout << " zone rename rename a zone\n";
238 cout << " zone placement list list zone's placement targets\n";
239 cout << " zone placement get get a zone placement target\n";
240 cout << " zone placement add add a zone placement target\n";
241 cout << " zone placement modify modify a zone placement target\n";
242 cout << " zone placement rm remove a zone placement target\n";
243 cout << " metadata sync status get metadata sync status\n";
244 cout << " metadata sync init init metadata sync\n";
245 cout << " metadata sync run run metadata sync\n";
246 cout << " data sync status get data sync status of the specified source zone\n";
247 cout << " data sync init init data sync for the specified source zone\n";
248 cout << " data sync run run data sync for the specified source zone\n";
249 cout << " pool add add an existing pool for data placement\n";
250 cout << " pool rm remove an existing pool from data placement set\n";
251 cout << " pools list list placement active set\n";
252 cout << " policy read bucket/object policy\n";
253 cout << " log list list log objects\n";
254 cout << " log show dump a log from specific object or (bucket + date\n";
255 cout << " + bucket-id)\n";
256 cout << " (NOTE: required to specify formatting of date\n";
257 cout << " to \"YYYY-MM-DD-hh\")\n";
258 cout << " log rm remove log object\n";
259 cout << " usage show show usage (by user, by bucket, date range)\n";
260 cout << " usage trim trim usage (by user, by bucket, date range)\n";
261 cout << " usage clear reset all the usage stats for the cluster\n";
262 cout << " gc list dump expired garbage collection objects (specify\n";
263 cout << " --include-all to list all entries, including unexpired)\n";
264 cout << " gc process manually process garbage (specify\n";
265 cout << " --include-all to process all entries, including unexpired)\n";
266 cout << " lc list list all bucket lifecycle progress\n";
267 cout << " lc get get a lifecycle bucket configuration\n";
268 cout << " lc process manually process lifecycle\n";
269 cout << " lc reshard fix fix LC for a resharded bucket\n";
270 cout << " metadata get get metadata info\n";
271 cout << " metadata put put metadata info\n";
272 cout << " metadata rm remove metadata info\n";
273 cout << " metadata list list metadata info\n";
274 cout << " mdlog list list metadata log\n";
275 cout << " mdlog autotrim auto trim metadata log\n";
276 cout << " mdlog trim trim metadata log (use marker)\n";
277 cout << " mdlog status read metadata log status\n";
278 cout << " bilog list list bucket index log\n";
279 cout << " bilog trim trim bucket index log (use start-marker, end-marker)\n";
280 cout << " bilog status read bucket index log status\n";
281 cout << " bilog autotrim auto trim bucket index log\n";
282 cout << " datalog list list data log\n";
283 cout << " datalog trim trim data log\n";
284 cout << " datalog status read data log status\n";
285 cout << " datalog type change datalog type to --log_type={fifo,omap}\n";
286 cout << " orphans find deprecated -- init and run search for leaked rados objects (use job-id, pool)\n";
287 cout << " orphans finish deprecated -- clean up search for leaked rados objects\n";
288 cout << " orphans list-jobs deprecated -- list the current job-ids for orphans search\n";
289 cout << " * the three 'orphans' sub-commands are now deprecated; consider using the `rgw-orphan-list` tool\n";
290 cout << " role create create a AWS role for use with STS\n";
291 cout << " role delete remove a role\n";
292 cout << " role get get a role\n";
293 cout << " role list list roles with specified path prefix\n";
294 cout << " role-trust-policy modify modify the assume role policy of an existing role\n";
295 cout << " role-policy put add/update permission policy to role\n";
296 cout << " role-policy list list policies attached to a role\n";
297 cout << " role-policy get get the specified inline policy document embedded with the given role\n";
298 cout << " role-policy delete remove policy attached to a role\n";
299 cout << " role update update max_session_duration of a role\n";
300 cout << " reshard add schedule a resharding of a bucket\n";
301 cout << " reshard list list all bucket resharding or scheduled to be resharded\n";
302 cout << " reshard status read bucket resharding status\n";
303 cout << " reshard process process of scheduled reshard jobs\n";
304 cout << " reshard cancel cancel resharding a bucket\n";
305 cout << " reshard stale-instances list list stale-instances from bucket resharding\n";
306 cout << " reshard stale-instances delete cleanup stale-instances from bucket resharding\n";
307 cout << " sync error list list sync error\n";
308 cout << " sync error trim trim sync error\n";
309 cout << " mfa create create a new MFA TOTP token\n";
310 cout << " mfa list list MFA TOTP tokens\n";
311 cout << " mfa get show MFA TOTP token\n";
312 cout << " mfa remove delete MFA TOTP token\n";
313 cout << " mfa check check MFA TOTP token\n";
314 cout << " mfa resync re-sync MFA TOTP token\n";
315 cout << " topic list list bucket notifications topics\n";
316 cout << " topic get get a bucket notifications topic\n";
317 cout << " topic rm remove a bucket notifications topic\n";
318 cout << " script put upload a lua script to a context\n";
319 cout << " script get get the lua script of a context\n";
320 cout << " script rm remove the lua scripts of a context\n";
321 cout << " script-package add add a lua package to the scripts allowlist\n";
322 cout << " script-package rm remove a lua package from the scripts allowlist\n";
323 cout << " script-package list get the lua packages allowlist\n";
324 cout << " notification list list bucket notifications configuration\n";
325 cout << " notification get get a bucket notifications configuration\n";
326 cout << " notification rm remove a bucket notifications configuration\n";
327 cout << "options:\n";
328 cout << " --tenant=<tenant> tenant name\n";
329 cout << " --user_ns=<namespace> namespace of user (oidc in case of users authenticated with oidc provider)\n";
330 cout << " --uid=<id> user id\n";
331 cout << " --new-uid=<id> new user id\n";
332 cout << " --subuser=<name> subuser name\n";
333 cout << " --access-key=<key> S3 access key\n";
334 cout << " --email=<email> user's email address\n";
335 cout << " --secret/--secret-key=<key>\n";
336 cout << " specify secret key\n";
337 cout << " --gen-access-key generate random access key (for S3)\n";
338 cout << " --gen-secret generate random secret key\n";
339 cout << " --key-type=<type> key type, options are: swift, s3\n";
340 cout << " --temp-url-key[-2]=<key> temp url key\n";
341 cout << " --access=<access> Set access permissions for sub-user, should be one\n";
342 cout << " of read, write, readwrite, full\n";
343 cout << " --display-name=<name> user's display name\n";
344 cout << " --max-buckets max number of buckets for a user\n";
345 cout << " --admin set the admin flag on the user\n";
346 cout << " --system set the system flag on the user\n";
347 cout << " --op-mask set the op mask on the user\n";
348 cout << " --bucket=<bucket> Specify the bucket name. Also used by the quota command.\n";
349 cout << " --pool=<pool> Specify the pool name. Also used to scan for leaked rados objects.\n";
350 cout << " --object=<object> object name\n";
351 cout << " --objects-file=<file> file containing a list of object names to process\n";
352 cout << " --object-version=<version> object version\n";
353 cout << " --date=<date> date in the format yyyy-mm-dd\n";
354 cout << " --start-date=<date> start date in the format yyyy-mm-dd\n";
355 cout << " --end-date=<date> end date in the format yyyy-mm-dd\n";
356 cout << " --bucket-id=<bucket-id> bucket id\n";
357 cout << " --bucket-new-name=<bucket>\n";
358 cout << " for bucket link: optional new name\n";
359 cout << " --shard-id=<shard-id> optional for: \n";
360 cout << " mdlog list\n";
361 cout << " data sync status\n";
362 cout << " required for: \n";
363 cout << " mdlog trim\n";
364 cout << " --gen=<gen-id> optional for: \n";
365 cout << " bilog list\n";
366 cout << " bilog trim\n";
367 cout << " bilog status\n";
368 cout << " --max-entries=<entries> max entries for listing operations\n";
369 cout << " --metadata-key=<key> key to retrieve metadata from with metadata get\n";
370 cout << " --remote=<remote> zone or zonegroup id of remote gateway\n";
371 cout << " --period=<id> period id\n";
372 cout << " --url=<url> url for pushing/pulling period/realm\n";
373 cout << " --epoch=<number> period epoch\n";
374 cout << " --commit commit the period during 'period update'\n";
375 cout << " --staging get staging period info\n";
376 cout << " --master set as master\n";
377 cout << " --master-zone=<id> master zone id\n";
378 cout << " --rgw-realm=<name> realm name\n";
379 cout << " --realm-id=<id> realm id\n";
380 cout << " --realm-new-name=<name> realm new name\n";
381 cout << " --rgw-zonegroup=<name> zonegroup name\n";
382 cout << " --zonegroup-id=<id> zonegroup id\n";
383 cout << " --zonegroup-new-name=<name>\n";
384 cout << " zonegroup new name\n";
385 cout << " --rgw-zone=<name> name of zone in which radosgw is running\n";
386 cout << " --zone-id=<id> zone id\n";
387 cout << " --zone-new-name=<name> zone new name\n";
388 cout << " --source-zone specify the source zone (for data sync)\n";
389 cout << " --default set entity (realm, zonegroup, zone) as default\n";
390 cout << " --read-only set zone as read-only (when adding to zonegroup)\n";
391 cout << " --redirect-zone specify zone id to redirect when response is 404 (not found)\n";
392 cout << " --placement-id placement id for zonegroup placement commands\n";
393 cout << " --storage-class storage class for zonegroup placement commands\n";
394 cout << " --tags=<list> list of tags for zonegroup placement add and modify commands\n";
395 cout << " --tags-add=<list> list of tags to add for zonegroup placement modify command\n";
396 cout << " --tags-rm=<list> list of tags to remove for zonegroup placement modify command\n";
397 cout << " --endpoints=<list> zone endpoints\n";
398 cout << " --index-pool=<pool> placement target index pool\n";
399 cout << " --data-pool=<pool> placement target data pool\n";
400 cout << " --data-extra-pool=<pool> placement target data extra (non-ec) pool\n";
401 cout << " --placement-index-type=<type>\n";
402 cout << " placement target index type (normal, indexless, or #id)\n";
403 cout << " --placement-inline-data=<true>\n";
404 cout << " set whether the placement target is configured to store a data\n";
405 cout << " chunk inline in head objects\n";
406 cout << " --compression=<type> placement target compression type (plugin name or empty/none)\n";
407 cout << " --tier-type=<type> zone tier type\n";
408 cout << " --tier-config=<k>=<v>[,...]\n";
409 cout << " set zone tier config keys, values\n";
410 cout << " --tier-config-rm=<k>[,...]\n";
411 cout << " unset zone tier config keys\n";
412 cout << " --sync-from-all[=false] set/reset whether zone syncs from all zonegroup peers\n";
413 cout << " --sync-from=[zone-name][,...]\n";
414 cout << " set list of zones to sync from\n";
415 cout << " --sync-from-rm=[zone-name][,...]\n";
416 cout << " remove zones from list of zones to sync from\n";
417 cout << " --bucket-index-max-shards override a zone/zonegroup's default bucket index shard count\n";
418 cout << " --fix besides checking bucket index, will also fix it\n";
419 cout << " --check-objects bucket check: rebuilds bucket index according to\n";
420 cout << " actual objects state\n";
421 cout << " --format=<format> specify output format for certain operations: xml,\n";
422 cout << " json\n";
423 cout << " --purge-data when specified, user removal will also purge all the\n";
424 cout << " user data\n";
425 cout << " --purge-keys when specified, subuser removal will also purge all the\n";
426 cout << " subuser keys\n";
427 cout << " --purge-objects remove a bucket's objects before deleting it\n";
428 cout << " (NOTE: required to delete a non-empty bucket)\n";
429 cout << " --sync-stats option to 'user stats', update user stats with current\n";
430 cout << " stats reported by user's buckets indexes\n";
431 cout << " --reset-stats option to 'user stats', reset stats in accordance with user buckets\n";
432 cout << " --show-config show configuration\n";
433 cout << " --show-log-entries=<flag> enable/disable dump of log entries on log show\n";
434 cout << " --show-log-sum=<flag> enable/disable dump of log summation on log show\n";
435 cout << " --skip-zero-entries log show only dumps entries that don't have zero value\n";
436 cout << " in one of the numeric field\n";
437 cout << " --infile=<file> file to read in when setting data\n";
438 cout << " --categories=<list> comma separated list of categories, used in usage show\n";
439 cout << " --caps=<caps> list of caps (e.g., \"usage=read, write; user=read\")\n";
440 cout << " --op-mask=<op-mask> permission of user's operations (e.g., \"read, write, delete, *\")\n";
441 cout << " --yes-i-really-mean-it required for certain operations\n";
442 cout << " --warnings-only when specified with bucket limit check, list\n";
443 cout << " only buckets nearing or over the current max\n";
444 cout << " objects per shard value\n";
445 cout << " --bypass-gc when specified with bucket deletion, triggers\n";
446 cout << " object deletions by not involving GC\n";
447 cout << " --inconsistent-index when specified with bucket deletion and bypass-gc set to true,\n";
448 cout << " ignores bucket index consistency\n";
449 cout << " --min-rewrite-size min object size for bucket rewrite (default 4M)\n";
450 cout << " --max-rewrite-size max object size for bucket rewrite (default ULLONG_MAX)\n";
451 cout << " --min-rewrite-stripe-size min stripe size for object rewrite (default 0)\n";
452 cout << " --trim-delay-ms time interval in msec to limit the frequency of sync error log entries trimming operations,\n";
453 cout << " the trimming process will sleep the specified msec for every 1000 entries trimmed\n";
454 cout << " --max-concurrent-ios maximum concurrent ios for bucket operations (default: 32)\n";
455 cout << " --enable-feature enable a zone/zonegroup feature\n";
456 cout << " --disable-feature disable a zone/zonegroup feature\n";
457 cout << "\n";
458 cout << "<date> := \"YYYY-MM-DD[ hh:mm:ss]\"\n";
459 cout << "\nQuota options:\n";
460 cout << " --max-objects specify max objects (negative value to disable)\n";
461 cout << " --max-size specify max size (in B/K/M/G/T, negative value to disable)\n";
462 cout << " --quota-scope scope of quota (bucket, user)\n";
463 cout << "\nRate limiting options:\n";
464 cout << " --max-read-ops specify max requests per minute for READ ops per RGW (GET and HEAD request methods), 0 means unlimited\n";
465 cout << " --max-read-bytes specify max bytes per minute for READ ops per RGW (GET and HEAD request methods), 0 means unlimited\n";
466 cout << " --max-write-ops specify max requests per minute for WRITE ops per RGW (Not GET or HEAD request methods), 0 means unlimited\n";
467 cout << " --max-write-bytes specify max bytes per minute for WRITE ops per RGW (Not GET or HEAD request methods), 0 means unlimited\n";
468 cout << " --ratelimit-scope scope of rate limiting: bucket, user, anonymous\n";
469 cout << " anonymous can be configured only with global rate limit\n";
470 cout << "\nOrphans search options:\n";
471 cout << " --num-shards num of shards to use for keeping the temporary scan info\n";
472 cout << " --orphan-stale-secs num of seconds to wait before declaring an object to be an orphan (default: 86400)\n";
473 cout << " --job-id set the job id (for orphans find)\n";
474 cout << " --detail detailed mode, log and stat head objects as well\n";
475 cout << "\nOrphans list-jobs options:\n";
476 cout << " --extra-info provide extra info in job list\n";
477 cout << "\nRole options:\n";
478 cout << " --role-name name of the role to create\n";
479 cout << " --path path to the role\n";
480 cout << " --assume-role-policy-doc the trust relationship policy document that grants an entity permission to assume the role\n";
481 cout << " --policy-name name of the policy document\n";
482 cout << " --policy-doc permission policy document\n";
483 cout << " --path-prefix path prefix for filtering roles\n";
484 cout << "\nMFA options:\n";
485 cout << " --totp-serial a string that represents the ID of a TOTP token\n";
486 cout << " --totp-seed the secret seed that is used to calculate the TOTP\n";
487 cout << " --totp-seconds the time resolution that is being used for TOTP generation\n";
488 cout << " --totp-window the number of TOTP tokens that are checked before and after the current token when validating token\n";
489 cout << " --totp-pin the valid value of a TOTP token at a certain time\n";
490 cout << "\nBucket notifications options:\n";
491 cout << " --topic bucket notifications topic name\n";
492 cout << " --notification-id bucket notifications id\n";
493 cout << "\nScript options:\n";
494 cout << " --context context in which the script runs. one of: "+LUA_CONTEXT_LIST+"\n";
495 cout << " --package name of the lua package that should be added/removed to/from the allowlist\n";
496 cout << " --allow-compilation package is allowed to compile C code as part of its installation\n";
497 cout << "\nBucket check olh/unlinked options:\n";
498 cout << " --min-age-hours minimum age of unlinked objects to consider for bucket check unlinked (default: 1)\n";
499 cout << " --dump-keys when specified, all keys identified as problematic are printed to stdout\n";
500 cout << " --hide-progress when specified, per-shard progress details are not printed to stderr\n";
501 cout << "\nradoslist options:\n";
502 cout << " --rgw-obj-fs the field separator that will separate the rados\n";
503 cout << " object name from the rgw object name;\n";
504 cout << " additionally rados objects for incomplete\n";
505 cout << " multipart uploads will not be output\n";
506 cout << "\n";
507 generic_client_usage();
508 }
509
510
511 class SimpleCmd {
512 public:
513 struct Def {
514 string cmd;
515 std::any opt;
516 };
517
518 using Aliases = std::vector<std::set<string> >;
519 using Commands = std::vector<Def>;
520
521 private:
522 struct Node {
523 map<string, Node> next;
524 set<string> expected; /* separate un-normalized list */
525 std::any opt;
526 };
527
528 Node cmd_root;
529 map<string, string> alias_map;
530
531 string normalize_alias(const string& s) const {
532 auto iter = alias_map.find(s);
533 if (iter == alias_map.end()) {
534 return s;
535 }
536
537 return iter->second;
538 }
539 void init_alias_map(Aliases& aliases) {
540 for (auto& alias_set : aliases) {
541 std::optional<string> first;
542
543 for (auto& alias : alias_set) {
544 if (!first) {
545 first = alias;
546 } else {
547 alias_map[alias] = *first;
548 }
549 }
550 }
551 }
552
553 bool gen_next_expected(Node *node, vector<string> *expected, bool ret) {
554 for (auto& next_cmd : node->expected) {
555 expected->push_back(next_cmd);
556 }
557 return ret;
558 }
559
560 Node root;
561
562 public:
563 SimpleCmd() {}
564
565 SimpleCmd(std::optional<Commands> cmds,
566 std::optional<Aliases> aliases) {
567 if (aliases) {
568 add_aliases(*aliases);
569 }
570
571 if (cmds) {
572 add_commands(*cmds);
573 }
574 }
575
576 void add_aliases(Aliases& aliases) {
577 init_alias_map(aliases);
578 }
579
580 void add_commands(std::vector<Def>& cmds) {
581 for (auto& cmd : cmds) {
582 vector<string> words;
583 get_str_vec(cmd.cmd, " ", words);
584
585 auto node = &cmd_root;
586 for (auto& word : words) {
587 auto norm = normalize_alias(word);
588 auto parent = node;
589
590 node->expected.insert(word);
591
592 node = &node->next[norm];
593
594 if (norm == "[*]") { /* optional param at the end */
595 parent->next["*"] = *node; /* can be also looked up by '*' */
596 parent->opt = cmd.opt;
597 }
598 }
599
600 node->opt = cmd.opt;
601 }
602 }
603
604 template <class Container>
605 bool find_command(Container& args,
606 std::any *opt_cmd,
607 vector<string> *extra_args,
608 string *error,
609 vector<string> *expected) {
610 auto node = &cmd_root;
611
612 std::optional<std::any> found_opt;
613
614 for (auto& arg : args) {
615 string norm = normalize_alias(arg);
616 auto iter = node->next.find(norm);
617 if (iter == node->next.end()) {
618 iter = node->next.find("*");
619 if (iter == node->next.end()) {
620 *error = string("ERROR: Unrecognized argument: '") + arg + "'";
621 return gen_next_expected(node, expected, false);
622 }
623 extra_args->push_back(arg);
624 if (!found_opt) {
625 found_opt = node->opt;
626 }
627 }
628 node = &(iter->second);
629 }
630
631 *opt_cmd = found_opt.value_or(node->opt);
632
633 if (!opt_cmd->has_value()) {
634 *error ="ERROR: Unknown command";
635 return gen_next_expected(node, expected, false);
636 }
637
638 return true;
639 }
640 };
641
642
643 namespace rgw_admin {
644
645 enum class OPT {
646 NO_CMD,
647 USER_CREATE,
648 USER_INFO,
649 USER_MODIFY,
650 USER_RENAME,
651 USER_RM,
652 USER_SUSPEND,
653 USER_ENABLE,
654 USER_CHECK,
655 USER_STATS,
656 USER_LIST,
657 SUBUSER_CREATE,
658 SUBUSER_MODIFY,
659 SUBUSER_RM,
660 KEY_CREATE,
661 KEY_RM,
662 BUCKETS_LIST,
663 BUCKET_LIMIT_CHECK,
664 BUCKET_LINK,
665 BUCKET_UNLINK,
666 BUCKET_LAYOUT,
667 BUCKET_STATS,
668 BUCKET_CHECK,
669 BUCKET_CHECK_OLH,
670 BUCKET_CHECK_UNLINKED,
671 BUCKET_SYNC_CHECKPOINT,
672 BUCKET_SYNC_INFO,
673 BUCKET_SYNC_STATUS,
674 BUCKET_SYNC_MARKERS,
675 BUCKET_SYNC_INIT,
676 BUCKET_SYNC_RUN,
677 BUCKET_SYNC_DISABLE,
678 BUCKET_SYNC_ENABLE,
679 BUCKET_RM,
680 BUCKET_REWRITE,
681 BUCKET_RESHARD,
682 BUCKET_CHOWN,
683 BUCKET_RADOS_LIST,
684 BUCKET_SHARD_OBJECTS,
685 BUCKET_OBJECT_SHARD,
686 BUCKET_RESYNC_ENCRYPTED_MULTIPART,
687 POLICY,
688 POOL_ADD,
689 POOL_RM,
690 POOLS_LIST,
691 LOG_LIST,
692 LOG_SHOW,
693 LOG_RM,
694 USAGE_SHOW,
695 USAGE_TRIM,
696 USAGE_CLEAR,
697 OBJECT_PUT,
698 OBJECT_RM,
699 OBJECT_UNLINK,
700 OBJECT_STAT,
701 OBJECT_REWRITE,
702 OBJECT_REINDEX,
703 OBJECTS_EXPIRE,
704 OBJECTS_EXPIRE_STALE_LIST,
705 OBJECTS_EXPIRE_STALE_RM,
706 BI_GET,
707 BI_PUT,
708 BI_LIST,
709 BI_PURGE,
710 OLH_GET,
711 OLH_READLOG,
712 QUOTA_SET,
713 QUOTA_ENABLE,
714 QUOTA_DISABLE,
715 GC_LIST,
716 GC_PROCESS,
717 LC_LIST,
718 LC_GET,
719 LC_PROCESS,
720 LC_RESHARD_FIX,
721 ORPHANS_FIND,
722 ORPHANS_FINISH,
723 ORPHANS_LIST_JOBS,
724 RATELIMIT_GET,
725 RATELIMIT_SET,
726 RATELIMIT_ENABLE,
727 RATELIMIT_DISABLE,
728 ZONEGROUP_ADD,
729 ZONEGROUP_CREATE,
730 ZONEGROUP_DEFAULT,
731 ZONEGROUP_DELETE,
732 ZONEGROUP_GET,
733 ZONEGROUP_MODIFY,
734 ZONEGROUP_SET,
735 ZONEGROUP_LIST,
736 ZONEGROUP_REMOVE,
737 ZONEGROUP_RENAME,
738 ZONEGROUP_PLACEMENT_ADD,
739 ZONEGROUP_PLACEMENT_MODIFY,
740 ZONEGROUP_PLACEMENT_RM,
741 ZONEGROUP_PLACEMENT_LIST,
742 ZONEGROUP_PLACEMENT_GET,
743 ZONEGROUP_PLACEMENT_DEFAULT,
744 ZONE_CREATE,
745 ZONE_DELETE,
746 ZONE_GET,
747 ZONE_MODIFY,
748 ZONE_SET,
749 ZONE_LIST,
750 ZONE_RENAME,
751 ZONE_DEFAULT,
752 ZONE_PLACEMENT_ADD,
753 ZONE_PLACEMENT_MODIFY,
754 ZONE_PLACEMENT_RM,
755 ZONE_PLACEMENT_LIST,
756 ZONE_PLACEMENT_GET,
757 CAPS_ADD,
758 CAPS_RM,
759 METADATA_GET,
760 METADATA_PUT,
761 METADATA_RM,
762 METADATA_LIST,
763 METADATA_SYNC_STATUS,
764 METADATA_SYNC_INIT,
765 METADATA_SYNC_RUN,
766 MDLOG_LIST,
767 MDLOG_AUTOTRIM,
768 MDLOG_TRIM,
769 MDLOG_FETCH,
770 MDLOG_STATUS,
771 SYNC_ERROR_LIST,
772 SYNC_ERROR_TRIM,
773 SYNC_GROUP_CREATE,
774 SYNC_GROUP_MODIFY,
775 SYNC_GROUP_GET,
776 SYNC_GROUP_REMOVE,
777 SYNC_GROUP_FLOW_CREATE,
778 SYNC_GROUP_FLOW_REMOVE,
779 SYNC_GROUP_PIPE_CREATE,
780 SYNC_GROUP_PIPE_MODIFY,
781 SYNC_GROUP_PIPE_REMOVE,
782 SYNC_POLICY_GET,
783 BILOG_LIST,
784 BILOG_TRIM,
785 BILOG_STATUS,
786 BILOG_AUTOTRIM,
787 DATA_SYNC_STATUS,
788 DATA_SYNC_INIT,
789 DATA_SYNC_RUN,
790 DATALOG_LIST,
791 DATALOG_STATUS,
792 DATALOG_AUTOTRIM,
793 DATALOG_TRIM,
794 DATALOG_TYPE,
795 DATALOG_PRUNE,
796 REALM_CREATE,
797 REALM_DELETE,
798 REALM_GET,
799 REALM_GET_DEFAULT,
800 REALM_LIST,
801 REALM_LIST_PERIODS,
802 REALM_RENAME,
803 REALM_SET,
804 REALM_DEFAULT,
805 REALM_PULL,
806 PERIOD_DELETE,
807 PERIOD_GET,
808 PERIOD_GET_CURRENT,
809 PERIOD_PULL,
810 PERIOD_PUSH,
811 PERIOD_LIST,
812 PERIOD_UPDATE,
813 PERIOD_COMMIT,
814 GLOBAL_QUOTA_GET,
815 GLOBAL_QUOTA_SET,
816 GLOBAL_QUOTA_ENABLE,
817 GLOBAL_QUOTA_DISABLE,
818 GLOBAL_RATELIMIT_GET,
819 GLOBAL_RATELIMIT_SET,
820 GLOBAL_RATELIMIT_ENABLE,
821 GLOBAL_RATELIMIT_DISABLE,
822 SYNC_INFO,
823 SYNC_STATUS,
824 ROLE_CREATE,
825 ROLE_DELETE,
826 ROLE_GET,
827 ROLE_TRUST_POLICY_MODIFY,
828 ROLE_LIST,
829 ROLE_POLICY_PUT,
830 ROLE_POLICY_LIST,
831 ROLE_POLICY_GET,
832 ROLE_POLICY_DELETE,
833 ROLE_UPDATE,
834 RESHARD_ADD,
835 RESHARD_LIST,
836 RESHARD_STATUS,
837 RESHARD_PROCESS,
838 RESHARD_CANCEL,
839 MFA_CREATE,
840 MFA_REMOVE,
841 MFA_GET,
842 MFA_LIST,
843 MFA_CHECK,
844 MFA_RESYNC,
845 RESHARD_STALE_INSTANCES_LIST,
846 RESHARD_STALE_INSTANCES_DELETE,
847 PUBSUB_TOPIC_LIST,
848 PUBSUB_TOPIC_GET,
849 PUBSUB_TOPIC_RM,
850 PUBSUB_NOTIFICATION_LIST,
851 PUBSUB_NOTIFICATION_GET,
852 PUBSUB_NOTIFICATION_RM,
853 SCRIPT_PUT,
854 SCRIPT_GET,
855 SCRIPT_RM,
856 SCRIPT_PACKAGE_ADD,
857 SCRIPT_PACKAGE_RM,
858 SCRIPT_PACKAGE_LIST
859 };
860
861 }
862
863 using namespace rgw_admin;
864
865 static SimpleCmd::Commands all_cmds = {
866 { "user create", OPT::USER_CREATE },
867 { "user info", OPT::USER_INFO },
868 { "user modify", OPT::USER_MODIFY },
869 { "user rename", OPT::USER_RENAME },
870 { "user rm", OPT::USER_RM },
871 { "user suspend", OPT::USER_SUSPEND },
872 { "user enable", OPT::USER_ENABLE },
873 { "user check", OPT::USER_CHECK },
874 { "user stats", OPT::USER_STATS },
875 { "user list", OPT::USER_LIST },
876 { "subuser create", OPT::SUBUSER_CREATE },
877 { "subuser modify", OPT::SUBUSER_MODIFY },
878 { "subuser rm", OPT::SUBUSER_RM },
879 { "key create", OPT::KEY_CREATE },
880 { "key rm", OPT::KEY_RM },
881 { "buckets list", OPT::BUCKETS_LIST },
882 { "bucket list", OPT::BUCKETS_LIST },
883 { "bucket limit check", OPT::BUCKET_LIMIT_CHECK },
884 { "bucket link", OPT::BUCKET_LINK },
885 { "bucket unlink", OPT::BUCKET_UNLINK },
886 { "bucket layout", OPT::BUCKET_LAYOUT },
887 { "bucket stats", OPT::BUCKET_STATS },
888 { "bucket check", OPT::BUCKET_CHECK },
889 { "bucket check olh", OPT::BUCKET_CHECK_OLH },
890 { "bucket check unlinked", OPT::BUCKET_CHECK_UNLINKED },
891 { "bucket sync checkpoint", OPT::BUCKET_SYNC_CHECKPOINT },
892 { "bucket sync info", OPT::BUCKET_SYNC_INFO },
893 { "bucket sync status", OPT::BUCKET_SYNC_STATUS },
894 { "bucket sync markers", OPT::BUCKET_SYNC_MARKERS },
895 { "bucket sync init", OPT::BUCKET_SYNC_INIT },
896 { "bucket sync run", OPT::BUCKET_SYNC_RUN },
897 { "bucket sync disable", OPT::BUCKET_SYNC_DISABLE },
898 { "bucket sync enable", OPT::BUCKET_SYNC_ENABLE },
899 { "bucket rm", OPT::BUCKET_RM },
900 { "bucket rewrite", OPT::BUCKET_REWRITE },
901 { "bucket reshard", OPT::BUCKET_RESHARD },
902 { "bucket chown", OPT::BUCKET_CHOWN },
903 { "bucket radoslist", OPT::BUCKET_RADOS_LIST },
904 { "bucket rados list", OPT::BUCKET_RADOS_LIST },
905 { "bucket shard objects", OPT::BUCKET_SHARD_OBJECTS },
906 { "bucket shard object", OPT::BUCKET_SHARD_OBJECTS },
907 { "bucket object shard", OPT::BUCKET_OBJECT_SHARD },
908 { "bucket resync encrypted multipart", OPT::BUCKET_RESYNC_ENCRYPTED_MULTIPART },
909 { "policy", OPT::POLICY },
910 { "pool add", OPT::POOL_ADD },
911 { "pool rm", OPT::POOL_RM },
912 { "pool list", OPT::POOLS_LIST },
913 { "pools list", OPT::POOLS_LIST },
914 { "log list", OPT::LOG_LIST },
915 { "log show", OPT::LOG_SHOW },
916 { "log rm", OPT::LOG_RM },
917 { "usage show", OPT::USAGE_SHOW },
918 { "usage trim", OPT::USAGE_TRIM },
919 { "usage clear", OPT::USAGE_CLEAR },
920 { "object put", OPT::OBJECT_PUT },
921 { "object rm", OPT::OBJECT_RM },
922 { "object unlink", OPT::OBJECT_UNLINK },
923 { "object stat", OPT::OBJECT_STAT },
924 { "object rewrite", OPT::OBJECT_REWRITE },
925 { "object reindex", OPT::OBJECT_REINDEX },
926 { "objects expire", OPT::OBJECTS_EXPIRE },
927 { "objects expire-stale list", OPT::OBJECTS_EXPIRE_STALE_LIST },
928 { "objects expire-stale rm", OPT::OBJECTS_EXPIRE_STALE_RM },
929 { "bi get", OPT::BI_GET },
930 { "bi put", OPT::BI_PUT },
931 { "bi list", OPT::BI_LIST },
932 { "bi purge", OPT::BI_PURGE },
933 { "olh get", OPT::OLH_GET },
934 { "olh readlog", OPT::OLH_READLOG },
935 { "quota set", OPT::QUOTA_SET },
936 { "quota enable", OPT::QUOTA_ENABLE },
937 { "quota disable", OPT::QUOTA_DISABLE },
938 { "ratelimit get", OPT::RATELIMIT_GET },
939 { "ratelimit set", OPT::RATELIMIT_SET },
940 { "ratelimit enable", OPT::RATELIMIT_ENABLE },
941 { "ratelimit disable", OPT::RATELIMIT_DISABLE },
942 { "gc list", OPT::GC_LIST },
943 { "gc process", OPT::GC_PROCESS },
944 { "lc list", OPT::LC_LIST },
945 { "lc get", OPT::LC_GET },
946 { "lc process", OPT::LC_PROCESS },
947 { "lc reshard fix", OPT::LC_RESHARD_FIX },
948 { "orphans find", OPT::ORPHANS_FIND },
949 { "orphans finish", OPT::ORPHANS_FINISH },
950 { "orphans list jobs", OPT::ORPHANS_LIST_JOBS },
951 { "orphans list-jobs", OPT::ORPHANS_LIST_JOBS },
952 { "zonegroup add", OPT::ZONEGROUP_ADD },
953 { "zonegroup create", OPT::ZONEGROUP_CREATE },
954 { "zonegroup default", OPT::ZONEGROUP_DEFAULT },
955 { "zonegroup delete", OPT::ZONEGROUP_DELETE },
956 { "zonegroup get", OPT::ZONEGROUP_GET },
957 { "zonegroup modify", OPT::ZONEGROUP_MODIFY },
958 { "zonegroup set", OPT::ZONEGROUP_SET },
959 { "zonegroup list", OPT::ZONEGROUP_LIST },
960 { "zonegroups list", OPT::ZONEGROUP_LIST },
961 { "zonegroup remove", OPT::ZONEGROUP_REMOVE },
962 { "zonegroup remove zone", OPT::ZONEGROUP_REMOVE },
963 { "zonegroup rename", OPT::ZONEGROUP_RENAME },
964 { "zonegroup placement add", OPT::ZONEGROUP_PLACEMENT_ADD },
965 { "zonegroup placement modify", OPT::ZONEGROUP_PLACEMENT_MODIFY },
966 { "zonegroup placement rm", OPT::ZONEGROUP_PLACEMENT_RM },
967 { "zonegroup placement list", OPT::ZONEGROUP_PLACEMENT_LIST },
968 { "zonegroup placement get", OPT::ZONEGROUP_PLACEMENT_GET },
969 { "zonegroup placement default", OPT::ZONEGROUP_PLACEMENT_DEFAULT },
970 { "zone create", OPT::ZONE_CREATE },
971 { "zone delete", OPT::ZONE_DELETE },
972 { "zone get", OPT::ZONE_GET },
973 { "zone modify", OPT::ZONE_MODIFY },
974 { "zone set", OPT::ZONE_SET },
975 { "zone list", OPT::ZONE_LIST },
976 { "zones list", OPT::ZONE_LIST },
977 { "zone rename", OPT::ZONE_RENAME },
978 { "zone default", OPT::ZONE_DEFAULT },
979 { "zone placement add", OPT::ZONE_PLACEMENT_ADD },
980 { "zone placement modify", OPT::ZONE_PLACEMENT_MODIFY },
981 { "zone placement rm", OPT::ZONE_PLACEMENT_RM },
982 { "zone placement list", OPT::ZONE_PLACEMENT_LIST },
983 { "zone placement get", OPT::ZONE_PLACEMENT_GET },
984 { "caps add", OPT::CAPS_ADD },
985 { "caps rm", OPT::CAPS_RM },
986 { "metadata get [*]", OPT::METADATA_GET },
987 { "metadata put [*]", OPT::METADATA_PUT },
988 { "metadata rm [*]", OPT::METADATA_RM },
989 { "metadata list [*]", OPT::METADATA_LIST },
990 { "metadata sync status", OPT::METADATA_SYNC_STATUS },
991 { "metadata sync init", OPT::METADATA_SYNC_INIT },
992 { "metadata sync run", OPT::METADATA_SYNC_RUN },
993 { "mdlog list", OPT::MDLOG_LIST },
994 { "mdlog autotrim", OPT::MDLOG_AUTOTRIM },
995 { "mdlog trim", OPT::MDLOG_TRIM },
996 { "mdlog fetch", OPT::MDLOG_FETCH },
997 { "mdlog status", OPT::MDLOG_STATUS },
998 { "sync error list", OPT::SYNC_ERROR_LIST },
999 { "sync error trim", OPT::SYNC_ERROR_TRIM },
1000 { "sync policy get", OPT::SYNC_POLICY_GET },
1001 { "sync group create", OPT::SYNC_GROUP_CREATE },
1002 { "sync group modify", OPT::SYNC_GROUP_MODIFY },
1003 { "sync group get", OPT::SYNC_GROUP_GET },
1004 { "sync group remove", OPT::SYNC_GROUP_REMOVE },
1005 { "sync group flow create", OPT::SYNC_GROUP_FLOW_CREATE },
1006 { "sync group flow remove", OPT::SYNC_GROUP_FLOW_REMOVE },
1007 { "sync group pipe create", OPT::SYNC_GROUP_PIPE_CREATE },
1008 { "sync group pipe modify", OPT::SYNC_GROUP_PIPE_MODIFY },
1009 { "sync group pipe remove", OPT::SYNC_GROUP_PIPE_REMOVE },
1010 { "bilog list", OPT::BILOG_LIST },
1011 { "bilog trim", OPT::BILOG_TRIM },
1012 { "bilog status", OPT::BILOG_STATUS },
1013 { "bilog autotrim", OPT::BILOG_AUTOTRIM },
1014 { "data sync status", OPT::DATA_SYNC_STATUS },
1015 { "data sync init", OPT::DATA_SYNC_INIT },
1016 { "data sync run", OPT::DATA_SYNC_RUN },
1017 { "datalog list", OPT::DATALOG_LIST },
1018 { "datalog status", OPT::DATALOG_STATUS },
1019 { "datalog autotrim", OPT::DATALOG_AUTOTRIM },
1020 { "datalog trim", OPT::DATALOG_TRIM },
1021 { "datalog type", OPT::DATALOG_TYPE },
1022 { "datalog prune", OPT::DATALOG_PRUNE },
1023 { "realm create", OPT::REALM_CREATE },
1024 { "realm rm", OPT::REALM_DELETE },
1025 { "realm get", OPT::REALM_GET },
1026 { "realm get default", OPT::REALM_GET_DEFAULT },
1027 { "realm get-default", OPT::REALM_GET_DEFAULT },
1028 { "realm list", OPT::REALM_LIST },
1029 { "realm list periods", OPT::REALM_LIST_PERIODS },
1030 { "realm list-periods", OPT::REALM_LIST_PERIODS },
1031 { "realm rename", OPT::REALM_RENAME },
1032 { "realm set", OPT::REALM_SET },
1033 { "realm default", OPT::REALM_DEFAULT },
1034 { "realm pull", OPT::REALM_PULL },
1035 { "period delete", OPT::PERIOD_DELETE },
1036 { "period get", OPT::PERIOD_GET },
1037 { "period get-current", OPT::PERIOD_GET_CURRENT },
1038 { "period get current", OPT::PERIOD_GET_CURRENT },
1039 { "period pull", OPT::PERIOD_PULL },
1040 { "period push", OPT::PERIOD_PUSH },
1041 { "period list", OPT::PERIOD_LIST },
1042 { "period update", OPT::PERIOD_UPDATE },
1043 { "period commit", OPT::PERIOD_COMMIT },
1044 { "global quota get", OPT::GLOBAL_QUOTA_GET },
1045 { "global quota set", OPT::GLOBAL_QUOTA_SET },
1046 { "global quota enable", OPT::GLOBAL_QUOTA_ENABLE },
1047 { "global quota disable", OPT::GLOBAL_QUOTA_DISABLE },
1048 { "global ratelimit get", OPT::GLOBAL_RATELIMIT_GET },
1049 { "global ratelimit set", OPT::GLOBAL_RATELIMIT_SET },
1050 { "global ratelimit enable", OPT::GLOBAL_RATELIMIT_ENABLE },
1051 { "global ratelimit disable", OPT::GLOBAL_RATELIMIT_DISABLE },
1052 { "sync info", OPT::SYNC_INFO },
1053 { "sync status", OPT::SYNC_STATUS },
1054 { "role create", OPT::ROLE_CREATE },
1055 { "role delete", OPT::ROLE_DELETE },
1056 { "role get", OPT::ROLE_GET },
1057 { "role-trust-policy modify", OPT::ROLE_TRUST_POLICY_MODIFY },
1058 { "role list", OPT::ROLE_LIST },
1059 { "role policy put", OPT::ROLE_POLICY_PUT },
1060 { "role-policy put", OPT::ROLE_POLICY_PUT },
1061 { "role policy list", OPT::ROLE_POLICY_LIST },
1062 { "role-policy list", OPT::ROLE_POLICY_LIST },
1063 { "role policy get", OPT::ROLE_POLICY_GET },
1064 { "role-policy get", OPT::ROLE_POLICY_GET },
1065 { "role policy delete", OPT::ROLE_POLICY_DELETE },
1066 { "role-policy delete", OPT::ROLE_POLICY_DELETE },
1067 { "role update", OPT::ROLE_UPDATE },
1068 { "reshard bucket", OPT::BUCKET_RESHARD },
1069 { "reshard add", OPT::RESHARD_ADD },
1070 { "reshard list", OPT::RESHARD_LIST },
1071 { "reshard status", OPT::RESHARD_STATUS },
1072 { "reshard process", OPT::RESHARD_PROCESS },
1073 { "reshard cancel", OPT::RESHARD_CANCEL },
1074 { "mfa create", OPT::MFA_CREATE },
1075 { "mfa remove", OPT::MFA_REMOVE },
1076 { "mfa get", OPT::MFA_GET },
1077 { "mfa list", OPT::MFA_LIST },
1078 { "mfa check", OPT::MFA_CHECK },
1079 { "mfa resync", OPT::MFA_RESYNC },
1080 { "reshard stale-instances list", OPT::RESHARD_STALE_INSTANCES_LIST },
1081 { "reshard stale list", OPT::RESHARD_STALE_INSTANCES_LIST },
1082 { "reshard stale-instances delete", OPT::RESHARD_STALE_INSTANCES_DELETE },
1083 { "reshard stale delete", OPT::RESHARD_STALE_INSTANCES_DELETE },
1084 { "topic list", OPT::PUBSUB_TOPIC_LIST },
1085 { "topic get", OPT::PUBSUB_TOPIC_GET },
1086 { "topic rm", OPT::PUBSUB_TOPIC_RM },
1087 { "notification list", OPT::PUBSUB_NOTIFICATION_LIST },
1088 { "notification get", OPT::PUBSUB_NOTIFICATION_GET },
1089 { "notification rm", OPT::PUBSUB_NOTIFICATION_RM },
1090 { "script put", OPT::SCRIPT_PUT },
1091 { "script get", OPT::SCRIPT_GET },
1092 { "script rm", OPT::SCRIPT_RM },
1093 { "script-package add", OPT::SCRIPT_PACKAGE_ADD },
1094 { "script-package rm", OPT::SCRIPT_PACKAGE_RM },
1095 { "script-package list", OPT::SCRIPT_PACKAGE_LIST },
1096 };
1097
1098 static SimpleCmd::Aliases cmd_aliases = {
1099 { "delete", "del" },
1100 { "remove", "rm" },
1101 { "rename", "mv" },
1102 };
1103
1104
1105
1106 BIIndexType get_bi_index_type(const string& type_str) {
1107 if (type_str == "plain")
1108 return BIIndexType::Plain;
1109 if (type_str == "instance")
1110 return BIIndexType::Instance;
1111 if (type_str == "olh")
1112 return BIIndexType::OLH;
1113
1114 return BIIndexType::Invalid;
1115 }
1116
1117 log_type get_log_type(const string& type_str) {
1118 if (strcasecmp(type_str.c_str(), "fifo") == 0)
1119 return log_type::fifo;
1120 if (strcasecmp(type_str.c_str(), "omap") == 0)
1121 return log_type::omap;
1122
1123 return static_cast<log_type>(0xff);
1124 }
1125
1126 void dump_bi_entry(bufferlist& bl, BIIndexType index_type, Formatter *formatter)
1127 {
1128 auto iter = bl.cbegin();
1129 switch (index_type) {
1130 case BIIndexType::Plain:
1131 case BIIndexType::Instance:
1132 {
1133 rgw_bucket_dir_entry entry;
1134 decode(entry, iter);
1135 encode_json("entry", entry, formatter);
1136 }
1137 break;
1138 case BIIndexType::OLH:
1139 {
1140 rgw_bucket_olh_entry entry;
1141 decode(entry, iter);
1142 encode_json("entry", entry, formatter);
1143 }
1144 break;
1145 default:
1146 ceph_abort();
1147 break;
1148 }
1149 }
1150
1151 static void show_user_info(RGWUserInfo& info, Formatter *formatter)
1152 {
1153 encode_json("user_info", info, formatter);
1154 formatter->flush(cout);
1155 cout << std::endl;
1156 }
1157
1158 static void show_perm_policy(string perm_policy, Formatter* formatter)
1159 {
1160 formatter->open_object_section("role");
1161 formatter->dump_string("Permission policy", perm_policy);
1162 formatter->close_section();
1163 formatter->flush(cout);
1164 }
1165
1166 static void show_policy_names(std::vector<string> policy_names, Formatter* formatter)
1167 {
1168 formatter->open_array_section("PolicyNames");
1169 for (const auto& it : policy_names) {
1170 formatter->dump_string("policyname", it);
1171 }
1172 formatter->close_section();
1173 formatter->flush(cout);
1174 }
1175
1176 static void show_role_info(rgw::sal::RGWRole* role, Formatter* formatter)
1177 {
1178 formatter->open_object_section("role");
1179 role->dump(formatter);
1180 formatter->close_section();
1181 formatter->flush(cout);
1182 }
1183
1184 static void show_roles_info(vector<std::unique_ptr<rgw::sal::RGWRole>>& roles, Formatter* formatter)
1185 {
1186 formatter->open_array_section("Roles");
1187 for (const auto& it : roles) {
1188 formatter->open_object_section("role");
1189 it->dump(formatter);
1190 formatter->close_section();
1191 }
1192 formatter->close_section();
1193 formatter->flush(cout);
1194 }
1195
1196 static void show_reshard_status(
1197 const list<cls_rgw_bucket_instance_entry>& status, Formatter *formatter)
1198 {
1199 formatter->open_array_section("status");
1200 for (const auto& entry : status) {
1201 formatter->open_object_section("entry");
1202 formatter->dump_string("reshard_status", to_string(entry.reshard_status));
1203 formatter->close_section();
1204 }
1205 formatter->close_section();
1206 formatter->flush(cout);
1207 }
1208
1209 class StoreDestructor {
1210 rgw::sal::Driver* driver;
1211 public:
1212 explicit StoreDestructor(rgw::sal::Driver* _s) : driver(_s) {}
1213 ~StoreDestructor() {
1214 DriverManager::close_storage(driver);
1215 rgw_http_client_cleanup();
1216 }
1217 };
1218
1219 static int init_bucket(rgw::sal::User* user, const rgw_bucket& b,
1220 std::unique_ptr<rgw::sal::Bucket>* bucket)
1221 {
1222 return driver->get_bucket(dpp(), user, b, bucket, null_yield);
1223 }
1224
1225 static int init_bucket(rgw::sal::User* user,
1226 const string& tenant_name,
1227 const string& bucket_name,
1228 const string& bucket_id,
1229 std::unique_ptr<rgw::sal::Bucket>* bucket)
1230 {
1231 rgw_bucket b{tenant_name, bucket_name, bucket_id};
1232 return init_bucket(user, b, bucket);
1233 }
1234
1235 static int read_input(const string& infile, bufferlist& bl)
1236 {
1237 int fd = 0;
1238 if (infile.size()) {
1239 fd = open(infile.c_str(), O_RDONLY);
1240 if (fd < 0) {
1241 int err = -errno;
1242 cerr << "error reading input file " << infile << std::endl;
1243 return err;
1244 }
1245 }
1246
1247 #define READ_CHUNK 8196
1248 int r;
1249 int err;
1250
1251 do {
1252 char buf[READ_CHUNK];
1253
1254 r = safe_read(fd, buf, READ_CHUNK);
1255 if (r < 0) {
1256 err = -errno;
1257 cerr << "error while reading input" << std::endl;
1258 goto out;
1259 }
1260 bl.append(buf, r);
1261 } while (r > 0);
1262 err = 0;
1263
1264 out:
1265 if (infile.size()) {
1266 close(fd);
1267 }
1268 return err;
1269 }
1270
1271 template <class T>
1272 static int read_decode_json(const string& infile, T& t)
1273 {
1274 bufferlist bl;
1275 int ret = read_input(infile, bl);
1276 if (ret < 0) {
1277 cerr << "ERROR: failed to read input: " << cpp_strerror(-ret) << std::endl;
1278 return ret;
1279 }
1280 JSONParser p;
1281 if (!p.parse(bl.c_str(), bl.length())) {
1282 cout << "failed to parse JSON" << std::endl;
1283 return -EINVAL;
1284 }
1285
1286 try {
1287 decode_json_obj(t, &p);
1288 } catch (const JSONDecoder::err& e) {
1289 cout << "failed to decode JSON input: " << e.what() << std::endl;
1290 return -EINVAL;
1291 }
1292 return 0;
1293 }
1294
1295 template <class T, class K>
1296 static int read_decode_json(const string& infile, T& t, K *k)
1297 {
1298 bufferlist bl;
1299 int ret = read_input(infile, bl);
1300 if (ret < 0) {
1301 cerr << "ERROR: failed to read input: " << cpp_strerror(-ret) << std::endl;
1302 return ret;
1303 }
1304 JSONParser p;
1305 if (!p.parse(bl.c_str(), bl.length())) {
1306 cout << "failed to parse JSON" << std::endl;
1307 return -EINVAL;
1308 }
1309
1310 try {
1311 t.decode_json(&p, k);
1312 } catch (const JSONDecoder::err& e) {
1313 cout << "failed to decode JSON input: " << e.what() << std::endl;
1314 return -EINVAL;
1315 }
1316 return 0;
1317 }
1318
1319 template <class T>
1320 static bool decode_dump(const char *field_name, bufferlist& bl, Formatter *f)
1321 {
1322 T t;
1323
1324 auto iter = bl.cbegin();
1325
1326 try {
1327 decode(t, iter);
1328 } catch (buffer::error& err) {
1329 return false;
1330 }
1331
1332 encode_json(field_name, t, f);
1333
1334 return true;
1335 }
1336
1337 static bool dump_string(const char *field_name, bufferlist& bl, Formatter *f)
1338 {
1339 string val = bl.to_str();
1340 f->dump_string(field_name, val.c_str() /* hide encoded null termination chars */);
1341
1342 return true;
1343 }
1344
1345 bool set_ratelimit_info(RGWRateLimitInfo& ratelimit, OPT opt_cmd, int64_t max_read_ops, int64_t max_write_ops,
1346 int64_t max_read_bytes, int64_t max_write_bytes,
1347 bool have_max_read_ops, bool have_max_write_ops,
1348 bool have_max_read_bytes, bool have_max_write_bytes)
1349 {
1350 bool ratelimit_configured = true;
1351 switch (opt_cmd) {
1352 case OPT::RATELIMIT_ENABLE:
1353 case OPT::GLOBAL_RATELIMIT_ENABLE:
1354 ratelimit.enabled = true;
1355 break;
1356
1357 case OPT::RATELIMIT_SET:
1358 case OPT::GLOBAL_RATELIMIT_SET:
1359 ratelimit_configured = false;
1360 if (have_max_read_ops) {
1361 if (max_read_ops >= 0) {
1362 ratelimit.max_read_ops = max_read_ops;
1363 ratelimit_configured = true;
1364 }
1365 }
1366 if (have_max_write_ops) {
1367 if (max_write_ops >= 0) {
1368 ratelimit.max_write_ops = max_write_ops;
1369 ratelimit_configured = true;
1370 }
1371 }
1372 if (have_max_read_bytes) {
1373 if (max_read_bytes >= 0) {
1374 ratelimit.max_read_bytes = max_read_bytes;
1375 ratelimit_configured = true;
1376 }
1377 }
1378 if (have_max_write_bytes) {
1379 if (max_write_bytes >= 0) {
1380 ratelimit.max_write_bytes = max_write_bytes;
1381 ratelimit_configured = true;
1382 }
1383 }
1384 break;
1385 case OPT::RATELIMIT_DISABLE:
1386 case OPT::GLOBAL_RATELIMIT_DISABLE:
1387 ratelimit.enabled = false;
1388 break;
1389 default:
1390 break;
1391 }
1392 return ratelimit_configured;
1393 }
1394
1395 void set_quota_info(RGWQuotaInfo& quota, OPT opt_cmd, int64_t max_size, int64_t max_objects,
1396 bool have_max_size, bool have_max_objects)
1397 {
1398 switch (opt_cmd) {
1399 case OPT::QUOTA_ENABLE:
1400 case OPT::GLOBAL_QUOTA_ENABLE:
1401 quota.enabled = true;
1402
1403 // falling through on purpose
1404
1405 case OPT::QUOTA_SET:
1406 case OPT::GLOBAL_QUOTA_SET:
1407 if (have_max_objects) {
1408 if (max_objects < 0) {
1409 quota.max_objects = -1;
1410 } else {
1411 quota.max_objects = max_objects;
1412 }
1413 }
1414 if (have_max_size) {
1415 if (max_size < 0) {
1416 quota.max_size = -1;
1417 } else {
1418 quota.max_size = rgw_rounded_kb(max_size) * 1024;
1419 }
1420 }
1421 break;
1422 case OPT::QUOTA_DISABLE:
1423 case OPT::GLOBAL_QUOTA_DISABLE:
1424 quota.enabled = false;
1425 break;
1426 default:
1427 break;
1428 }
1429 }
1430
1431 int set_bucket_quota(rgw::sal::Driver* driver, OPT opt_cmd,
1432 const string& tenant_name, const string& bucket_name,
1433 int64_t max_size, int64_t max_objects,
1434 bool have_max_size, bool have_max_objects)
1435 {
1436 std::unique_ptr<rgw::sal::Bucket> bucket;
1437 int r = driver->get_bucket(dpp(), nullptr, tenant_name, bucket_name, &bucket, null_yield);
1438 if (r < 0) {
1439 cerr << "could not get bucket info for bucket=" << bucket_name << ": " << cpp_strerror(-r) << std::endl;
1440 return -r;
1441 }
1442
1443 set_quota_info(bucket->get_info().quota, opt_cmd, max_size, max_objects, have_max_size, have_max_objects);
1444
1445 r = bucket->put_info(dpp(), false, real_time());
1446 if (r < 0) {
1447 cerr << "ERROR: failed writing bucket instance info: " << cpp_strerror(-r) << std::endl;
1448 return -r;
1449 }
1450 return 0;
1451 }
1452
1453 int set_bucket_ratelimit(rgw::sal::Driver* driver, OPT opt_cmd,
1454 const string& tenant_name, const string& bucket_name,
1455 int64_t max_read_ops, int64_t max_write_ops,
1456 int64_t max_read_bytes, int64_t max_write_bytes,
1457 bool have_max_read_ops, bool have_max_write_ops,
1458 bool have_max_read_bytes, bool have_max_write_bytes)
1459 {
1460 std::unique_ptr<rgw::sal::Bucket> bucket;
1461 int r = driver->get_bucket(dpp(), nullptr, tenant_name, bucket_name, &bucket, null_yield);
1462 if (r < 0) {
1463 cerr << "could not get bucket info for bucket=" << bucket_name << ": " << cpp_strerror(-r) << std::endl;
1464 return -r;
1465 }
1466 RGWRateLimitInfo ratelimit_info;
1467 auto iter = bucket->get_attrs().find(RGW_ATTR_RATELIMIT);
1468 if(iter != bucket->get_attrs().end()) {
1469 try {
1470 bufferlist& bl = iter->second;
1471 auto biter = bl.cbegin();
1472 decode(ratelimit_info, biter);
1473 } catch (buffer::error& err) {
1474 ldpp_dout(dpp(), 0) << "ERROR: failed to decode rate limit" << dendl;
1475 return -EIO;
1476 }
1477 }
1478 bool ratelimit_configured = set_ratelimit_info(ratelimit_info, opt_cmd, max_read_ops, max_write_ops,
1479 max_read_bytes, max_write_bytes,
1480 have_max_read_ops, have_max_write_ops,
1481 have_max_read_bytes, have_max_write_bytes);
1482 if (!ratelimit_configured) {
1483 ldpp_dout(dpp(), 0) << "ERROR: no rate limit values have been specified" << dendl;
1484 return -EINVAL;
1485 }
1486 bufferlist bl;
1487 ratelimit_info.encode(bl);
1488 rgw::sal::Attrs attr;
1489 attr[RGW_ATTR_RATELIMIT] = bl;
1490 r = bucket->merge_and_store_attrs(dpp(), attr, null_yield);
1491 if (r < 0) {
1492 cerr << "ERROR: failed writing bucket instance info: " << cpp_strerror(-r) << std::endl;
1493 return -r;
1494 }
1495 return 0;
1496 }
1497
1498 int set_user_ratelimit(OPT opt_cmd, std::unique_ptr<rgw::sal::User>& user,
1499 int64_t max_read_ops, int64_t max_write_ops,
1500 int64_t max_read_bytes, int64_t max_write_bytes,
1501 bool have_max_read_ops, bool have_max_write_ops,
1502 bool have_max_read_bytes, bool have_max_write_bytes)
1503 {
1504 RGWRateLimitInfo ratelimit_info;
1505 user->load_user(dpp(), null_yield);
1506 auto iter = user->get_attrs().find(RGW_ATTR_RATELIMIT);
1507 if(iter != user->get_attrs().end()) {
1508 try {
1509 bufferlist& bl = iter->second;
1510 auto biter = bl.cbegin();
1511 decode(ratelimit_info, biter);
1512 } catch (buffer::error& err) {
1513 ldpp_dout(dpp(), 0) << "ERROR: failed to decode rate limit" << dendl;
1514 return -EIO;
1515 }
1516 }
1517 bool ratelimit_configured = set_ratelimit_info(ratelimit_info, opt_cmd, max_read_ops, max_write_ops,
1518 max_read_bytes, max_write_bytes,
1519 have_max_read_ops, have_max_write_ops,
1520 have_max_read_bytes, have_max_write_bytes);
1521 if (!ratelimit_configured) {
1522 ldpp_dout(dpp(), 0) << "ERROR: no rate limit values have been specified" << dendl;
1523 return -EINVAL;
1524 }
1525 bufferlist bl;
1526 ratelimit_info.encode(bl);
1527 rgw::sal::Attrs attr;
1528 attr[RGW_ATTR_RATELIMIT] = bl;
1529 int r = user->merge_and_store_attrs(dpp(), attr, null_yield);
1530 if (r < 0) {
1531 cerr << "ERROR: failed writing user instance info: " << cpp_strerror(-r) << std::endl;
1532 return -r;
1533 }
1534 return 0;
1535 }
1536
1537 int show_user_ratelimit(std::unique_ptr<rgw::sal::User>& user, Formatter *formatter)
1538 {
1539 RGWRateLimitInfo ratelimit_info;
1540 user->load_user(dpp(), null_yield);
1541 auto iter = user->get_attrs().find(RGW_ATTR_RATELIMIT);
1542 if(iter != user->get_attrs().end()) {
1543 try {
1544 bufferlist& bl = iter->second;
1545 auto biter = bl.cbegin();
1546 decode(ratelimit_info, biter);
1547 } catch (buffer::error& err) {
1548 ldpp_dout(dpp(), 0) << "ERROR: failed to decode rate limit" << dendl;
1549 return -EIO;
1550 }
1551 }
1552 formatter->open_object_section("user_ratelimit");
1553 encode_json("user_ratelimit", ratelimit_info, formatter);
1554 formatter->close_section();
1555 formatter->flush(cout);
1556 cout << std::endl;
1557 return 0;
1558 }
1559
1560 int show_bucket_ratelimit(rgw::sal::Driver* driver, const string& tenant_name,
1561 const string& bucket_name, Formatter *formatter)
1562 {
1563 std::unique_ptr<rgw::sal::Bucket> bucket;
1564 int r = driver->get_bucket(dpp(), nullptr, tenant_name, bucket_name, &bucket, null_yield);
1565 if (r < 0) {
1566 cerr << "could not get bucket info for bucket=" << bucket_name << ": " << cpp_strerror(-r) << std::endl;
1567 return -r;
1568 }
1569 RGWRateLimitInfo ratelimit_info;
1570 auto iter = bucket->get_attrs().find(RGW_ATTR_RATELIMIT);
1571 if (iter != bucket->get_attrs().end()) {
1572 try {
1573 bufferlist& bl = iter->second;
1574 auto biter = bl.cbegin();
1575 decode(ratelimit_info, biter);
1576 } catch (buffer::error& err) {
1577 ldpp_dout(dpp(), 0) << "ERROR: failed to decode rate limit" << dendl;
1578 return -EIO;
1579 }
1580 }
1581 formatter->open_object_section("bucket_ratelimit");
1582 encode_json("bucket_ratelimit", ratelimit_info, formatter);
1583 formatter->close_section();
1584 formatter->flush(cout);
1585 cout << std::endl;
1586 return 0;
1587 }
1588 int set_user_bucket_quota(OPT opt_cmd, RGWUser& user, RGWUserAdminOpState& op_state, int64_t max_size, int64_t max_objects,
1589 bool have_max_size, bool have_max_objects)
1590 {
1591 RGWUserInfo& user_info = op_state.get_user_info();
1592
1593 set_quota_info(user_info.quota.bucket_quota, opt_cmd, max_size, max_objects, have_max_size, have_max_objects);
1594
1595 op_state.set_bucket_quota(user_info.quota.bucket_quota);
1596
1597 string err;
1598 int r = user.modify(dpp(), op_state, null_yield, &err);
1599 if (r < 0) {
1600 cerr << "ERROR: failed updating user info: " << cpp_strerror(-r) << ": " << err << std::endl;
1601 return -r;
1602 }
1603 return 0;
1604 }
1605
1606 int set_user_quota(OPT opt_cmd, RGWUser& user, RGWUserAdminOpState& op_state, int64_t max_size, int64_t max_objects,
1607 bool have_max_size, bool have_max_objects)
1608 {
1609 RGWUserInfo& user_info = op_state.get_user_info();
1610
1611 set_quota_info(user_info.quota.user_quota, opt_cmd, max_size, max_objects, have_max_size, have_max_objects);
1612
1613 op_state.set_user_quota(user_info.quota.user_quota);
1614
1615 string err;
1616 int r = user.modify(dpp(), op_state, null_yield, &err);
1617 if (r < 0) {
1618 cerr << "ERROR: failed updating user info: " << cpp_strerror(-r) << ": " << err << std::endl;
1619 return -r;
1620 }
1621 return 0;
1622 }
1623
1624 int check_min_obj_stripe_size(rgw::sal::Driver* driver, rgw::sal::Object* obj, uint64_t min_stripe_size, bool *need_rewrite)
1625 {
1626 int ret = obj->get_obj_attrs(null_yield, dpp());
1627 if (ret < 0) {
1628 ldpp_dout(dpp(), -1) << "ERROR: failed to stat object, returned error: " << cpp_strerror(-ret) << dendl;
1629 return ret;
1630 }
1631
1632 map<string, bufferlist>::iterator iter;
1633 iter = obj->get_attrs().find(RGW_ATTR_MANIFEST);
1634 if (iter == obj->get_attrs().end()) {
1635 *need_rewrite = (obj->get_obj_size() >= min_stripe_size);
1636 return 0;
1637 }
1638
1639 RGWObjManifest manifest;
1640
1641 try {
1642 bufferlist& bl = iter->second;
1643 auto biter = bl.cbegin();
1644 decode(manifest, biter);
1645 } catch (buffer::error& err) {
1646 ldpp_dout(dpp(), 0) << "ERROR: failed to decode manifest" << dendl;
1647 return -EIO;
1648 }
1649
1650 map<uint64_t, RGWObjManifestPart>& objs = manifest.get_explicit_objs();
1651 map<uint64_t, RGWObjManifestPart>::iterator oiter;
1652 for (oiter = objs.begin(); oiter != objs.end(); ++oiter) {
1653 RGWObjManifestPart& part = oiter->second;
1654
1655 if (part.size >= min_stripe_size) {
1656 *need_rewrite = true;
1657 return 0;
1658 }
1659 }
1660 *need_rewrite = false;
1661
1662 return 0;
1663 }
1664
1665
1666 int check_obj_locator_underscore(rgw::sal::Object* obj, bool fix, bool remove_bad, Formatter *f) {
1667 f->open_object_section("object");
1668 f->open_object_section("key");
1669 f->dump_string("type", "head");
1670 f->dump_string("name", obj->get_name());
1671 f->dump_string("instance", obj->get_instance());
1672 f->close_section();
1673
1674 string oid;
1675 string locator;
1676
1677 get_obj_bucket_and_oid_loc(obj->get_obj(), oid, locator);
1678
1679 f->dump_string("oid", oid);
1680 f->dump_string("locator", locator);
1681
1682 std::unique_ptr<rgw::sal::Object::ReadOp> read_op = obj->get_read_op();
1683
1684 int ret = read_op->prepare(null_yield, dpp());
1685 bool needs_fixing = (ret == -ENOENT);
1686
1687 f->dump_bool("needs_fixing", needs_fixing);
1688
1689 string status = (needs_fixing ? "needs_fixing" : "ok");
1690
1691 if ((needs_fixing || remove_bad) && fix) {
1692 ret = static_cast<rgw::sal::RadosStore*>(driver)->getRados()->fix_head_obj_locator(dpp(), obj->get_bucket()->get_info(), needs_fixing, remove_bad, obj->get_key());
1693 if (ret < 0) {
1694 cerr << "ERROR: fix_head_object_locator() returned ret=" << ret << std::endl;
1695 goto done;
1696 }
1697 status = "fixed";
1698 }
1699
1700 done:
1701 f->dump_string("status", status);
1702
1703 f->close_section();
1704
1705 return 0;
1706 }
1707
1708 int check_obj_tail_locator_underscore(RGWBucketInfo& bucket_info, rgw_obj_key& key, bool fix, Formatter *f) {
1709 f->open_object_section("object");
1710 f->open_object_section("key");
1711 f->dump_string("type", "tail");
1712 f->dump_string("name", key.name);
1713 f->dump_string("instance", key.instance);
1714 f->close_section();
1715
1716 bool needs_fixing;
1717 string status;
1718
1719 int ret = static_cast<rgw::sal::RadosStore*>(driver)->getRados()->fix_tail_obj_locator(dpp(), bucket_info, key, fix, &needs_fixing, null_yield);
1720 if (ret < 0) {
1721 cerr << "ERROR: fix_tail_object_locator_underscore() returned ret=" << ret << std::endl;
1722 status = "failed";
1723 } else {
1724 status = (needs_fixing && !fix ? "needs_fixing" : "ok");
1725 }
1726
1727 f->dump_bool("needs_fixing", needs_fixing);
1728 f->dump_string("status", status);
1729
1730 f->close_section();
1731
1732 return 0;
1733 }
1734
1735 int do_check_object_locator(const string& tenant_name, const string& bucket_name,
1736 bool fix, bool remove_bad, Formatter *f)
1737 {
1738 if (remove_bad && !fix) {
1739 cerr << "ERROR: can't have remove_bad specified without fix" << std::endl;
1740 return -EINVAL;
1741 }
1742
1743 std::unique_ptr<rgw::sal::Bucket> bucket;
1744 string bucket_id;
1745
1746 f->open_object_section("bucket");
1747 f->dump_string("bucket", bucket_name);
1748 int ret = init_bucket(nullptr, tenant_name, bucket_name, bucket_id, &bucket);
1749 if (ret < 0) {
1750 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
1751 return ret;
1752 }
1753 int count = 0;
1754
1755 int max_entries = 1000;
1756
1757 string prefix;
1758 string delim;
1759 string marker;
1760 vector<rgw_bucket_dir_entry> result;
1761 string ns;
1762
1763 rgw::sal::Bucket::ListParams params;
1764 rgw::sal::Bucket::ListResults results;
1765
1766 params.prefix = prefix;
1767 params.delim = delim;
1768 params.marker = rgw_obj_key(marker);
1769 params.ns = ns;
1770 params.enforce_ns = true;
1771 params.list_versions = true;
1772
1773 f->open_array_section("check_objects");
1774 do {
1775 ret = bucket->list(dpp(), params, max_entries - count, results, null_yield);
1776 if (ret < 0) {
1777 cerr << "ERROR: driver->list_objects(): " << cpp_strerror(-ret) << std::endl;
1778 return -ret;
1779 }
1780
1781 count += results.objs.size();
1782
1783 for (vector<rgw_bucket_dir_entry>::iterator iter = results.objs.begin(); iter != results.objs.end(); ++iter) {
1784 std::unique_ptr<rgw::sal::Object> obj = bucket->get_object(iter->key);
1785
1786 if (obj->get_name()[0] == '_') {
1787 ret = check_obj_locator_underscore(obj.get(), fix, remove_bad, f);
1788
1789 if (ret >= 0) {
1790 ret = check_obj_tail_locator_underscore(bucket->get_info(), obj->get_key(), fix, f);
1791 if (ret < 0) {
1792 cerr << "ERROR: check_obj_tail_locator_underscore(): " << cpp_strerror(-ret) << std::endl;
1793 return -ret;
1794 }
1795 }
1796 }
1797 }
1798 f->flush(cout);
1799 } while (results.is_truncated && count < max_entries);
1800 f->close_section();
1801 f->close_section();
1802
1803 f->flush(cout);
1804
1805 return 0;
1806 }
1807
1808 /// search for a matching zone/zonegroup id and return a connection if found
1809 static boost::optional<RGWRESTConn> get_remote_conn(rgw::sal::RadosStore* driver,
1810 const RGWZoneGroup& zonegroup,
1811 const std::string& remote)
1812 {
1813 boost::optional<RGWRESTConn> conn;
1814 if (remote == zonegroup.get_id()) {
1815 conn.emplace(driver->ctx(), driver, remote, zonegroup.endpoints, zonegroup.api_name);
1816 } else {
1817 for (const auto& z : zonegroup.zones) {
1818 const auto& zone = z.second;
1819 if (remote == zone.id) {
1820 conn.emplace(driver->ctx(), driver, remote, zone.endpoints, zonegroup.api_name);
1821 break;
1822 }
1823 }
1824 }
1825 return conn;
1826 }
1827
1828 /// search each zonegroup for a connection
1829 static boost::optional<RGWRESTConn> get_remote_conn(rgw::sal::RadosStore* driver,
1830 const RGWPeriodMap& period_map,
1831 const std::string& remote)
1832 {
1833 boost::optional<RGWRESTConn> conn;
1834 for (const auto& zg : period_map.zonegroups) {
1835 conn = get_remote_conn(driver, zg.second, remote);
1836 if (conn) {
1837 break;
1838 }
1839 }
1840 return conn;
1841 }
1842
1843 // we expect a very small response
1844 static constexpr size_t MAX_REST_RESPONSE = 128 * 1024;
1845
1846 static int send_to_remote_gateway(RGWRESTConn* conn, req_info& info,
1847 bufferlist& in_data, JSONParser& parser)
1848 {
1849 if (!conn) {
1850 return -EINVAL;
1851 }
1852
1853 ceph::bufferlist response;
1854 rgw_user user;
1855 int ret = conn->forward(dpp(), user, info, nullptr, MAX_REST_RESPONSE, &in_data, &response, null_yield);
1856
1857 int parse_ret = parser.parse(response.c_str(), response.length());
1858 if (parse_ret < 0) {
1859 cerr << "failed to parse response" << std::endl;
1860 return parse_ret;
1861 }
1862 return ret;
1863 }
1864
1865 static int send_to_url(const string& url,
1866 std::optional<string> opt_region,
1867 const string& access,
1868 const string& secret, req_info& info,
1869 bufferlist& in_data, JSONParser& parser)
1870 {
1871 if (access.empty() || secret.empty()) {
1872 cerr << "An --access-key and --secret must be provided with --url." << std::endl;
1873 return -EINVAL;
1874 }
1875 RGWAccessKey key;
1876 key.id = access;
1877 key.key = secret;
1878
1879 param_vec_t params;
1880 RGWRESTSimpleRequest req(g_ceph_context, info.method, url, NULL, &params, opt_region);
1881
1882 bufferlist response;
1883 int ret = req.forward_request(dpp(), key, info, MAX_REST_RESPONSE, &in_data, &response, null_yield);
1884
1885 int parse_ret = parser.parse(response.c_str(), response.length());
1886 if (parse_ret < 0) {
1887 cout << "failed to parse response" << std::endl;
1888 return parse_ret;
1889 }
1890 return ret;
1891 }
1892
1893 static int send_to_remote_or_url(RGWRESTConn *conn, const string& url,
1894 std::optional<string> opt_region,
1895 const string& access, const string& secret,
1896 req_info& info, bufferlist& in_data,
1897 JSONParser& parser)
1898 {
1899 if (url.empty()) {
1900 return send_to_remote_gateway(conn, info, in_data, parser);
1901 }
1902 return send_to_url(url, opt_region, access, secret, info, in_data, parser);
1903 }
1904
1905 static int commit_period(rgw::sal::ConfigStore* cfgstore,
1906 RGWRealm& realm, rgw::sal::RealmWriter& realm_writer,
1907 RGWPeriod& period, string remote, const string& url,
1908 std::optional<string> opt_region,
1909 const string& access, const string& secret,
1910 bool force)
1911 {
1912 auto& master_zone = period.get_master_zone().id;
1913 if (master_zone.empty()) {
1914 cerr << "cannot commit period: period does not have a master zone of a master zonegroup" << std::endl;
1915 return -EINVAL;
1916 }
1917 // are we the period's master zone?
1918 if (driver->get_zone()->get_id() == master_zone) {
1919 // read the current period
1920 RGWPeriod current_period;
1921 int ret = cfgstore->read_period(dpp(), null_yield, realm.current_period,
1922 std::nullopt, current_period);
1923 if (ret < 0) {
1924 cerr << "failed to load current period: " << cpp_strerror(ret) << std::endl;
1925 return ret;
1926 }
1927 // the master zone can commit locally
1928 ret = rgw::commit_period(dpp(), null_yield, cfgstore, driver,
1929 realm, realm_writer, current_period,
1930 period, cerr, force);
1931 if (ret < 0) {
1932 cerr << "failed to commit period: " << cpp_strerror(-ret) << std::endl;
1933 }
1934 return ret;
1935 }
1936
1937 if (remote.empty() && url.empty()) {
1938 // use the new master zone's connection
1939 remote = master_zone;
1940 cerr << "Sending period to new master zone " << remote << std::endl;
1941 }
1942 boost::optional<RGWRESTConn> conn;
1943 RGWRESTConn *remote_conn = nullptr;
1944 if (!remote.empty()) {
1945 conn = get_remote_conn(static_cast<rgw::sal::RadosStore*>(driver), period.get_map(), remote);
1946 if (!conn) {
1947 cerr << "failed to find a zone or zonegroup for remote "
1948 << remote << std::endl;
1949 return -ENOENT;
1950 }
1951 remote_conn = &*conn;
1952 }
1953
1954 // push period to the master with an empty period id
1955 period.set_id(string());
1956
1957 RGWEnv env;
1958 req_info info(g_ceph_context, &env);
1959 info.method = "POST";
1960 info.request_uri = "/admin/realm/period";
1961
1962 // json format into a bufferlist
1963 JSONFormatter jf(false);
1964 encode_json("period", period, &jf);
1965 bufferlist bl;
1966 jf.flush(bl);
1967
1968 JSONParser p;
1969 int ret = send_to_remote_or_url(remote_conn, url, opt_region, access, secret, info, bl, p);
1970 if (ret < 0) {
1971 cerr << "request failed: " << cpp_strerror(-ret) << std::endl;
1972
1973 // did we parse an error message?
1974 auto message = p.find_obj("Message");
1975 if (message) {
1976 cerr << "Reason: " << message->get_data() << std::endl;
1977 }
1978 return ret;
1979 }
1980
1981 // decode the response and driver it back
1982 try {
1983 decode_json_obj(period, &p);
1984 } catch (const JSONDecoder::err& e) {
1985 cout << "failed to decode JSON input: " << e.what() << std::endl;
1986 return -EINVAL;
1987 }
1988 if (period.get_id().empty()) {
1989 cerr << "Period commit got back an empty period id" << std::endl;
1990 return -EINVAL;
1991 }
1992 // the master zone gave us back the period that it committed, so it's
1993 // safe to save it as our latest epoch
1994 constexpr bool exclusive = false;
1995 ret = cfgstore->create_period(dpp(), null_yield, exclusive, period);
1996 if (ret < 0) {
1997 cerr << "Error storing committed period " << period.get_id() << ": "
1998 << cpp_strerror(ret) << std::endl;
1999 return ret;
2000 }
2001 ret = rgw::reflect_period(dpp(), null_yield, cfgstore, period);
2002 if (ret < 0) {
2003 cerr << "Error updating local objects: " << cpp_strerror(ret) << std::endl;
2004 return ret;
2005 }
2006 (void) cfgstore->realm_notify_new_period(dpp(), null_yield, period);
2007 return ret;
2008 }
2009
2010 static int update_period(rgw::sal::ConfigStore* cfgstore,
2011 const string& realm_id, const string& realm_name,
2012 const string& period_epoch, bool commit,
2013 const string& remote, const string& url,
2014 std::optional<string> opt_region,
2015 const string& access, const string& secret,
2016 Formatter *formatter, bool force)
2017 {
2018 RGWRealm realm;
2019 std::unique_ptr<rgw::sal::RealmWriter> realm_writer;
2020 int ret = rgw::read_realm(dpp(), null_yield, cfgstore,
2021 realm_id, realm_name,
2022 realm, &realm_writer);
2023 if (ret < 0) {
2024 cerr << "failed to load realm " << cpp_strerror(-ret) << std::endl;
2025 return ret;
2026 }
2027 std::optional<epoch_t> epoch;
2028 if (!period_epoch.empty()) {
2029 epoch = atoi(period_epoch.c_str());
2030 }
2031 RGWPeriod period;
2032 ret = cfgstore->read_period(dpp(), null_yield, realm.current_period,
2033 epoch, period);
2034 if (ret < 0) {
2035 cerr << "failed to load current period: " << cpp_strerror(-ret) << std::endl;
2036 return ret;
2037 }
2038 // convert to the realm's staging period
2039 rgw::fork_period(dpp(), period);
2040 // update the staging period with all of the realm's zonegroups
2041 ret = rgw::update_period(dpp(), null_yield, cfgstore, period);
2042 if (ret < 0) {
2043 return ret;
2044 }
2045
2046 constexpr bool exclusive = false;
2047 ret = cfgstore->create_period(dpp(), null_yield, exclusive, period);
2048 if (ret < 0) {
2049 cerr << "failed to driver period: " << cpp_strerror(-ret) << std::endl;
2050 return ret;
2051 }
2052 if (commit) {
2053 ret = commit_period(cfgstore, realm, *realm_writer, period, remote, url,
2054 opt_region, access, secret, force);
2055 if (ret < 0) {
2056 cerr << "failed to commit period: " << cpp_strerror(-ret) << std::endl;
2057 return ret;
2058 }
2059 }
2060 encode_json("period", period, formatter);
2061 formatter->flush(cout);
2062 return 0;
2063 }
2064
2065 static int init_bucket_for_sync(rgw::sal::User* user,
2066 const string& tenant, const string& bucket_name,
2067 const string& bucket_id,
2068 std::unique_ptr<rgw::sal::Bucket>* bucket)
2069 {
2070 int ret = init_bucket(user, tenant, bucket_name, bucket_id, bucket);
2071 if (ret < 0) {
2072 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
2073 return ret;
2074 }
2075
2076 return 0;
2077 }
2078
2079 static int do_period_pull(rgw::sal::ConfigStore* cfgstore,
2080 RGWRESTConn *remote_conn, const string& url,
2081 std::optional<string> opt_region,
2082 const string& access_key, const string& secret_key,
2083 const string& realm_id, const string& realm_name,
2084 const string& period_id, const string& period_epoch,
2085 RGWPeriod *period)
2086 {
2087 RGWEnv env;
2088 req_info info(g_ceph_context, &env);
2089 info.method = "GET";
2090 info.request_uri = "/admin/realm/period";
2091
2092 map<string, string> &params = info.args.get_params();
2093 if (!realm_id.empty())
2094 params["realm_id"] = realm_id;
2095 if (!realm_name.empty())
2096 params["realm_name"] = realm_name;
2097 if (!period_id.empty())
2098 params["period_id"] = period_id;
2099 if (!period_epoch.empty())
2100 params["epoch"] = period_epoch;
2101
2102 bufferlist bl;
2103 JSONParser p;
2104 int ret = send_to_remote_or_url(remote_conn, url, opt_region, access_key, secret_key,
2105 info, bl, p);
2106 if (ret < 0) {
2107 cerr << "request failed: " << cpp_strerror(-ret) << std::endl;
2108 return ret;
2109 }
2110 try {
2111 decode_json_obj(*period, &p);
2112 } catch (const JSONDecoder::err& e) {
2113 cout << "failed to decode JSON input: " << e.what() << std::endl;
2114 return -EINVAL;
2115 }
2116 constexpr bool exclusive = false;
2117 ret = cfgstore->create_period(dpp(), null_yield, exclusive, *period);
2118 if (ret < 0) {
2119 cerr << "Error storing period " << period->get_id() << ": " << cpp_strerror(ret) << std::endl;
2120 }
2121 return 0;
2122 }
2123
2124 void flush_ss(stringstream& ss, list<string>& l)
2125 {
2126 if (!ss.str().empty()) {
2127 l.push_back(ss.str());
2128 }
2129 ss.str("");
2130 }
2131
2132 stringstream& push_ss(stringstream& ss, list<string>& l, int tab = 0)
2133 {
2134 flush_ss(ss, l);
2135 if (tab > 0) {
2136 ss << setw(tab) << "" << setw(1);
2137 }
2138 return ss;
2139 }
2140
2141 static void get_md_sync_status(list<string>& status)
2142 {
2143 RGWMetaSyncStatusManager sync(static_cast<rgw::sal::RadosStore*>(driver), static_cast<rgw::sal::RadosStore*>(driver)->svc()->rados->get_async_processor());
2144
2145 int ret = sync.init(dpp());
2146 if (ret < 0) {
2147 status.push_back(string("failed to retrieve sync info: sync.init() failed: ") + cpp_strerror(-ret));
2148 return;
2149 }
2150
2151 rgw_meta_sync_status sync_status;
2152 ret = sync.read_sync_status(dpp(), &sync_status);
2153 if (ret < 0) {
2154 status.push_back(string("failed to read sync status: ") + cpp_strerror(-ret));
2155 return;
2156 }
2157
2158 string status_str;
2159 switch (sync_status.sync_info.state) {
2160 case rgw_meta_sync_info::StateInit:
2161 status_str = "init";
2162 break;
2163 case rgw_meta_sync_info::StateBuildingFullSyncMaps:
2164 status_str = "preparing for full sync";
2165 break;
2166 case rgw_meta_sync_info::StateSync:
2167 status_str = "syncing";
2168 break;
2169 default:
2170 status_str = "unknown";
2171 }
2172
2173 status.push_back(status_str);
2174
2175 uint64_t full_total = 0;
2176 uint64_t full_complete = 0;
2177
2178 int num_full = 0;
2179 int num_inc = 0;
2180 int total_shards = 0;
2181 set<int> shards_behind_set;
2182
2183 for (auto marker_iter : sync_status.sync_markers) {
2184 full_total += marker_iter.second.total_entries;
2185 total_shards++;
2186 if (marker_iter.second.state == rgw_meta_sync_marker::SyncState::FullSync) {
2187 num_full++;
2188 full_complete += marker_iter.second.pos;
2189 int shard_id = marker_iter.first;
2190 shards_behind_set.insert(shard_id);
2191 } else {
2192 full_complete += marker_iter.second.total_entries;
2193 }
2194 if (marker_iter.second.state == rgw_meta_sync_marker::SyncState::IncrementalSync) {
2195 num_inc++;
2196 }
2197 }
2198
2199 stringstream ss;
2200 push_ss(ss, status) << "full sync: " << num_full << "/" << total_shards << " shards";
2201
2202 if (num_full > 0) {
2203 push_ss(ss, status) << "full sync: " << full_total - full_complete << " entries to sync";
2204 }
2205
2206 push_ss(ss, status) << "incremental sync: " << num_inc << "/" << total_shards << " shards";
2207
2208 map<int, RGWMetadataLogInfo> master_shards_info;
2209 string master_period = static_cast<rgw::sal::RadosStore*>(driver)->svc()->zone->get_current_period_id();
2210
2211 ret = sync.read_master_log_shards_info(dpp(), master_period, &master_shards_info);
2212 if (ret < 0) {
2213 status.push_back(string("failed to fetch master sync status: ") + cpp_strerror(-ret));
2214 return;
2215 }
2216
2217 map<int, string> shards_behind;
2218 if (sync_status.sync_info.period != master_period) {
2219 status.push_back(string("master is on a different period: master_period=" +
2220 master_period + " local_period=" + sync_status.sync_info.period));
2221 } else {
2222 for (auto local_iter : sync_status.sync_markers) {
2223 int shard_id = local_iter.first;
2224 auto iter = master_shards_info.find(shard_id);
2225
2226 if (iter == master_shards_info.end()) {
2227 /* huh? */
2228 derr << "ERROR: could not find remote sync shard status for shard_id=" << shard_id << dendl;
2229 continue;
2230 }
2231 auto master_marker = iter->second.marker;
2232 if (local_iter.second.state == rgw_meta_sync_marker::SyncState::IncrementalSync &&
2233 master_marker > local_iter.second.marker) {
2234 shards_behind[shard_id] = local_iter.second.marker;
2235 shards_behind_set.insert(shard_id);
2236 }
2237 }
2238 }
2239
2240 // fetch remote log entries to determine the oldest change
2241 std::optional<std::pair<int, ceph::real_time>> oldest;
2242 if (!shards_behind.empty()) {
2243 map<int, rgw_mdlog_shard_data> master_pos;
2244 ret = sync.read_master_log_shards_next(dpp(), sync_status.sync_info.period, shards_behind, &master_pos);
2245 if (ret < 0) {
2246 derr << "ERROR: failed to fetch master next positions (" << cpp_strerror(-ret) << ")" << dendl;
2247 } else {
2248 for (auto iter : master_pos) {
2249 rgw_mdlog_shard_data& shard_data = iter.second;
2250
2251 if (shard_data.entries.empty()) {
2252 // there aren't any entries in this shard, so we're not really behind
2253 shards_behind.erase(iter.first);
2254 shards_behind_set.erase(iter.first);
2255 } else {
2256 rgw_mdlog_entry& entry = shard_data.entries.front();
2257 if (!oldest) {
2258 oldest.emplace(iter.first, entry.timestamp);
2259 } else if (!ceph::real_clock::is_zero(entry.timestamp) && entry.timestamp < oldest->second) {
2260 oldest.emplace(iter.first, entry.timestamp);
2261 }
2262 }
2263 }
2264 }
2265 }
2266
2267 int total_behind = shards_behind.size() + (sync_status.sync_info.num_shards - num_inc);
2268 if (total_behind == 0) {
2269 push_ss(ss, status) << "metadata is caught up with master";
2270 } else {
2271 push_ss(ss, status) << "metadata is behind on " << total_behind << " shards";
2272 push_ss(ss, status) << "behind shards: " << "[" << shards_behind_set << "]";
2273 if (oldest) {
2274 push_ss(ss, status) << "oldest incremental change not applied: "
2275 << oldest->second << " [" << oldest->first << ']';
2276 }
2277 }
2278
2279 flush_ss(ss, status);
2280 }
2281
2282 static void get_data_sync_status(const rgw_zone_id& source_zone, list<string>& status, int tab)
2283 {
2284 stringstream ss;
2285
2286 RGWZone *sz;
2287
2288 if (!(sz = static_cast<rgw::sal::RadosStore*>(driver)->svc()->zone->find_zone(source_zone))) {
2289 push_ss(ss, status, tab) << string("zone not found");
2290 flush_ss(ss, status);
2291 return;
2292 }
2293
2294 if (!static_cast<rgw::sal::RadosStore*>(driver)->svc()->zone->zone_syncs_from(*sz)) {
2295 push_ss(ss, status, tab) << string("not syncing from zone");
2296 flush_ss(ss, status);
2297 return;
2298 }
2299 RGWDataSyncStatusManager sync(static_cast<rgw::sal::RadosStore*>(driver), static_cast<rgw::sal::RadosStore*>(driver)->svc()->rados->get_async_processor(), source_zone, nullptr);
2300
2301 int ret = sync.init(dpp());
2302 if (ret < 0) {
2303 push_ss(ss, status, tab) << string("failed to retrieve sync info: ") + cpp_strerror(-ret);
2304 flush_ss(ss, status);
2305 return;
2306 }
2307
2308 rgw_data_sync_status sync_status;
2309 ret = sync.read_sync_status(dpp(), &sync_status);
2310 if (ret < 0 && ret != -ENOENT) {
2311 push_ss(ss, status, tab) << string("failed read sync status: ") + cpp_strerror(-ret);
2312 return;
2313 }
2314
2315 set<int> recovering_shards;
2316 ret = sync.read_recovering_shards(dpp(), sync_status.sync_info.num_shards, recovering_shards);
2317 if (ret < 0 && ret != ENOENT) {
2318 push_ss(ss, status, tab) << string("failed read recovering shards: ") + cpp_strerror(-ret);
2319 return;
2320 }
2321
2322 string status_str;
2323 switch (sync_status.sync_info.state) {
2324 case rgw_data_sync_info::StateInit:
2325 status_str = "init";
2326 break;
2327 case rgw_data_sync_info::StateBuildingFullSyncMaps:
2328 status_str = "preparing for full sync";
2329 break;
2330 case rgw_data_sync_info::StateSync:
2331 status_str = "syncing";
2332 break;
2333 default:
2334 status_str = "unknown";
2335 }
2336
2337 push_ss(ss, status, tab) << status_str;
2338
2339 uint64_t full_total = 0;
2340 uint64_t full_complete = 0;
2341
2342 int num_full = 0;
2343 int num_inc = 0;
2344 int total_shards = 0;
2345 set<int> shards_behind_set;
2346
2347 for (auto marker_iter : sync_status.sync_markers) {
2348 full_total += marker_iter.second.total_entries;
2349 total_shards++;
2350 if (marker_iter.second.state == rgw_data_sync_marker::SyncState::FullSync) {
2351 num_full++;
2352 full_complete += marker_iter.second.pos;
2353 int shard_id = marker_iter.first;
2354 shards_behind_set.insert(shard_id);
2355 } else {
2356 full_complete += marker_iter.second.total_entries;
2357 }
2358 if (marker_iter.second.state == rgw_data_sync_marker::SyncState::IncrementalSync) {
2359 num_inc++;
2360 }
2361 }
2362
2363 push_ss(ss, status, tab) << "full sync: " << num_full << "/" << total_shards << " shards";
2364
2365 if (num_full > 0) {
2366 push_ss(ss, status, tab) << "full sync: " << full_total - full_complete << " buckets to sync";
2367 }
2368
2369 push_ss(ss, status, tab) << "incremental sync: " << num_inc << "/" << total_shards << " shards";
2370
2371 map<int, RGWDataChangesLogInfo> source_shards_info;
2372
2373 ret = sync.read_source_log_shards_info(dpp(), &source_shards_info);
2374 if (ret < 0) {
2375 push_ss(ss, status, tab) << string("failed to fetch source sync status: ") + cpp_strerror(-ret);
2376 return;
2377 }
2378
2379 map<int, string> shards_behind;
2380
2381 for (auto local_iter : sync_status.sync_markers) {
2382 int shard_id = local_iter.first;
2383 auto iter = source_shards_info.find(shard_id);
2384
2385 if (iter == source_shards_info.end()) {
2386 /* huh? */
2387 derr << "ERROR: could not find remote sync shard status for shard_id=" << shard_id << dendl;
2388 continue;
2389 }
2390 auto master_marker = iter->second.marker;
2391 if (local_iter.second.state == rgw_data_sync_marker::SyncState::IncrementalSync &&
2392 master_marker > local_iter.second.marker) {
2393 shards_behind[shard_id] = local_iter.second.marker;
2394 shards_behind_set.insert(shard_id);
2395 }
2396 }
2397
2398 std::optional<std::pair<int, ceph::real_time>> oldest;
2399 if (!shards_behind.empty()) {
2400 map<int, rgw_datalog_shard_data> master_pos;
2401 ret = sync.read_source_log_shards_next(dpp(), shards_behind, &master_pos);
2402
2403 if (ret < 0) {
2404 derr << "ERROR: failed to fetch next positions (" << cpp_strerror(-ret) << ")" << dendl;
2405 } else {
2406 for (auto iter : master_pos) {
2407 rgw_datalog_shard_data& shard_data = iter.second;
2408 if (shard_data.entries.empty()) {
2409 // there aren't any entries in this shard, so we're not really behind
2410 shards_behind.erase(iter.first);
2411 shards_behind_set.erase(iter.first);
2412 } else {
2413 rgw_datalog_entry& entry = shard_data.entries.front();
2414 if (!oldest) {
2415 oldest.emplace(iter.first, entry.timestamp);
2416 } else if (!ceph::real_clock::is_zero(entry.timestamp) && entry.timestamp < oldest->second) {
2417 oldest.emplace(iter.first, entry.timestamp);
2418 }
2419 }
2420 }
2421 }
2422 }
2423
2424 int total_behind = shards_behind.size() + (sync_status.sync_info.num_shards - num_inc);
2425 int total_recovering = recovering_shards.size();
2426
2427 if (total_behind == 0 && total_recovering == 0) {
2428 push_ss(ss, status, tab) << "data is caught up with source";
2429 } else if (total_behind > 0) {
2430 push_ss(ss, status, tab) << "data is behind on " << total_behind << " shards";
2431 push_ss(ss, status, tab) << "behind shards: " << "[" << shards_behind_set << "]" ;
2432 if (oldest) {
2433 push_ss(ss, status, tab) << "oldest incremental change not applied: "
2434 << oldest->second << " [" << oldest->first << ']';
2435 }
2436 }
2437
2438 if (total_recovering > 0) {
2439 push_ss(ss, status, tab) << total_recovering << " shards are recovering";
2440 push_ss(ss, status, tab) << "recovering shards: " << "[" << recovering_shards << "]";
2441 }
2442
2443 flush_ss(ss, status);
2444 }
2445
2446 static void tab_dump(const string& header, int width, const list<string>& entries)
2447 {
2448 string s = header;
2449
2450 for (auto e : entries) {
2451 cout << std::setw(width) << s << std::setw(1) << " " << e << std::endl;
2452 s.clear();
2453 }
2454 }
2455
2456 // return features that are supported but not enabled
2457 static auto get_disabled_features(const rgw::zone_features::set& enabled) {
2458 auto features = rgw::zone_features::set{rgw::zone_features::supported.begin(),
2459 rgw::zone_features::supported.end()};
2460 for (const auto& feature : enabled) {
2461 features.erase(feature);
2462 }
2463 return features;
2464 }
2465
2466
2467 static void sync_status(Formatter *formatter)
2468 {
2469 const rgw::sal::ZoneGroup& zonegroup = driver->get_zone()->get_zonegroup();
2470 rgw::sal::Zone* zone = driver->get_zone();
2471
2472 int width = 15;
2473
2474 cout << std::setw(width) << "realm" << std::setw(1) << " " << zone->get_realm_id() << " (" << zone->get_realm_name() << ")" << std::endl;
2475 cout << std::setw(width) << "zonegroup" << std::setw(1) << " " << zonegroup.get_id() << " (" << zonegroup.get_name() << ")" << std::endl;
2476 cout << std::setw(width) << "zone" << std::setw(1) << " " << zone->get_id() << " (" << zone->get_name() << ")" << std::endl;
2477 cout << std::setw(width) << "current time" << std::setw(1) << " "
2478 << to_iso_8601(ceph::real_clock::now(), iso_8601_format::YMDhms) << std::endl;
2479
2480 const auto& rzg =
2481 static_cast<const rgw::sal::RadosZoneGroup&>(zonegroup).get_group();
2482
2483 cout << std::setw(width) << "zonegroup features enabled: " << rzg.enabled_features << std::endl;
2484 if (auto d = get_disabled_features(rzg.enabled_features); !d.empty()) {
2485 cout << std::setw(width) << " disabled: " << d << std::endl;
2486 }
2487
2488 list<string> md_status;
2489
2490 if (driver->is_meta_master()) {
2491 md_status.push_back("no sync (zone is master)");
2492 } else {
2493 get_md_sync_status(md_status);
2494 }
2495
2496 tab_dump("metadata sync", width, md_status);
2497
2498 list<string> data_status;
2499
2500 auto& zone_conn_map = static_cast<rgw::sal::RadosStore*>(driver)->svc()->zone->get_zone_conn_map();
2501
2502 for (auto iter : zone_conn_map) {
2503 const rgw_zone_id& source_id = iter.first;
2504 string source_str = "source: ";
2505 string s = source_str + source_id.id;
2506 std::unique_ptr<rgw::sal::Zone> sz;
2507 if (driver->get_zone()->get_zonegroup().get_zone_by_id(source_id.id, &sz) == 0) {
2508 s += string(" (") + sz->get_name() + ")";
2509 }
2510 data_status.push_back(s);
2511 get_data_sync_status(source_id, data_status, source_str.size());
2512 }
2513
2514 tab_dump("data sync", width, data_status);
2515 }
2516
2517 struct indented {
2518 int w; // indent width
2519 std::string_view header;
2520 indented(int w, std::string_view header = "") : w(w), header(header) {}
2521 };
2522 std::ostream& operator<<(std::ostream& out, const indented& h) {
2523 return out << std::setw(h.w) << h.header << std::setw(1) << ' ';
2524 }
2525
2526 static int bucket_source_sync_status(const DoutPrefixProvider *dpp, rgw::sal::RadosStore* driver, const RGWZone& zone,
2527 const RGWZone& source, RGWRESTConn *conn,
2528 const RGWBucketInfo& bucket_info,
2529 rgw_sync_bucket_pipe pipe,
2530 int width, std::ostream& out)
2531 {
2532 out << indented{width, "source zone"} << source.id << " (" << source.name << ")" << std::endl;
2533
2534 // syncing from this zone?
2535 if (!driver->svc()->zone->zone_syncs_from(zone, source)) {
2536 out << indented{width} << "does not sync from zone\n";
2537 return 0;
2538 }
2539
2540 if (!pipe.source.bucket) {
2541 ldpp_dout(dpp, -1) << __func__ << "(): missing source bucket" << dendl;
2542 return -EINVAL;
2543 }
2544
2545 std::unique_ptr<rgw::sal::Bucket> source_bucket;
2546 int r = init_bucket(nullptr, *pipe.source.bucket, &source_bucket);
2547 if (r < 0) {
2548 ldpp_dout(dpp, -1) << "failed to read source bucket info: " << cpp_strerror(r) << dendl;
2549 return r;
2550 }
2551
2552 out << indented{width, "source bucket"} << source_bucket->get_key() << std::endl;
2553 pipe.source.bucket = source_bucket->get_key();
2554
2555 pipe.dest.bucket = bucket_info.bucket;
2556
2557 uint64_t gen = 0;
2558 std::vector<rgw_bucket_shard_sync_info> shard_status;
2559
2560 // check for full sync status
2561 rgw_bucket_sync_status full_status;
2562 r = rgw_read_bucket_full_sync_status(dpp, driver, pipe, &full_status, null_yield);
2563 if (r >= 0) {
2564 if (full_status.state == BucketSyncState::Init) {
2565 out << indented{width} << "init: bucket sync has not started\n";
2566 return 0;
2567 }
2568 if (full_status.state == BucketSyncState::Stopped) {
2569 out << indented{width} << "stopped: bucket sync is disabled\n";
2570 return 0;
2571 }
2572 if (full_status.state == BucketSyncState::Full) {
2573 out << indented{width} << "full sync: " << full_status.full.count << " objects completed\n";
2574 return 0;
2575 }
2576 gen = full_status.incremental_gen;
2577 shard_status.resize(full_status.shards_done_with_gen.size());
2578 } else if (r == -ENOENT) {
2579 // no full status, but there may be per-shard status from before upgrade
2580 const auto& logs = source_bucket->get_info().layout.logs;
2581 if (logs.empty()) {
2582 out << indented{width} << "init: bucket sync has not started\n";
2583 return 0;
2584 }
2585 const auto& log = logs.front();
2586 if (log.gen > 0) {
2587 // this isn't the backward-compatible case, so we just haven't started yet
2588 out << indented{width} << "init: bucket sync has not started\n";
2589 return 0;
2590 }
2591 if (log.layout.type != rgw::BucketLogType::InIndex) {
2592 ldpp_dout(dpp, -1) << "unrecognized log layout type " << log.layout.type << dendl;
2593 return -EINVAL;
2594 }
2595 // use shard count from our log gen=0
2596 shard_status.resize(rgw::num_shards(log.layout.in_index));
2597 } else {
2598 lderr(driver->ctx()) << "failed to read bucket full sync status: " << cpp_strerror(r) << dendl;
2599 return r;
2600 }
2601
2602 r = rgw_read_bucket_inc_sync_status(dpp, driver, pipe, gen, &shard_status);
2603 if (r < 0) {
2604 lderr(driver->ctx()) << "failed to read bucket incremental sync status: " << cpp_strerror(r) << dendl;
2605 return r;
2606 }
2607
2608 const int total_shards = shard_status.size();
2609
2610 out << indented{width} << "incremental sync on " << total_shards << " shards\n";
2611
2612 rgw_bucket_index_marker_info remote_info;
2613 BucketIndexShardsManager remote_markers;
2614 r = rgw_read_remote_bilog_info(dpp, conn, source_bucket->get_key(),
2615 remote_info, remote_markers, null_yield);
2616 if (r < 0) {
2617 ldpp_dout(dpp, -1) << "failed to read remote log: " << cpp_strerror(r) << dendl;
2618 return r;
2619 }
2620
2621 std::set<int> shards_behind;
2622 for (const auto& r : remote_markers.get()) {
2623 auto shard_id = r.first;
2624 if (r.second.empty()) {
2625 continue; // empty bucket index shard
2626 }
2627 if (shard_id >= total_shards) {
2628 // unexpected shard id. we don't have status for it, so we're behind
2629 shards_behind.insert(shard_id);
2630 continue;
2631 }
2632 auto& m = shard_status[shard_id];
2633 const auto pos = BucketIndexShardsManager::get_shard_marker(m.inc_marker.position);
2634 if (pos < r.second) {
2635 shards_behind.insert(shard_id);
2636 }
2637 }
2638 if (!shards_behind.empty()) {
2639 out << indented{width} << "bucket is behind on " << shards_behind.size() << " shards\n";
2640 out << indented{width} << "behind shards: [" << shards_behind << "]\n" ;
2641 } else {
2642 out << indented{width} << "bucket is caught up with source\n";
2643 }
2644 return 0;
2645 }
2646
2647 void encode_json(const char *name, const RGWBucketSyncFlowManager::pipe_set& pset, Formatter *f)
2648 {
2649 Formatter::ObjectSection top_section(*f, name);
2650 Formatter::ArraySection as(*f, "entries");
2651
2652 for (auto& pipe_handler : pset) {
2653 Formatter::ObjectSection hs(*f, "handler");
2654 encode_json("source", pipe_handler.source, f);
2655 encode_json("dest", pipe_handler.dest, f);
2656 }
2657 }
2658
2659 static std::vector<string> convert_bucket_set_to_str_vec(const std::set<rgw_bucket>& bs)
2660 {
2661 std::vector<string> result;
2662 result.reserve(bs.size());
2663 for (auto& b : bs) {
2664 result.push_back(b.get_key());
2665 }
2666 return result;
2667 }
2668
2669 static void get_hint_entities(const std::set<rgw_zone_id>& zones, const std::set<rgw_bucket>& buckets,
2670 std::set<rgw_sync_bucket_entity> *hint_entities)
2671 {
2672 for (auto& zone_id : zones) {
2673 for (auto& b : buckets) {
2674 std::unique_ptr<rgw::sal::Bucket> hint_bucket;
2675 int ret = init_bucket(nullptr, b, &hint_bucket);
2676 if (ret < 0) {
2677 ldpp_dout(dpp(), 20) << "could not init bucket info for hint bucket=" << b << " ... skipping" << dendl;
2678 continue;
2679 }
2680
2681 hint_entities->insert(rgw_sync_bucket_entity(zone_id, hint_bucket->get_key()));
2682 }
2683 }
2684 }
2685
2686 static rgw_zone_id resolve_zone_id(const string& s)
2687 {
2688 std::unique_ptr<rgw::sal::Zone> zone;
2689 int ret = driver->get_zone()->get_zonegroup().get_zone_by_id(s, &zone);
2690 if (ret < 0)
2691 ret = driver->get_zone()->get_zonegroup().get_zone_by_name(s, &zone);
2692 if (ret < 0)
2693 return rgw_zone_id(s);
2694
2695 return rgw_zone_id(zone->get_id());
2696 }
2697
2698 rgw_zone_id validate_zone_id(const rgw_zone_id& zone_id)
2699 {
2700 return resolve_zone_id(zone_id.id);
2701 }
2702
2703 static int sync_info(std::optional<rgw_zone_id> opt_target_zone, std::optional<rgw_bucket> opt_bucket, Formatter *formatter)
2704 {
2705 rgw_zone_id zone_id = opt_target_zone.value_or(driver->get_zone()->get_id());
2706
2707 auto zone_policy_handler = driver->get_zone()->get_sync_policy_handler();
2708
2709 RGWBucketSyncPolicyHandlerRef bucket_handler;
2710
2711 std::optional<rgw_bucket> eff_bucket = opt_bucket;
2712
2713 auto handler = zone_policy_handler;
2714
2715 if (eff_bucket) {
2716 std::unique_ptr<rgw::sal::Bucket> bucket;
2717
2718 int ret = init_bucket(nullptr, *eff_bucket, &bucket);
2719 if (ret < 0 && ret != -ENOENT) {
2720 cerr << "ERROR: init_bucket failed: " << cpp_strerror(-ret) << std::endl;
2721 return ret;
2722 }
2723
2724 if (ret >= 0) {
2725 rgw::sal::Attrs attrs = bucket->get_attrs();
2726 bucket_handler.reset(handler->alloc_child(bucket->get_info(), std::move(attrs)));
2727 } else {
2728 cerr << "WARNING: bucket not found, simulating result" << std::endl;
2729 bucket_handler.reset(handler->alloc_child(*eff_bucket, nullopt));
2730 }
2731
2732 ret = bucket_handler->init(dpp(), null_yield);
2733 if (ret < 0) {
2734 cerr << "ERROR: failed to init bucket sync policy handler: " << cpp_strerror(-ret) << " (ret=" << ret << ")" << std::endl;
2735 return ret;
2736 }
2737
2738 handler = bucket_handler;
2739 }
2740
2741 std::set<rgw_sync_bucket_pipe> sources;
2742 std::set<rgw_sync_bucket_pipe> dests;
2743
2744 handler->get_pipes(&sources, &dests, std::nullopt);
2745
2746 auto source_hints_vec = convert_bucket_set_to_str_vec(handler->get_source_hints());
2747 auto target_hints_vec = convert_bucket_set_to_str_vec(handler->get_target_hints());
2748
2749 std::set<rgw_sync_bucket_pipe> resolved_sources;
2750 std::set<rgw_sync_bucket_pipe> resolved_dests;
2751
2752 rgw_sync_bucket_entity self_entity(zone_id, opt_bucket);
2753
2754 set<rgw_zone_id> source_zones;
2755 set<rgw_zone_id> target_zones;
2756
2757 zone_policy_handler->reflect(dpp(), nullptr, nullptr,
2758 nullptr, nullptr,
2759 &source_zones,
2760 &target_zones,
2761 false); /* relaxed: also get all zones that we allow to sync to/from */
2762
2763 std::set<rgw_sync_bucket_entity> hint_entities;
2764
2765 get_hint_entities(source_zones, handler->get_source_hints(), &hint_entities);
2766 get_hint_entities(target_zones, handler->get_target_hints(), &hint_entities);
2767
2768 for (auto& hint_entity : hint_entities) {
2769 if (!hint_entity.zone ||
2770 !hint_entity.bucket) {
2771 continue; /* shouldn't really happen */
2772 }
2773
2774 auto zid = validate_zone_id(*hint_entity.zone);
2775 auto& hint_bucket = *hint_entity.bucket;
2776
2777 RGWBucketSyncPolicyHandlerRef hint_bucket_handler;
2778 int r = driver->get_sync_policy_handler(dpp(), zid, hint_bucket, &hint_bucket_handler, null_yield);
2779 if (r < 0) {
2780 ldpp_dout(dpp(), 20) << "could not get bucket sync policy handler for hint bucket=" << hint_bucket << " ... skipping" << dendl;
2781 continue;
2782 }
2783
2784 hint_bucket_handler->get_pipes(&resolved_dests,
2785 &resolved_sources,
2786 self_entity); /* flipping resolved dests and sources as these are
2787 relative to the remote entity */
2788 }
2789
2790 {
2791 Formatter::ObjectSection os(*formatter, "result");
2792 encode_json("sources", sources, formatter);
2793 encode_json("dests", dests, formatter);
2794 {
2795 Formatter::ObjectSection hints_section(*formatter, "hints");
2796 encode_json("sources", source_hints_vec, formatter);
2797 encode_json("dests", target_hints_vec, formatter);
2798 }
2799 {
2800 Formatter::ObjectSection resolved_hints_section(*formatter, "resolved-hints-1");
2801 encode_json("sources", resolved_sources, formatter);
2802 encode_json("dests", resolved_dests, formatter);
2803 }
2804 {
2805 Formatter::ObjectSection resolved_hints_section(*formatter, "resolved-hints");
2806 encode_json("sources", handler->get_resolved_source_hints(), formatter);
2807 encode_json("dests", handler->get_resolved_dest_hints(), formatter);
2808 }
2809 }
2810
2811 formatter->flush(cout);
2812
2813 return 0;
2814 }
2815
2816 static int bucket_sync_info(rgw::sal::Driver* driver, const RGWBucketInfo& info,
2817 std::ostream& out)
2818 {
2819 const rgw::sal::ZoneGroup& zonegroup = driver->get_zone()->get_zonegroup();
2820 rgw::sal::Zone* zone = driver->get_zone();
2821 constexpr int width = 15;
2822
2823 out << indented{width, "realm"} << zone->get_realm_id() << " (" << zone->get_realm_name() << ")\n";
2824 out << indented{width, "zonegroup"} << zonegroup.get_id() << " (" << zonegroup.get_name() << ")\n";
2825 out << indented{width, "zone"} << zone->get_id() << " (" << zone->get_name() << ")\n";
2826 out << indented{width, "bucket"} << info.bucket << "\n\n";
2827
2828 if (!static_cast<rgw::sal::RadosStore*>(driver)->ctl()->bucket->bucket_imports_data(info.bucket, null_yield, dpp())) {
2829 out << "Sync is disabled for bucket " << info.bucket.name << '\n';
2830 return 0;
2831 }
2832
2833 RGWBucketSyncPolicyHandlerRef handler;
2834
2835 int r = driver->get_sync_policy_handler(dpp(), std::nullopt, info.bucket, &handler, null_yield);
2836 if (r < 0) {
2837 ldpp_dout(dpp(), -1) << "ERROR: failed to get policy handler for bucket (" << info.bucket << "): r=" << r << ": " << cpp_strerror(-r) << dendl;
2838 return r;
2839 }
2840
2841 auto& sources = handler->get_sources();
2842
2843 for (auto& m : sources) {
2844 auto& zone = m.first;
2845 out << indented{width, "source zone"} << zone << std::endl;
2846 for (auto& pipe_handler : m.second) {
2847 out << indented{width, "bucket"} << *pipe_handler.source.bucket << std::endl;
2848 }
2849 }
2850
2851 return 0;
2852 }
2853
2854 static int bucket_sync_status(rgw::sal::Driver* driver, const RGWBucketInfo& info,
2855 const rgw_zone_id& source_zone_id,
2856 std::optional<rgw_bucket>& opt_source_bucket,
2857 std::ostream& out)
2858 {
2859 const rgw::sal::ZoneGroup& zonegroup = driver->get_zone()->get_zonegroup();
2860 rgw::sal::Zone* zone = driver->get_zone();
2861 constexpr int width = 15;
2862
2863 out << indented{width, "realm"} << zone->get_realm_id() << " (" << zone->get_realm_name() << ")\n";
2864 out << indented{width, "zonegroup"} << zonegroup.get_id() << " (" << zonegroup.get_name() << ")\n";
2865 out << indented{width, "zone"} << zone->get_id() << " (" << zone->get_name() << ")\n";
2866 out << indented{width, "bucket"} << info.bucket << "\n";
2867 out << indented{width, "current time"}
2868 << to_iso_8601(ceph::real_clock::now(), iso_8601_format::YMDhms) << "\n\n";
2869
2870
2871 if (!static_cast<rgw::sal::RadosStore*>(driver)->ctl()->bucket->bucket_imports_data(info.bucket, null_yield, dpp())) {
2872 out << "Sync is disabled for bucket " << info.bucket.name << " or bucket has no sync sources" << std::endl;
2873 return 0;
2874 }
2875
2876 RGWBucketSyncPolicyHandlerRef handler;
2877
2878 int r = driver->get_sync_policy_handler(dpp(), std::nullopt, info.bucket, &handler, null_yield);
2879 if (r < 0) {
2880 ldpp_dout(dpp(), -1) << "ERROR: failed to get policy handler for bucket (" << info.bucket << "): r=" << r << ": " << cpp_strerror(-r) << dendl;
2881 return r;
2882 }
2883
2884 auto sources = handler->get_all_sources();
2885
2886 auto& zone_conn_map = static_cast<rgw::sal::RadosStore*>(driver)->svc()->zone->get_zone_conn_map();
2887 set<rgw_zone_id> zone_ids;
2888
2889 if (!source_zone_id.empty()) {
2890 std::unique_ptr<rgw::sal::Zone> zone;
2891 int ret = driver->get_zone()->get_zonegroup().get_zone_by_id(source_zone_id.id, &zone);
2892 if (ret < 0) {
2893 ldpp_dout(dpp(), -1) << "Source zone not found in zonegroup "
2894 << zonegroup.get_name() << dendl;
2895 return -EINVAL;
2896 }
2897 auto c = zone_conn_map.find(source_zone_id);
2898 if (c == zone_conn_map.end()) {
2899 ldpp_dout(dpp(), -1) << "No connection to zone " << zone->get_name() << dendl;
2900 return -EINVAL;
2901 }
2902 zone_ids.insert(source_zone_id);
2903 } else {
2904 std::list<std::string> ids;
2905 int ret = driver->get_zone()->get_zonegroup().list_zones(ids);
2906 if (ret == 0) {
2907 for (const auto& entry : ids) {
2908 zone_ids.insert(entry);
2909 }
2910 }
2911 }
2912
2913 for (auto& zone_id : zone_ids) {
2914 auto z = static_cast<rgw::sal::RadosStore*>(driver)->svc()->zone->get_zonegroup().zones.find(zone_id.id);
2915 if (z == static_cast<rgw::sal::RadosStore*>(driver)->svc()->zone->get_zonegroup().zones.end()) { /* should't happen */
2916 continue;
2917 }
2918 auto c = zone_conn_map.find(zone_id.id);
2919 if (c == zone_conn_map.end()) { /* should't happen */
2920 continue;
2921 }
2922
2923 for (auto& entry : sources) {
2924 auto& pipe = entry.second;
2925 if (opt_source_bucket &&
2926 pipe.source.bucket != opt_source_bucket) {
2927 continue;
2928 }
2929 if (pipe.source.zone.value_or(rgw_zone_id()) == z->second.id) {
2930 bucket_source_sync_status(dpp(), static_cast<rgw::sal::RadosStore*>(driver), static_cast<rgw::sal::RadosStore*>(driver)->svc()->zone->get_zone(), z->second,
2931 c->second,
2932 info, pipe,
2933 width, out);
2934 }
2935 }
2936 }
2937
2938 return 0;
2939 }
2940
2941 static void parse_tier_config_param(const string& s, map<string, string, ltstr_nocase>& out)
2942 {
2943 int level = 0;
2944 string cur_conf;
2945 list<string> confs;
2946 for (auto c : s) {
2947 if (c == ',') {
2948 if (level == 0) {
2949 confs.push_back(cur_conf);
2950 cur_conf.clear();
2951 continue;
2952 }
2953 }
2954 if (c == '{') {
2955 ++level;
2956 } else if (c == '}') {
2957 --level;
2958 }
2959 cur_conf += c;
2960 }
2961 if (!cur_conf.empty()) {
2962 confs.push_back(cur_conf);
2963 }
2964
2965 for (auto c : confs) {
2966 ssize_t pos = c.find("=");
2967 if (pos < 0) {
2968 out[c] = "";
2969 } else {
2970 out[c.substr(0, pos)] = c.substr(pos + 1);
2971 }
2972 }
2973 }
2974
2975 static int check_pool_support_omap(const rgw_pool& pool)
2976 {
2977 librados::IoCtx io_ctx;
2978 int ret = static_cast<rgw::sal::RadosStore*>(driver)->getRados()->get_rados_handle()->ioctx_create(pool.to_str().c_str(), io_ctx);
2979 if (ret < 0) {
2980 // the pool may not exist at this moment, we have no way to check if it supports omap.
2981 return 0;
2982 }
2983
2984 ret = io_ctx.omap_clear("__omap_test_not_exist_oid__");
2985 if (ret == -EOPNOTSUPP) {
2986 io_ctx.close();
2987 return ret;
2988 }
2989 io_ctx.close();
2990 return 0;
2991 }
2992
2993 int check_reshard_bucket_params(rgw::sal::Driver* driver,
2994 const string& bucket_name,
2995 const string& tenant,
2996 const string& bucket_id,
2997 bool num_shards_specified,
2998 int num_shards,
2999 int yes_i_really_mean_it,
3000 std::unique_ptr<rgw::sal::Bucket>* bucket)
3001 {
3002 if (bucket_name.empty()) {
3003 cerr << "ERROR: bucket not specified" << std::endl;
3004 return -EINVAL;
3005 }
3006
3007 if (!num_shards_specified) {
3008 cerr << "ERROR: --num-shards not specified" << std::endl;
3009 return -EINVAL;
3010 }
3011
3012 if (num_shards > (int)static_cast<rgw::sal::RadosStore*>(driver)->getRados()->get_max_bucket_shards()) {
3013 cerr << "ERROR: num_shards too high, max value: " << static_cast<rgw::sal::RadosStore*>(driver)->getRados()->get_max_bucket_shards() << std::endl;
3014 return -EINVAL;
3015 }
3016
3017 if (num_shards < 0) {
3018 cerr << "ERROR: num_shards must be non-negative integer" << std::endl;
3019 return -EINVAL;
3020 }
3021
3022 int ret = init_bucket(nullptr, tenant, bucket_name, bucket_id, bucket);
3023 if (ret < 0) {
3024 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
3025 return ret;
3026 }
3027
3028 int num_source_shards = rgw::current_num_shards((*bucket)->get_info().layout);
3029
3030 if (num_shards <= num_source_shards && !yes_i_really_mean_it) {
3031 cerr << "num shards is less or equal to current shards count" << std::endl
3032 << "do you really mean it? (requires --yes-i-really-mean-it)" << std::endl;
3033 return -EINVAL;
3034 }
3035 return 0;
3036 }
3037
3038 static int scan_totp(CephContext *cct, ceph::real_time& now, rados::cls::otp::otp_info_t& totp, vector<string>& pins,
3039 time_t *pofs)
3040 {
3041 #define MAX_TOTP_SKEW_HOURS (24 * 7)
3042 time_t start_time = ceph::real_clock::to_time_t(now);
3043 time_t time_ofs = 0, time_ofs_abs = 0;
3044 time_t step_size = totp.step_size;
3045 if (step_size == 0) {
3046 step_size = OATH_TOTP_DEFAULT_TIME_STEP_SIZE;
3047 }
3048 uint32_t count = 0;
3049 int sign = 1;
3050
3051 uint32_t max_skew = MAX_TOTP_SKEW_HOURS * 3600;
3052
3053 while (time_ofs_abs < max_skew) {
3054 int rc = oath_totp_validate2(totp.seed_bin.c_str(), totp.seed_bin.length(),
3055 start_time,
3056 step_size,
3057 time_ofs,
3058 1,
3059 nullptr,
3060 pins[0].c_str());
3061 if (rc != OATH_INVALID_OTP) {
3062 rc = oath_totp_validate2(totp.seed_bin.c_str(), totp.seed_bin.length(),
3063 start_time,
3064 step_size,
3065 time_ofs - step_size, /* smaller time_ofs moves time forward */
3066 1,
3067 nullptr,
3068 pins[1].c_str());
3069 if (rc != OATH_INVALID_OTP) {
3070 *pofs = time_ofs - step_size + step_size * totp.window / 2;
3071 ldpp_dout(dpp(), 20) << "found at time=" << start_time - time_ofs << " time_ofs=" << time_ofs << dendl;
3072 return 0;
3073 }
3074 }
3075 sign = -sign;
3076 time_ofs_abs = (++count) * step_size;
3077 time_ofs = sign * time_ofs_abs;
3078 }
3079
3080 return -ENOENT;
3081 }
3082
3083 static int trim_sync_error_log(int shard_id, const string& marker, int delay_ms)
3084 {
3085 auto oid = RGWSyncErrorLogger::get_shard_oid(RGW_SYNC_ERROR_LOG_SHARD_PREFIX,
3086 shard_id);
3087 // call cls_log_trim() until it returns -ENODATA
3088 for (;;) {
3089 int ret = static_cast<rgw::sal::RadosStore*>(driver)->svc()->cls->timelog.trim(dpp(), oid, {}, {}, {}, marker, nullptr,
3090 null_yield);
3091 if (ret == -ENODATA) {
3092 return 0;
3093 }
3094 if (ret < 0) {
3095 return ret;
3096 }
3097 if (delay_ms) {
3098 std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms));
3099 }
3100 }
3101 // unreachable
3102 }
3103
3104 static bool symmetrical_flow_opt(const string& opt)
3105 {
3106 return (opt == "symmetrical" || opt == "symmetric");
3107 }
3108
3109 static bool directional_flow_opt(const string& opt)
3110 {
3111 return (opt == "directional" || opt == "direction");
3112 }
3113
3114 template <class T>
3115 static bool require_opt(std::optional<T> opt, bool extra_check = true)
3116 {
3117 if (!opt || !extra_check) {
3118 return false;
3119 }
3120 return true;
3121 }
3122
3123 template <class T>
3124 static bool require_non_empty_opt(std::optional<T> opt, bool extra_check = true)
3125 {
3126 if (!opt || opt->empty() || !extra_check) {
3127 return false;
3128 }
3129 return true;
3130 }
3131
3132 template <class T>
3133 static void show_result(T& obj,
3134 Formatter *formatter,
3135 ostream& os)
3136 {
3137 encode_json("obj", obj, formatter);
3138
3139 formatter->flush(cout);
3140 }
3141
3142 void init_optional_bucket(std::optional<rgw_bucket>& opt_bucket,
3143 std::optional<string>& opt_tenant,
3144 std::optional<string>& opt_bucket_name,
3145 std::optional<string>& opt_bucket_id)
3146 {
3147 if (opt_tenant || opt_bucket_name || opt_bucket_id) {
3148 opt_bucket.emplace();
3149 if (opt_tenant) {
3150 opt_bucket->tenant = *opt_tenant;
3151 }
3152 if (opt_bucket_name) {
3153 opt_bucket->name = *opt_bucket_name;
3154 }
3155 if (opt_bucket_id) {
3156 opt_bucket->bucket_id = *opt_bucket_id;
3157 }
3158 }
3159 }
3160
3161 class SyncPolicyContext
3162 {
3163 rgw::sal::ConfigStore* cfgstore;
3164 RGWZoneGroup zonegroup;
3165 std::unique_ptr<rgw::sal::ZoneGroupWriter> zonegroup_writer;
3166
3167 std::optional<rgw_bucket> b;
3168 std::unique_ptr<rgw::sal::Bucket> bucket;
3169
3170 rgw_sync_policy_info *policy{nullptr};
3171
3172 std::optional<rgw_user> owner;
3173
3174 public:
3175 SyncPolicyContext(rgw::sal::ConfigStore* cfgstore,
3176 std::optional<rgw_bucket> _bucket)
3177 : cfgstore(cfgstore), b(std::move(_bucket)) {}
3178
3179 int init(const string& zonegroup_id, const string& zonegroup_name) {
3180 int ret = rgw::read_zonegroup(dpp(), null_yield, cfgstore,
3181 zonegroup_id, zonegroup_name,
3182 zonegroup, &zonegroup_writer);
3183 if (ret < 0) {
3184 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
3185 return ret;
3186 }
3187
3188 if (!b) {
3189 policy = &zonegroup.sync_policy;
3190 return 0;
3191 }
3192
3193 ret = init_bucket(nullptr, *b, &bucket);
3194 if (ret < 0) {
3195 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
3196 return ret;
3197 }
3198
3199 owner = bucket->get_info().owner;
3200
3201 if (!bucket->get_info().sync_policy) {
3202 rgw_sync_policy_info new_policy;
3203 bucket->get_info().set_sync_policy(std::move(new_policy));
3204 }
3205
3206 policy = &(*bucket->get_info().sync_policy);
3207
3208 return 0;
3209 }
3210
3211 int write_policy() {
3212 if (!b) {
3213 int ret = zonegroup_writer->write(dpp(), null_yield, zonegroup);
3214 if (ret < 0) {
3215 cerr << "failed to update zonegroup: " << cpp_strerror(-ret) << std::endl;
3216 return -ret;
3217 }
3218 return 0;
3219 }
3220
3221 int ret = bucket->put_info(dpp(), false, real_time());
3222 if (ret < 0) {
3223 cerr << "failed to driver bucket info: " << cpp_strerror(-ret) << std::endl;
3224 return -ret;
3225 }
3226
3227 return 0;
3228 }
3229
3230 rgw_sync_policy_info& get_policy() {
3231 return *policy;
3232 }
3233
3234 std::optional<rgw_user>& get_owner() {
3235 return owner;
3236 }
3237 };
3238
3239 void resolve_zone_id_opt(std::optional<string>& zone_name, std::optional<rgw_zone_id>& zone_id)
3240 {
3241 if (!zone_name || zone_id) {
3242 return;
3243 }
3244 zone_id.emplace();
3245 std::unique_ptr<rgw::sal::Zone> zone;
3246 int ret = driver->get_zone()->get_zonegroup().get_zone_by_name(*zone_name, &zone);
3247 if (ret < 0) {
3248 cerr << "WARNING: cannot find source zone id for name=" << *zone_name << std::endl;
3249 zone_id = rgw_zone_id(*zone_name);
3250 } else {
3251 zone_id->id = zone->get_id();
3252 }
3253 }
3254 void resolve_zone_ids_opt(std::optional<vector<string> >& names, std::optional<vector<rgw_zone_id> >& ids)
3255 {
3256 if (!names || ids) {
3257 return;
3258 }
3259 ids.emplace();
3260 for (auto& name : *names) {
3261 rgw_zone_id zid;
3262 std::unique_ptr<rgw::sal::Zone> zone;
3263 int ret = driver->get_zone()->get_zonegroup().get_zone_by_name(name, &zone);
3264 if (ret < 0) {
3265 cerr << "WARNING: cannot find source zone id for name=" << name << std::endl;
3266 zid = rgw_zone_id(name);
3267 } else {
3268 zid.id = zone->get_id();
3269 }
3270 ids->push_back(zid);
3271 }
3272 }
3273
3274 static vector<rgw_zone_id> zone_ids_from_str(const string& val)
3275 {
3276 vector<rgw_zone_id> result;
3277 vector<string> v;
3278 get_str_vec(val, v);
3279 for (auto& z : v) {
3280 result.push_back(rgw_zone_id(z));
3281 }
3282 return result;
3283 }
3284
3285 class JSONFormatter_PrettyZone : public JSONFormatter {
3286 class Handler : public JSONEncodeFilter::Handler<rgw_zone_id> {
3287 void encode_json(const char *name, const void *pval, ceph::Formatter *f) const override {
3288 auto zone_id = *(static_cast<const rgw_zone_id *>(pval));
3289 string zone_name;
3290 std::unique_ptr<rgw::sal::Zone> zone;
3291 if (driver->get_zone()->get_zonegroup().get_zone_by_id(zone_id.id, &zone) == 0) {
3292 zone_name = zone->get_name();
3293 } else {
3294 cerr << "WARNING: cannot find zone name for id=" << zone_id << std::endl;
3295 zone_name = zone_id.id;
3296 }
3297
3298 ::encode_json(name, zone_name, f);
3299 }
3300 } zone_id_type_handler;
3301
3302 JSONEncodeFilter encode_filter;
3303 public:
3304 JSONFormatter_PrettyZone(bool pretty_format) : JSONFormatter(pretty_format) {
3305 encode_filter.register_type(&zone_id_type_handler);
3306 }
3307
3308 void *get_external_feature_handler(const std::string& feature) override {
3309 if (feature != "JSONEncodeFilter") {
3310 return nullptr;
3311 }
3312 return &encode_filter;
3313 }
3314 };
3315
3316 void init_realm_param(CephContext *cct, string& var, std::optional<string>& opt_var, const string& conf_name)
3317 {
3318 var = cct->_conf.get_val<string>(conf_name);
3319 if (!var.empty()) {
3320 opt_var = var;
3321 }
3322 }
3323
3324 int main(int argc, const char **argv)
3325 {
3326 auto args = argv_to_vec(argc, argv);
3327 if (args.empty()) {
3328 cerr << argv[0] << ": -h or --help for usage" << std::endl;
3329 exit(1);
3330 }
3331 if (ceph_argparse_need_usage(args)) {
3332 usage();
3333 exit(0);
3334 }
3335
3336 auto cct = rgw_global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT,
3337 CODE_ENVIRONMENT_UTILITY, 0);
3338
3339 // for region -> zonegroup conversion (must happen before common_init_finish())
3340 if (!g_conf()->rgw_region.empty() && g_conf()->rgw_zonegroup.empty()) {
3341 g_conf().set_val_or_die("rgw_zonegroup", g_conf()->rgw_region.c_str());
3342 }
3343
3344 rgw_user user_id_arg;
3345 std::unique_ptr<rgw::sal::User> user;
3346 string tenant;
3347 string user_ns;
3348 rgw_user new_user_id;
3349 std::string access_key, secret_key, user_email, display_name;
3350 std::string bucket_name, pool_name, object;
3351 rgw_pool pool;
3352 std::string date, subuser, access, format;
3353 std::string start_date, end_date;
3354 std::string key_type_str;
3355 std::string period_id, period_epoch, remote, url;
3356 std::optional<string> opt_region;
3357 std::string master_zone;
3358 std::string realm_name, realm_id, realm_new_name;
3359 std::optional<string> opt_realm_name, opt_realm_id;
3360 std::string zone_name, zone_id, zone_new_name;
3361 std::optional<string> opt_zone_name, opt_zone_id;
3362 std::string zonegroup_name, zonegroup_id, zonegroup_new_name;
3363 std::optional<string> opt_zonegroup_name, opt_zonegroup_id;
3364 std::string api_name;
3365 std::string role_name, path, assume_role_doc, policy_name, perm_policy_doc, path_prefix, max_session_duration;
3366 std::string redirect_zone;
3367 bool redirect_zone_set = false;
3368 list<string> endpoints;
3369 int tmp_int;
3370 int sync_from_all_specified = false;
3371 bool sync_from_all = false;
3372 list<string> sync_from;
3373 list<string> sync_from_rm;
3374 int is_master_int;
3375 int set_default = 0;
3376 bool is_master = false;
3377 bool is_master_set = false;
3378 int read_only_int;
3379 bool read_only = false;
3380 int is_read_only_set = false;
3381 int commit = false;
3382 int staging = false;
3383 int key_type = KEY_TYPE_UNDEFINED;
3384 std::unique_ptr<rgw::sal::Bucket> bucket;
3385 uint32_t perm_mask = 0;
3386 RGWUserInfo info;
3387 OPT opt_cmd = OPT::NO_CMD;
3388 int gen_access_key = 0;
3389 int gen_secret_key = 0;
3390 bool set_perm = false;
3391 bool set_temp_url_key = false;
3392 map<int, string> temp_url_keys;
3393 string bucket_id;
3394 string new_bucket_name;
3395 std::unique_ptr<Formatter> formatter;
3396 std::unique_ptr<Formatter> zone_formatter;
3397 int purge_data = false;
3398 int pretty_format = false;
3399 int show_log_entries = true;
3400 int show_log_sum = true;
3401 int skip_zero_entries = false; // log show
3402 int purge_keys = false;
3403 int yes_i_really_mean_it = false;
3404 int delete_child_objects = false;
3405 int fix = false;
3406 int remove_bad = false;
3407 int check_head_obj_locator = false;
3408 int max_buckets = -1;
3409 bool max_buckets_specified = false;
3410 map<string, bool> categories;
3411 string caps;
3412 int check_objects = false;
3413 RGWBucketAdminOpState bucket_op;
3414 string infile;
3415 string metadata_key;
3416 RGWObjVersionTracker objv_tracker;
3417 string marker;
3418 string start_marker;
3419 string end_marker;
3420 int max_entries = -1;
3421 bool max_entries_specified = false;
3422 int admin = false;
3423 bool admin_specified = false;
3424 int system = false;
3425 bool system_specified = false;
3426 int shard_id = -1;
3427 bool specified_shard_id = false;
3428 string client_id;
3429 string op_id;
3430 string op_mask_str;
3431 string quota_scope;
3432 string ratelimit_scope;
3433 std::string objects_file;
3434 string object_version;
3435 string placement_id;
3436 std::optional<string> opt_storage_class;
3437 list<string> tags;
3438 list<string> tags_add;
3439 list<string> tags_rm;
3440 int placement_inline_data = true;
3441 bool placement_inline_data_specified = false;
3442
3443 int64_t max_objects = -1;
3444 int64_t max_size = -1;
3445 int64_t max_read_ops = 0;
3446 int64_t max_write_ops = 0;
3447 int64_t max_read_bytes = 0;
3448 int64_t max_write_bytes = 0;
3449 bool have_max_objects = false;
3450 bool have_max_size = false;
3451 bool have_max_write_ops = false;
3452 bool have_max_read_ops = false;
3453 bool have_max_write_bytes = false;
3454 bool have_max_read_bytes = false;
3455 int include_all = false;
3456 int allow_unordered = false;
3457
3458 int sync_stats = false;
3459 int reset_stats = false;
3460 int bypass_gc = false;
3461 int warnings_only = false;
3462 int inconsistent_index = false;
3463
3464 int verbose = false;
3465
3466 int extra_info = false;
3467
3468 uint64_t min_rewrite_size = 4 * 1024 * 1024;
3469 uint64_t max_rewrite_size = ULLONG_MAX;
3470 uint64_t min_rewrite_stripe_size = 0;
3471
3472 BIIndexType bi_index_type = BIIndexType::Plain;
3473 std::optional<log_type> opt_log_type;
3474
3475 string job_id;
3476 int num_shards = 0;
3477 bool num_shards_specified = false;
3478 std::optional<int> bucket_index_max_shards;
3479
3480 int max_concurrent_ios = 32;
3481 ceph::timespan min_age = std::chrono::hours(1);
3482 bool hide_progress = false;
3483 bool dump_keys = false;
3484 uint64_t orphan_stale_secs = (24 * 3600);
3485 int detail = false;
3486
3487 std::string val;
3488 std::ostringstream errs;
3489 string err;
3490
3491 string source_zone_name;
3492 rgw_zone_id source_zone; /* zone id */
3493
3494 string tier_type;
3495 bool tier_type_specified = false;
3496
3497 map<string, string, ltstr_nocase> tier_config_add;
3498 map<string, string, ltstr_nocase> tier_config_rm;
3499
3500 boost::optional<string> index_pool;
3501 boost::optional<string> data_pool;
3502 boost::optional<string> data_extra_pool;
3503 rgw::BucketIndexType placement_index_type = rgw::BucketIndexType::Normal;
3504 bool index_type_specified = false;
3505
3506 boost::optional<std::string> compression_type;
3507
3508 string totp_serial;
3509 string totp_seed;
3510 string totp_seed_type = "hex";
3511 vector<string> totp_pin;
3512 int totp_seconds = 0;
3513 int totp_window = 0;
3514 int trim_delay_ms = 0;
3515
3516 string topic_name;
3517 string notification_id;
3518 string sub_name;
3519 string event_id;
3520
3521 std::optional<uint64_t> gen;
3522 std::optional<std::string> str_script_ctx;
3523 std::optional<std::string> script_package;
3524 int allow_compilation = false;
3525
3526 std::optional<string> opt_group_id;
3527 std::optional<string> opt_status;
3528 std::optional<string> opt_flow_type;
3529 std::optional<vector<string> > opt_zone_names;
3530 std::optional<vector<rgw_zone_id> > opt_zone_ids;
3531 std::optional<string> opt_flow_id;
3532 std::optional<string> opt_source_zone_name;
3533 std::optional<rgw_zone_id> opt_source_zone_id;
3534 std::optional<string> opt_dest_zone_name;
3535 std::optional<rgw_zone_id> opt_dest_zone_id;
3536 std::optional<vector<string> > opt_source_zone_names;
3537 std::optional<vector<rgw_zone_id> > opt_source_zone_ids;
3538 std::optional<vector<string> > opt_dest_zone_names;
3539 std::optional<vector<rgw_zone_id> > opt_dest_zone_ids;
3540 std::optional<string> opt_pipe_id;
3541 std::optional<rgw_bucket> opt_bucket;
3542 std::optional<string> opt_tenant;
3543 std::optional<string> opt_bucket_name;
3544 std::optional<string> opt_bucket_id;
3545 std::optional<rgw_bucket> opt_source_bucket;
3546 std::optional<string> opt_source_tenant;
3547 std::optional<string> opt_source_bucket_name;
3548 std::optional<string> opt_source_bucket_id;
3549 std::optional<rgw_bucket> opt_dest_bucket;
3550 std::optional<string> opt_dest_tenant;
3551 std::optional<string> opt_dest_bucket_name;
3552 std::optional<string> opt_dest_bucket_id;
3553 std::optional<string> opt_effective_zone_name;
3554 std::optional<rgw_zone_id> opt_effective_zone_id;
3555
3556 std::optional<string> opt_prefix;
3557 std::optional<string> opt_prefix_rm;
3558
3559 std::optional<int> opt_priority;
3560 std::optional<string> opt_mode;
3561 std::optional<rgw_user> opt_dest_owner;
3562 ceph::timespan opt_retry_delay_ms = std::chrono::milliseconds(2000);
3563 ceph::timespan opt_timeout_sec = std::chrono::seconds(60);
3564
3565 std::optional<std::string> inject_error_at;
3566 std::optional<int> inject_error_code;
3567 std::optional<std::string> inject_abort_at;
3568 std::optional<std::string> inject_delay_at;
3569 ceph::timespan inject_delay = std::chrono::milliseconds(2000);
3570
3571 rgw::zone_features::set enable_features;
3572 rgw::zone_features::set disable_features;
3573
3574 SimpleCmd cmd(all_cmds, cmd_aliases);
3575 bool raw_storage_op = false;
3576
3577 std::optional<std::string> rgw_obj_fs; // radoslist field separator
3578
3579 init_realm_param(cct.get(), realm_id, opt_realm_id, "rgw_realm_id");
3580 init_realm_param(cct.get(), zonegroup_id, opt_zonegroup_id, "rgw_zonegroup_id");
3581 init_realm_param(cct.get(), zone_id, opt_zone_id, "rgw_zone_id");
3582
3583 for (std::vector<const char*>::iterator i = args.begin(); i != args.end(); ) {
3584 if (ceph_argparse_double_dash(args, i)) {
3585 break;
3586 } else if (ceph_argparse_witharg(args, i, &val, "-i", "--uid", (char*)NULL)) {
3587 user_id_arg.from_str(val);
3588 if (user_id_arg.empty()) {
3589 cerr << "no value for uid" << std::endl;
3590 exit(1);
3591 }
3592 } else if (ceph_argparse_witharg(args, i, &val, "--new-uid", (char*)NULL)) {
3593 new_user_id.from_str(val);
3594 } else if (ceph_argparse_witharg(args, i, &val, "--tenant", (char*)NULL)) {
3595 tenant = val;
3596 opt_tenant = val;
3597 } else if (ceph_argparse_witharg(args, i, &val, "--user_ns", (char*)NULL)) {
3598 user_ns = val;
3599 } else if (ceph_argparse_witharg(args, i, &val, "--access-key", (char*)NULL)) {
3600 access_key = val;
3601 } else if (ceph_argparse_witharg(args, i, &val, "--subuser", (char*)NULL)) {
3602 subuser = val;
3603 } else if (ceph_argparse_witharg(args, i, &val, "--secret", "--secret-key", (char*)NULL)) {
3604 secret_key = val;
3605 } else if (ceph_argparse_witharg(args, i, &val, "-e", "--email", (char*)NULL)) {
3606 user_email = val;
3607 } else if (ceph_argparse_witharg(args, i, &val, "-n", "--display-name", (char*)NULL)) {
3608 display_name = val;
3609 } else if (ceph_argparse_witharg(args, i, &val, "-b", "--bucket", (char*)NULL)) {
3610 bucket_name = val;
3611 opt_bucket_name = val;
3612 } else if (ceph_argparse_witharg(args, i, &val, "-p", "--pool", (char*)NULL)) {
3613 pool_name = val;
3614 pool = rgw_pool(pool_name);
3615 } else if (ceph_argparse_witharg(args, i, &val, "-o", "--object", (char*)NULL)) {
3616 object = val;
3617 } else if (ceph_argparse_witharg(args, i, &val, "--objects-file", (char*)NULL)) {
3618 objects_file = val;
3619 } else if (ceph_argparse_witharg(args, i, &val, "--object-version", (char*)NULL)) {
3620 object_version = val;
3621 } else if (ceph_argparse_witharg(args, i, &val, "--client-id", (char*)NULL)) {
3622 client_id = val;
3623 } else if (ceph_argparse_witharg(args, i, &val, "--op-id", (char*)NULL)) {
3624 op_id = val;
3625 } else if (ceph_argparse_witharg(args, i, &val, "--op-mask", (char*)NULL)) {
3626 op_mask_str = val;
3627 } else if (ceph_argparse_witharg(args, i, &val, "--key-type", (char*)NULL)) {
3628 key_type_str = val;
3629 if (key_type_str.compare("swift") == 0) {
3630 key_type = KEY_TYPE_SWIFT;
3631 } else if (key_type_str.compare("s3") == 0) {
3632 key_type = KEY_TYPE_S3;
3633 } else {
3634 cerr << "bad key type: " << key_type_str << std::endl;
3635 exit(1);
3636 }
3637 } else if (ceph_argparse_witharg(args, i, &val, "--job-id", (char*)NULL)) {
3638 job_id = val;
3639 } else if (ceph_argparse_binary_flag(args, i, &gen_access_key, NULL, "--gen-access-key", (char*)NULL)) {
3640 // do nothing
3641 } else if (ceph_argparse_binary_flag(args, i, &gen_secret_key, NULL, "--gen-secret", (char*)NULL)) {
3642 // do nothing
3643 } else if (ceph_argparse_binary_flag(args, i, &show_log_entries, NULL, "--show-log-entries", (char*)NULL)) {
3644 // do nothing
3645 } else if (ceph_argparse_binary_flag(args, i, &show_log_sum, NULL, "--show-log-sum", (char*)NULL)) {
3646 // do nothing
3647 } else if (ceph_argparse_binary_flag(args, i, &skip_zero_entries, NULL, "--skip-zero-entries", (char*)NULL)) {
3648 // do nothing
3649 } else if (ceph_argparse_binary_flag(args, i, &admin, NULL, "--admin", (char*)NULL)) {
3650 admin_specified = true;
3651 } else if (ceph_argparse_binary_flag(args, i, &system, NULL, "--system", (char*)NULL)) {
3652 system_specified = true;
3653 } else if (ceph_argparse_binary_flag(args, i, &verbose, NULL, "--verbose", (char*)NULL)) {
3654 // do nothing
3655 } else if (ceph_argparse_binary_flag(args, i, &staging, NULL, "--staging", (char*)NULL)) {
3656 // do nothing
3657 } else if (ceph_argparse_binary_flag(args, i, &commit, NULL, "--commit", (char*)NULL)) {
3658 // do nothing
3659 } else if (ceph_argparse_witharg(args, i, &val, "--min-rewrite-size", (char*)NULL)) {
3660 min_rewrite_size = (uint64_t)atoll(val.c_str());
3661 } else if (ceph_argparse_witharg(args, i, &val, "--max-rewrite-size", (char*)NULL)) {
3662 max_rewrite_size = (uint64_t)atoll(val.c_str());
3663 } else if (ceph_argparse_witharg(args, i, &val, "--min-rewrite-stripe-size", (char*)NULL)) {
3664 min_rewrite_stripe_size = (uint64_t)atoll(val.c_str());
3665 } else if (ceph_argparse_witharg(args, i, &val, "--max-buckets", (char*)NULL)) {
3666 max_buckets = (int)strict_strtol(val.c_str(), 10, &err);
3667 if (!err.empty()) {
3668 cerr << "ERROR: failed to parse max buckets: " << err << std::endl;
3669 return EINVAL;
3670 }
3671 max_buckets_specified = true;
3672 } else if (ceph_argparse_witharg(args, i, &val, "--max-entries", (char*)NULL)) {
3673 max_entries = (int)strict_strtol(val.c_str(), 10, &err);
3674 max_entries_specified = true;
3675 if (!err.empty()) {
3676 cerr << "ERROR: failed to parse max entries: " << err << std::endl;
3677 return EINVAL;
3678 }
3679 } else if (ceph_argparse_witharg(args, i, &val, "--max-size", (char*)NULL)) {
3680 max_size = strict_iec_cast<long long>(val, &err);
3681 if (!err.empty()) {
3682 cerr << "ERROR: failed to parse max size: " << err << std::endl;
3683 return EINVAL;
3684 }
3685 have_max_size = true;
3686 } else if (ceph_argparse_witharg(args, i, &val, "--max-objects", (char*)NULL)) {
3687 max_objects = (int64_t)strict_strtoll(val.c_str(), 10, &err);
3688 if (!err.empty()) {
3689 cerr << "ERROR: failed to parse max objects: " << err << std::endl;
3690 return EINVAL;
3691 }
3692 have_max_objects = true;
3693 } else if (ceph_argparse_witharg(args, i, &val, "--max-read-ops", (char*)NULL)) {
3694 max_read_ops = (int64_t)strict_strtoll(val.c_str(), 10, &err);
3695 if (!err.empty()) {
3696 cerr << "ERROR: failed to parse max read requests: " << err << std::endl;
3697 return EINVAL;
3698 }
3699 have_max_read_ops = true;
3700 } else if (ceph_argparse_witharg(args, i, &val, "--max-write-ops", (char*)NULL)) {
3701 max_write_ops = (int64_t)strict_strtoll(val.c_str(), 10, &err);
3702 if (!err.empty()) {
3703 cerr << "ERROR: failed to parse max write requests: " << err << std::endl;
3704 return EINVAL;
3705 }
3706 have_max_write_ops = true;
3707 } else if (ceph_argparse_witharg(args, i, &val, "--max-read-bytes", (char*)NULL)) {
3708 max_read_bytes = (int64_t)strict_strtoll(val.c_str(), 10, &err);
3709 if (!err.empty()) {
3710 cerr << "ERROR: failed to parse max read bytes: " << err << std::endl;
3711 return EINVAL;
3712 }
3713 have_max_read_bytes = true;
3714 } else if (ceph_argparse_witharg(args, i, &val, "--max-write-bytes", (char*)NULL)) {
3715 max_write_bytes = (int64_t)strict_strtoll(val.c_str(), 10, &err);
3716 if (!err.empty()) {
3717 cerr << "ERROR: failed to parse max write bytes: " << err << std::endl;
3718 return EINVAL;
3719 }
3720 have_max_write_bytes = true;
3721 } else if (ceph_argparse_witharg(args, i, &val, "--date", "--time", (char*)NULL)) {
3722 date = val;
3723 if (end_date.empty())
3724 end_date = date;
3725 } else if (ceph_argparse_witharg(args, i, &val, "--start-date", "--start-time", (char*)NULL)) {
3726 start_date = val;
3727 } else if (ceph_argparse_witharg(args, i, &val, "--end-date", "--end-time", (char*)NULL)) {
3728 end_date = val;
3729 } else if (ceph_argparse_witharg(args, i, &val, "--num-shards", (char*)NULL)) {
3730 num_shards = (int)strict_strtol(val.c_str(), 10, &err);
3731 if (!err.empty()) {
3732 cerr << "ERROR: failed to parse num shards: " << err << std::endl;
3733 return EINVAL;
3734 }
3735 num_shards_specified = true;
3736 } else if (ceph_argparse_witharg(args, i, &val, "--bucket-index-max-shards", (char*)NULL)) {
3737 bucket_index_max_shards = (int)strict_strtol(val.c_str(), 10, &err);
3738 if (!err.empty()) {
3739 cerr << "ERROR: failed to parse bucket-index-max-shards: " << err << std::endl;
3740 return EINVAL;
3741 }
3742 } else if (ceph_argparse_witharg(args, i, &val, "--max-concurrent-ios", (char*)NULL)) {
3743 max_concurrent_ios = (int)strict_strtol(val.c_str(), 10, &err);
3744 if (!err.empty()) {
3745 cerr << "ERROR: failed to parse max concurrent ios: " << err << std::endl;
3746 return EINVAL;
3747 }
3748 } else if (ceph_argparse_witharg(args, i, &val, "--min-age-hours", (char*)NULL)) {
3749 min_age = std::chrono::hours(atoi(val.c_str()));
3750 } else if (ceph_argparse_witharg(args, i, &val, "--orphan-stale-secs", (char*)NULL)) {
3751 orphan_stale_secs = (uint64_t)strict_strtoll(val.c_str(), 10, &err);
3752 if (!err.empty()) {
3753 cerr << "ERROR: failed to parse orphan stale secs: " << err << std::endl;
3754 return EINVAL;
3755 }
3756 } else if (ceph_argparse_witharg(args, i, &val, "--shard-id", (char*)NULL)) {
3757 shard_id = (int)strict_strtol(val.c_str(), 10, &err);
3758 if (!err.empty()) {
3759 cerr << "ERROR: failed to parse shard id: " << err << std::endl;
3760 return EINVAL;
3761 }
3762 specified_shard_id = true;
3763 } else if (ceph_argparse_witharg(args, i, &val, "--gen", (char*)NULL)) {
3764 gen = strict_strtoll(val.c_str(), 10, &err);
3765 if (!err.empty()) {
3766 cerr << "ERROR: failed to parse gen id: " << err << std::endl;
3767 return EINVAL;
3768 }
3769 } else if (ceph_argparse_witharg(args, i, &val, "--access", (char*)NULL)) {
3770 access = val;
3771 perm_mask = rgw_str_to_perm(access.c_str());
3772 set_perm = true;
3773 } else if (ceph_argparse_witharg(args, i, &val, "--temp-url-key", (char*)NULL)) {
3774 temp_url_keys[0] = val;
3775 set_temp_url_key = true;
3776 } else if (ceph_argparse_witharg(args, i, &val, "--temp-url-key2", "--temp-url-key-2", (char*)NULL)) {
3777 temp_url_keys[1] = val;
3778 set_temp_url_key = true;
3779 } else if (ceph_argparse_witharg(args, i, &val, "--bucket-id", (char*)NULL)) {
3780 bucket_id = val;
3781 opt_bucket_id = val;
3782 if (bucket_id.empty()) {
3783 cerr << "no value for bucket-id" << std::endl;
3784 exit(1);
3785 }
3786 } else if (ceph_argparse_witharg(args, i, &val, "--bucket-new-name", (char*)NULL)) {
3787 new_bucket_name = val;
3788 } else if (ceph_argparse_witharg(args, i, &val, "--format", (char*)NULL)) {
3789 format = val;
3790 } else if (ceph_argparse_witharg(args, i, &val, "--categories", (char*)NULL)) {
3791 string cat_str = val;
3792 list<string> cat_list;
3793 list<string>::iterator iter;
3794 get_str_list(cat_str, cat_list);
3795 for (iter = cat_list.begin(); iter != cat_list.end(); ++iter) {
3796 categories[*iter] = true;
3797 }
3798 } else if (ceph_argparse_binary_flag(args, i, &delete_child_objects, NULL, "--purge-objects", (char*)NULL)) {
3799 // do nothing
3800 } else if (ceph_argparse_binary_flag(args, i, &pretty_format, NULL, "--pretty-format", (char*)NULL)) {
3801 // do nothing
3802 } else if (ceph_argparse_binary_flag(args, i, &purge_data, NULL, "--purge-data", (char*)NULL)) {
3803 delete_child_objects = purge_data;
3804 } else if (ceph_argparse_binary_flag(args, i, &purge_keys, NULL, "--purge-keys", (char*)NULL)) {
3805 // do nothing
3806 } else if (ceph_argparse_binary_flag(args, i, &yes_i_really_mean_it, NULL, "--yes-i-really-mean-it", (char*)NULL)) {
3807 // do nothing
3808 } else if (ceph_argparse_binary_flag(args, i, &fix, NULL, "--fix", (char*)NULL)) {
3809 // do nothing
3810 } else if (ceph_argparse_binary_flag(args, i, &remove_bad, NULL, "--remove-bad", (char*)NULL)) {
3811 // do nothing
3812 } else if (ceph_argparse_binary_flag(args, i, &check_head_obj_locator, NULL, "--check-head-obj-locator", (char*)NULL)) {
3813 // do nothing
3814 } else if (ceph_argparse_binary_flag(args, i, &check_objects, NULL, "--check-objects", (char*)NULL)) {
3815 // do nothing
3816 } else if (ceph_argparse_binary_flag(args, i, &sync_stats, NULL, "--sync-stats", (char*)NULL)) {
3817 // do nothing
3818 } else if (ceph_argparse_binary_flag(args, i, &reset_stats, NULL, "--reset-stats", (char*)NULL)) {
3819 // do nothing
3820 } else if (ceph_argparse_binary_flag(args, i, &include_all, NULL, "--include-all", (char*)NULL)) {
3821 // do nothing
3822 } else if (ceph_argparse_binary_flag(args, i, &allow_unordered, NULL, "--allow-unordered", (char*)NULL)) {
3823 // do nothing
3824 } else if (ceph_argparse_binary_flag(args, i, &extra_info, NULL, "--extra-info", (char*)NULL)) {
3825 // do nothing
3826 } else if (ceph_argparse_binary_flag(args, i, &bypass_gc, NULL, "--bypass-gc", (char*)NULL)) {
3827 // do nothing
3828 } else if (ceph_argparse_binary_flag(args, i, &warnings_only, NULL, "--warnings-only", (char*)NULL)) {
3829 // do nothing
3830 } else if (ceph_argparse_binary_flag(args, i, &inconsistent_index, NULL, "--inconsistent-index", (char*)NULL)) {
3831 // do nothing
3832 } else if (ceph_argparse_flag(args, i, "--hide-progress", (char*)NULL)) {
3833 hide_progress = true;
3834 } else if (ceph_argparse_flag(args, i, "--dump-keys", (char*)NULL)) {
3835 dump_keys = true;
3836 } else if (ceph_argparse_binary_flag(args, i, &placement_inline_data, NULL, "--placement-inline-data", (char*)NULL)) {
3837 placement_inline_data_specified = true;
3838 // do nothing
3839 } else if (ceph_argparse_witharg(args, i, &val, "--caps", (char*)NULL)) {
3840 caps = val;
3841 } else if (ceph_argparse_witharg(args, i, &val, "--infile", (char*)NULL)) {
3842 infile = val;
3843 } else if (ceph_argparse_witharg(args, i, &val, "--metadata-key", (char*)NULL)) {
3844 metadata_key = val;
3845 } else if (ceph_argparse_witharg(args, i, &val, "--marker", (char*)NULL)) {
3846 marker = val;
3847 } else if (ceph_argparse_witharg(args, i, &val, "--start-marker", (char*)NULL)) {
3848 start_marker = val;
3849 } else if (ceph_argparse_witharg(args, i, &val, "--end-marker", (char*)NULL)) {
3850 end_marker = val;
3851 } else if (ceph_argparse_witharg(args, i, &val, "--quota-scope", (char*)NULL)) {
3852 quota_scope = val;
3853 } else if (ceph_argparse_witharg(args, i, &val, "--ratelimit-scope", (char*)NULL)) {
3854 ratelimit_scope = val;
3855 } else if (ceph_argparse_witharg(args, i, &val, "--index-type", (char*)NULL)) {
3856 string index_type_str = val;
3857 bi_index_type = get_bi_index_type(index_type_str);
3858 if (bi_index_type == BIIndexType::Invalid) {
3859 cerr << "ERROR: invalid bucket index entry type" << std::endl;
3860 return EINVAL;
3861 }
3862 } else if (ceph_argparse_witharg(args, i, &val, "--log-type", (char*)NULL)) {
3863 string log_type_str = val;
3864 auto l = get_log_type(log_type_str);
3865 if (l == static_cast<log_type>(0xff)) {
3866 cerr << "ERROR: invalid log type" << std::endl;
3867 return EINVAL;
3868 }
3869 opt_log_type = l;
3870 } else if (ceph_argparse_binary_flag(args, i, &is_master_int, NULL, "--master", (char*)NULL)) {
3871 is_master = (bool)is_master_int;
3872 is_master_set = true;
3873 } else if (ceph_argparse_binary_flag(args, i, &set_default, NULL, "--default", (char*)NULL)) {
3874 /* do nothing */
3875 } else if (ceph_argparse_witharg(args, i, &val, "--redirect-zone", (char*)NULL)) {
3876 redirect_zone = val;
3877 redirect_zone_set = true;
3878 } else if (ceph_argparse_binary_flag(args, i, &read_only_int, NULL, "--read-only", (char*)NULL)) {
3879 read_only = (bool)read_only_int;
3880 is_read_only_set = true;
3881 } else if (ceph_argparse_witharg(args, i, &val, "--master-zone", (char*)NULL)) {
3882 master_zone = val;
3883 } else if (ceph_argparse_witharg(args, i, &val, "--period", (char*)NULL)) {
3884 period_id = val;
3885 } else if (ceph_argparse_witharg(args, i, &val, "--epoch", (char*)NULL)) {
3886 period_epoch = val;
3887 } else if (ceph_argparse_witharg(args, i, &val, "--remote", (char*)NULL)) {
3888 remote = val;
3889 } else if (ceph_argparse_witharg(args, i, &val, "--url", (char*)NULL)) {
3890 url = val;
3891 } else if (ceph_argparse_witharg(args, i, &val, "--region", (char*)NULL)) {
3892 opt_region = val;
3893 } else if (ceph_argparse_witharg(args, i, &val, "--realm-id", (char*)NULL)) {
3894 realm_id = val;
3895 opt_realm_id = val;
3896 g_conf().set_val("rgw_realm_id", val);
3897 } else if (ceph_argparse_witharg(args, i, &val, "--realm-new-name", (char*)NULL)) {
3898 realm_new_name = val;
3899 } else if (ceph_argparse_witharg(args, i, &val, "--zonegroup-id", (char*)NULL)) {
3900 zonegroup_id = val;
3901 opt_zonegroup_id = val;
3902 g_conf().set_val("rgw_zonegroup_id", val);
3903 } else if (ceph_argparse_witharg(args, i, &val, "--zonegroup-new-name", (char*)NULL)) {
3904 zonegroup_new_name = val;
3905 } else if (ceph_argparse_witharg(args, i, &val, "--placement-id", (char*)NULL)) {
3906 placement_id = val;
3907 } else if (ceph_argparse_witharg(args, i, &val, "--storage-class", (char*)NULL)) {
3908 opt_storage_class = val;
3909 } else if (ceph_argparse_witharg(args, i, &val, "--tags", (char*)NULL)) {
3910 get_str_list(val, ",", tags);
3911 } else if (ceph_argparse_witharg(args, i, &val, "--tags-add", (char*)NULL)) {
3912 get_str_list(val, ",", tags_add);
3913 } else if (ceph_argparse_witharg(args, i, &val, "--tags-rm", (char*)NULL)) {
3914 get_str_list(val, ",", tags_rm);
3915 } else if (ceph_argparse_witharg(args, i, &val, "--api-name", (char*)NULL)) {
3916 api_name = val;
3917 } else if (ceph_argparse_witharg(args, i, &val, "--zone-id", (char*)NULL)) {
3918 zone_id = val;
3919 opt_zone_id = val;
3920 g_conf().set_val("rgw_zone_id", val);
3921 } else if (ceph_argparse_witharg(args, i, &val, "--zone-new-name", (char*)NULL)) {
3922 zone_new_name = val;
3923 } else if (ceph_argparse_witharg(args, i, &val, "--endpoints", (char*)NULL)) {
3924 get_str_list(val, endpoints);
3925 } else if (ceph_argparse_witharg(args, i, &val, "--sync-from", (char*)NULL)) {
3926 get_str_list(val, sync_from);
3927 } else if (ceph_argparse_witharg(args, i, &val, "--sync-from-rm", (char*)NULL)) {
3928 get_str_list(val, sync_from_rm);
3929 } else if (ceph_argparse_binary_flag(args, i, &tmp_int, NULL, "--sync-from-all", (char*)NULL)) {
3930 sync_from_all = (bool)tmp_int;
3931 sync_from_all_specified = true;
3932 } else if (ceph_argparse_witharg(args, i, &val, "--source-zone", (char*)NULL)) {
3933 source_zone_name = val;
3934 opt_source_zone_name = val;
3935 } else if (ceph_argparse_witharg(args, i, &val, "--source-zone-id", (char*)NULL)) {
3936 opt_source_zone_id = val;
3937 } else if (ceph_argparse_witharg(args, i, &val, "--dest-zone", (char*)NULL)) {
3938 opt_dest_zone_name = val;
3939 } else if (ceph_argparse_witharg(args, i, &val, "--dest-zone-id", (char*)NULL)) {
3940 opt_dest_zone_id = val;
3941 } else if (ceph_argparse_witharg(args, i, &val, "--tier-type", (char*)NULL)) {
3942 tier_type = val;
3943 tier_type_specified = true;
3944 } else if (ceph_argparse_witharg(args, i, &val, "--tier-config", (char*)NULL)) {
3945 parse_tier_config_param(val, tier_config_add);
3946 } else if (ceph_argparse_witharg(args, i, &val, "--tier-config-rm", (char*)NULL)) {
3947 parse_tier_config_param(val, tier_config_rm);
3948 } else if (ceph_argparse_witharg(args, i, &val, "--index-pool", (char*)NULL)) {
3949 index_pool = val;
3950 } else if (ceph_argparse_witharg(args, i, &val, "--data-pool", (char*)NULL)) {
3951 data_pool = val;
3952 } else if (ceph_argparse_witharg(args, i, &val, "--data-extra-pool", (char*)NULL)) {
3953 data_extra_pool = val;
3954 } else if (ceph_argparse_witharg(args, i, &val, "--placement-index-type", (char*)NULL)) {
3955 if (val == "normal") {
3956 placement_index_type = rgw::BucketIndexType::Normal;
3957 } else if (val == "indexless") {
3958 placement_index_type = rgw::BucketIndexType::Indexless;
3959 } else {
3960 placement_index_type = (rgw::BucketIndexType)strict_strtol(val.c_str(), 10, &err);
3961 if (!err.empty()) {
3962 cerr << "ERROR: failed to parse index type index: " << err << std::endl;
3963 return EINVAL;
3964 }
3965 }
3966 index_type_specified = true;
3967 } else if (ceph_argparse_witharg(args, i, &val, "--compression", (char*)NULL)) {
3968 compression_type = val;
3969 } else if (ceph_argparse_witharg(args, i, &val, "--role-name", (char*)NULL)) {
3970 role_name = val;
3971 } else if (ceph_argparse_witharg(args, i, &val, "--path", (char*)NULL)) {
3972 path = val;
3973 } else if (ceph_argparse_witharg(args, i, &val, "--assume-role-policy-doc", (char*)NULL)) {
3974 assume_role_doc = val;
3975 } else if (ceph_argparse_witharg(args, i, &val, "--policy-name", (char*)NULL)) {
3976 policy_name = val;
3977 } else if (ceph_argparse_witharg(args, i, &val, "--policy-doc", (char*)NULL)) {
3978 perm_policy_doc = val;
3979 } else if (ceph_argparse_witharg(args, i, &val, "--path-prefix", (char*)NULL)) {
3980 path_prefix = val;
3981 } else if (ceph_argparse_witharg(args, i, &val, "--max-session-duration", (char*)NULL)) {
3982 max_session_duration = val;
3983 } else if (ceph_argparse_witharg(args, i, &val, "--totp-serial", (char*)NULL)) {
3984 totp_serial = val;
3985 } else if (ceph_argparse_witharg(args, i, &val, "--totp-pin", (char*)NULL)) {
3986 totp_pin.push_back(val);
3987 } else if (ceph_argparse_witharg(args, i, &val, "--totp-seed", (char*)NULL)) {
3988 totp_seed = val;
3989 } else if (ceph_argparse_witharg(args, i, &val, "--totp-seed-type", (char*)NULL)) {
3990 totp_seed_type = val;
3991 } else if (ceph_argparse_witharg(args, i, &val, "--totp-seconds", (char*)NULL)) {
3992 totp_seconds = atoi(val.c_str());
3993 } else if (ceph_argparse_witharg(args, i, &val, "--totp-window", (char*)NULL)) {
3994 totp_window = atoi(val.c_str());
3995 } else if (ceph_argparse_witharg(args, i, &val, "--trim-delay-ms", (char*)NULL)) {
3996 trim_delay_ms = atoi(val.c_str());
3997 } else if (ceph_argparse_witharg(args, i, &val, "--topic", (char*)NULL)) {
3998 topic_name = val;
3999 } else if (ceph_argparse_witharg(args, i, &val, "--notification-id", (char*)NULL)) {
4000 notification_id = val;
4001 } else if (ceph_argparse_witharg(args, i, &val, "--subscription", (char*)NULL)) {
4002 sub_name = val;
4003 } else if (ceph_argparse_witharg(args, i, &val, "--event-id", (char*)NULL)) {
4004 event_id = val;
4005 } else if (ceph_argparse_witharg(args, i, &val, "--group-id", (char*)NULL)) {
4006 opt_group_id = val;
4007 } else if (ceph_argparse_witharg(args, i, &val, "--status", (char*)NULL)) {
4008 opt_status = val;
4009 } else if (ceph_argparse_witharg(args, i, &val, "--flow-type", (char*)NULL)) {
4010 opt_flow_type = val;
4011 } else if (ceph_argparse_witharg(args, i, &val, "--zones", "--zone-names", (char*)NULL)) {
4012 vector<string> v;
4013 get_str_vec(val, v);
4014 opt_zone_names = std::move(v);
4015 } else if (ceph_argparse_witharg(args, i, &val, "--zone-ids", (char*)NULL)) {
4016 opt_zone_ids = zone_ids_from_str(val);
4017 } else if (ceph_argparse_witharg(args, i, &val, "--source-zones", "--source-zone-names", (char*)NULL)) {
4018 vector<string> v;
4019 get_str_vec(val, v);
4020 opt_source_zone_names = std::move(v);
4021 } else if (ceph_argparse_witharg(args, i, &val, "--source-zone-ids", (char*)NULL)) {
4022 opt_source_zone_ids = zone_ids_from_str(val);
4023 } else if (ceph_argparse_witharg(args, i, &val, "--dest-zones", "--dest-zone-names", (char*)NULL)) {
4024 vector<string> v;
4025 get_str_vec(val, v);
4026 opt_dest_zone_names = std::move(v);
4027 } else if (ceph_argparse_witharg(args, i, &val, "--dest-zone-ids", (char*)NULL)) {
4028 opt_dest_zone_ids = zone_ids_from_str(val);
4029 } else if (ceph_argparse_witharg(args, i, &val, "--flow-id", (char*)NULL)) {
4030 opt_flow_id = val;
4031 } else if (ceph_argparse_witharg(args, i, &val, "--pipe-id", (char*)NULL)) {
4032 opt_pipe_id = val;
4033 } else if (ceph_argparse_witharg(args, i, &val, "--source-tenant", (char*)NULL)) {
4034 opt_source_tenant = val;
4035 } else if (ceph_argparse_witharg(args, i, &val, "--source-bucket", (char*)NULL)) {
4036 opt_source_bucket_name = val;
4037 } else if (ceph_argparse_witharg(args, i, &val, "--source-bucket-id", (char*)NULL)) {
4038 opt_source_bucket_id = val;
4039 } else if (ceph_argparse_witharg(args, i, &val, "--dest-tenant", (char*)NULL)) {
4040 opt_dest_tenant = val;
4041 } else if (ceph_argparse_witharg(args, i, &val, "--dest-bucket", (char*)NULL)) {
4042 opt_dest_bucket_name = val;
4043 } else if (ceph_argparse_witharg(args, i, &val, "--dest-bucket-id", (char*)NULL)) {
4044 opt_dest_bucket_id = val;
4045 } else if (ceph_argparse_witharg(args, i, &val, "--effective-zone-name", "--effective-zone", (char*)NULL)) {
4046 opt_effective_zone_name = val;
4047 } else if (ceph_argparse_witharg(args, i, &val, "--effective-zone-id", (char*)NULL)) {
4048 opt_effective_zone_id = rgw_zone_id(val);
4049 } else if (ceph_argparse_witharg(args, i, &val, "--prefix", (char*)NULL)) {
4050 opt_prefix = val;
4051 } else if (ceph_argparse_witharg(args, i, &val, "--prefix-rm", (char*)NULL)) {
4052 opt_prefix_rm = val;
4053 } else if (ceph_argparse_witharg(args, i, &val, "--priority", (char*)NULL)) {
4054 opt_priority = atoi(val.c_str());
4055 } else if (ceph_argparse_witharg(args, i, &val, "--mode", (char*)NULL)) {
4056 opt_mode = val;
4057 } else if (ceph_argparse_witharg(args, i, &val, "--dest-owner", (char*)NULL)) {
4058 opt_dest_owner.emplace(val);
4059 opt_dest_owner = val;
4060 } else if (ceph_argparse_witharg(args, i, &val, "--retry-delay-ms", (char*)NULL)) {
4061 opt_retry_delay_ms = std::chrono::milliseconds(atoi(val.c_str()));
4062 } else if (ceph_argparse_witharg(args, i, &val, "--timeout-sec", (char*)NULL)) {
4063 opt_timeout_sec = std::chrono::seconds(atoi(val.c_str()));
4064 } else if (ceph_argparse_witharg(args, i, &val, "--inject-error-at", (char*)NULL)) {
4065 inject_error_at = val;
4066 } else if (ceph_argparse_witharg(args, i, &val, "--inject-error-code", (char*)NULL)) {
4067 inject_error_code = atoi(val.c_str());
4068 } else if (ceph_argparse_witharg(args, i, &val, "--inject-abort-at", (char*)NULL)) {
4069 inject_abort_at = val;
4070 } else if (ceph_argparse_witharg(args, i, &val, "--inject-delay-at", (char*)NULL)) {
4071 inject_delay_at = val;
4072 } else if (ceph_argparse_witharg(args, i, &val, "--inject-delay-ms", (char*)NULL)) {
4073 inject_delay = std::chrono::milliseconds(atoi(val.c_str()));
4074 } else if (ceph_argparse_binary_flag(args, i, &detail, NULL, "--detail", (char*)NULL)) {
4075 // do nothing
4076 } else if (ceph_argparse_witharg(args, i, &val, "--context", (char*)NULL)) {
4077 str_script_ctx = val;
4078 } else if (ceph_argparse_witharg(args, i, &val, "--package", (char*)NULL)) {
4079 script_package = val;
4080 } else if (ceph_argparse_binary_flag(args, i, &allow_compilation, NULL, "--allow-compilation", (char*)NULL)) {
4081 // do nothing
4082 } else if (ceph_argparse_witharg(args, i, &val, "--rgw-obj-fs", (char*)NULL)) {
4083 rgw_obj_fs = val;
4084 } else if (ceph_argparse_witharg(args, i, &val, "--enable-feature", (char*)NULL)) {
4085 if (!rgw::zone_features::supports(val)) {
4086 std::cerr << "ERROR: Cannot enable unrecognized zone feature \"" << val << "\"" << std::endl;
4087 return EINVAL;
4088 }
4089 enable_features.insert(val);
4090 } else if (ceph_argparse_witharg(args, i, &val, "--disable-feature", (char*)NULL)) {
4091 disable_features.insert(val);
4092 } else if (strncmp(*i, "-", 1) == 0) {
4093 cerr << "ERROR: invalid flag " << *i << std::endl;
4094 return EINVAL;
4095 } else {
4096 ++i;
4097 }
4098 }
4099
4100 /* common_init_finish needs to be called after g_conf().set_val() */
4101 common_init_finish(g_ceph_context);
4102
4103 std::unique_ptr<rgw::sal::ConfigStore> cfgstore;
4104
4105 if (args.empty()) {
4106 usage();
4107 exit(1);
4108 }
4109 else {
4110 std::vector<string> extra_args;
4111 std::vector<string> expected;
4112
4113 std::any _opt_cmd;
4114
4115 if (!cmd.find_command(args, &_opt_cmd, &extra_args, &err, &expected)) {
4116 if (!expected.empty()) {
4117 cerr << err << std::endl;
4118 cerr << "Expected one of the following:" << std::endl;
4119 for (auto& exp : expected) {
4120 if (exp == "*" || exp == "[*]") {
4121 continue;
4122 }
4123 cerr << " " << exp << std::endl;
4124 }
4125 } else {
4126 cerr << "Command not found:";
4127 for (auto& arg : args) {
4128 cerr << " " << arg;
4129 }
4130 cerr << std::endl;
4131 }
4132 exit(1);
4133 }
4134
4135 opt_cmd = std::any_cast<OPT>(_opt_cmd);
4136
4137 /* some commands may have an optional extra param */
4138 if (!extra_args.empty()) {
4139 switch (opt_cmd) {
4140 case OPT::METADATA_GET:
4141 case OPT::METADATA_PUT:
4142 case OPT::METADATA_RM:
4143 case OPT::METADATA_LIST:
4144 metadata_key = extra_args[0];
4145 break;
4146 default:
4147 break;
4148 }
4149 }
4150
4151 // not a raw op if 'period update' needs to commit to master
4152 bool raw_period_update = opt_cmd == OPT::PERIOD_UPDATE && !commit;
4153 // not a raw op if 'period pull' needs to read zone/period configuration
4154 bool raw_period_pull = opt_cmd == OPT::PERIOD_PULL && !url.empty();
4155
4156 std::set<OPT> raw_storage_ops_list = {OPT::ZONEGROUP_ADD, OPT::ZONEGROUP_CREATE,
4157 OPT::ZONEGROUP_DELETE,
4158 OPT::ZONEGROUP_GET, OPT::ZONEGROUP_LIST,
4159 OPT::ZONEGROUP_SET, OPT::ZONEGROUP_DEFAULT,
4160 OPT::ZONEGROUP_RENAME, OPT::ZONEGROUP_MODIFY,
4161 OPT::ZONEGROUP_REMOVE,
4162 OPT::ZONEGROUP_PLACEMENT_ADD, OPT::ZONEGROUP_PLACEMENT_RM,
4163 OPT::ZONEGROUP_PLACEMENT_MODIFY, OPT::ZONEGROUP_PLACEMENT_LIST,
4164 OPT::ZONEGROUP_PLACEMENT_GET,
4165 OPT::ZONEGROUP_PLACEMENT_DEFAULT,
4166 OPT::ZONE_CREATE, OPT::ZONE_DELETE,
4167 OPT::ZONE_GET, OPT::ZONE_SET, OPT::ZONE_RENAME,
4168 OPT::ZONE_LIST, OPT::ZONE_MODIFY, OPT::ZONE_DEFAULT,
4169 OPT::ZONE_PLACEMENT_ADD, OPT::ZONE_PLACEMENT_RM,
4170 OPT::ZONE_PLACEMENT_MODIFY, OPT::ZONE_PLACEMENT_LIST,
4171 OPT::ZONE_PLACEMENT_GET,
4172 OPT::REALM_CREATE,
4173 OPT::PERIOD_DELETE, OPT::PERIOD_GET,
4174 OPT::PERIOD_GET_CURRENT, OPT::PERIOD_LIST,
4175 OPT::GLOBAL_QUOTA_GET, OPT::GLOBAL_QUOTA_SET,
4176 OPT::GLOBAL_QUOTA_ENABLE, OPT::GLOBAL_QUOTA_DISABLE,
4177 OPT::GLOBAL_RATELIMIT_GET, OPT::GLOBAL_RATELIMIT_SET,
4178 OPT::GLOBAL_RATELIMIT_ENABLE, OPT::GLOBAL_RATELIMIT_DISABLE,
4179 OPT::REALM_DELETE, OPT::REALM_GET, OPT::REALM_LIST,
4180 OPT::REALM_LIST_PERIODS,
4181 OPT::REALM_GET_DEFAULT,
4182 OPT::REALM_RENAME, OPT::REALM_SET,
4183 OPT::REALM_DEFAULT, OPT::REALM_PULL};
4184
4185 std::set<OPT> readonly_ops_list = {
4186 OPT::USER_INFO,
4187 OPT::USER_STATS,
4188 OPT::BUCKETS_LIST,
4189 OPT::BUCKET_LIMIT_CHECK,
4190 OPT::BUCKET_LAYOUT,
4191 OPT::BUCKET_STATS,
4192 OPT::BUCKET_SYNC_CHECKPOINT,
4193 OPT::BUCKET_SYNC_INFO,
4194 OPT::BUCKET_SYNC_STATUS,
4195 OPT::BUCKET_SYNC_MARKERS,
4196 OPT::BUCKET_SHARD_OBJECTS,
4197 OPT::BUCKET_OBJECT_SHARD,
4198 OPT::LOG_LIST,
4199 OPT::LOG_SHOW,
4200 OPT::USAGE_SHOW,
4201 OPT::OBJECT_STAT,
4202 OPT::BI_GET,
4203 OPT::BI_LIST,
4204 OPT::OLH_GET,
4205 OPT::OLH_READLOG,
4206 OPT::GC_LIST,
4207 OPT::LC_LIST,
4208 OPT::ORPHANS_LIST_JOBS,
4209 OPT::ZONEGROUP_GET,
4210 OPT::ZONEGROUP_LIST,
4211 OPT::ZONEGROUP_PLACEMENT_LIST,
4212 OPT::ZONEGROUP_PLACEMENT_GET,
4213 OPT::ZONE_GET,
4214 OPT::ZONE_LIST,
4215 OPT::ZONE_PLACEMENT_LIST,
4216 OPT::ZONE_PLACEMENT_GET,
4217 OPT::METADATA_GET,
4218 OPT::METADATA_LIST,
4219 OPT::METADATA_SYNC_STATUS,
4220 OPT::MDLOG_LIST,
4221 OPT::MDLOG_STATUS,
4222 OPT::SYNC_ERROR_LIST,
4223 OPT::SYNC_GROUP_GET,
4224 OPT::SYNC_POLICY_GET,
4225 OPT::BILOG_LIST,
4226 OPT::BILOG_STATUS,
4227 OPT::DATA_SYNC_STATUS,
4228 OPT::DATALOG_LIST,
4229 OPT::DATALOG_STATUS,
4230 OPT::REALM_GET,
4231 OPT::REALM_GET_DEFAULT,
4232 OPT::REALM_LIST,
4233 OPT::REALM_LIST_PERIODS,
4234 OPT::PERIOD_GET,
4235 OPT::PERIOD_GET_CURRENT,
4236 OPT::PERIOD_LIST,
4237 OPT::GLOBAL_QUOTA_GET,
4238 OPT::GLOBAL_RATELIMIT_GET,
4239 OPT::SYNC_INFO,
4240 OPT::SYNC_STATUS,
4241 OPT::ROLE_GET,
4242 OPT::ROLE_LIST,
4243 OPT::ROLE_POLICY_LIST,
4244 OPT::ROLE_POLICY_GET,
4245 OPT::RESHARD_LIST,
4246 OPT::RESHARD_STATUS,
4247 OPT::PUBSUB_TOPIC_LIST,
4248 OPT::PUBSUB_NOTIFICATION_LIST,
4249 OPT::PUBSUB_TOPIC_GET,
4250 OPT::PUBSUB_NOTIFICATION_GET,
4251 OPT::SCRIPT_GET,
4252 };
4253
4254 std::set<OPT> gc_ops_list = {
4255 OPT::GC_LIST,
4256 OPT::GC_PROCESS,
4257 OPT::OBJECT_RM,
4258 OPT::BUCKET_RM, // --purge-objects
4259 OPT::USER_RM, // --purge-data
4260 OPT::OBJECTS_EXPIRE,
4261 OPT::OBJECTS_EXPIRE_STALE_RM,
4262 OPT::LC_PROCESS,
4263 OPT::BUCKET_SYNC_RUN,
4264 OPT::DATA_SYNC_RUN,
4265 OPT::BUCKET_REWRITE,
4266 OPT::OBJECT_REWRITE
4267 };
4268
4269 raw_storage_op = (raw_storage_ops_list.find(opt_cmd) != raw_storage_ops_list.end() ||
4270 raw_period_update || raw_period_pull);
4271 bool need_cache = readonly_ops_list.find(opt_cmd) == readonly_ops_list.end();
4272 bool need_gc = (gc_ops_list.find(opt_cmd) != gc_ops_list.end()) && !bypass_gc;
4273
4274 DriverManager::Config cfg = DriverManager::get_config(true, g_ceph_context);
4275
4276 auto config_store_type = g_conf().get_val<std::string>("rgw_config_store");
4277 cfgstore = DriverManager::create_config_store(dpp(), config_store_type);
4278 if (!cfgstore) {
4279 cerr << "couldn't init config storage provider" << std::endl;
4280 return EIO;
4281 }
4282
4283 if (raw_storage_op) {
4284 driver = DriverManager::get_raw_storage(dpp(),
4285 g_ceph_context,
4286 cfg);
4287 } else {
4288 driver = DriverManager::get_storage(dpp(),
4289 g_ceph_context,
4290 cfg,
4291 false,
4292 false,
4293 false,
4294 false,
4295 false,
4296 need_cache && g_conf()->rgw_cache_enabled,
4297 need_gc);
4298 }
4299 if (!driver) {
4300 cerr << "couldn't init storage provider" << std::endl;
4301 return EIO;
4302 }
4303
4304 /* Needs to be after the driver is initialized. Note, user could be empty here. */
4305 user = driver->get_user(user_id_arg);
4306
4307 init_optional_bucket(opt_bucket, opt_tenant,
4308 opt_bucket_name, opt_bucket_id);
4309 init_optional_bucket(opt_source_bucket, opt_source_tenant,
4310 opt_source_bucket_name, opt_source_bucket_id);
4311 init_optional_bucket(opt_dest_bucket, opt_dest_tenant,
4312 opt_dest_bucket_name, opt_dest_bucket_id);
4313
4314 if (tenant.empty()) {
4315 tenant = user->get_tenant();
4316 } else {
4317 if (rgw::sal::User::empty(user) && opt_cmd != OPT::ROLE_CREATE
4318 && opt_cmd != OPT::ROLE_DELETE
4319 && opt_cmd != OPT::ROLE_GET
4320 && opt_cmd != OPT::ROLE_TRUST_POLICY_MODIFY
4321 && opt_cmd != OPT::ROLE_LIST
4322 && opt_cmd != OPT::ROLE_POLICY_PUT
4323 && opt_cmd != OPT::ROLE_POLICY_LIST
4324 && opt_cmd != OPT::ROLE_POLICY_GET
4325 && opt_cmd != OPT::ROLE_POLICY_DELETE
4326 && opt_cmd != OPT::ROLE_UPDATE
4327 && opt_cmd != OPT::RESHARD_ADD
4328 && opt_cmd != OPT::RESHARD_CANCEL
4329 && opt_cmd != OPT::RESHARD_STATUS
4330 && opt_cmd != OPT::PUBSUB_TOPIC_LIST
4331 && opt_cmd != OPT::PUBSUB_NOTIFICATION_LIST
4332 && opt_cmd != OPT::PUBSUB_TOPIC_GET
4333 && opt_cmd != OPT::PUBSUB_NOTIFICATION_GET
4334 && opt_cmd != OPT::PUBSUB_TOPIC_RM
4335 && opt_cmd != OPT::PUBSUB_NOTIFICATION_RM) {
4336 cerr << "ERROR: --tenant is set, but there's no user ID" << std::endl;
4337 return EINVAL;
4338 }
4339 user->set_tenant(tenant);
4340 }
4341 if (user_ns.empty()) {
4342 user_ns = user->get_id().ns;
4343 } else {
4344 user->set_ns(user_ns);
4345 }
4346
4347 if (!new_user_id.empty() && !tenant.empty()) {
4348 new_user_id.tenant = tenant;
4349 }
4350
4351 /* check key parameter conflict */
4352 if ((!access_key.empty()) && gen_access_key) {
4353 cerr << "ERROR: key parameter conflict, --access-key & --gen-access-key" << std::endl;
4354 return EINVAL;
4355 }
4356 if ((!secret_key.empty()) && gen_secret_key) {
4357 cerr << "ERROR: key parameter conflict, --secret & --gen-secret" << std::endl;
4358 return EINVAL;
4359 }
4360 }
4361
4362 // default to pretty json
4363 if (format.empty()) {
4364 format = "json";
4365 pretty_format = true;
4366 }
4367
4368 if (format == "xml")
4369 formatter = make_unique<XMLFormatter>(new XMLFormatter(pretty_format));
4370 else if (format == "json")
4371 formatter = make_unique<JSONFormatter>(new JSONFormatter(pretty_format));
4372 else {
4373 cerr << "unrecognized format: " << format << std::endl;
4374 exit(1);
4375 }
4376
4377 zone_formatter = std::make_unique<JSONFormatter_PrettyZone>(pretty_format);
4378
4379 realm_name = g_conf()->rgw_realm;
4380 zone_name = g_conf()->rgw_zone;
4381 zonegroup_name = g_conf()->rgw_zonegroup;
4382
4383 if (!realm_name.empty()) {
4384 opt_realm_name = realm_name;
4385 }
4386
4387 if (!zone_name.empty()) {
4388 opt_zone_name = zone_name;
4389 }
4390
4391 if (!zonegroup_name.empty()) {
4392 opt_zonegroup_name = zonegroup_name;
4393 }
4394
4395 RGWStreamFlusher stream_flusher(formatter.get(), cout);
4396
4397 RGWUserAdminOpState user_op(driver);
4398 if (!user_email.empty()) {
4399 user_op.user_email_specified=true;
4400 }
4401
4402 if (!source_zone_name.empty()) {
4403 std::unique_ptr<rgw::sal::Zone> zone;
4404 if (driver->get_zone()->get_zonegroup().get_zone_by_name(source_zone_name, &zone) < 0) {
4405 cerr << "WARNING: cannot find source zone id for name=" << source_zone_name << std::endl;
4406 source_zone = source_zone_name;
4407 } else {
4408 source_zone.id = zone->get_id();
4409 }
4410 }
4411
4412 rgw_http_client_init(g_ceph_context);
4413
4414 struct rgw_curl_setup {
4415 rgw_curl_setup() {
4416 rgw::curl::setup_curl(boost::none);
4417 }
4418 ~rgw_curl_setup() {
4419 rgw::curl::cleanup_curl();
4420 }
4421 } curl_cleanup;
4422
4423 oath_init();
4424
4425 StoreDestructor store_destructor(driver);
4426
4427 if (raw_storage_op) {
4428 switch (opt_cmd) {
4429 case OPT::PERIOD_DELETE:
4430 {
4431 if (period_id.empty()) {
4432 cerr << "missing period id" << std::endl;
4433 return EINVAL;
4434 }
4435 int ret = cfgstore->delete_period(dpp(), null_yield, period_id);
4436 if (ret < 0) {
4437 cerr << "ERROR: couldn't delete period: " << cpp_strerror(-ret) << std::endl;
4438 return -ret;
4439 }
4440
4441 }
4442 break;
4443 case OPT::PERIOD_GET:
4444 {
4445 std::optional<epoch_t> epoch;
4446 if (!period_epoch.empty()) {
4447 epoch = atoi(period_epoch.c_str());
4448 }
4449 if (staging) {
4450 RGWRealm realm;
4451 int ret = rgw::read_realm(dpp(), null_yield, cfgstore.get(),
4452 realm_id, realm_name, realm);
4453 if (ret < 0 ) {
4454 cerr << "failed to load realm: " << cpp_strerror(-ret) << std::endl;
4455 return -ret;
4456 }
4457 realm_id = realm.get_id();
4458 realm_name = realm.get_name();
4459 period_id = RGWPeriod::get_staging_id(realm_id);
4460 epoch = 1;
4461 }
4462 if (period_id.empty()) {
4463 // use realm's current period
4464 RGWRealm realm;
4465 int ret = rgw::read_realm(dpp(), null_yield, cfgstore.get(),
4466 realm_id, realm_name, realm);
4467 if (ret < 0 ) {
4468 cerr << "failed to load realm: " << cpp_strerror(-ret) << std::endl;
4469 return -ret;
4470 }
4471 period_id = realm.current_period;
4472 }
4473
4474 RGWPeriod period;
4475 int ret = cfgstore->read_period(dpp(), null_yield, period_id,
4476 epoch, period);
4477 if (ret < 0) {
4478 cerr << "failed to load period: " << cpp_strerror(-ret) << std::endl;
4479 return -ret;
4480 }
4481 encode_json("period", period, formatter.get());
4482 formatter->flush(cout);
4483 }
4484 break;
4485 case OPT::PERIOD_GET_CURRENT:
4486 {
4487 RGWRealm realm;
4488 int ret = rgw::read_realm(dpp(), null_yield, cfgstore.get(),
4489 realm_id, realm_name, realm);
4490 if (ret < 0) {
4491 std::cerr << "failed to load realm: " << cpp_strerror(ret) << std::endl;
4492 return -ret;
4493 }
4494
4495 formatter->open_object_section("period_get_current");
4496 encode_json("current_period", realm.current_period, formatter.get());
4497 formatter->close_section();
4498 formatter->flush(cout);
4499 }
4500 break;
4501 case OPT::PERIOD_LIST:
4502 {
4503 Formatter::ObjectSection periods_list{*formatter, "periods_list"};
4504 Formatter::ArraySection periods{*formatter, "periods"};
4505 rgw::sal::ListResult<std::string> listing;
4506 std::array<std::string, 1000> period_ids; // list in pages of 1000
4507 do {
4508 int ret = cfgstore->list_period_ids(dpp(), null_yield, listing.next,
4509 period_ids, listing);
4510 if (ret < 0) {
4511 std::cerr << "failed to list periods: " << cpp_strerror(-ret) << std::endl;
4512 return -ret;
4513 }
4514 for (const auto& id : listing.entries) {
4515 encode_json("id", id, formatter.get());
4516 }
4517 } while (!listing.next.empty());
4518 } // close sections periods and periods_list
4519 formatter->flush(cout);
4520 break;
4521 case OPT::PERIOD_UPDATE:
4522 {
4523 int ret = update_period(cfgstore.get(), realm_id, realm_name,
4524 period_epoch, commit, remote, url,
4525 opt_region, access_key, secret_key,
4526 formatter.get(), yes_i_really_mean_it);
4527 if (ret < 0) {
4528 return -ret;
4529 }
4530 }
4531 break;
4532 case OPT::PERIOD_PULL:
4533 {
4534 boost::optional<RGWRESTConn> conn;
4535 RGWRESTConn *remote_conn = nullptr;
4536 if (url.empty()) {
4537 // load current period for endpoints
4538 RGWRealm realm;
4539 int ret = rgw::read_realm(dpp(), null_yield, cfgstore.get(),
4540 realm_id, realm_name, realm);
4541 if (ret < 0 ) {
4542 cerr << "failed to load realm: " << cpp_strerror(-ret) << std::endl;
4543 return -ret;
4544 }
4545 period_id = realm.current_period;
4546
4547 RGWPeriod current_period;
4548 ret = cfgstore->read_period(dpp(), null_yield, period_id,
4549 std::nullopt, current_period);
4550 if (ret < 0) {
4551 cerr << "failed to load current period: " << cpp_strerror(-ret) << std::endl;
4552 return -ret;
4553 }
4554 if (remote.empty()) {
4555 // use realm master zone as remote
4556 remote = current_period.get_master_zone().id;
4557 }
4558 conn = get_remote_conn(static_cast<rgw::sal::RadosStore*>(driver), current_period.get_map(), remote);
4559 if (!conn) {
4560 cerr << "failed to find a zone or zonegroup for remote "
4561 << remote << std::endl;
4562 return -ENOENT;
4563 }
4564 remote_conn = &*conn;
4565 }
4566
4567 RGWPeriod period;
4568 int ret = do_period_pull(cfgstore.get(), remote_conn, url,
4569 opt_region, access_key, secret_key,
4570 realm_id, realm_name, period_id, period_epoch,
4571 &period);
4572 if (ret < 0) {
4573 cerr << "period pull failed: " << cpp_strerror(-ret) << std::endl;
4574 return -ret;
4575 }
4576
4577 encode_json("period", period, formatter.get());
4578 formatter->flush(cout);
4579 }
4580 break;
4581 case OPT::GLOBAL_RATELIMIT_GET:
4582 case OPT::GLOBAL_RATELIMIT_SET:
4583 case OPT::GLOBAL_RATELIMIT_ENABLE:
4584 case OPT::GLOBAL_RATELIMIT_DISABLE:
4585 {
4586 if (realm_id.empty()) {
4587 if (!realm_name.empty()) {
4588 // look up realm_id for the given realm_name
4589 int ret = cfgstore->read_realm_id(dpp(), null_yield,
4590 realm_name, realm_id);
4591 if (ret < 0) {
4592 cerr << "ERROR: failed to read realm for " << realm_name
4593 << ": " << cpp_strerror(-ret) << std::endl;
4594 return -ret;
4595 }
4596 } else {
4597 // use default realm_id when none is given
4598 int ret = cfgstore->read_default_realm_id(dpp(), null_yield,
4599 realm_id);
4600 if (ret < 0 && ret != -ENOENT) { // on ENOENT, use empty realm_id
4601 cerr << "ERROR: failed to read default realm: "
4602 << cpp_strerror(-ret) << std::endl;
4603 return -ret;
4604 }
4605 }
4606 }
4607
4608 RGWPeriodConfig period_config;
4609 int ret = cfgstore->read_period_config(dpp(), null_yield, realm_id,
4610 period_config);
4611 if (ret < 0 && ret != -ENOENT) {
4612 cerr << "ERROR: failed to read period config: "
4613 << cpp_strerror(-ret) << std::endl;
4614 return -ret;
4615 }
4616 bool ratelimit_configured = true;
4617 formatter->open_object_section("period_config");
4618 if (ratelimit_scope == "bucket") {
4619 ratelimit_configured = set_ratelimit_info(period_config.bucket_ratelimit, opt_cmd,
4620 max_read_ops, max_write_ops,
4621 max_read_bytes, max_write_bytes,
4622 have_max_read_ops, have_max_write_ops,
4623 have_max_read_bytes, have_max_write_bytes);
4624 encode_json("bucket_ratelimit", period_config.bucket_ratelimit, formatter.get());
4625 } else if (ratelimit_scope == "user") {
4626 ratelimit_configured = set_ratelimit_info(period_config.user_ratelimit, opt_cmd,
4627 max_read_ops, max_write_ops,
4628 max_read_bytes, max_write_bytes,
4629 have_max_read_ops, have_max_write_ops,
4630 have_max_read_bytes, have_max_write_bytes);
4631 encode_json("user_ratelimit", period_config.user_ratelimit, formatter.get());
4632 } else if (ratelimit_scope == "anonymous") {
4633 ratelimit_configured = set_ratelimit_info(period_config.anon_ratelimit, opt_cmd,
4634 max_read_ops, max_write_ops,
4635 max_read_bytes, max_write_bytes,
4636 have_max_read_ops, have_max_write_ops,
4637 have_max_read_bytes, have_max_write_bytes);
4638 encode_json("anonymous_ratelimit", period_config.anon_ratelimit, formatter.get());
4639 } else if (ratelimit_scope.empty() && opt_cmd == OPT::GLOBAL_RATELIMIT_GET) {
4640 // if no scope is given for GET, print both
4641 encode_json("bucket_ratelimit", period_config.bucket_ratelimit, formatter.get());
4642 encode_json("user_ratelimit", period_config.user_ratelimit, formatter.get());
4643 encode_json("anonymous_ratelimit", period_config.anon_ratelimit, formatter.get());
4644 } else {
4645 cerr << "ERROR: invalid rate limit scope specification. Please specify "
4646 "either --ratelimit-scope=bucket, or --ratelimit-scope=user or --ratelimit-scope=anonymous" << std::endl;
4647 return EINVAL;
4648 }
4649 if (!ratelimit_configured) {
4650 cerr << "ERROR: no rate limit values have been specified" << std::endl;
4651 return EINVAL;
4652 }
4653
4654 formatter->close_section();
4655
4656 if (opt_cmd != OPT::GLOBAL_RATELIMIT_GET) {
4657 // write the modified period config
4658 constexpr bool exclusive = false;
4659 ret = cfgstore->write_period_config(dpp(), null_yield, exclusive,
4660 realm_id, period_config);
4661 if (ret < 0) {
4662 cerr << "ERROR: failed to write period config: "
4663 << cpp_strerror(-ret) << std::endl;
4664 return -ret;
4665 }
4666 if (!realm_id.empty()) {
4667 cout << "Global ratelimit changes saved. Use 'period update' to apply "
4668 "them to the staging period, and 'period commit' to commit the "
4669 "new period." << std::endl;
4670 } else {
4671 cout << "Global ratelimit changes saved. They will take effect as "
4672 "the gateways are restarted." << std::endl;
4673 }
4674 }
4675
4676 formatter->flush(cout);
4677 }
4678 break;
4679 case OPT::GLOBAL_QUOTA_GET:
4680 case OPT::GLOBAL_QUOTA_SET:
4681 case OPT::GLOBAL_QUOTA_ENABLE:
4682 case OPT::GLOBAL_QUOTA_DISABLE:
4683 {
4684 if (realm_id.empty()) {
4685 if (!realm_name.empty()) {
4686 // look up realm_id for the given realm_name
4687 int ret = cfgstore->read_realm_id(dpp(), null_yield,
4688 realm_name, realm_id);
4689 if (ret < 0) {
4690 cerr << "ERROR: failed to read realm for " << realm_name
4691 << ": " << cpp_strerror(-ret) << std::endl;
4692 return -ret;
4693 }
4694 } else {
4695 // use default realm_id when none is given
4696 int ret = cfgstore->read_default_realm_id(dpp(), null_yield,
4697 realm_id);
4698 if (ret < 0 && ret != -ENOENT) { // on ENOENT, use empty realm_id
4699 cerr << "ERROR: failed to read default realm: "
4700 << cpp_strerror(-ret) << std::endl;
4701 return -ret;
4702 }
4703 }
4704 }
4705
4706 RGWPeriodConfig period_config;
4707 int ret = cfgstore->read_period_config(dpp(), null_yield, realm_id,
4708 period_config);
4709 if (ret < 0 && ret != -ENOENT) {
4710 cerr << "ERROR: failed to read period config: "
4711 << cpp_strerror(-ret) << std::endl;
4712 return -ret;
4713 }
4714
4715 formatter->open_object_section("period_config");
4716 if (quota_scope == "bucket") {
4717 set_quota_info(period_config.quota.bucket_quota, opt_cmd,
4718 max_size, max_objects,
4719 have_max_size, have_max_objects);
4720 encode_json("bucket quota", period_config.quota.bucket_quota, formatter.get());
4721 } else if (quota_scope == "user") {
4722 set_quota_info(period_config.quota.user_quota, opt_cmd,
4723 max_size, max_objects,
4724 have_max_size, have_max_objects);
4725 encode_json("user quota", period_config.quota.user_quota, formatter.get());
4726 } else if (quota_scope.empty() && opt_cmd == OPT::GLOBAL_QUOTA_GET) {
4727 // if no scope is given for GET, print both
4728 encode_json("bucket quota", period_config.quota.bucket_quota, formatter.get());
4729 encode_json("user quota", period_config.quota.user_quota, formatter.get());
4730 } else {
4731 cerr << "ERROR: invalid quota scope specification. Please specify "
4732 "either --quota-scope=bucket, or --quota-scope=user" << std::endl;
4733 return EINVAL;
4734 }
4735 formatter->close_section();
4736
4737 if (opt_cmd != OPT::GLOBAL_QUOTA_GET) {
4738 // write the modified period config
4739 constexpr bool exclusive = false;
4740 ret = cfgstore->write_period_config(dpp(), null_yield, exclusive,
4741 realm_id, period_config);
4742 if (ret < 0) {
4743 cerr << "ERROR: failed to write period config: "
4744 << cpp_strerror(-ret) << std::endl;
4745 return -ret;
4746 }
4747 if (!realm_id.empty()) {
4748 cout << "Global quota changes saved. Use 'period update' to apply "
4749 "them to the staging period, and 'period commit' to commit the "
4750 "new period." << std::endl;
4751 } else {
4752 cout << "Global quota changes saved. They will take effect as "
4753 "the gateways are restarted." << std::endl;
4754 }
4755 }
4756
4757 formatter->flush(cout);
4758 }
4759 break;
4760 case OPT::REALM_CREATE:
4761 {
4762 if (realm_name.empty()) {
4763 cerr << "missing realm name" << std::endl;
4764 return EINVAL;
4765 }
4766
4767 RGWRealm realm;
4768 realm.name = realm_name;
4769
4770 constexpr bool exclusive = true;
4771 int ret = rgw::create_realm(dpp(), null_yield, cfgstore.get(),
4772 exclusive, realm);
4773 if (ret < 0) {
4774 cerr << "ERROR: couldn't create realm " << realm_name << ": " << cpp_strerror(-ret) << std::endl;
4775 return -ret;
4776 }
4777
4778 if (set_default) {
4779 ret = rgw::set_default_realm(dpp(), null_yield, cfgstore.get(), realm);
4780 if (ret < 0) {
4781 cerr << "failed to set realm " << realm_name << " as default: " << cpp_strerror(-ret) << std::endl;
4782 }
4783 }
4784
4785 encode_json("realm", realm, formatter.get());
4786 formatter->flush(cout);
4787 }
4788 break;
4789 case OPT::REALM_DELETE:
4790 {
4791 if (realm_id.empty() && realm_name.empty()) {
4792 cerr << "missing realm name or id" << std::endl;
4793 return EINVAL;
4794 }
4795 RGWRealm realm;
4796 std::unique_ptr<rgw::sal::RealmWriter> writer;
4797 int ret = rgw::read_realm(dpp(), null_yield, cfgstore.get(),
4798 realm_id, realm_name, realm, &writer);
4799 if (ret < 0) {
4800 cerr << "failed to load realm: " << cpp_strerror(-ret) << std::endl;
4801 return -ret;
4802 }
4803 ret = writer->remove(dpp(), null_yield);
4804 if (ret < 0) {
4805 cerr << "failed to remove realm: " << cpp_strerror(-ret) << std::endl;
4806 return -ret;
4807 }
4808
4809 }
4810 break;
4811 case OPT::REALM_GET:
4812 {
4813 RGWRealm realm;
4814 int ret = rgw::read_realm(dpp(), null_yield, cfgstore.get(),
4815 realm_id, realm_name, realm);
4816 if (ret < 0) {
4817 if (ret == -ENOENT && realm_name.empty() && realm_id.empty()) {
4818 cerr << "missing realm name or id, or default realm not found" << std::endl;
4819 } else {
4820 cerr << "failed to load realm: " << cpp_strerror(-ret) << std::endl;
4821 }
4822 return -ret;
4823 }
4824 encode_json("realm", realm, formatter.get());
4825 formatter->flush(cout);
4826 }
4827 break;
4828 case OPT::REALM_GET_DEFAULT:
4829 {
4830 string default_id;
4831 int ret = cfgstore->read_default_realm_id(dpp(), null_yield, default_id);
4832 if (ret == -ENOENT) {
4833 cout << "No default realm is set" << std::endl;
4834 return -ret;
4835 } else if (ret < 0) {
4836 cerr << "Error reading default realm: " << cpp_strerror(-ret) << std::endl;
4837 return -ret;
4838 }
4839 cout << "default realm: " << default_id << std::endl;
4840 }
4841 break;
4842 case OPT::REALM_LIST:
4843 {
4844 std::string default_id;
4845 int ret = cfgstore->read_default_realm_id(dpp(), null_yield,
4846 default_id);
4847 if (ret < 0 && ret != -ENOENT) {
4848 cerr << "could not determine default realm: " << cpp_strerror(-ret) << std::endl;
4849 }
4850
4851 Formatter::ObjectSection realms_list{*formatter, "realms_list"};
4852 encode_json("default_info", default_id, formatter.get());
4853
4854 Formatter::ArraySection realms{*formatter, "realms"};
4855 rgw::sal::ListResult<std::string> listing;
4856 std::array<std::string, 1000> names; // list in pages of 1000
4857 do {
4858 ret = cfgstore->list_realm_names(dpp(), null_yield, listing.next,
4859 names, listing);
4860 if (ret < 0) {
4861 std::cerr << "failed to list realms: " << cpp_strerror(-ret) << std::endl;
4862 return -ret;
4863 }
4864 for (const auto& name : listing.entries) {
4865 encode_json("name", name, formatter.get());
4866 }
4867 } while (!listing.next.empty());
4868 } // close sections realms and realms_list
4869 formatter->flush(cout);
4870 break;
4871 case OPT::REALM_LIST_PERIODS:
4872 {
4873 // use realm's current period
4874 RGWRealm realm;
4875 int ret = rgw::read_realm(dpp(), null_yield, cfgstore.get(),
4876 realm_id, realm_name, realm);
4877 if (ret < 0) {
4878 cerr << "failed to load realm: " << cpp_strerror(-ret) << std::endl;
4879 return -ret;
4880 }
4881 period_id = realm.current_period;
4882
4883 Formatter::ObjectSection periods_list{*formatter, "realm_periods_list"};
4884 encode_json("current_period", period_id, formatter.get());
4885
4886 Formatter::ArraySection periods{*formatter, "periods"};
4887
4888 while (!period_id.empty()) {
4889 RGWPeriod period;
4890 ret = cfgstore->read_period(dpp(), null_yield, period_id,
4891 std::nullopt, period);
4892 if (ret < 0) {
4893 cerr << "failed to load period id " << period_id
4894 << ": " << cpp_strerror(-ret) << std::endl;
4895 return -ret;
4896 }
4897 encode_json("id", period_id, formatter.get());
4898 period_id = period.predecessor_uuid;
4899 }
4900 } // close sections periods and realm_periods_list
4901 formatter->flush(cout);
4902 break;
4903
4904 case OPT::REALM_RENAME:
4905 {
4906 if (realm_new_name.empty()) {
4907 cerr << "missing realm new name" << std::endl;
4908 return EINVAL;
4909 }
4910 if (realm_name.empty() && realm_id.empty()) {
4911 cerr << "missing realm name or id" << std::endl;
4912 return EINVAL;
4913 }
4914
4915 RGWRealm realm;
4916 std::unique_ptr<rgw::sal::RealmWriter> writer;
4917 int ret = rgw::read_realm(dpp(), null_yield, cfgstore.get(),
4918 realm_id, realm_name, realm, &writer);
4919 if (ret < 0) {
4920 cerr << "failed to load realm: " << cpp_strerror(-ret) << std::endl;
4921 return -ret;
4922 }
4923 ret = writer->rename(dpp(), null_yield, realm, realm_new_name);
4924 if (ret < 0) {
4925 cerr << "rename failed: " << cpp_strerror(-ret) << std::endl;
4926 return -ret;
4927 }
4928 cout << "Realm name updated. Note that this change only applies to "
4929 "the current cluster, so this command must be run separately "
4930 "on each of the realm's other clusters." << std::endl;
4931 }
4932 break;
4933 case OPT::REALM_SET:
4934 {
4935 if (realm_id.empty() && realm_name.empty()) {
4936 cerr << "no realm name or id provided" << std::endl;
4937 return EINVAL;
4938 }
4939 bool new_realm = false;
4940 RGWRealm realm;
4941 std::unique_ptr<rgw::sal::RealmWriter> writer;
4942 int ret = rgw::read_realm(dpp(), null_yield, cfgstore.get(),
4943 realm_id, realm_name, realm, &writer);
4944 if (ret < 0 && ret != -ENOENT) {
4945 cerr << "failed to init realm: " << cpp_strerror(-ret) << std::endl;
4946 return -ret;
4947 } else if (ret == -ENOENT) {
4948 new_realm = true;
4949 }
4950 ret = read_decode_json(infile, realm);
4951 if (ret < 0) {
4952 return 1;
4953 }
4954 if (!realm_name.empty() && realm.get_name() != realm_name) {
4955 cerr << "mismatch between --rgw-realm " << realm_name << " and json input file name " <<
4956 realm.get_name() << std::endl;
4957 return EINVAL;
4958 }
4959 /* new realm */
4960 if (new_realm) {
4961 cout << "clearing period and epoch for new realm" << std::endl;
4962 realm.clear_current_period_and_epoch();
4963 constexpr bool exclusive = true;
4964 ret = rgw::create_realm(dpp(), null_yield, cfgstore.get(),
4965 exclusive, realm);
4966 if (ret < 0) {
4967 cerr << "ERROR: couldn't create new realm: " << cpp_strerror(-ret) << std::endl;
4968 return 1;
4969 }
4970 } else {
4971 ret = writer->write(dpp(), null_yield, realm);
4972 if (ret < 0) {
4973 cerr << "ERROR: couldn't driver realm info: " << cpp_strerror(-ret) << std::endl;
4974 return 1;
4975 }
4976 }
4977
4978 if (set_default) {
4979 ret = rgw::set_default_realm(dpp(), null_yield, cfgstore.get(), realm);
4980 if (ret < 0) {
4981 cerr << "failed to set realm " << realm_name << " as default: " << cpp_strerror(-ret) << std::endl;
4982 }
4983 }
4984 encode_json("realm", realm, formatter.get());
4985 formatter->flush(cout);
4986 }
4987 break;
4988
4989 case OPT::REALM_DEFAULT:
4990 {
4991 RGWRealm realm;
4992 int ret = rgw::read_realm(dpp(), null_yield, cfgstore.get(),
4993 realm_id, realm_name, realm);
4994 if (ret < 0) {
4995 cerr << "failed to load realm: " << cpp_strerror(-ret) << std::endl;
4996 return -ret;
4997 }
4998 ret = rgw::set_default_realm(dpp(), null_yield, cfgstore.get(), realm);
4999 if (ret < 0) {
5000 cerr << "failed to set realm as default: " << cpp_strerror(-ret) << std::endl;
5001 return -ret;
5002 }
5003 }
5004 break;
5005 case OPT::REALM_PULL:
5006 {
5007 if (url.empty()) {
5008 cerr << "A --url must be provided." << std::endl;
5009 return EINVAL;
5010 }
5011 RGWEnv env;
5012 req_info info(g_ceph_context, &env);
5013 info.method = "GET";
5014 info.request_uri = "/admin/realm";
5015
5016 map<string, string> &params = info.args.get_params();
5017 if (!realm_id.empty())
5018 params["id"] = realm_id;
5019 if (!realm_name.empty())
5020 params["name"] = realm_name;
5021
5022 bufferlist bl;
5023 JSONParser p;
5024 int ret = send_to_url(url, opt_region, access_key, secret_key, info, bl, p);
5025 if (ret < 0) {
5026 cerr << "request failed: " << cpp_strerror(-ret) << std::endl;
5027 if (ret == -EACCES) {
5028 cerr << "If the realm has been changed on the master zone, the "
5029 "master zone's gateway may need to be restarted to recognize "
5030 "this user." << std::endl;
5031 }
5032 return -ret;
5033 }
5034 RGWRealm realm;
5035 try {
5036 decode_json_obj(realm, &p);
5037 } catch (const JSONDecoder::err& e) {
5038 cerr << "failed to decode JSON response: " << e.what() << std::endl;
5039 return EINVAL;
5040 }
5041 RGWPeriod period;
5042 auto& current_period = realm.get_current_period();
5043 if (!current_period.empty()) {
5044 // pull the latest epoch of the realm's current period
5045 ret = do_period_pull(cfgstore.get(), nullptr, url, opt_region,
5046 access_key, secret_key,
5047 realm_id, realm_name, current_period, "",
5048 &period);
5049 if (ret < 0) {
5050 cerr << "could not fetch period " << current_period << std::endl;
5051 return -ret;
5052 }
5053 }
5054 constexpr bool exclusive = false;
5055 ret = rgw::create_realm(dpp(), null_yield, cfgstore.get(),
5056 exclusive, realm);
5057 if (ret < 0) {
5058 cerr << "Error storing realm " << realm.get_id() << ": "
5059 << cpp_strerror(ret) << std::endl;
5060 return -ret;
5061 }
5062
5063 if (set_default) {
5064 ret = rgw::set_default_realm(dpp(), null_yield, cfgstore.get(), realm);
5065 if (ret < 0) {
5066 cerr << "failed to set realm " << realm_name << " as default: " << cpp_strerror(-ret) << std::endl;
5067 }
5068 }
5069
5070 encode_json("realm", realm, formatter.get());
5071 formatter->flush(cout);
5072 }
5073 break;
5074
5075 case OPT::ZONEGROUP_ADD:
5076 {
5077 if (zonegroup_id.empty() && zonegroup_name.empty()) {
5078 cerr << "no zonegroup name or id provided" << std::endl;
5079 return EINVAL;
5080 }
5081
5082 // load the zonegroup and zone params
5083 RGWZoneGroup zonegroup;
5084 std::unique_ptr<rgw::sal::ZoneGroupWriter> zonegroup_writer;
5085 int ret = rgw::read_zonegroup(dpp(), null_yield, cfgstore.get(),
5086 zonegroup_id, zonegroup_name,
5087 zonegroup, &zonegroup_writer);
5088 if (ret < 0) {
5089 cerr << "failed to load zonegroup " << zonegroup_name << " id "
5090 << zonegroup_id << ": " << cpp_strerror(-ret) << std::endl;
5091 return -ret;
5092 }
5093
5094 RGWZoneParams zone_params;
5095 std::unique_ptr<rgw::sal::ZoneWriter> zone_writer;
5096 ret = rgw::read_zone(dpp(), null_yield, cfgstore.get(),
5097 zone_id, zone_name, zone_params, &zone_writer);
5098 if (ret < 0) {
5099 cerr << "unable to load zone: " << cpp_strerror(-ret) << std::endl;
5100 return -ret;
5101 }
5102
5103 // update zone_params if necessary
5104 bool need_zone_update = false;
5105
5106 if (zone_params.realm_id != zonegroup.realm_id) {
5107 if (!zone_params.realm_id.empty()) {
5108 cerr << "WARNING: overwriting zone realm_id=" << zone_params.realm_id
5109 << " to match zonegroup realm_id=" << zonegroup.realm_id << std::endl;
5110 }
5111 zone_params.realm_id = zonegroup.realm_id;
5112 need_zone_update = true;
5113 }
5114
5115 for (auto a : tier_config_add) {
5116 ret = zone_params.tier_config.set(a.first, a.second);
5117 if (ret < 0) {
5118 cerr << "ERROR: failed to set configurable: " << a << std::endl;
5119 return EINVAL;
5120 }
5121 need_zone_update = true;
5122 }
5123
5124 if (need_zone_update) {
5125 ret = zone_writer->write(dpp(), null_yield, zone_params);
5126 if (ret < 0) {
5127 cerr << "failed to save zone info: " << cpp_strerror(-ret) << std::endl;
5128 return -ret;
5129 }
5130 }
5131
5132 const bool *pis_master = (is_master_set ? &is_master : nullptr);
5133 const bool *pread_only = (is_read_only_set ? &read_only : nullptr);
5134 const bool *psync_from_all = (sync_from_all_specified ? &sync_from_all : nullptr);
5135 const string *predirect_zone = (redirect_zone_set ? &redirect_zone : nullptr);
5136
5137 // validate --tier-type if specified
5138 const string *ptier_type = (tier_type_specified ? &tier_type : nullptr);
5139 if (ptier_type) {
5140 auto sync_mgr = static_cast<rgw::sal::RadosStore*>(driver)->svc()->sync_modules->get_manager();
5141 if (!sync_mgr->get_module(*ptier_type, nullptr)) {
5142 ldpp_dout(dpp(), -1) << "ERROR: could not find sync module: "
5143 << *ptier_type << ", valid sync modules: "
5144 << sync_mgr->get_registered_module_names() << dendl;
5145 return EINVAL;
5146 }
5147 }
5148
5149 if (enable_features.empty()) { // enable all features by default
5150 enable_features.insert(rgw::zone_features::supported.begin(),
5151 rgw::zone_features::supported.end());
5152 }
5153
5154 // add/update the public zone information stored in the zonegroup
5155 ret = rgw::add_zone_to_group(dpp(), zonegroup, zone_params,
5156 pis_master, pread_only, endpoints,
5157 ptier_type, psync_from_all,
5158 sync_from, sync_from_rm,
5159 predirect_zone, bucket_index_max_shards,
5160 enable_features, disable_features);
5161 if (ret < 0) {
5162 return -ret;
5163 }
5164
5165 // write the updated zonegroup
5166 ret = zonegroup_writer->write(dpp(), null_yield, zonegroup);
5167 if (ret < 0) {
5168 cerr << "failed to write updated zonegroup " << zonegroup.get_name()
5169 << ": " << cpp_strerror(-ret) << std::endl;
5170 return -ret;
5171 }
5172
5173 encode_json("zonegroup", zonegroup, formatter.get());
5174 formatter->flush(cout);
5175 }
5176 break;
5177 case OPT::ZONEGROUP_CREATE:
5178 {
5179 if (zonegroup_name.empty()) {
5180 cerr << "Missing zonegroup name" << std::endl;
5181 return EINVAL;
5182 }
5183 RGWRealm realm;
5184 int ret = rgw::read_realm(dpp(), null_yield, cfgstore.get(),
5185 realm_id, realm_name, realm);
5186 if (ret < 0) {
5187 cerr << "failed to init realm: " << cpp_strerror(-ret) << std::endl;
5188 return -ret;
5189 }
5190
5191 RGWZoneGroup zonegroup;
5192 zonegroup.name = zonegroup_name;
5193 zonegroup.is_master = is_master;
5194 zonegroup.realm_id = realm.get_id();
5195 zonegroup.endpoints = endpoints;
5196 zonegroup.api_name = (api_name.empty() ? zonegroup_name : api_name);
5197
5198 zonegroup.enabled_features = enable_features;
5199 if (zonegroup.enabled_features.empty()) { // enable features by default
5200 zonegroup.enabled_features.insert(rgw::zone_features::enabled.begin(),
5201 rgw::zone_features::enabled.end());
5202 }
5203 for (const auto& feature : disable_features) {
5204 auto i = zonegroup.enabled_features.find(feature);
5205 if (i == zonegroup.enabled_features.end()) {
5206 ldout(cct, 1) << "WARNING: zone feature \"" << feature
5207 << "\" was not enabled in zonegroup " << zonegroup_name << dendl;
5208 continue;
5209 }
5210 zonegroup.enabled_features.erase(i);
5211 }
5212
5213 constexpr bool exclusive = true;
5214 ret = rgw::create_zonegroup(dpp(), null_yield, cfgstore.get(),
5215 exclusive, zonegroup);
5216 if (ret < 0) {
5217 cerr << "failed to create zonegroup " << zonegroup_name << ": " << cpp_strerror(-ret) << std::endl;
5218 return -ret;
5219 }
5220
5221 if (set_default) {
5222 ret = rgw::set_default_zonegroup(dpp(), null_yield, cfgstore.get(),
5223 zonegroup);
5224 if (ret < 0) {
5225 cerr << "failed to set zonegroup " << zonegroup_name << " as default: " << cpp_strerror(-ret) << std::endl;
5226 }
5227 }
5228
5229 encode_json("zonegroup", zonegroup, formatter.get());
5230 formatter->flush(cout);
5231 }
5232 break;
5233 case OPT::ZONEGROUP_DEFAULT:
5234 {
5235 if (zonegroup_id.empty() && zonegroup_name.empty()) {
5236 cerr << "no zonegroup name or id provided" << std::endl;
5237 return EINVAL;
5238 }
5239
5240 RGWZoneGroup zonegroup;
5241 int ret = rgw::read_zonegroup(dpp(), null_yield, cfgstore.get(),
5242 zonegroup_id, zonegroup_name,
5243 zonegroup);
5244 if (ret < 0) {
5245 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
5246 return -ret;
5247 }
5248
5249 ret = rgw::set_default_zonegroup(dpp(), null_yield, cfgstore.get(),
5250 zonegroup);
5251 if (ret < 0) {
5252 cerr << "failed to set zonegroup as default: " << cpp_strerror(-ret) << std::endl;
5253 return -ret;
5254 }
5255 }
5256 break;
5257 case OPT::ZONEGROUP_DELETE:
5258 {
5259 if (zonegroup_id.empty() && zonegroup_name.empty()) {
5260 cerr << "no zonegroup name or id provided" << std::endl;
5261 return EINVAL;
5262 }
5263 RGWZoneGroup zonegroup;
5264 std::unique_ptr<rgw::sal::ZoneGroupWriter> writer;
5265 int ret = rgw::read_zonegroup(dpp(), null_yield, cfgstore.get(),
5266 zonegroup_id, zonegroup_name,
5267 zonegroup, &writer);
5268 if (ret < 0) {
5269 cerr << "failed to load zonegroup: " << cpp_strerror(-ret) << std::endl;
5270 return -ret;
5271 }
5272 ret = writer->remove(dpp(), null_yield);
5273 if (ret < 0) {
5274 cerr << "ERROR: couldn't delete zonegroup: " << cpp_strerror(-ret) << std::endl;
5275 return -ret;
5276 }
5277 }
5278 break;
5279 case OPT::ZONEGROUP_GET:
5280 {
5281 RGWZoneGroup zonegroup;
5282 int ret = rgw::read_zonegroup(dpp(), null_yield, cfgstore.get(),
5283 zonegroup_id, zonegroup_name, zonegroup);
5284 if (ret < 0) {
5285 cerr << "failed to load zonegroup: " << cpp_strerror(-ret) << std::endl;
5286 return -ret;
5287 }
5288
5289 encode_json("zonegroup", zonegroup, formatter.get());
5290 formatter->flush(cout);
5291 }
5292 break;
5293 case OPT::ZONEGROUP_LIST:
5294 {
5295 RGWZoneGroup default_zonegroup;
5296 int ret = rgw::read_zonegroup(dpp(), null_yield, cfgstore.get(),
5297 {}, {}, default_zonegroup);
5298 if (ret < 0 && ret != -ENOENT) {
5299 cerr << "could not determine default zonegroup: " << cpp_strerror(-ret) << std::endl;
5300 }
5301
5302 Formatter::ObjectSection zonegroups_list{*formatter, "zonegroups_list"};
5303 encode_json("default_info", default_zonegroup.id, formatter.get());
5304
5305 Formatter::ArraySection zonegroups{*formatter, "zonegroups"};
5306 rgw::sal::ListResult<std::string> listing;
5307 std::array<std::string, 1000> names; // list in pages of 1000
5308 do {
5309 ret = cfgstore->list_zonegroup_names(dpp(), null_yield, listing.next,
5310 names, listing);
5311 if (ret < 0) {
5312 std::cerr << "failed to list zonegroups: " << cpp_strerror(-ret) << std::endl;
5313 return -ret;
5314 }
5315 for (const auto& name : listing.entries) {
5316 encode_json("name", name, formatter.get());
5317 }
5318 } while (!listing.next.empty());
5319 } // close sections zonegroups and zonegroups_list
5320 formatter->flush(cout);
5321 break;
5322 case OPT::ZONEGROUP_MODIFY:
5323 {
5324 RGWZoneGroup zonegroup;
5325 std::unique_ptr<rgw::sal::ZoneGroupWriter> writer;
5326 int ret = rgw::read_zonegroup(dpp(), null_yield, cfgstore.get(),
5327 zonegroup_id, zonegroup_name,
5328 zonegroup, &writer);
5329 if (ret < 0) {
5330 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
5331 return -ret;
5332 }
5333
5334 bool need_update = false;
5335
5336 if (!master_zone.empty()) {
5337 zonegroup.master_zone = master_zone;
5338 need_update = true;
5339 }
5340
5341 if (is_master_set) {
5342 zonegroup.is_master = is_master;
5343 need_update = true;
5344 }
5345
5346 if (!endpoints.empty()) {
5347 zonegroup.endpoints = endpoints;
5348 need_update = true;
5349 }
5350
5351 if (!api_name.empty()) {
5352 zonegroup.api_name = api_name;
5353 need_update = true;
5354 }
5355
5356 if (!realm_id.empty()) {
5357 zonegroup.realm_id = realm_id;
5358 need_update = true;
5359 } else if (!realm_name.empty()) {
5360 // get realm id from name
5361 ret = cfgstore->read_realm_id(dpp(), null_yield, realm_name,
5362 zonegroup.realm_id);
5363 if (ret < 0) {
5364 cerr << "failed to find realm by name " << realm_name << std::endl;
5365 return -ret;
5366 }
5367 need_update = true;
5368 }
5369
5370 if (bucket_index_max_shards) {
5371 for (auto& [name, zone] : zonegroup.zones) {
5372 zone.bucket_index_max_shards = *bucket_index_max_shards;
5373 }
5374 need_update = true;
5375 }
5376
5377 for (const auto& feature : enable_features) {
5378 zonegroup.enabled_features.insert(feature);
5379 need_update = true;
5380 }
5381 for (const auto& feature : disable_features) {
5382 auto i = zonegroup.enabled_features.find(feature);
5383 if (i == zonegroup.enabled_features.end()) {
5384 ldout(cct, 1) << "WARNING: zone feature \"" << feature
5385 << "\" was not enabled in zonegroup "
5386 << zonegroup.get_name() << dendl;
5387 continue;
5388 }
5389 zonegroup.enabled_features.erase(i);
5390 need_update = true;
5391 }
5392
5393 if (need_update) {
5394 ret = writer->write(dpp(), null_yield, zonegroup);
5395 if (ret < 0) {
5396 cerr << "failed to update zonegroup: " << cpp_strerror(-ret) << std::endl;
5397 return -ret;
5398 }
5399 }
5400
5401 if (set_default) {
5402 ret = rgw::set_default_zonegroup(dpp(), null_yield, cfgstore.get(),
5403 zonegroup);
5404 if (ret < 0) {
5405 cerr << "failed to set zonegroup " << zonegroup_name << " as default: " << cpp_strerror(-ret) << std::endl;
5406 }
5407 }
5408
5409 encode_json("zonegroup", zonegroup, formatter.get());
5410 formatter->flush(cout);
5411 }
5412 break;
5413 case OPT::ZONEGROUP_SET:
5414 {
5415 RGWRealm realm;
5416 int ret = rgw::read_realm(dpp(), null_yield, cfgstore.get(),
5417 realm_id, realm_name, realm);
5418 bool default_realm_not_exist = (ret == -ENOENT && realm_id.empty() && realm_name.empty());
5419
5420 if (ret < 0 && !default_realm_not_exist) {
5421 cerr << "failed to init realm: " << cpp_strerror(-ret) << std::endl;
5422 return -ret;
5423 }
5424
5425 RGWZoneGroup zonegroup;
5426 ret = read_decode_json(infile, zonegroup);
5427 if (ret < 0) {
5428 return 1;
5429 }
5430 if (zonegroup.realm_id.empty() && !default_realm_not_exist) {
5431 zonegroup.realm_id = realm.get_id();
5432 }
5433 // validate zonegroup features
5434 for (const auto& feature : zonegroup.enabled_features) {
5435 if (!rgw::zone_features::supports(feature)) {
5436 std::cerr << "ERROR: Unrecognized zonegroup feature \""
5437 << feature << "\"" << std::endl;
5438 return EINVAL;
5439 }
5440 }
5441 for (const auto& [name, zone] : zonegroup.zones) {
5442 // validate zone features
5443 for (const auto& feature : zone.supported_features) {
5444 if (!rgw::zone_features::supports(feature)) {
5445 std::cerr << "ERROR: Unrecognized zone feature \""
5446 << feature << "\" in zone " << zone.name << std::endl;
5447 return EINVAL;
5448 }
5449 }
5450 // zone must support everything zonegroup does
5451 for (const auto& feature : zonegroup.enabled_features) {
5452 if (!zone.supports(feature)) {
5453 std::cerr << "ERROR: Zone " << name << " does not support feature \""
5454 << feature << "\" required by zonegroup" << std::endl;
5455 return EINVAL;
5456 }
5457 }
5458 }
5459
5460 // create/overwrite the zonegroup info
5461 constexpr bool exclusive = false;
5462 ret = rgw::create_zonegroup(dpp(), null_yield, cfgstore.get(),
5463 exclusive, zonegroup);
5464 if (ret < 0) {
5465 cerr << "ERROR: couldn't create zonegroup info: " << cpp_strerror(-ret) << std::endl;
5466 return 1;
5467 }
5468
5469 if (set_default) {
5470 ret = rgw::set_default_zonegroup(dpp(), null_yield, cfgstore.get(),
5471 zonegroup);
5472 if (ret < 0) {
5473 cerr << "failed to set zonegroup " << zonegroup_name << " as default: " << cpp_strerror(-ret) << std::endl;
5474 }
5475 }
5476
5477 encode_json("zonegroup", zonegroup, formatter.get());
5478 formatter->flush(cout);
5479 }
5480 break;
5481 case OPT::ZONEGROUP_REMOVE:
5482 {
5483 RGWZoneGroup zonegroup;
5484 std::unique_ptr<rgw::sal::ZoneGroupWriter> writer;
5485 int ret = rgw::read_zonegroup(dpp(), null_yield, cfgstore.get(),
5486 zonegroup_id, zonegroup_name,
5487 zonegroup, &writer);
5488 if (ret < 0) {
5489 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
5490 return -ret;
5491 }
5492
5493 if (zone_id.empty()) {
5494 if (zone_name.empty()) {
5495 cerr << "no --zone-id or --rgw-zone name provided" << std::endl;
5496 return EINVAL;
5497 }
5498 // look up zone id by name
5499 for (auto& z : zonegroup.zones) {
5500 if (zone_name == z.second.name) {
5501 zone_id = z.second.id;
5502 break;
5503 }
5504 }
5505 if (zone_id.empty()) {
5506 cerr << "zone name " << zone_name << " not found in zonegroup "
5507 << zonegroup.get_name() << std::endl;
5508 return ENOENT;
5509 }
5510 }
5511
5512 ret = rgw::remove_zone_from_group(dpp(), zonegroup, zone_id);
5513 if (ret < 0) {
5514 cerr << "failed to remove zone: " << cpp_strerror(-ret) << std::endl;
5515 return -ret;
5516 }
5517
5518 ret = writer->write(dpp(), null_yield, zonegroup);
5519 if (ret < 0) {
5520 cerr << "failed to write zonegroup: " << cpp_strerror(-ret) << std::endl;
5521 return -ret;
5522 }
5523
5524 encode_json("zonegroup", zonegroup, formatter.get());
5525 formatter->flush(cout);
5526 }
5527 break;
5528 case OPT::ZONEGROUP_RENAME:
5529 {
5530 if (zonegroup_new_name.empty()) {
5531 cerr << " missing zonegroup new name" << std::endl;
5532 return EINVAL;
5533 }
5534 if (zonegroup_id.empty() && zonegroup_name.empty()) {
5535 cerr << "no zonegroup name or id provided" << std::endl;
5536 return EINVAL;
5537 }
5538 RGWZoneGroup zonegroup;
5539 std::unique_ptr<rgw::sal::ZoneGroupWriter> writer;
5540 int ret = rgw::read_zonegroup(dpp(), null_yield, cfgstore.get(),
5541 zonegroup_id, zonegroup_name,
5542 zonegroup, &writer);
5543 if (ret < 0) {
5544 cerr << "failed to load zonegroup: " << cpp_strerror(-ret) << std::endl;
5545 return -ret;
5546 }
5547 ret = writer->rename(dpp(), null_yield, zonegroup, zonegroup_new_name);
5548 if (ret < 0) {
5549 cerr << "failed to rename zonegroup: " << cpp_strerror(-ret) << std::endl;
5550 return -ret;
5551 }
5552 }
5553 break;
5554 case OPT::ZONEGROUP_PLACEMENT_LIST:
5555 {
5556 RGWZoneGroup zonegroup;
5557 int ret = rgw::read_zonegroup(dpp(), null_yield, cfgstore.get(),
5558 zonegroup_id, zonegroup_name, zonegroup);
5559 if (ret < 0) {
5560 cerr << "failed to load zonegroup: " << cpp_strerror(-ret) << std::endl;
5561 return -ret;
5562 }
5563
5564 encode_json("placement_targets", zonegroup.placement_targets, formatter.get());
5565 formatter->flush(cout);
5566 }
5567 break;
5568 case OPT::ZONEGROUP_PLACEMENT_GET:
5569 {
5570 if (placement_id.empty()) {
5571 cerr << "ERROR: --placement-id not specified" << std::endl;
5572 return EINVAL;
5573 }
5574
5575 RGWZoneGroup zonegroup;
5576 int ret = rgw::read_zonegroup(dpp(), null_yield, cfgstore.get(),
5577 zonegroup_id, zonegroup_name, zonegroup);
5578 if (ret < 0) {
5579 cerr << "failed to load zonegroup: " << cpp_strerror(-ret) << std::endl;
5580 return -ret;
5581 }
5582
5583 auto p = zonegroup.placement_targets.find(placement_id);
5584 if (p == zonegroup.placement_targets.end()) {
5585 cerr << "failed to find a zonegroup placement target named '" << placement_id << "'" << std::endl;
5586 return -ENOENT;
5587 }
5588 encode_json("placement_targets", p->second, formatter.get());
5589 formatter->flush(cout);
5590 }
5591 break;
5592 case OPT::ZONEGROUP_PLACEMENT_ADD:
5593 case OPT::ZONEGROUP_PLACEMENT_MODIFY:
5594 case OPT::ZONEGROUP_PLACEMENT_RM:
5595 case OPT::ZONEGROUP_PLACEMENT_DEFAULT:
5596 {
5597 if (placement_id.empty()) {
5598 cerr << "ERROR: --placement-id not specified" << std::endl;
5599 return EINVAL;
5600 }
5601
5602 rgw_placement_rule rule;
5603 rule.from_str(placement_id);
5604
5605 if (!rule.storage_class.empty() && opt_storage_class &&
5606 rule.storage_class != *opt_storage_class) {
5607 cerr << "ERROR: provided contradicting storage class configuration" << std::endl;
5608 return EINVAL;
5609 } else if (rule.storage_class.empty()) {
5610 rule.storage_class = opt_storage_class.value_or(string());
5611 }
5612
5613 RGWZoneGroup zonegroup;
5614 std::unique_ptr<rgw::sal::ZoneGroupWriter> writer;
5615 int ret = rgw::read_zonegroup(dpp(), null_yield, cfgstore.get(),
5616 zonegroup_id, zonegroup_name,
5617 zonegroup, &writer);
5618 if (ret < 0) {
5619 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
5620 return -ret;
5621 }
5622
5623 if (opt_cmd == OPT::ZONEGROUP_PLACEMENT_ADD ||
5624 opt_cmd == OPT::ZONEGROUP_PLACEMENT_MODIFY) {
5625 RGWZoneGroupPlacementTarget& target = zonegroup.placement_targets[placement_id];
5626 if (!tags.empty()) {
5627 target.tags.clear();
5628 for (auto& t : tags) {
5629 target.tags.insert(t);
5630 }
5631 }
5632
5633 target.name = placement_id;
5634 for (auto& t : tags_rm) {
5635 target.tags.erase(t);
5636 }
5637 for (auto& t : tags_add) {
5638 target.tags.insert(t);
5639 }
5640 target.storage_classes.insert(rule.get_storage_class());
5641
5642 /* Tier options */
5643 bool tier_class = false;
5644 std::string storage_class = rule.get_storage_class();
5645 RGWZoneGroupPlacementTier t{storage_class};
5646 RGWZoneGroupPlacementTier *pt = &t;
5647
5648 auto ptiter = target.tier_targets.find(storage_class);
5649 if (ptiter != target.tier_targets.end()) {
5650 pt = &ptiter->second;
5651 tier_class = true;
5652 } else if (tier_type_specified) {
5653 if (tier_type == "cloud-s3") {
5654 /* we support only cloud-s3 tier-type for now.
5655 * Once set cant be reset. */
5656 tier_class = true;
5657 pt->tier_type = tier_type;
5658 pt->storage_class = storage_class;
5659 } else {
5660 cerr << "ERROR: Invalid tier-type specified" << std::endl;
5661 return EINVAL;
5662 }
5663 }
5664
5665 if (tier_class) {
5666 if (tier_config_add.size() > 0) {
5667 JSONFormattable tconfig;
5668 for (auto add : tier_config_add) {
5669 int r = tconfig.set(add.first, add.second);
5670 if (r < 0) {
5671 cerr << "ERROR: failed to set configurable: " << add << std::endl;
5672 return EINVAL;
5673 }
5674 }
5675 int r = pt->update_params(tconfig);
5676 if (r < 0) {
5677 cerr << "ERROR: failed to update tier_config options"<< std::endl;
5678 }
5679 }
5680 if (tier_config_rm.size() > 0) {
5681 JSONFormattable tconfig;
5682 for (auto add : tier_config_rm) {
5683 int r = tconfig.set(add.first, add.second);
5684 if (r < 0) {
5685 cerr << "ERROR: failed to set configurable: " << add << std::endl;
5686 return EINVAL;
5687 }
5688 }
5689 int r = pt->clear_params(tconfig);
5690 if (r < 0) {
5691 cerr << "ERROR: failed to update tier_config options"<< std::endl;
5692 }
5693 }
5694
5695 target.tier_targets.emplace(std::make_pair(storage_class, *pt));
5696 }
5697
5698 if (zonegroup.default_placement.empty()) {
5699 zonegroup.default_placement.init(rule.name, RGW_STORAGE_CLASS_STANDARD);
5700 }
5701 } else if (opt_cmd == OPT::ZONEGROUP_PLACEMENT_RM) {
5702 if (!opt_storage_class || opt_storage_class->empty()) {
5703 zonegroup.placement_targets.erase(placement_id);
5704 if (zonegroup.default_placement.name == placement_id) {
5705 // clear default placement
5706 zonegroup.default_placement.clear();
5707 }
5708 } else {
5709 auto iter = zonegroup.placement_targets.find(placement_id);
5710 if (iter != zonegroup.placement_targets.end()) {
5711 RGWZoneGroupPlacementTarget& info = zonegroup.placement_targets[placement_id];
5712 info.storage_classes.erase(*opt_storage_class);
5713
5714 if (zonegroup.default_placement == rule) {
5715 // clear default storage class
5716 zonegroup.default_placement.storage_class.clear();
5717 }
5718
5719 auto ptiter = info.tier_targets.find(*opt_storage_class);
5720 if (ptiter != info.tier_targets.end()) {
5721 info.tier_targets.erase(ptiter);
5722 }
5723 }
5724 }
5725 } else if (opt_cmd == OPT::ZONEGROUP_PLACEMENT_DEFAULT) {
5726 if (!zonegroup.placement_targets.count(placement_id)) {
5727 cerr << "failed to find a zonegroup placement target named '"
5728 << placement_id << "'" << std::endl;
5729 return -ENOENT;
5730 }
5731 zonegroup.default_placement = rule;
5732 }
5733
5734 ret = writer->write(dpp(), null_yield, zonegroup);
5735 if (ret < 0) {
5736 cerr << "failed to update zonegroup: " << cpp_strerror(-ret) << std::endl;
5737 return -ret;
5738 }
5739
5740 encode_json("placement_targets", zonegroup.placement_targets, formatter.get());
5741 formatter->flush(cout);
5742 }
5743 break;
5744 case OPT::ZONE_CREATE:
5745 {
5746 if (zone_name.empty()) {
5747 cerr << "zone name not provided" << std::endl;
5748 return EINVAL;
5749 }
5750
5751 RGWZoneGroup zonegroup;
5752 std::unique_ptr<rgw::sal::ZoneGroupWriter> zonegroup_writer;
5753 /* if the user didn't provide zonegroup info , create stand alone zone */
5754 if (!zonegroup_id.empty() || !zonegroup_name.empty()) {
5755 int ret = rgw::read_zonegroup(dpp(), null_yield, cfgstore.get(),
5756 zonegroup_id, zonegroup_name,
5757 zonegroup, &zonegroup_writer);
5758 if (ret < 0) {
5759 cerr << "failed to load zonegroup " << zonegroup_name << ": " << cpp_strerror(-ret) << std::endl;
5760 return -ret;
5761 }
5762 if (realm_id.empty() && realm_name.empty()) {
5763 realm_id = zonegroup.realm_id;
5764 }
5765 }
5766
5767 // create the local zone params
5768 RGWZoneParams zone_params;
5769 zone_params.id = zone_id;
5770 zone_params.name = zone_name;
5771
5772 zone_params.system_key.id = access_key;
5773 zone_params.system_key.key = secret_key;
5774 zone_params.realm_id = realm_id;
5775 for (const auto& a : tier_config_add) {
5776 int r = zone_params.tier_config.set(a.first, a.second);
5777 if (r < 0) {
5778 cerr << "ERROR: failed to set configurable: " << a << std::endl;
5779 return EINVAL;
5780 }
5781 }
5782
5783 if (zone_params.realm_id.empty()) {
5784 RGWRealm realm;
5785 int ret = rgw::read_realm(dpp(), null_yield, cfgstore.get(),
5786 realm_id, realm_name, realm);
5787 if (ret < 0 && ret != -ENOENT) {
5788 cerr << "failed to load realm: " << cpp_strerror(-ret) << std::endl;
5789 return -ret;
5790 }
5791 zone_params.realm_id = realm.id;
5792 cerr << "NOTICE: set zone's realm_id=" << realm.id << std::endl;
5793 }
5794
5795 constexpr bool exclusive = true;
5796 int ret = rgw::create_zone(dpp(), null_yield, cfgstore.get(),
5797 exclusive, zone_params);
5798 if (ret < 0) {
5799 cerr << "failed to create zone " << zone_name << ": " << cpp_strerror(-ret) << std::endl;
5800 return -ret;
5801 }
5802
5803 if (zonegroup_writer) {
5804 const bool *pis_master = (is_master_set ? &is_master : nullptr);
5805 const bool *pread_only = (is_read_only_set ? &read_only : nullptr);
5806 const bool *psync_from_all = (sync_from_all_specified ? &sync_from_all : nullptr);
5807 const string *predirect_zone = (redirect_zone_set ? &redirect_zone : nullptr);
5808
5809 // validate --tier-type if specified
5810 const string *ptier_type = (tier_type_specified ? &tier_type : nullptr);
5811 if (ptier_type) {
5812 auto sync_mgr = static_cast<rgw::sal::RadosStore*>(driver)->svc()->sync_modules->get_manager();
5813 if (!sync_mgr->get_module(*ptier_type, nullptr)) {
5814 ldpp_dout(dpp(), -1) << "ERROR: could not find sync module: "
5815 << *ptier_type << ", valid sync modules: "
5816 << sync_mgr->get_registered_module_names() << dendl;
5817 return EINVAL;
5818 }
5819 }
5820
5821 if (enable_features.empty()) { // enable all features by default
5822 enable_features.insert(rgw::zone_features::supported.begin(),
5823 rgw::zone_features::supported.end());
5824 }
5825
5826 // add/update the public zone information stored in the zonegroup
5827 ret = rgw::add_zone_to_group(dpp(), zonegroup, zone_params,
5828 pis_master, pread_only, endpoints,
5829 ptier_type, psync_from_all,
5830 sync_from, sync_from_rm,
5831 predirect_zone, bucket_index_max_shards,
5832 enable_features, disable_features);
5833 if (ret < 0) {
5834 return -ret;
5835 }
5836
5837 // write the updated zonegroup
5838 ret = zonegroup_writer->write(dpp(), null_yield, zonegroup);
5839 if (ret < 0) {
5840 cerr << "failed to add zone " << zone_name << " to zonegroup " << zonegroup.get_name()
5841 << ": " << cpp_strerror(-ret) << std::endl;
5842 return -ret;
5843 }
5844 }
5845
5846 if (set_default) {
5847 ret = rgw::set_default_zone(dpp(), null_yield, cfgstore.get(),
5848 zone_params);
5849 if (ret < 0) {
5850 cerr << "failed to set zone " << zone_name << " as default: " << cpp_strerror(-ret) << std::endl;
5851 }
5852 }
5853
5854 encode_json("zone", zone_params, formatter.get());
5855 formatter->flush(cout);
5856 }
5857 break;
5858 case OPT::ZONE_DEFAULT:
5859 {
5860 if (zone_id.empty() && zone_name.empty()) {
5861 cerr << "no zone name or id provided" << std::endl;
5862 return EINVAL;
5863 }
5864 RGWZoneParams zone_params;
5865 int ret = rgw::read_zone(dpp(), null_yield, cfgstore.get(),
5866 zone_id, zone_name, zone_params);
5867 if (ret < 0) {
5868 cerr << "unable to load zone: " << cpp_strerror(-ret) << std::endl;
5869 return -ret;
5870 }
5871
5872 ret = rgw::set_default_zone(dpp(), null_yield, cfgstore.get(),
5873 zone_params);
5874 if (ret < 0) {
5875 cerr << "failed to set zone as default: " << cpp_strerror(-ret) << std::endl;
5876 return -ret;
5877 }
5878 }
5879 break;
5880 case OPT::ZONE_DELETE:
5881 {
5882 if (zone_id.empty() && zone_name.empty()) {
5883 cerr << "no zone name or id provided" << std::endl;
5884 return EINVAL;
5885 }
5886 RGWZoneParams zone_params;
5887 std::unique_ptr<rgw::sal::ZoneWriter> writer;
5888 int ret = rgw::read_zone(dpp(), null_yield, cfgstore.get(),
5889 zone_id, zone_name, zone_params, &writer);
5890 if (ret < 0) {
5891 cerr << "failed to load zone: " << cpp_strerror(-ret) << std::endl;
5892 return -ret;
5893 }
5894
5895 ret = rgw::delete_zone(dpp(), null_yield, cfgstore.get(),
5896 zone_params, *writer);
5897 if (ret < 0) {
5898 cerr << "failed to delete zone " << zone_params.get_name()
5899 << ": " << cpp_strerror(-ret) << std::endl;
5900 return -ret;
5901 }
5902 }
5903 break;
5904 case OPT::ZONE_GET:
5905 {
5906 RGWZoneParams zone_params;
5907 int ret = rgw::read_zone(dpp(), null_yield, cfgstore.get(),
5908 zone_id, zone_name, zone_params);
5909 if (ret < 0) {
5910 cerr << "failed to load zone: " << cpp_strerror(-ret) << std::endl;
5911 return -ret;
5912 }
5913 encode_json("zone", zone_params, formatter.get());
5914 formatter->flush(cout);
5915 }
5916 break;
5917 case OPT::ZONE_SET:
5918 {
5919 RGWZoneParams zone;
5920 std::unique_ptr<rgw::sal::ZoneWriter> writer;
5921 int ret = rgw::read_zone(dpp(), null_yield, cfgstore.get(),
5922 zone_id, zone_name, zone, &writer);
5923 if (ret < 0 && ret != -ENOENT) {
5924 cerr << "failed to load zone: " << cpp_strerror(ret) << std::endl;
5925 return -ret;
5926 }
5927
5928 string orig_id = zone.get_id();
5929
5930 ret = read_decode_json(infile, zone);
5931 if (ret < 0) {
5932 return 1;
5933 }
5934
5935 if (zone.realm_id.empty()) {
5936 RGWRealm realm;
5937 ret = rgw::read_realm(dpp(), null_yield, cfgstore.get(),
5938 realm_id, realm_name, realm);
5939 if (ret < 0 && ret != -ENOENT) {
5940 cerr << "failed to load realm: " << cpp_strerror(-ret) << std::endl;
5941 return -ret;
5942 }
5943 zone.realm_id = realm.get_id();
5944 cerr << "NOTICE: set zone's realm_id=" << zone.realm_id << std::endl;
5945 }
5946
5947 if (!zone_name.empty() && !zone.get_name().empty() && zone.get_name() != zone_name) {
5948 cerr << "Error: zone name " << zone_name << " is different than the zone name " << zone.get_name() << " in the provided json " << std::endl;
5949 return EINVAL;
5950 }
5951
5952 if (zone.get_name().empty()) {
5953 zone.set_name(zone_name);
5954 if (zone.get_name().empty()) {
5955 cerr << "no zone name specified" << std::endl;
5956 return EINVAL;
5957 }
5958 }
5959
5960 zone_name = zone.get_name();
5961
5962 if (zone.get_id().empty()) {
5963 zone.set_id(orig_id);
5964 }
5965
5966 constexpr bool exclusive = false;
5967 ret = rgw::create_zone(dpp(), null_yield, cfgstore.get(),
5968 exclusive, zone);
5969 if (ret < 0) {
5970 cerr << "ERROR: couldn't create zone: " << cpp_strerror(-ret) << std::endl;
5971 return -ret;
5972 }
5973
5974 if (set_default) {
5975 ret = rgw::set_default_zone(dpp(), null_yield, cfgstore.get(), zone);
5976 if (ret < 0) {
5977 cerr << "failed to set zone " << zone_name << " as default: " << cpp_strerror(-ret) << std::endl;
5978 }
5979 }
5980
5981 encode_json("zone", zone, formatter.get());
5982 formatter->flush(cout);
5983 }
5984 break;
5985 case OPT::ZONE_LIST:
5986 {
5987 RGWZoneParams default_zone_params;
5988 int ret = rgw::read_zone(dpp(), null_yield, cfgstore.get(),
5989 {}, {}, default_zone_params);
5990 if (ret < 0 && ret != -ENOENT) {
5991 cerr << "could not determine default zone: " << cpp_strerror(-ret) << std::endl;
5992 }
5993
5994 Formatter::ObjectSection zones_list{*formatter, "zones_list"};
5995 encode_json("default_info", default_zone_params.id, formatter.get());
5996
5997 Formatter::ArraySection zones{*formatter, "zones"};
5998 rgw::sal::ListResult<std::string> listing;
5999 std::array<std::string, 1000> names; // list in pages of 1000
6000 do {
6001 ret = cfgstore->list_zone_names(dpp(), null_yield, listing.next,
6002 names, listing);
6003 if (ret < 0) {
6004 std::cerr << "failed to list zones: " << cpp_strerror(-ret) << std::endl;
6005 return -ret;
6006 }
6007 for (const auto& name : listing.entries) {
6008 encode_json("name", name, formatter.get());
6009 }
6010 } while (!listing.next.empty());
6011 } // close sections zones and zones_list
6012 formatter->flush(cout);
6013 break;
6014 case OPT::ZONE_MODIFY:
6015 {
6016 RGWZoneParams zone_params;
6017 std::unique_ptr<rgw::sal::ZoneWriter> zone_writer;
6018 int ret = rgw::read_zone(dpp(), null_yield, cfgstore.get(),
6019 zone_id, zone_name, zone_params, &zone_writer);
6020 if (ret < 0) {
6021 cerr << "failed to load zone: " << cpp_strerror(-ret) << std::endl;
6022 return -ret;
6023 }
6024
6025 bool need_zone_update = false;
6026 if (!access_key.empty()) {
6027 zone_params.system_key.id = access_key;
6028 need_zone_update = true;
6029 }
6030
6031 if (!secret_key.empty()) {
6032 zone_params.system_key.key = secret_key;
6033 need_zone_update = true;
6034 }
6035
6036 if (!realm_id.empty()) {
6037 zone_params.realm_id = realm_id;
6038 need_zone_update = true;
6039 } else if (!realm_name.empty()) {
6040 // get realm id from name
6041 ret = cfgstore->read_realm_id(dpp(), null_yield,
6042 realm_name, zone_params.realm_id);
6043 if (ret < 0) {
6044 cerr << "failed to find realm by name " << realm_name << std::endl;
6045 return -ret;
6046 }
6047 need_zone_update = true;
6048 }
6049
6050 for (const auto& add : tier_config_add) {
6051 ret = zone_params.tier_config.set(add.first, add.second);
6052 if (ret < 0) {
6053 cerr << "ERROR: failed to set configurable: " << add << std::endl;
6054 return EINVAL;
6055 }
6056 need_zone_update = true;
6057 }
6058
6059 for (const auto& rm : tier_config_rm) {
6060 if (!rm.first.empty()) { /* otherwise will remove the entire config */
6061 zone_params.tier_config.erase(rm.first);
6062 need_zone_update = true;
6063 }
6064 }
6065
6066 if (need_zone_update) {
6067 ret = zone_writer->write(dpp(), null_yield, zone_params);
6068 if (ret < 0) {
6069 cerr << "failed to save zone info: " << cpp_strerror(-ret) << std::endl;
6070 return -ret;
6071 }
6072 }
6073
6074 RGWZoneGroup zonegroup;
6075 std::unique_ptr<rgw::sal::ZoneGroupWriter> zonegroup_writer;
6076 ret = rgw::read_zonegroup(dpp(), null_yield, cfgstore.get(),
6077 zonegroup_id, zonegroup_name,
6078 zonegroup, &zonegroup_writer);
6079 if (ret < 0) {
6080 cerr << "failed to load zonegroup: " << cpp_strerror(-ret) << std::endl;
6081 return -ret;
6082 }
6083
6084 const bool *pis_master = (is_master_set ? &is_master : nullptr);
6085 const bool *pread_only = (is_read_only_set ? &read_only : nullptr);
6086 const bool *psync_from_all = (sync_from_all_specified ? &sync_from_all : nullptr);
6087 const string *predirect_zone = (redirect_zone_set ? &redirect_zone : nullptr);
6088
6089 // validate --tier-type if specified
6090 const string *ptier_type = (tier_type_specified ? &tier_type : nullptr);
6091 if (ptier_type) {
6092 auto sync_mgr = static_cast<rgw::sal::RadosStore*>(driver)->svc()->sync_modules->get_manager();
6093 if (!sync_mgr->get_module(*ptier_type, nullptr)) {
6094 ldpp_dout(dpp(), -1) << "ERROR: could not find sync module: "
6095 << *ptier_type << ", valid sync modules: "
6096 << sync_mgr->get_registered_module_names() << dendl;
6097 return EINVAL;
6098 }
6099 }
6100
6101 if (enable_features.empty()) { // enable all features by default
6102 enable_features.insert(rgw::zone_features::supported.begin(),
6103 rgw::zone_features::supported.end());
6104 }
6105
6106 // add/update the public zone information stored in the zonegroup
6107 ret = rgw::add_zone_to_group(dpp(), zonegroup, zone_params,
6108 pis_master, pread_only, endpoints,
6109 ptier_type, psync_from_all,
6110 sync_from, sync_from_rm,
6111 predirect_zone, bucket_index_max_shards,
6112 enable_features, disable_features);
6113 if (ret < 0) {
6114 return -ret;
6115 }
6116
6117 // write the updated zonegroup
6118 ret = zonegroup_writer->write(dpp(), null_yield, zonegroup);
6119 if (ret < 0) {
6120 cerr << "failed to update zonegroup: " << cpp_strerror(-ret) << std::endl;
6121 return -ret;
6122 }
6123
6124 if (set_default) {
6125 ret = rgw::set_default_zone(dpp(), null_yield, cfgstore.get(),
6126 zone_params);
6127 if (ret < 0) {
6128 cerr << "failed to set zone " << zone_name << " as default: " << cpp_strerror(-ret) << std::endl;
6129 }
6130 }
6131
6132 encode_json("zone", zone_params, formatter.get());
6133 formatter->flush(cout);
6134 }
6135 break;
6136 case OPT::ZONE_RENAME:
6137 {
6138 if (zone_new_name.empty()) {
6139 cerr << " missing zone new name" << std::endl;
6140 return EINVAL;
6141 }
6142 if (zone_id.empty() && zone_name.empty()) {
6143 cerr << "no zone name or id provided" << std::endl;
6144 return EINVAL;
6145 }
6146
6147 RGWZoneParams zone_params;
6148 std::unique_ptr<rgw::sal::ZoneWriter> zone_writer;
6149 int ret = rgw::read_zone(dpp(), null_yield, cfgstore.get(),
6150 zone_id, zone_name, zone_params, &zone_writer);
6151 if (ret < 0) {
6152 cerr << "failed to load zone: " << cpp_strerror(-ret) << std::endl;
6153 return -ret;
6154 }
6155
6156 ret = zone_writer->rename(dpp(), null_yield, zone_params, zone_new_name);
6157 if (ret < 0) {
6158 cerr << "failed to rename zone " << zone_name << " to " << zone_new_name << ": " << cpp_strerror(-ret)
6159 << std::endl;
6160 return -ret;
6161 }
6162
6163 RGWZoneGroup zonegroup;
6164 std::unique_ptr<rgw::sal::ZoneGroupWriter> zonegroup_writer;
6165 ret = rgw::read_zonegroup(dpp(), null_yield, cfgstore.get(),
6166 zonegroup_id, zonegroup_name,
6167 zonegroup, &zonegroup_writer);
6168 if (ret < 0) {
6169 cerr << "WARNING: failed to load zonegroup " << zonegroup_name << std::endl;
6170 return EXIT_SUCCESS;
6171 }
6172
6173 auto z = zonegroup.zones.find(zone_params.id);
6174 if (z == zonegroup.zones.end()) {
6175 return EXIT_SUCCESS;
6176 }
6177 z->second.name = zone_params.name;
6178
6179 ret = zonegroup_writer->write(dpp(), null_yield, zonegroup);
6180 if (ret < 0) {
6181 cerr << "Error in zonegroup rename for " << zone_name << ": " << cpp_strerror(-ret) << std::endl;
6182 return -ret;
6183 }
6184 }
6185 break;
6186 case OPT::ZONE_PLACEMENT_ADD:
6187 case OPT::ZONE_PLACEMENT_MODIFY:
6188 case OPT::ZONE_PLACEMENT_RM:
6189 {
6190 if (placement_id.empty()) {
6191 cerr << "ERROR: --placement-id not specified" << std::endl;
6192 return EINVAL;
6193 }
6194 // validate compression type
6195 if (compression_type && *compression_type != "random"
6196 && !Compressor::get_comp_alg_type(*compression_type)) {
6197 std::cerr << "Unrecognized compression type" << std::endl;
6198 return EINVAL;
6199 }
6200
6201 RGWZoneParams zone;
6202 std::unique_ptr<rgw::sal::ZoneWriter> writer;
6203 int ret = rgw::read_zone(dpp(), null_yield, cfgstore.get(),
6204 zone_id, zone_name, zone, &writer);
6205 if (ret < 0) {
6206 cerr << "failed to init zone: " << cpp_strerror(-ret) << std::endl;
6207 return -ret;
6208 }
6209
6210 if (opt_cmd == OPT::ZONE_PLACEMENT_ADD ||
6211 opt_cmd == OPT::ZONE_PLACEMENT_MODIFY) {
6212 RGWZoneGroup zonegroup;
6213 ret = rgw::read_zonegroup(dpp(), null_yield, cfgstore.get(),
6214 zonegroup_id, zonegroup_name, zonegroup);
6215 if (ret < 0) {
6216 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
6217 return -ret;
6218 }
6219
6220 auto ptiter = zonegroup.placement_targets.find(placement_id);
6221 if (ptiter == zonegroup.placement_targets.end()) {
6222 cerr << "ERROR: placement id '" << placement_id << "' is not configured in zonegroup placement targets" << std::endl;
6223 return EINVAL;
6224 }
6225
6226 string storage_class = rgw_placement_rule::get_canonical_storage_class(opt_storage_class.value_or(string()));
6227 if (ptiter->second.storage_classes.find(storage_class) == ptiter->second.storage_classes.end()) {
6228 cerr << "ERROR: storage class '" << storage_class << "' is not defined in zonegroup '" << placement_id << "' placement target" << std::endl;
6229 return EINVAL;
6230 }
6231 if (ptiter->second.tier_targets.find(storage_class) != ptiter->second.tier_targets.end()) {
6232 cerr << "ERROR: storage class '" << storage_class << "' is of tier type in zonegroup '" << placement_id << "' placement target" << std::endl;
6233 return EINVAL;
6234 }
6235
6236 RGWZonePlacementInfo& info = zone.placement_pools[placement_id];
6237
6238 string opt_index_pool = index_pool.value_or(string());
6239 string opt_data_pool = data_pool.value_or(string());
6240
6241 if (!opt_index_pool.empty()) {
6242 info.index_pool = opt_index_pool;
6243 }
6244
6245 if (info.index_pool.empty()) {
6246 cerr << "ERROR: index pool not configured, need to specify --index-pool" << std::endl;
6247 return EINVAL;
6248 }
6249
6250 if (opt_data_pool.empty()) {
6251 const RGWZoneStorageClass *porig_sc{nullptr};
6252 if (info.storage_classes.find(storage_class, &porig_sc)) {
6253 if (porig_sc->data_pool) {
6254 opt_data_pool = porig_sc->data_pool->to_str();
6255 }
6256 }
6257 if (opt_data_pool.empty()) {
6258 cerr << "ERROR: data pool not configured, need to specify --data-pool" << std::endl;
6259 return EINVAL;
6260 }
6261 }
6262
6263 rgw_pool dp = opt_data_pool;
6264 info.storage_classes.set_storage_class(storage_class, &dp, compression_type.get_ptr());
6265
6266 if (data_extra_pool) {
6267 info.data_extra_pool = *data_extra_pool;
6268 }
6269 if (index_type_specified) {
6270 info.index_type = placement_index_type;
6271 }
6272 if (placement_inline_data_specified) {
6273 info.inline_data = placement_inline_data;
6274 }
6275
6276 ret = check_pool_support_omap(info.get_data_extra_pool());
6277 if (ret < 0) {
6278 cerr << "ERROR: the data extra (non-ec) pool '" << info.get_data_extra_pool()
6279 << "' does not support omap" << std::endl;
6280 return ret;
6281 }
6282 } else if (opt_cmd == OPT::ZONE_PLACEMENT_RM) {
6283 if (!opt_storage_class ||
6284 opt_storage_class->empty()) {
6285 zone.placement_pools.erase(placement_id);
6286 } else {
6287 auto iter = zone.placement_pools.find(placement_id);
6288 if (iter != zone.placement_pools.end()) {
6289 RGWZonePlacementInfo& info = zone.placement_pools[placement_id];
6290 info.storage_classes.remove_storage_class(*opt_storage_class);
6291 }
6292 }
6293 }
6294
6295 ret = writer->write(dpp(), null_yield, zone);
6296 if (ret < 0) {
6297 cerr << "failed to save zone info: " << cpp_strerror(-ret) << std::endl;
6298 return -ret;
6299 }
6300
6301 encode_json("zone", zone, formatter.get());
6302 formatter->flush(cout);
6303 }
6304 break;
6305 case OPT::ZONE_PLACEMENT_LIST:
6306 {
6307 RGWZoneParams zone;
6308 int ret = rgw::read_zone(dpp(), null_yield, cfgstore.get(),
6309 zone_id, zone_name, zone);
6310 if (ret < 0) {
6311 cerr << "unable to initialize zone: " << cpp_strerror(-ret) << std::endl;
6312 return -ret;
6313 }
6314 encode_json("placement_pools", zone.placement_pools, formatter.get());
6315 formatter->flush(cout);
6316 }
6317 break;
6318 case OPT::ZONE_PLACEMENT_GET:
6319 {
6320 if (placement_id.empty()) {
6321 cerr << "ERROR: --placement-id not specified" << std::endl;
6322 return EINVAL;
6323 }
6324
6325 RGWZoneParams zone;
6326 int ret = rgw::read_zone(dpp(), null_yield, cfgstore.get(),
6327 zone_id, zone_name, zone);
6328 if (ret < 0) {
6329 cerr << "unable to initialize zone: " << cpp_strerror(-ret) << std::endl;
6330 return -ret;
6331 }
6332 auto p = zone.placement_pools.find(placement_id);
6333 if (p == zone.placement_pools.end()) {
6334 cerr << "ERROR: zone placement target '" << placement_id << "' not found" << std::endl;
6335 return ENOENT;
6336 }
6337 encode_json("placement_pools", p->second, formatter.get());
6338 formatter->flush(cout);
6339 }
6340 default:
6341 break;
6342 }
6343 return 0;
6344 }
6345
6346 resolve_zone_id_opt(opt_effective_zone_name, opt_effective_zone_id);
6347 resolve_zone_id_opt(opt_source_zone_name, opt_source_zone_id);
6348 resolve_zone_id_opt(opt_dest_zone_name, opt_dest_zone_id);
6349 resolve_zone_ids_opt(opt_zone_names, opt_zone_ids);
6350 resolve_zone_ids_opt(opt_source_zone_names, opt_source_zone_ids);
6351 resolve_zone_ids_opt(opt_dest_zone_names, opt_dest_zone_ids);
6352
6353 bool non_master_cmd = (!driver->is_meta_master() && !yes_i_really_mean_it);
6354 std::set<OPT> non_master_ops_list = {OPT::USER_CREATE, OPT::USER_RM,
6355 OPT::USER_MODIFY, OPT::USER_ENABLE,
6356 OPT::USER_SUSPEND, OPT::SUBUSER_CREATE,
6357 OPT::SUBUSER_MODIFY, OPT::SUBUSER_RM,
6358 OPT::BUCKET_LINK, OPT::BUCKET_UNLINK,
6359 OPT::BUCKET_RM,
6360 OPT::BUCKET_CHOWN, OPT::METADATA_PUT,
6361 OPT::METADATA_RM, OPT::MFA_CREATE,
6362 OPT::MFA_REMOVE, OPT::MFA_RESYNC,
6363 OPT::CAPS_ADD, OPT::CAPS_RM,
6364 OPT::ROLE_CREATE, OPT::ROLE_DELETE,
6365 OPT::ROLE_POLICY_PUT, OPT::ROLE_POLICY_DELETE};
6366
6367 bool print_warning_message = (non_master_ops_list.find(opt_cmd) != non_master_ops_list.end() &&
6368 non_master_cmd);
6369
6370 if (print_warning_message) {
6371 cerr << "Please run the command on master zone. Performing this operation on non-master zone leads to inconsistent metadata between zones" << std::endl;
6372 cerr << "Are you sure you want to go ahead? (requires --yes-i-really-mean-it)" << std::endl;
6373 return EINVAL;
6374 }
6375
6376 if (!rgw::sal::User::empty(user)) {
6377 user_op.set_user_id(user->get_id());
6378 bucket_op.set_user_id(user->get_id());
6379 }
6380
6381 if (!display_name.empty())
6382 user_op.set_display_name(display_name);
6383
6384 if (!user_email.empty())
6385 user_op.set_user_email(user_email);
6386
6387 if (!rgw::sal::User::empty(user)) {
6388 user_op.set_new_user_id(new_user_id);
6389 }
6390
6391 if (!access_key.empty())
6392 user_op.set_access_key(access_key);
6393
6394 if (!secret_key.empty())
6395 user_op.set_secret_key(secret_key);
6396
6397 if (!subuser.empty())
6398 user_op.set_subuser(subuser);
6399
6400 if (!caps.empty())
6401 user_op.set_caps(caps);
6402
6403 user_op.set_purge_data(purge_data);
6404
6405 if (purge_keys)
6406 user_op.set_purge_keys();
6407
6408 if (gen_access_key)
6409 user_op.set_generate_key();
6410
6411 if (gen_secret_key)
6412 user_op.set_gen_secret(); // assume that a key pair should be created
6413
6414 if (max_buckets_specified)
6415 user_op.set_max_buckets(max_buckets);
6416
6417 if (admin_specified)
6418 user_op.set_admin(admin);
6419
6420 if (system_specified)
6421 user_op.set_system(system);
6422
6423 if (set_perm)
6424 user_op.set_perm(perm_mask);
6425
6426 if (set_temp_url_key) {
6427 map<int, string>::iterator iter = temp_url_keys.begin();
6428 for (; iter != temp_url_keys.end(); ++iter) {
6429 user_op.set_temp_url_key(iter->second, iter->first);
6430 }
6431 }
6432
6433 if (!op_mask_str.empty()) {
6434 uint32_t op_mask;
6435 int ret = rgw_parse_op_type_list(op_mask_str, &op_mask);
6436 if (ret < 0) {
6437 cerr << "failed to parse op_mask: " << cpp_strerror(-ret) << std::endl;
6438 return -ret;
6439 }
6440
6441 user_op.set_op_mask(op_mask);
6442 }
6443
6444 if (key_type != KEY_TYPE_UNDEFINED)
6445 user_op.set_key_type(key_type);
6446
6447 // set suspension operation parameters
6448 if (opt_cmd == OPT::USER_ENABLE)
6449 user_op.set_suspension(false);
6450 else if (opt_cmd == OPT::USER_SUSPEND)
6451 user_op.set_suspension(true);
6452
6453 if (!placement_id.empty()) {
6454 rgw_placement_rule target_rule;
6455 target_rule.name = placement_id;
6456 target_rule.storage_class = opt_storage_class.value_or("");
6457 if (!driver->valid_placement(target_rule)) {
6458 cerr << "NOTICE: invalid dest placement: " << target_rule.to_str() << std::endl;
6459 return EINVAL;
6460 }
6461 user_op.set_default_placement(target_rule);
6462 }
6463
6464 if (!tags.empty()) {
6465 user_op.set_placement_tags(tags);
6466 }
6467
6468 // RGWUser to use for user operations
6469 RGWUser ruser;
6470 int ret = 0;
6471 if (!(rgw::sal::User::empty(user) && access_key.empty()) || !subuser.empty()) {
6472 ret = ruser.init(dpp(), driver, user_op, null_yield);
6473 if (ret < 0) {
6474 cerr << "user.init failed: " << cpp_strerror(-ret) << std::endl;
6475 return -ret;
6476 }
6477 }
6478
6479 /* populate bucket operation */
6480 bucket_op.set_bucket_name(bucket_name);
6481 bucket_op.set_object(object);
6482 bucket_op.set_check_objects(check_objects);
6483 bucket_op.set_delete_children(delete_child_objects);
6484 bucket_op.set_fix_index(fix);
6485 bucket_op.set_max_aio(max_concurrent_ios);
6486 bucket_op.set_min_age(min_age);
6487 bucket_op.set_dump_keys(dump_keys);
6488 bucket_op.set_hide_progress(hide_progress);
6489
6490 // required to gather errors from operations
6491 std::string err_msg;
6492
6493 bool output_user_info = true;
6494
6495 switch (opt_cmd) {
6496 case OPT::USER_INFO:
6497 if (rgw::sal::User::empty(user) && access_key.empty()) {
6498 cerr << "ERROR: --uid or --access-key required" << std::endl;
6499 return EINVAL;
6500 }
6501 break;
6502 case OPT::USER_CREATE:
6503 if (!user_op.has_existing_user()) {
6504 user_op.set_generate_key(); // generate a new key by default
6505 }
6506 ret = ruser.add(dpp(), user_op, null_yield, &err_msg);
6507 if (ret < 0) {
6508 cerr << "could not create user: " << err_msg << std::endl;
6509 if (ret == -ERR_INVALID_TENANT_NAME)
6510 ret = -EINVAL;
6511
6512 return -ret;
6513 }
6514 if (!subuser.empty()) {
6515 ret = ruser.subusers.add(dpp(),user_op, null_yield, &err_msg);
6516 if (ret < 0) {
6517 cerr << "could not create subuser: " << err_msg << std::endl;
6518 return -ret;
6519 }
6520 }
6521 break;
6522 case OPT::USER_RM:
6523 ret = ruser.remove(dpp(), user_op, null_yield, &err_msg);
6524 if (ret < 0) {
6525 cerr << "could not remove user: " << err_msg << std::endl;
6526 return -ret;
6527 }
6528
6529 output_user_info = false;
6530 break;
6531 case OPT::USER_RENAME:
6532 if (yes_i_really_mean_it) {
6533 user_op.set_overwrite_new_user(true);
6534 }
6535 ret = ruser.rename(user_op, null_yield, dpp(), &err_msg);
6536 if (ret < 0) {
6537 if (ret == -EEXIST) {
6538 err_msg += ". to overwrite this user, add --yes-i-really-mean-it";
6539 }
6540 cerr << "could not rename user: " << err_msg << std::endl;
6541 return -ret;
6542 }
6543
6544 break;
6545 case OPT::USER_ENABLE:
6546 case OPT::USER_SUSPEND:
6547 case OPT::USER_MODIFY:
6548 ret = ruser.modify(dpp(), user_op, null_yield, &err_msg);
6549 if (ret < 0) {
6550 cerr << "could not modify user: " << err_msg << std::endl;
6551 return -ret;
6552 }
6553
6554 break;
6555 case OPT::SUBUSER_CREATE:
6556 ret = ruser.subusers.add(dpp(), user_op, null_yield, &err_msg);
6557 if (ret < 0) {
6558 cerr << "could not create subuser: " << err_msg << std::endl;
6559 return -ret;
6560 }
6561
6562 break;
6563 case OPT::SUBUSER_MODIFY:
6564 ret = ruser.subusers.modify(dpp(), user_op, null_yield, &err_msg);
6565 if (ret < 0) {
6566 cerr << "could not modify subuser: " << err_msg << std::endl;
6567 return -ret;
6568 }
6569
6570 break;
6571 case OPT::SUBUSER_RM:
6572 ret = ruser.subusers.remove(dpp(), user_op, null_yield, &err_msg);
6573 if (ret < 0) {
6574 cerr << "could not remove subuser: " << err_msg << std::endl;
6575 return -ret;
6576 }
6577
6578 break;
6579 case OPT::CAPS_ADD:
6580 ret = ruser.caps.add(dpp(), user_op, null_yield, &err_msg);
6581 if (ret < 0) {
6582 cerr << "could not add caps: " << err_msg << std::endl;
6583 return -ret;
6584 }
6585
6586 break;
6587 case OPT::CAPS_RM:
6588 ret = ruser.caps.remove(dpp(), user_op, null_yield, &err_msg);
6589 if (ret < 0) {
6590 cerr << "could not remove caps: " << err_msg << std::endl;
6591 return -ret;
6592 }
6593
6594 break;
6595 case OPT::KEY_CREATE:
6596 ret = ruser.keys.add(dpp(), user_op, null_yield, &err_msg);
6597 if (ret < 0) {
6598 cerr << "could not create key: " << err_msg << std::endl;
6599 return -ret;
6600 }
6601
6602 break;
6603 case OPT::KEY_RM:
6604 ret = ruser.keys.remove(dpp(), user_op, null_yield, &err_msg);
6605 if (ret < 0) {
6606 cerr << "could not remove key: " << err_msg << std::endl;
6607 return -ret;
6608 }
6609 break;
6610 case OPT::PERIOD_PUSH:
6611 {
6612 RGWEnv env;
6613 req_info info(g_ceph_context, &env);
6614 info.method = "POST";
6615 info.request_uri = "/admin/realm/period";
6616
6617 map<string, string> &params = info.args.get_params();
6618 if (!realm_id.empty())
6619 params["realm_id"] = realm_id;
6620 if (!realm_name.empty())
6621 params["realm_name"] = realm_name;
6622 if (!period_id.empty())
6623 params["period_id"] = period_id;
6624 if (!period_epoch.empty())
6625 params["epoch"] = period_epoch;
6626
6627 // load the period
6628 RGWPeriod period;
6629 int ret = cfgstore->read_period(dpp(), null_yield, period_id,
6630 std::nullopt, period);
6631 if (ret < 0) {
6632 cerr << "failed to load period: " << cpp_strerror(-ret) << std::endl;
6633 return -ret;
6634 }
6635 // json format into a bufferlist
6636 JSONFormatter jf(false);
6637 encode_json("period", period, &jf);
6638 bufferlist bl;
6639 jf.flush(bl);
6640
6641 JSONParser p;
6642 ret = send_to_remote_or_url(nullptr, url, opt_region,
6643 access_key, secret_key,
6644 info, bl, p);
6645 if (ret < 0) {
6646 cerr << "request failed: " << cpp_strerror(-ret) << std::endl;
6647 return -ret;
6648 }
6649 }
6650 return 0;
6651 case OPT::PERIOD_UPDATE:
6652 {
6653 int ret = update_period(cfgstore.get(), realm_id, realm_name,
6654 period_epoch, commit, remote, url,
6655 opt_region, access_key, secret_key,
6656 formatter.get(), yes_i_really_mean_it);
6657 if (ret < 0) {
6658 return -ret;
6659 }
6660 }
6661 return 0;
6662 case OPT::PERIOD_COMMIT:
6663 {
6664 // read realm and staging period
6665 RGWRealm realm;
6666 std::unique_ptr<rgw::sal::RealmWriter> realm_writer;
6667 int ret = rgw::read_realm(dpp(), null_yield, cfgstore.get(),
6668 realm_id, realm_name,
6669 realm, &realm_writer);
6670 if (ret < 0) {
6671 cerr << "Error initializing realm: " << cpp_strerror(-ret) << std::endl;
6672 return -ret;
6673 }
6674 period_id = rgw::get_staging_period_id(realm.id);
6675 epoch_t epoch = 1;
6676
6677 RGWPeriod period;
6678 ret = cfgstore->read_period(dpp(), null_yield, period_id, epoch, period);
6679 if (ret < 0) {
6680 cerr << "failed to load period: " << cpp_strerror(-ret) << std::endl;
6681 return -ret;
6682 }
6683 ret = commit_period(cfgstore.get(), realm, *realm_writer, period,
6684 remote, url, opt_region, access_key, secret_key,
6685 yes_i_really_mean_it);
6686 if (ret < 0) {
6687 cerr << "failed to commit period: " << cpp_strerror(-ret) << std::endl;
6688 return -ret;
6689 }
6690
6691 encode_json("period", period, formatter.get());
6692 formatter->flush(cout);
6693 }
6694 return 0;
6695 case OPT::ROLE_CREATE:
6696 {
6697 if (role_name.empty()) {
6698 cerr << "ERROR: role name is empty" << std::endl;
6699 return -EINVAL;
6700 }
6701
6702 if (assume_role_doc.empty()) {
6703 cerr << "ERROR: assume role policy document is empty" << std::endl;
6704 return -EINVAL;
6705 }
6706 bufferlist bl = bufferlist::static_from_string(assume_role_doc);
6707 try {
6708 const rgw::IAM::Policy p(
6709 g_ceph_context, tenant, bl,
6710 g_ceph_context->_conf.get_val<bool>(
6711 "rgw_policy_reject_invalid_principals"));
6712 } catch (rgw::IAM::PolicyParseException& e) {
6713 cerr << "failed to parse policy: " << e.what() << std::endl;
6714 return -EINVAL;
6715 }
6716 std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(role_name, tenant, path, assume_role_doc);
6717 ret = role->create(dpp(), true, "", null_yield);
6718 if (ret < 0) {
6719 return -ret;
6720 }
6721 show_role_info(role.get(), formatter.get());
6722 return 0;
6723 }
6724 case OPT::ROLE_DELETE:
6725 {
6726 if (role_name.empty()) {
6727 cerr << "ERROR: empty role name" << std::endl;
6728 return -EINVAL;
6729 }
6730 std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(role_name, tenant);
6731 ret = role->delete_obj(dpp(), null_yield);
6732 if (ret < 0) {
6733 return -ret;
6734 }
6735 cout << "role: " << role_name << " successfully deleted" << std::endl;
6736 return 0;
6737 }
6738 case OPT::ROLE_GET:
6739 {
6740 if (role_name.empty()) {
6741 cerr << "ERROR: empty role name" << std::endl;
6742 return -EINVAL;
6743 }
6744 std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(role_name, tenant);
6745 ret = role->get(dpp(), null_yield);
6746 if (ret < 0) {
6747 return -ret;
6748 }
6749 show_role_info(role.get(), formatter.get());
6750 return 0;
6751 }
6752 case OPT::ROLE_TRUST_POLICY_MODIFY:
6753 {
6754 if (role_name.empty()) {
6755 cerr << "ERROR: role name is empty" << std::endl;
6756 return -EINVAL;
6757 }
6758
6759 if (assume_role_doc.empty()) {
6760 cerr << "ERROR: assume role policy document is empty" << std::endl;
6761 return -EINVAL;
6762 }
6763
6764 bufferlist bl = bufferlist::static_from_string(assume_role_doc);
6765 try {
6766 const rgw::IAM::Policy p(g_ceph_context, tenant, bl,
6767 g_ceph_context->_conf.get_val<bool>(
6768 "rgw_policy_reject_invalid_principals"));
6769 } catch (rgw::IAM::PolicyParseException& e) {
6770 cerr << "failed to parse policy: " << e.what() << std::endl;
6771 return -EINVAL;
6772 }
6773
6774 std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(role_name, tenant);
6775 ret = role->get(dpp(), null_yield);
6776 if (ret < 0) {
6777 return -ret;
6778 }
6779 role->update_trust_policy(assume_role_doc);
6780 ret = role->update(dpp(), null_yield);
6781 if (ret < 0) {
6782 return -ret;
6783 }
6784 cout << "Assume role policy document updated successfully for role: " << role_name << std::endl;
6785 return 0;
6786 }
6787 case OPT::ROLE_LIST:
6788 {
6789 vector<std::unique_ptr<rgw::sal::RGWRole>> result;
6790 ret = driver->get_roles(dpp(), null_yield, path_prefix, tenant, result);
6791 if (ret < 0) {
6792 return -ret;
6793 }
6794 show_roles_info(result, formatter.get());
6795 return 0;
6796 }
6797 case OPT::ROLE_POLICY_PUT:
6798 {
6799 if (role_name.empty()) {
6800 cerr << "role name is empty" << std::endl;
6801 return -EINVAL;
6802 }
6803
6804 if (policy_name.empty()) {
6805 cerr << "policy name is empty" << std::endl;
6806 return -EINVAL;
6807 }
6808
6809 if (perm_policy_doc.empty() && infile.empty()) {
6810 cerr << "permission policy document is empty" << std::endl;
6811 return -EINVAL;
6812 }
6813
6814 bufferlist bl;
6815 if (!infile.empty()) {
6816 int ret = read_input(infile, bl);
6817 if (ret < 0) {
6818 cerr << "ERROR: failed to read input policy document: " << cpp_strerror(-ret) << std::endl;
6819 return -ret;
6820 }
6821 perm_policy_doc = bl.to_str();
6822 } else {
6823 bl = bufferlist::static_from_string(perm_policy_doc);
6824 }
6825 try {
6826 const rgw::IAM::Policy p(g_ceph_context, tenant, bl,
6827 g_ceph_context->_conf.get_val<bool>(
6828 "rgw_policy_reject_invalid_principals"));
6829 } catch (rgw::IAM::PolicyParseException& e) {
6830 cerr << "failed to parse perm policy: " << e.what() << std::endl;
6831 return -EINVAL;
6832 }
6833
6834 std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(role_name, tenant);
6835 ret = role->get(dpp(), null_yield);
6836 if (ret < 0) {
6837 return -ret;
6838 }
6839 role->set_perm_policy(policy_name, perm_policy_doc);
6840 ret = role->update(dpp(), null_yield);
6841 if (ret < 0) {
6842 return -ret;
6843 }
6844 cout << "Permission policy attached successfully" << std::endl;
6845 return 0;
6846 }
6847 case OPT::ROLE_POLICY_LIST:
6848 {
6849 if (role_name.empty()) {
6850 cerr << "ERROR: Role name is empty" << std::endl;
6851 return -EINVAL;
6852 }
6853 std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(role_name, tenant);
6854 ret = role->get(dpp(), null_yield);
6855 if (ret < 0) {
6856 return -ret;
6857 }
6858 std::vector<string> policy_names = role->get_role_policy_names();
6859 show_policy_names(policy_names, formatter.get());
6860 return 0;
6861 }
6862 case OPT::ROLE_POLICY_GET:
6863 {
6864 if (role_name.empty()) {
6865 cerr << "ERROR: role name is empty" << std::endl;
6866 return -EINVAL;
6867 }
6868
6869 if (policy_name.empty()) {
6870 cerr << "ERROR: policy name is empty" << std::endl;
6871 return -EINVAL;
6872 }
6873 std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(role_name, tenant);
6874 int ret = role->get(dpp(), null_yield);
6875 if (ret < 0) {
6876 return -ret;
6877 }
6878 string perm_policy;
6879 ret = role->get_role_policy(dpp(), policy_name, perm_policy);
6880 if (ret < 0) {
6881 return -ret;
6882 }
6883 show_perm_policy(perm_policy, formatter.get());
6884 return 0;
6885 }
6886 case OPT::ROLE_POLICY_DELETE:
6887 {
6888 if (role_name.empty()) {
6889 cerr << "ERROR: role name is empty" << std::endl;
6890 return -EINVAL;
6891 }
6892
6893 if (policy_name.empty()) {
6894 cerr << "ERROR: policy name is empty" << std::endl;
6895 return -EINVAL;
6896 }
6897 std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(role_name, tenant);
6898 ret = role->get(dpp(), null_yield);
6899 if (ret < 0) {
6900 return -ret;
6901 }
6902 ret = role->delete_policy(dpp(), policy_name);
6903 if (ret < 0) {
6904 return -ret;
6905 }
6906 ret = role->update(dpp(), null_yield);
6907 if (ret < 0) {
6908 return -ret;
6909 }
6910 cout << "Policy: " << policy_name << " successfully deleted for role: "
6911 << role_name << std::endl;
6912 return 0;
6913 }
6914 case OPT::ROLE_UPDATE:
6915 {
6916 if (role_name.empty()) {
6917 cerr << "ERROR: role name is empty" << std::endl;
6918 return -EINVAL;
6919 }
6920
6921 std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(role_name, tenant);
6922 ret = role->get(dpp(), null_yield);
6923 if (ret < 0) {
6924 return -ret;
6925 }
6926 if (!role->validate_max_session_duration(dpp())) {
6927 ret = -EINVAL;
6928 return ret;
6929 }
6930 role->update_max_session_duration(max_session_duration);
6931 ret = role->update(dpp(), null_yield);
6932 if (ret < 0) {
6933 return -ret;
6934 }
6935 cout << "Max session duration updated successfully for role: " << role_name << std::endl;
6936 return 0;
6937 }
6938 default:
6939 output_user_info = false;
6940 }
6941
6942 // output the result of a user operation
6943 if (output_user_info) {
6944 ret = ruser.info(info, &err_msg);
6945 if (ret < 0) {
6946 cerr << "could not fetch user info: " << err_msg << std::endl;
6947 return -ret;
6948 }
6949 show_user_info(info, formatter.get());
6950 }
6951
6952 if (opt_cmd == OPT::POLICY) {
6953 if (format == "xml") {
6954 int ret = RGWBucketAdminOp::dump_s3_policy(driver, bucket_op, cout, dpp());
6955 if (ret < 0) {
6956 cerr << "ERROR: failed to get policy: " << cpp_strerror(-ret) << std::endl;
6957 return -ret;
6958 }
6959 } else {
6960 int ret = RGWBucketAdminOp::get_policy(driver, bucket_op, stream_flusher, dpp());
6961 if (ret < 0) {
6962 cerr << "ERROR: failed to get policy: " << cpp_strerror(-ret) << std::endl;
6963 return -ret;
6964 }
6965 }
6966 }
6967
6968 if (opt_cmd == OPT::BUCKET_LIMIT_CHECK) {
6969 void *handle;
6970 std::list<std::string> user_ids;
6971 metadata_key = "user";
6972 int max = 1000;
6973
6974 bool truncated;
6975
6976 if (!rgw::sal::User::empty(user)) {
6977 user_ids.push_back(user->get_id().id);
6978 ret =
6979 RGWBucketAdminOp::limit_check(driver, bucket_op, user_ids, stream_flusher,
6980 null_yield, dpp(), warnings_only);
6981 } else {
6982 /* list users in groups of max-keys, then perform user-bucket
6983 * limit-check on each group */
6984 ret = driver->meta_list_keys_init(dpp(), metadata_key, string(), &handle);
6985 if (ret < 0) {
6986 cerr << "ERROR: buckets limit check can't get user metadata_key: "
6987 << cpp_strerror(-ret) << std::endl;
6988 return -ret;
6989 }
6990
6991 do {
6992 ret = driver->meta_list_keys_next(dpp(), handle, max, user_ids,
6993 &truncated);
6994 if (ret < 0 && ret != -ENOENT) {
6995 cerr << "ERROR: buckets limit check lists_keys_next(): "
6996 << cpp_strerror(-ret) << std::endl;
6997 break;
6998 } else {
6999 /* ok, do the limit checks for this group */
7000 ret =
7001 RGWBucketAdminOp::limit_check(driver, bucket_op, user_ids, stream_flusher,
7002 null_yield, dpp(), warnings_only);
7003 if (ret < 0)
7004 break;
7005 }
7006 user_ids.clear();
7007 } while (truncated);
7008 driver->meta_list_keys_complete(handle);
7009 }
7010 return -ret;
7011 } /* OPT::BUCKET_LIMIT_CHECK */
7012
7013 if (opt_cmd == OPT::BUCKETS_LIST) {
7014 if (bucket_name.empty()) {
7015 if (!rgw::sal::User::empty(user)) {
7016 if (!user_op.has_existing_user()) {
7017 cerr << "ERROR: could not find user: " << user << std::endl;
7018 return -ENOENT;
7019 }
7020 }
7021 RGWBucketAdminOp::info(driver, bucket_op, stream_flusher, null_yield, dpp());
7022 } else {
7023 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
7024 if (ret < 0) {
7025 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7026 return -ret;
7027 }
7028 formatter->open_array_section("entries");
7029
7030 int count = 0;
7031
7032 static constexpr int MAX_PAGINATE_SIZE = 10000;
7033 static constexpr int DEFAULT_MAX_ENTRIES = 1000;
7034
7035 if (max_entries < 0) {
7036 max_entries = DEFAULT_MAX_ENTRIES;
7037 }
7038 const int paginate_size = std::min(max_entries, MAX_PAGINATE_SIZE);
7039
7040 string prefix;
7041 string delim;
7042 string ns;
7043
7044 rgw::sal::Bucket::ListParams params;
7045 rgw::sal::Bucket::ListResults results;
7046
7047 params.prefix = prefix;
7048 params.delim = delim;
7049 params.marker = rgw_obj_key(marker);
7050 params.ns = ns;
7051 params.enforce_ns = false;
7052 params.list_versions = true;
7053 params.allow_unordered = bool(allow_unordered);
7054
7055 do {
7056 const int remaining = max_entries - count;
7057 ret = bucket->list(dpp(), params, std::min(remaining, paginate_size), results,
7058 null_yield);
7059 if (ret < 0) {
7060 cerr << "ERROR: driver->list_objects(): " << cpp_strerror(-ret) << std::endl;
7061 return -ret;
7062 }
7063 ldpp_dout(dpp(), 20) << "INFO: " << __func__ <<
7064 ": list() returned without error; results.objs.sizie()=" <<
7065 results.objs.size() << "results.is_truncated=" << results.is_truncated << ", marker=" <<
7066 params.marker << dendl;
7067
7068 count += results.objs.size();
7069
7070 for (const auto& entry : results.objs) {
7071 encode_json("entry", entry, formatter.get());
7072 }
7073 formatter->flush(cout);
7074 } while (results.is_truncated && count < max_entries);
7075 ldpp_dout(dpp(), 20) << "INFO: " << __func__ << ": done" << dendl;
7076
7077 formatter->close_section();
7078 formatter->flush(cout);
7079 } /* have bucket_name */
7080 } /* OPT::BUCKETS_LIST */
7081
7082 if (opt_cmd == OPT::BUCKET_RADOS_LIST) {
7083 RGWRadosList lister(static_cast<rgw::sal::RadosStore*>(driver),
7084 max_concurrent_ios, orphan_stale_secs, tenant);
7085 if (rgw_obj_fs) {
7086 lister.set_field_separator(*rgw_obj_fs);
7087 }
7088
7089 if (bucket_name.empty()) {
7090 // yes_i_really_mean_it means continue with listing even if
7091 // there are indexless buckets
7092 ret = lister.run(dpp(), yes_i_really_mean_it);
7093 } else {
7094 ret = lister.run(dpp(), bucket_name);
7095 }
7096
7097 if (ret < 0) {
7098 std::cerr <<
7099 "ERROR: bucket radoslist failed to finish before " <<
7100 "encountering error: " << cpp_strerror(-ret) << std::endl;
7101 std::cerr << "************************************"
7102 "************************************" << std::endl;
7103 std::cerr << "WARNING: THE RESULTS ARE NOT RELIABLE AND SHOULD NOT " <<
7104 "BE USED IN DELETING ORPHANS" << std::endl;
7105 std::cerr << "************************************"
7106 "************************************" << std::endl;
7107 return -ret;
7108 }
7109 }
7110
7111 if (opt_cmd == OPT::BUCKET_LAYOUT) {
7112 if (bucket_name.empty()) {
7113 cerr << "ERROR: bucket not specified" << std::endl;
7114 return EINVAL;
7115 }
7116 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
7117 if (ret < 0) {
7118 return -ret;
7119 }
7120 const auto& bucket_info = bucket->get_info();
7121 formatter->open_object_section("layout");
7122 encode_json("layout", bucket_info.layout, formatter.get());
7123 formatter->close_section();
7124 formatter->flush(cout);
7125 }
7126
7127 if (opt_cmd == OPT::BUCKET_STATS) {
7128 if (bucket_name.empty() && !bucket_id.empty()) {
7129 rgw_bucket bucket;
7130 if (!rgw_find_bucket_by_id(dpp(), driver->ctx(), driver, marker, bucket_id, &bucket)) {
7131 cerr << "failure: no such bucket id" << std::endl;
7132 return -ENOENT;
7133 }
7134 bucket_op.set_tenant(bucket.tenant);
7135 bucket_op.set_bucket_name(bucket.name);
7136 }
7137 bucket_op.set_fetch_stats(true);
7138
7139 int r = RGWBucketAdminOp::info(driver, bucket_op, stream_flusher, null_yield, dpp());
7140 if (r < 0) {
7141 cerr << "failure: " << cpp_strerror(-r) << ": " << err << std::endl;
7142 return posix_errortrans(-r);
7143 }
7144 }
7145
7146 if (opt_cmd == OPT::BUCKET_LINK) {
7147 bucket_op.set_bucket_id(bucket_id);
7148 bucket_op.set_new_bucket_name(new_bucket_name);
7149 string err;
7150 int r = RGWBucketAdminOp::link(driver, bucket_op, dpp(), &err);
7151 if (r < 0) {
7152 cerr << "failure: " << cpp_strerror(-r) << ": " << err << std::endl;
7153 return -r;
7154 }
7155 }
7156
7157 if (opt_cmd == OPT::BUCKET_UNLINK) {
7158 int r = RGWBucketAdminOp::unlink(driver, bucket_op, dpp());
7159 if (r < 0) {
7160 cerr << "failure: " << cpp_strerror(-r) << std::endl;
7161 return -r;
7162 }
7163 }
7164
7165 if (opt_cmd == OPT::BUCKET_SHARD_OBJECTS) {
7166 const auto prefix = opt_prefix ? *opt_prefix : "obj"s;
7167 if (!num_shards_specified) {
7168 cerr << "ERROR: num-shards must be specified."
7169 << std::endl;
7170 return EINVAL;
7171 }
7172
7173 if (specified_shard_id) {
7174 if (shard_id >= num_shards) {
7175 cerr << "ERROR: shard-id must be less than num-shards."
7176 << std::endl;
7177 return EINVAL;
7178 }
7179 std::string obj;
7180 uint64_t ctr = 0;
7181 int shard;
7182 do {
7183 obj = fmt::format("{}{:0>20}", prefix, ctr);
7184 shard = RGWSI_BucketIndex_RADOS::bucket_shard_index(obj, num_shards);
7185 ++ctr;
7186 } while (shard != shard_id);
7187
7188 formatter->open_object_section("shard_obj");
7189 encode_json("obj", obj, formatter.get());
7190 formatter->close_section();
7191 formatter->flush(cout);
7192 } else {
7193 std::vector<std::string> objs(num_shards);
7194 for (uint64_t ctr = 0, shardsleft = num_shards; shardsleft > 0; ++ctr) {
7195 auto key = fmt::format("{}{:0>20}", prefix, ctr);
7196 auto shard = RGWSI_BucketIndex_RADOS::bucket_shard_index(key, num_shards);
7197 if (objs[shard].empty()) {
7198 objs[shard] = std::move(key);
7199 --shardsleft;
7200 }
7201 }
7202
7203 formatter->open_object_section("shard_objs");
7204 encode_json("objs", objs, formatter.get());
7205 formatter->close_section();
7206 formatter->flush(cout);
7207 }
7208 }
7209
7210 if (opt_cmd == OPT::BUCKET_OBJECT_SHARD) {
7211 if (!num_shards_specified || object.empty()) {
7212 cerr << "ERROR: num-shards and object must be specified."
7213 << std::endl;
7214 return EINVAL;
7215 }
7216 auto shard = RGWSI_BucketIndex_RADOS::bucket_shard_index(object, num_shards);
7217 formatter->open_object_section("obj_shard");
7218 encode_json("shard", shard, formatter.get());
7219 formatter->close_section();
7220 formatter->flush(cout);
7221 }
7222
7223 if (opt_cmd == OPT::BUCKET_RESYNC_ENCRYPTED_MULTIPART) {
7224 // repair logic for replication of encrypted multipart uploads:
7225 // https://tracker.ceph.com/issues/46062
7226 if (bucket_name.empty()) {
7227 cerr << "ERROR: bucket not specified" << std::endl;
7228 return EINVAL;
7229 }
7230 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
7231 if (ret < 0) {
7232 return -ret;
7233 }
7234
7235 auto rados_driver = dynamic_cast<rgw::sal::RadosStore*>(driver);
7236 if (!rados_driver) {
7237 cerr << "ERROR: this command can only work when the cluster "
7238 "has a RADOS backing store." << std::endl;
7239 return EPERM;
7240 }
7241
7242 // fail if recovery wouldn't generate replication log entries
7243 if (!rados_driver->svc()->zone->need_to_log_data() && !yes_i_really_mean_it) {
7244 cerr << "This command is only necessary for replicated buckets." << std::endl;
7245 cerr << "do you really mean it? (requires --yes-i-really-mean-it)" << std::endl;
7246 return EPERM;
7247 }
7248
7249 formatter->open_object_section("modified");
7250 encode_json("bucket", bucket->get_name(), formatter.get());
7251 encode_json("bucket_id", bucket->get_bucket_id(), formatter.get());
7252
7253 ret = rados_driver->getRados()->bucket_resync_encrypted_multipart(
7254 dpp(), null_yield, rados_driver, bucket->get_info(),
7255 marker, stream_flusher);
7256 if (ret < 0) {
7257 return -ret;
7258 }
7259 formatter->close_section();
7260 formatter->flush(cout);
7261 return 0;
7262 }
7263
7264 if (opt_cmd == OPT::BUCKET_CHOWN) {
7265 if (bucket_name.empty()) {
7266 cerr << "ERROR: bucket name not specified" << std::endl;
7267 return EINVAL;
7268 }
7269
7270 bucket_op.set_bucket_name(bucket_name);
7271 bucket_op.set_new_bucket_name(new_bucket_name);
7272 string err;
7273
7274 int r = RGWBucketAdminOp::chown(driver, bucket_op, marker, dpp(), &err);
7275 if (r < 0) {
7276 cerr << "failure: " << cpp_strerror(-r) << ": " << err << std::endl;
7277 return -r;
7278 }
7279 }
7280
7281 if (opt_cmd == OPT::LOG_LIST) {
7282 // filter by date?
7283 if (date.size() && date.size() != 10) {
7284 cerr << "bad date format for '" << date << "', expect YYYY-MM-DD" << std::endl;
7285 return EINVAL;
7286 }
7287
7288 formatter->reset();
7289 formatter->open_array_section("logs");
7290 RGWAccessHandle h;
7291 int r = static_cast<rgw::sal::RadosStore*>(driver)->getRados()->log_list_init(dpp(), date, &h);
7292 if (r == -ENOENT) {
7293 // no logs.
7294 } else {
7295 if (r < 0) {
7296 cerr << "log list: error " << r << std::endl;
7297 return -r;
7298 }
7299 while (true) {
7300 string name;
7301 int r = static_cast<rgw::sal::RadosStore*>(driver)->getRados()->log_list_next(h, &name);
7302 if (r == -ENOENT)
7303 break;
7304 if (r < 0) {
7305 cerr << "log list: error " << r << std::endl;
7306 return -r;
7307 }
7308 formatter->dump_string("object", name);
7309 }
7310 }
7311 formatter->close_section();
7312 formatter->flush(cout);
7313 cout << std::endl;
7314 }
7315
7316 if (opt_cmd == OPT::LOG_SHOW || opt_cmd == OPT::LOG_RM) {
7317 if (object.empty() && (date.empty() || bucket_name.empty() || bucket_id.empty())) {
7318 cerr << "specify an object or a date, bucket and bucket-id" << std::endl;
7319 exit(1);
7320 }
7321
7322 string oid;
7323 if (!object.empty()) {
7324 oid = object;
7325 } else {
7326 oid = date;
7327 oid += "-";
7328 oid += bucket_id;
7329 oid += "-";
7330 oid += bucket_name;
7331 }
7332
7333 if (opt_cmd == OPT::LOG_SHOW) {
7334 RGWAccessHandle h;
7335
7336 int r = static_cast<rgw::sal::RadosStore*>(driver)->getRados()->log_show_init(dpp(), oid, &h);
7337 if (r < 0) {
7338 cerr << "error opening log " << oid << ": " << cpp_strerror(-r) << std::endl;
7339 return -r;
7340 }
7341
7342 formatter->reset();
7343 formatter->open_object_section("log");
7344
7345 struct rgw_log_entry entry;
7346
7347 // peek at first entry to get bucket metadata
7348 r = static_cast<rgw::sal::RadosStore*>(driver)->getRados()->log_show_next(dpp(), h, &entry);
7349 if (r < 0) {
7350 cerr << "error reading log " << oid << ": " << cpp_strerror(-r) << std::endl;
7351 return -r;
7352 }
7353 formatter->dump_string("bucket_id", entry.bucket_id);
7354 formatter->dump_string("bucket_owner", entry.bucket_owner.to_str());
7355 formatter->dump_string("bucket", entry.bucket);
7356
7357 uint64_t agg_time = 0;
7358 uint64_t agg_bytes_sent = 0;
7359 uint64_t agg_bytes_received = 0;
7360 uint64_t total_entries = 0;
7361
7362 if (show_log_entries)
7363 formatter->open_array_section("log_entries");
7364
7365 do {
7366 using namespace std::chrono;
7367 uint64_t total_time = duration_cast<milliseconds>(entry.total_time).count();
7368
7369 agg_time += total_time;
7370 agg_bytes_sent += entry.bytes_sent;
7371 agg_bytes_received += entry.bytes_received;
7372 total_entries++;
7373
7374 if (skip_zero_entries && entry.bytes_sent == 0 &&
7375 entry.bytes_received == 0)
7376 goto next;
7377
7378 if (show_log_entries) {
7379
7380 rgw_format_ops_log_entry(entry, formatter.get());
7381 formatter->flush(cout);
7382 }
7383 next:
7384 r = static_cast<rgw::sal::RadosStore*>(driver)->getRados()->log_show_next(dpp(), h, &entry);
7385 } while (r > 0);
7386
7387 if (r < 0) {
7388 cerr << "error reading log " << oid << ": " << cpp_strerror(-r) << std::endl;
7389 return -r;
7390 }
7391 if (show_log_entries)
7392 formatter->close_section();
7393
7394 if (show_log_sum) {
7395 formatter->open_object_section("log_sum");
7396 formatter->dump_int("bytes_sent", agg_bytes_sent);
7397 formatter->dump_int("bytes_received", agg_bytes_received);
7398 formatter->dump_int("total_time", agg_time);
7399 formatter->dump_int("total_entries", total_entries);
7400 formatter->close_section();
7401 }
7402 formatter->close_section();
7403 formatter->flush(cout);
7404 cout << std::endl;
7405 }
7406 if (opt_cmd == OPT::LOG_RM) {
7407 int r = static_cast<rgw::sal::RadosStore*>(driver)->getRados()->log_remove(dpp(), oid);
7408 if (r < 0) {
7409 cerr << "error removing log " << oid << ": " << cpp_strerror(-r) << std::endl;
7410 return -r;
7411 }
7412 }
7413 }
7414
7415 if (opt_cmd == OPT::POOL_ADD) {
7416 if (pool_name.empty()) {
7417 cerr << "need to specify pool to add!" << std::endl;
7418 exit(1);
7419 }
7420
7421 int ret = static_cast<rgw::sal::RadosStore*>(driver)->svc()->zone->add_bucket_placement(dpp(), pool, null_yield);
7422 if (ret < 0)
7423 cerr << "failed to add bucket placement: " << cpp_strerror(-ret) << std::endl;
7424 }
7425
7426 if (opt_cmd == OPT::POOL_RM) {
7427 if (pool_name.empty()) {
7428 cerr << "need to specify pool to remove!" << std::endl;
7429 exit(1);
7430 }
7431
7432 int ret = static_cast<rgw::sal::RadosStore*>(driver)->svc()->zone->remove_bucket_placement(dpp(), pool, null_yield);
7433 if (ret < 0)
7434 cerr << "failed to remove bucket placement: " << cpp_strerror(-ret) << std::endl;
7435 }
7436
7437 if (opt_cmd == OPT::POOLS_LIST) {
7438 set<rgw_pool> pools;
7439 int ret = static_cast<rgw::sal::RadosStore*>(driver)->svc()->zone->list_placement_set(dpp(), pools, null_yield);
7440 if (ret < 0) {
7441 cerr << "could not list placement set: " << cpp_strerror(-ret) << std::endl;
7442 return -ret;
7443 }
7444 formatter->reset();
7445 formatter->open_array_section("pools");
7446 for (auto siter = pools.begin(); siter != pools.end(); ++siter) {
7447 formatter->open_object_section("pool");
7448 formatter->dump_string("name", siter->to_str());
7449 formatter->close_section();
7450 }
7451 formatter->close_section();
7452 formatter->flush(cout);
7453 cout << std::endl;
7454 }
7455
7456 if (opt_cmd == OPT::USAGE_SHOW) {
7457 uint64_t start_epoch = 0;
7458 uint64_t end_epoch = (uint64_t)-1;
7459
7460 int ret;
7461
7462 if (!start_date.empty()) {
7463 ret = utime_t::parse_date(start_date, &start_epoch, NULL);
7464 if (ret < 0) {
7465 cerr << "ERROR: failed to parse start date" << std::endl;
7466 return 1;
7467 }
7468 }
7469 if (!end_date.empty()) {
7470 ret = utime_t::parse_date(end_date, &end_epoch, NULL);
7471 if (ret < 0) {
7472 cerr << "ERROR: failed to parse end date" << std::endl;
7473 return 1;
7474 }
7475 }
7476
7477
7478 if (!bucket_name.empty()) {
7479 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
7480 if (ret < 0) {
7481 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7482 return -ret;
7483 }
7484 }
7485 ret = RGWUsage::show(dpp(), driver, user.get(), bucket.get(), start_epoch,
7486 end_epoch, show_log_entries, show_log_sum, &categories,
7487 stream_flusher);
7488 if (ret < 0) {
7489 cerr << "ERROR: failed to show usage" << std::endl;
7490 return 1;
7491 }
7492 }
7493
7494 if (opt_cmd == OPT::USAGE_TRIM) {
7495 if (rgw::sal::User::empty(user) && bucket_name.empty() &&
7496 start_date.empty() && end_date.empty() && !yes_i_really_mean_it) {
7497 cerr << "usage trim without user/date/bucket specified will remove *all* users data" << std::endl;
7498 cerr << "do you really mean it? (requires --yes-i-really-mean-it)" << std::endl;
7499 return 1;
7500 }
7501 int ret;
7502 uint64_t start_epoch = 0;
7503 uint64_t end_epoch = (uint64_t)-1;
7504
7505
7506 if (!start_date.empty()) {
7507 ret = utime_t::parse_date(start_date, &start_epoch, NULL);
7508 if (ret < 0) {
7509 cerr << "ERROR: failed to parse start date" << std::endl;
7510 return 1;
7511 }
7512 }
7513
7514 if (!end_date.empty()) {
7515 ret = utime_t::parse_date(end_date, &end_epoch, NULL);
7516 if (ret < 0) {
7517 cerr << "ERROR: failed to parse end date" << std::endl;
7518 return 1;
7519 }
7520 }
7521
7522 if (!bucket_name.empty()) {
7523 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
7524 if (ret < 0) {
7525 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7526 return -ret;
7527 }
7528 }
7529 ret = RGWUsage::trim(dpp(), driver, user.get(), bucket.get(), start_epoch, end_epoch);
7530 if (ret < 0) {
7531 cerr << "ERROR: read_usage() returned ret=" << ret << std::endl;
7532 return 1;
7533 }
7534 }
7535
7536 if (opt_cmd == OPT::USAGE_CLEAR) {
7537 if (!yes_i_really_mean_it) {
7538 cerr << "usage clear would remove *all* users usage data for all time" << std::endl;
7539 cerr << "do you really mean it? (requires --yes-i-really-mean-it)" << std::endl;
7540 return 1;
7541 }
7542
7543 ret = RGWUsage::clear(dpp(), driver);
7544 if (ret < 0) {
7545 return ret;
7546 }
7547 }
7548
7549
7550 if (opt_cmd == OPT::OLH_GET || opt_cmd == OPT::OLH_READLOG) {
7551 if (bucket_name.empty()) {
7552 cerr << "ERROR: bucket not specified" << std::endl;
7553 return EINVAL;
7554 }
7555 if (object.empty()) {
7556 cerr << "ERROR: object not specified" << std::endl;
7557 return EINVAL;
7558 }
7559 }
7560
7561 if (opt_cmd == OPT::OLH_GET) {
7562 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
7563 if (ret < 0) {
7564 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7565 return -ret;
7566 }
7567 RGWOLHInfo olh;
7568 rgw_obj obj(bucket->get_key(), object);
7569 ret = static_cast<rgw::sal::RadosStore*>(driver)->getRados()->get_olh(dpp(), bucket->get_info(), obj, &olh);
7570 if (ret < 0) {
7571 cerr << "ERROR: failed reading olh: " << cpp_strerror(-ret) << std::endl;
7572 return -ret;
7573 }
7574 encode_json("olh", olh, formatter.get());
7575 formatter->flush(cout);
7576 }
7577
7578 if (opt_cmd == OPT::OLH_READLOG) {
7579 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
7580 if (ret < 0) {
7581 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7582 return -ret;
7583 }
7584 map<uint64_t, vector<rgw_bucket_olh_log_entry> > log;
7585 bool is_truncated;
7586
7587 std::unique_ptr<rgw::sal::Object> obj = bucket->get_object(object);
7588
7589 RGWObjState *state;
7590
7591 ret = obj->get_obj_state(dpp(), &state, null_yield);
7592 if (ret < 0) {
7593 return -ret;
7594 }
7595
7596 ret = static_cast<rgw::sal::RadosStore*>(driver)->getRados()->bucket_index_read_olh_log(dpp(), bucket->get_info(), *state, obj->get_obj(), 0, &log, &is_truncated);
7597 if (ret < 0) {
7598 cerr << "ERROR: failed reading olh: " << cpp_strerror(-ret) << std::endl;
7599 return -ret;
7600 }
7601 formatter->open_object_section("result");
7602 encode_json("is_truncated", is_truncated, formatter.get());
7603 encode_json("log", log, formatter.get());
7604 formatter->close_section();
7605 formatter->flush(cout);
7606 }
7607
7608 if (opt_cmd == OPT::BI_GET) {
7609 if (bucket_name.empty()) {
7610 cerr << "ERROR: bucket name not specified" << std::endl;
7611 return EINVAL;
7612 }
7613 if (object.empty()) {
7614 cerr << "ERROR: object not specified" << std::endl;
7615 return EINVAL;
7616 }
7617 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
7618 if (ret < 0) {
7619 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7620 return -ret;
7621 }
7622 rgw_obj obj(bucket->get_key(), object);
7623 if (!object_version.empty()) {
7624 obj.key.set_instance(object_version);
7625 }
7626
7627 rgw_cls_bi_entry entry;
7628 ret = static_cast<rgw::sal::RadosStore*>(driver)->getRados()->bi_get(dpp(), bucket->get_info(), obj, bi_index_type, &entry);
7629 if (ret < 0) {
7630 cerr << "ERROR: bi_get(): " << cpp_strerror(-ret) << std::endl;
7631 return -ret;
7632 }
7633
7634 encode_json("entry", entry, formatter.get());
7635 formatter->flush(cout);
7636 }
7637
7638 if (opt_cmd == OPT::BI_PUT) {
7639 if (bucket_name.empty()) {
7640 cerr << "ERROR: bucket name not specified" << std::endl;
7641 return EINVAL;
7642 }
7643 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
7644 if (ret < 0) {
7645 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7646 return -ret;
7647 }
7648
7649 rgw_cls_bi_entry entry;
7650 cls_rgw_obj_key key;
7651 ret = read_decode_json(infile, entry, &key);
7652 if (ret < 0) {
7653 return 1;
7654 }
7655
7656 rgw_obj obj(bucket->get_key(), key);
7657
7658 ret = static_cast<rgw::sal::RadosStore*>(driver)->getRados()->bi_put(dpp(), bucket->get_key(), obj, entry);
7659 if (ret < 0) {
7660 cerr << "ERROR: bi_put(): " << cpp_strerror(-ret) << std::endl;
7661 return -ret;
7662 }
7663 }
7664
7665 if (opt_cmd == OPT::BI_LIST) {
7666 if (bucket_name.empty()) {
7667 cerr << "ERROR: bucket name not specified" << std::endl;
7668 return EINVAL;
7669 }
7670
7671 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
7672 if (ret < 0) {
7673 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7674 return -ret;
7675 }
7676
7677 std::list<rgw_cls_bi_entry> entries;
7678 bool is_truncated;
7679 const auto& index = bucket->get_info().layout.current_index;
7680 const int max_shards = rgw::num_shards(index);
7681 if (max_entries < 0) {
7682 max_entries = 1000;
7683 }
7684
7685 ldpp_dout(dpp(), 20) << "INFO: " << __func__ << ": max_entries=" << max_entries <<
7686 ", index=" << index << ", max_shards=" << max_shards << dendl;
7687
7688 formatter->open_array_section("entries");
7689
7690 int i = (specified_shard_id ? shard_id : 0);
7691 for (; i < max_shards; i++) {
7692 ldpp_dout(dpp(), 20) << "INFO: " << __func__ << ": starting shard=" << i << dendl;
7693
7694 RGWRados::BucketShard bs(static_cast<rgw::sal::RadosStore*>(driver)->getRados());
7695 int ret = bs.init(dpp(), bucket->get_info(), index, i);
7696 marker.clear();
7697
7698 if (ret < 0) {
7699 cerr << "ERROR: bs.init(bucket=" << bucket << ", shard=" << i << "): " << cpp_strerror(-ret) << std::endl;
7700 return -ret;
7701 }
7702
7703 do {
7704 entries.clear();
7705 // if object is specified, we use that as a filter to only retrieve some some entries
7706 ret = static_cast<rgw::sal::RadosStore*>(driver)->getRados()->bi_list(bs, object, marker, max_entries, &entries, &is_truncated);
7707 if (ret < 0) {
7708 cerr << "ERROR: bi_list(): " << cpp_strerror(-ret) << std::endl;
7709 return -ret;
7710 }
7711 ldpp_dout(dpp(), 20) << "INFO: " << __func__ <<
7712 ": bi_list() returned without error; entries.size()=" <<
7713 entries.size() << ", is_truncated=" << is_truncated <<
7714 ", marker=" << marker << dendl;
7715
7716 for (const auto& entry : entries) {
7717 encode_json("entry", entry, formatter.get());
7718 marker = entry.idx;
7719 }
7720 formatter->flush(cout);
7721 } while (is_truncated);
7722
7723 formatter->flush(cout);
7724
7725 if (specified_shard_id) {
7726 break;
7727 }
7728 }
7729 ldpp_dout(dpp(), 20) << "INFO: " << __func__ << ": done" << dendl;
7730
7731 formatter->close_section();
7732 formatter->flush(cout);
7733 }
7734
7735 if (opt_cmd == OPT::BI_PURGE) {
7736 if (bucket_name.empty()) {
7737 cerr << "ERROR: bucket name not specified" << std::endl;
7738 return EINVAL;
7739 }
7740 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
7741 if (ret < 0) {
7742 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7743 return -ret;
7744 }
7745
7746 std::unique_ptr<rgw::sal::Bucket> cur_bucket;
7747 ret = init_bucket(user.get(), tenant, bucket_name, string(), &cur_bucket);
7748 if (ret == -ENOENT) {
7749 // no bucket entrypoint
7750 } else if (ret < 0) {
7751 cerr << "ERROR: could not init current bucket info for bucket_name=" << bucket_name << ": " << cpp_strerror(-ret) << std::endl;
7752 return -ret;
7753 } else if (cur_bucket->get_bucket_id() == bucket->get_bucket_id() &&
7754 !yes_i_really_mean_it) {
7755 cerr << "specified bucket instance points to a current bucket instance" << std::endl;
7756 cerr << "do you really mean it? (requires --yes-i-really-mean-it)" << std::endl;
7757 return EINVAL;
7758 }
7759
7760 const auto& index = bucket->get_info().layout.current_index;
7761 if (index.layout.type == rgw::BucketIndexType::Indexless) {
7762 cerr << "ERROR: indexless bucket has no index to purge" << std::endl;
7763 return EINVAL;
7764 }
7765
7766 const int max_shards = rgw::num_shards(index);
7767 for (int i = 0; i < max_shards; i++) {
7768 RGWRados::BucketShard bs(static_cast<rgw::sal::RadosStore*>(driver)->getRados());
7769 int ret = bs.init(dpp(), bucket->get_info(), index, i);
7770 if (ret < 0) {
7771 cerr << "ERROR: bs.init(bucket=" << bucket << ", shard=" << i << "): " << cpp_strerror(-ret) << std::endl;
7772 return -ret;
7773 }
7774
7775 ret = static_cast<rgw::sal::RadosStore*>(driver)->getRados()->bi_remove(dpp(), bs);
7776 if (ret < 0) {
7777 cerr << "ERROR: failed to remove bucket index object: " << cpp_strerror(-ret) << std::endl;
7778 return -ret;
7779 }
7780 }
7781 }
7782
7783 if (opt_cmd == OPT::OBJECT_PUT) {
7784 if (bucket_name.empty()) {
7785 cerr << "ERROR: bucket not specified" << std::endl;
7786 return EINVAL;
7787 }
7788 if (object.empty()) {
7789 cerr << "ERROR: object not specified" << std::endl;
7790 return EINVAL;
7791 }
7792
7793 RGWDataAccess data_access(driver);
7794 rgw_obj_key key(object, object_version);
7795
7796 RGWDataAccess::BucketRef b;
7797 RGWDataAccess::ObjectRef obj;
7798
7799 int ret = data_access.get_bucket(dpp(), tenant, bucket_name, bucket_id, &b, null_yield);
7800 if (ret < 0) {
7801 cerr << "ERROR: failed to init bucket: " << cpp_strerror(-ret) << std::endl;
7802 return -ret;
7803 }
7804
7805 ret = b->get_object(key, &obj);
7806 if (ret < 0) {
7807 cerr << "ERROR: failed to get object: " << cpp_strerror(-ret) << std::endl;
7808 return -ret;
7809 }
7810
7811 bufferlist bl;
7812 ret = read_input(infile, bl);
7813 if (ret < 0) {
7814 cerr << "ERROR: failed to read input: " << cpp_strerror(-ret) << std::endl;
7815 }
7816
7817 map<string, bufferlist> attrs;
7818 ret = obj->put(bl, attrs, dpp(), null_yield);
7819 if (ret < 0) {
7820 cerr << "ERROR: put object returned error: " << cpp_strerror(-ret) << std::endl;
7821 }
7822 }
7823
7824 if (opt_cmd == OPT::OBJECT_RM) {
7825 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
7826 if (ret < 0) {
7827 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7828 return -ret;
7829 }
7830 rgw_obj_key key(object, object_version);
7831 ret = rgw_remove_object(dpp(), driver, bucket.get(), key);
7832
7833 if (ret < 0) {
7834 cerr << "ERROR: object remove returned: " << cpp_strerror(-ret) << std::endl;
7835 return -ret;
7836 }
7837 }
7838
7839 if (opt_cmd == OPT::OBJECT_REWRITE) {
7840 if (bucket_name.empty()) {
7841 cerr << "ERROR: bucket not specified" << std::endl;
7842 return EINVAL;
7843 }
7844 if (object.empty()) {
7845 cerr << "ERROR: object not specified" << std::endl;
7846 return EINVAL;
7847 }
7848
7849 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
7850 if (ret < 0) {
7851 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7852 return -ret;
7853 }
7854
7855 std::unique_ptr<rgw::sal::Object> obj = bucket->get_object(object);
7856 obj->set_instance(object_version);
7857 bool need_rewrite = true;
7858 if (min_rewrite_stripe_size > 0) {
7859 ret = check_min_obj_stripe_size(driver, obj.get(), min_rewrite_stripe_size, &need_rewrite);
7860 if (ret < 0) {
7861 ldpp_dout(dpp(), 0) << "WARNING: check_min_obj_stripe_size failed, r=" << ret << dendl;
7862 }
7863 }
7864 if (need_rewrite) {
7865 RGWRados* store = static_cast<rgw::sal::RadosStore*>(driver)->getRados();
7866 ret = store->rewrite_obj(bucket->get_info(), obj->get_obj(), dpp(), null_yield);
7867 if (ret < 0) {
7868 cerr << "ERROR: object rewrite returned: " << cpp_strerror(-ret) << std::endl;
7869 return -ret;
7870 }
7871 } else {
7872 ldpp_dout(dpp(), 20) << "skipped object" << dendl;
7873 }
7874 } // OPT::OBJECT_REWRITE
7875
7876 if (opt_cmd == OPT::OBJECT_REINDEX) {
7877 if (bucket_name.empty()) {
7878 cerr << "ERROR: --bucket not specified." << std::endl;
7879 return EINVAL;
7880 }
7881 if (object.empty() && objects_file.empty()) {
7882 cerr << "ERROR: neither --object nor --objects-file specified." << std::endl;
7883 return EINVAL;
7884 } else if (!object.empty() && !objects_file.empty()) {
7885 cerr << "ERROR: both --object and --objects-file specified and only one is allowed." << std::endl;
7886 return EINVAL;
7887 } else if (!objects_file.empty() && !object_version.empty()) {
7888 cerr << "ERROR: cannot specify --object_version when --objects-file specified." << std::endl;
7889 return EINVAL;
7890 }
7891
7892 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
7893 if (ret < 0) {
7894 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) <<
7895 "." << std::endl;
7896 return -ret;
7897 }
7898
7899 rgw::sal::RadosStore* rados_store = dynamic_cast<rgw::sal::RadosStore*>(driver);
7900 if (!rados_store) {
7901 cerr <<
7902 "ERROR: this command can only work when the cluster has a RADOS backing store." <<
7903 std::endl;
7904 return EPERM;
7905 }
7906 RGWRados* store = rados_store->getRados();
7907
7908 auto process = [&](const std::string& p_object, const std::string& p_object_version) -> int {
7909 std::unique_ptr<rgw::sal::Object> obj = bucket->get_object(p_object);
7910 obj->set_instance(p_object_version);
7911 ret = store->reindex_obj(bucket->get_info(), obj->get_obj(), dpp(), null_yield);
7912 if (ret < 0) {
7913 return ret;
7914 }
7915 return 0;
7916 };
7917
7918 if (!object.empty()) {
7919 ret = process(object, object_version);
7920 if (ret < 0) {
7921 return -ret;
7922 }
7923 } else {
7924 std::ifstream file;
7925 file.open(objects_file);
7926 if (!file.is_open()) {
7927 std::cerr << "ERROR: unable to open objects-file \"" <<
7928 objects_file << "\"." << std::endl;
7929 return ENOENT;
7930 }
7931
7932 std::string obj_name;
7933 const std::string empty_version;
7934 while (std::getline(file, obj_name)) {
7935 ret = process(obj_name, empty_version);
7936 if (ret < 0) {
7937 std::cerr << "ERROR: while processing \"" << obj_name <<
7938 "\", received " << cpp_strerror(-ret) << "." << std::endl;
7939 if (!yes_i_really_mean_it) {
7940 std::cerr <<
7941 "NOTE: with *caution* you can use --yes-i-really-mean-it to push through errors and continue processing." <<
7942 std::endl;
7943 return -ret;
7944 }
7945 }
7946 } // while
7947 }
7948 } // OPT::OBJECT_REINDEX
7949
7950 if (opt_cmd == OPT::OBJECTS_EXPIRE) {
7951 if (!static_cast<rgw::sal::RadosStore*>(driver)->getRados()->process_expire_objects(dpp())) {
7952 cerr << "ERROR: process_expire_objects() processing returned error." << std::endl;
7953 return 1;
7954 }
7955 }
7956
7957 if (opt_cmd == OPT::OBJECTS_EXPIRE_STALE_LIST) {
7958 ret = RGWBucketAdminOp::fix_obj_expiry(driver, bucket_op, stream_flusher, dpp(), true);
7959 if (ret < 0) {
7960 cerr << "ERROR: listing returned " << cpp_strerror(-ret) << std::endl;
7961 return -ret;
7962 }
7963 }
7964
7965 if (opt_cmd == OPT::OBJECTS_EXPIRE_STALE_RM) {
7966 ret = RGWBucketAdminOp::fix_obj_expiry(driver, bucket_op, stream_flusher, dpp(), false);
7967 if (ret < 0) {
7968 cerr << "ERROR: removing returned " << cpp_strerror(-ret) << std::endl;
7969 return -ret;
7970 }
7971 }
7972
7973 if (opt_cmd == OPT::BUCKET_REWRITE) {
7974 if (bucket_name.empty()) {
7975 cerr << "ERROR: bucket not specified" << std::endl;
7976 return EINVAL;
7977 }
7978
7979 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
7980 if (ret < 0) {
7981 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7982 return -ret;
7983 }
7984
7985 uint64_t start_epoch = 0;
7986 uint64_t end_epoch = 0;
7987
7988 if (!end_date.empty()) {
7989 int ret = utime_t::parse_date(end_date, &end_epoch, NULL);
7990 if (ret < 0) {
7991 cerr << "ERROR: failed to parse end date" << std::endl;
7992 return EINVAL;
7993 }
7994 }
7995 if (!start_date.empty()) {
7996 int ret = utime_t::parse_date(start_date, &start_epoch, NULL);
7997 if (ret < 0) {
7998 cerr << "ERROR: failed to parse start date" << std::endl;
7999 return EINVAL;
8000 }
8001 }
8002
8003 bool is_truncated = true;
8004 bool cls_filtered = true;
8005
8006 rgw_obj_index_key marker;
8007 string empty_prefix;
8008 string empty_delimiter;
8009
8010 formatter->open_object_section("result");
8011 formatter->dump_string("bucket", bucket_name);
8012 formatter->open_array_section("objects");
8013
8014 constexpr uint32_t NUM_ENTRIES = 1000;
8015 uint16_t expansion_factor = 1;
8016 while (is_truncated) {
8017 RGWRados::ent_map_t result;
8018 result.reserve(NUM_ENTRIES);
8019
8020 const auto& current_index = bucket->get_info().layout.current_index;
8021 int r = static_cast<rgw::sal::RadosStore*>(driver)->getRados()->cls_bucket_list_ordered(
8022 dpp(), bucket->get_info(), current_index, RGW_NO_SHARD,
8023 marker, empty_prefix, empty_delimiter,
8024 NUM_ENTRIES, true, expansion_factor,
8025 result, &is_truncated, &cls_filtered, &marker,
8026 null_yield,
8027 rgw_bucket_object_check_filter);
8028 if (r < 0 && r != -ENOENT) {
8029 cerr << "ERROR: failed operation r=" << r << std::endl;
8030 } else if (r == -ENOENT) {
8031 break;
8032 }
8033
8034 if (result.size() < NUM_ENTRIES / 8) {
8035 ++expansion_factor;
8036 } else if (result.size() > NUM_ENTRIES * 7 / 8 &&
8037 expansion_factor > 1) {
8038 --expansion_factor;
8039 }
8040
8041 for (auto iter = result.begin(); iter != result.end(); ++iter) {
8042 rgw_obj_key key = iter->second.key;
8043 rgw_bucket_dir_entry& entry = iter->second;
8044
8045 formatter->open_object_section("object");
8046 formatter->dump_string("name", key.name);
8047 formatter->dump_string("instance", key.instance);
8048 formatter->dump_int("size", entry.meta.size);
8049 utime_t ut(entry.meta.mtime);
8050 ut.gmtime(formatter->dump_stream("mtime"));
8051
8052 if ((entry.meta.size < min_rewrite_size) ||
8053 (entry.meta.size > max_rewrite_size) ||
8054 (start_epoch > 0 && start_epoch > (uint64_t)ut.sec()) ||
8055 (end_epoch > 0 && end_epoch < (uint64_t)ut.sec())) {
8056 formatter->dump_string("status", "Skipped");
8057 } else {
8058 std::unique_ptr<rgw::sal::Object> obj = bucket->get_object(key);
8059
8060 bool need_rewrite = true;
8061 if (min_rewrite_stripe_size > 0) {
8062 r = check_min_obj_stripe_size(driver, obj.get(), min_rewrite_stripe_size, &need_rewrite);
8063 if (r < 0) {
8064 ldpp_dout(dpp(), 0) << "WARNING: check_min_obj_stripe_size failed, r=" << r << dendl;
8065 }
8066 }
8067 if (!need_rewrite) {
8068 formatter->dump_string("status", "Skipped");
8069 } else {
8070 RGWRados* store = static_cast<rgw::sal::RadosStore*>(driver)->getRados();
8071 r = store->rewrite_obj(bucket->get_info(), obj->get_obj(), dpp(), null_yield);
8072 if (r == 0) {
8073 formatter->dump_string("status", "Success");
8074 } else {
8075 formatter->dump_string("status", cpp_strerror(-r));
8076 }
8077 }
8078 }
8079 formatter->dump_int("flags", entry.flags);
8080
8081 formatter->close_section();
8082 formatter->flush(cout);
8083 }
8084 }
8085 formatter->close_section();
8086 formatter->close_section();
8087 formatter->flush(cout);
8088 }
8089
8090 if (opt_cmd == OPT::BUCKET_RESHARD) {
8091 int ret = check_reshard_bucket_params(driver,
8092 bucket_name,
8093 tenant,
8094 bucket_id,
8095 num_shards_specified,
8096 num_shards,
8097 yes_i_really_mean_it,
8098 &bucket);
8099 if (ret < 0) {
8100 return ret;
8101 }
8102
8103 auto zone_svc = static_cast<rgw::sal::RadosStore*>(driver)->svc()->zone;
8104 if (!zone_svc->can_reshard()) {
8105 const auto& zonegroup = zone_svc->get_zonegroup();
8106 std::cerr << "The zonegroup '" << zonegroup.get_name() << "' does not "
8107 "have the resharding feature enabled." << std::endl;
8108 return ENOTSUP;
8109 }
8110 if (!RGWBucketReshard::can_reshard(bucket->get_info(), zone_svc) &&
8111 !yes_i_really_mean_it) {
8112 std::cerr << "Bucket '" << bucket->get_name() << "' already has too many "
8113 "log generations (" << bucket->get_info().layout.logs.size() << ") "
8114 "from previous reshards that peer zones haven't finished syncing. "
8115 "Resharding is not recommended until the old generations sync, but "
8116 "you can force a reshard with --yes-i-really-mean-it." << std::endl;
8117 return EINVAL;
8118 }
8119
8120 RGWBucketReshard br(static_cast<rgw::sal::RadosStore*>(driver),
8121 bucket->get_info(), bucket->get_attrs(),
8122 nullptr /* no callback */);
8123
8124 #define DEFAULT_RESHARD_MAX_ENTRIES 1000
8125 if (max_entries < 1) {
8126 max_entries = DEFAULT_RESHARD_MAX_ENTRIES;
8127 }
8128
8129 ReshardFaultInjector fault;
8130 if (inject_error_at) {
8131 const int code = -inject_error_code.value_or(EIO);
8132 fault.inject(*inject_error_at, InjectError{code, dpp()});
8133 } else if (inject_abort_at) {
8134 fault.inject(*inject_abort_at, InjectAbort{});
8135 } else if (inject_delay_at) {
8136 fault.inject(*inject_delay_at, InjectDelay{inject_delay, dpp()});
8137 }
8138 ret = br.execute(num_shards, fault, max_entries, dpp(),
8139 verbose, &cout, formatter.get());
8140 return -ret;
8141 }
8142
8143 if (opt_cmd == OPT::RESHARD_ADD) {
8144 int ret = check_reshard_bucket_params(driver,
8145 bucket_name,
8146 tenant,
8147 bucket_id,
8148 num_shards_specified,
8149 num_shards,
8150 yes_i_really_mean_it,
8151 &bucket);
8152 if (ret < 0) {
8153 return ret;
8154 }
8155
8156 int num_source_shards = rgw::current_num_shards(bucket->get_info().layout);
8157
8158 RGWReshard reshard(static_cast<rgw::sal::RadosStore*>(driver), dpp());
8159 cls_rgw_reshard_entry entry;
8160 entry.time = real_clock::now();
8161 entry.tenant = tenant;
8162 entry.bucket_name = bucket_name;
8163 entry.bucket_id = bucket->get_info().bucket.bucket_id;
8164 entry.old_num_shards = num_source_shards;
8165 entry.new_num_shards = num_shards;
8166
8167 return reshard.add(dpp(), entry);
8168 }
8169
8170 if (opt_cmd == OPT::RESHARD_LIST) {
8171 int ret;
8172 int count = 0;
8173 if (max_entries < 0) {
8174 max_entries = 1000;
8175 }
8176
8177 int num_logshards =
8178 driver->ctx()->_conf.get_val<uint64_t>("rgw_reshard_num_logs");
8179
8180 RGWReshard reshard(static_cast<rgw::sal::RadosStore*>(driver), dpp());
8181
8182 formatter->open_array_section("reshard");
8183 for (int i = 0; i < num_logshards; i++) {
8184 bool is_truncated = true;
8185 std::string marker;
8186 do {
8187 std::list<cls_rgw_reshard_entry> entries;
8188 ret = reshard.list(dpp(), i, marker, max_entries - count, entries, &is_truncated);
8189 if (ret < 0) {
8190 cerr << "Error listing resharding buckets: " << cpp_strerror(-ret) << std::endl;
8191 return ret;
8192 }
8193 for (const auto& entry : entries) {
8194 encode_json("entry", entry, formatter.get());
8195 }
8196 if (is_truncated) {
8197 entries.crbegin()->get_key(&marker); // last entry's key becomes marker
8198 }
8199 count += entries.size();
8200 formatter->flush(cout);
8201 } while (is_truncated && count < max_entries);
8202
8203 if (count >= max_entries) {
8204 break;
8205 }
8206 }
8207
8208 formatter->close_section();
8209 formatter->flush(cout);
8210
8211 return 0;
8212 }
8213
8214 if (opt_cmd == OPT::RESHARD_STATUS) {
8215 if (bucket_name.empty()) {
8216 cerr << "ERROR: bucket not specified" << std::endl;
8217 return EINVAL;
8218 }
8219
8220 ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
8221 if (ret < 0) {
8222 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
8223 return -ret;
8224 }
8225
8226 RGWBucketReshard br(static_cast<rgw::sal::RadosStore*>(driver),
8227 bucket->get_info(), bucket->get_attrs(),
8228 nullptr /* no callback */);
8229 list<cls_rgw_bucket_instance_entry> status;
8230 int r = br.get_status(dpp(), &status);
8231 if (r < 0) {
8232 cerr << "ERROR: could not get resharding status for bucket " <<
8233 bucket_name << std::endl;
8234 return -r;
8235 }
8236
8237 show_reshard_status(status, formatter.get());
8238 }
8239
8240 if (opt_cmd == OPT::RESHARD_PROCESS) {
8241 RGWReshard reshard(static_cast<rgw::sal::RadosStore*>(driver), true, &cout);
8242
8243 int ret = reshard.process_all_logshards(dpp());
8244 if (ret < 0) {
8245 cerr << "ERROR: failed to process reshard logs, error=" << cpp_strerror(-ret) << std::endl;
8246 return -ret;
8247 }
8248 }
8249
8250 if (opt_cmd == OPT::RESHARD_CANCEL) {
8251 if (bucket_name.empty()) {
8252 cerr << "ERROR: bucket not specified" << std::endl;
8253 return EINVAL;
8254 }
8255
8256 bool bucket_initable = true;
8257 ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
8258 if (ret < 0) {
8259 if (yes_i_really_mean_it) {
8260 bucket_initable = false;
8261 } else {
8262 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) <<
8263 "; if you want to cancel the reshard request nonetheless, please "
8264 "use the --yes-i-really-mean-it option" << std::endl;
8265 return -ret;
8266 }
8267 }
8268
8269 bool resharding_underway = true;
8270
8271 if (bucket_initable) {
8272 // we did not encounter an error, so let's work with the bucket
8273 RGWBucketReshard br(static_cast<rgw::sal::RadosStore*>(driver),
8274 bucket->get_info(), bucket->get_attrs(),
8275 nullptr /* no callback */);
8276 int ret = br.cancel(dpp());
8277 if (ret < 0) {
8278 if (ret == -EBUSY) {
8279 cerr << "There is ongoing resharding, please retry after " <<
8280 driver->ctx()->_conf.get_val<uint64_t>("rgw_reshard_bucket_lock_duration") <<
8281 " seconds." << std::endl;
8282 return -ret;
8283 } else if (ret == -EINVAL) {
8284 resharding_underway = false;
8285 // we can continue and try to unschedule
8286 } else {
8287 cerr << "Error cancelling bucket \"" << bucket_name <<
8288 "\" resharding: " << cpp_strerror(-ret) << std::endl;
8289 return -ret;
8290 }
8291 }
8292 }
8293
8294 RGWReshard reshard(static_cast<rgw::sal::RadosStore*>(driver), dpp());
8295
8296 cls_rgw_reshard_entry entry;
8297 entry.tenant = tenant;
8298 entry.bucket_name = bucket_name;
8299
8300 ret = reshard.remove(dpp(), entry);
8301 if (ret == -ENOENT) {
8302 if (!resharding_underway) {
8303 cerr << "Error, bucket \"" << bucket_name <<
8304 "\" is neither undergoing resharding nor scheduled to undergo "
8305 "resharding." << std::endl;
8306 return EINVAL;
8307 } else {
8308 // we cancelled underway resharding above, so we're good
8309 return 0;
8310 }
8311 } else if (ret < 0) {
8312 cerr << "Error in updating reshard log with bucket \"" <<
8313 bucket_name << "\": " << cpp_strerror(-ret) << std::endl;
8314 return -ret;
8315 }
8316 } // OPT_RESHARD_CANCEL
8317
8318 if (opt_cmd == OPT::OBJECT_UNLINK) {
8319 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
8320 if (ret < 0) {
8321 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
8322 return -ret;
8323 }
8324 list<rgw_obj_index_key> oid_list;
8325 rgw_obj_key key(object, object_version);
8326 rgw_obj_index_key index_key;
8327 key.get_index_key(&index_key);
8328 oid_list.push_back(index_key);
8329
8330 // note: under rados this removes directly from rados index objects
8331 ret = bucket->remove_objs_from_index(dpp(), oid_list);
8332 if (ret < 0) {
8333 cerr << "ERROR: remove_obj_from_index() returned error: " << cpp_strerror(-ret) << std::endl;
8334 return 1;
8335 }
8336 }
8337
8338 if (opt_cmd == OPT::OBJECT_STAT) {
8339 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
8340 if (ret < 0) {
8341 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
8342 return -ret;
8343 }
8344 std::unique_ptr<rgw::sal::Object> obj = bucket->get_object(object);
8345 obj->set_instance(object_version);
8346
8347 ret = obj->get_obj_attrs(null_yield, dpp());
8348 if (ret < 0) {
8349 cerr << "ERROR: failed to stat object, returned error: " << cpp_strerror(-ret) << std::endl;
8350 return 1;
8351 }
8352 formatter->open_object_section("object_metadata");
8353 formatter->dump_string("name", object);
8354 formatter->dump_unsigned("size", obj->get_obj_size());
8355
8356 map<string, bufferlist>::iterator iter;
8357 map<string, bufferlist> other_attrs;
8358 for (iter = obj->get_attrs().begin(); iter != obj->get_attrs().end(); ++iter) {
8359 bufferlist& bl = iter->second;
8360 bool handled = false;
8361 if (iter->first == RGW_ATTR_MANIFEST) {
8362 handled = decode_dump<RGWObjManifest>("manifest", bl, formatter.get());
8363 } else if (iter->first == RGW_ATTR_ACL) {
8364 handled = decode_dump<RGWAccessControlPolicy>("policy", bl, formatter.get());
8365 } else if (iter->first == RGW_ATTR_ID_TAG) {
8366 handled = dump_string("tag", bl, formatter.get());
8367 } else if (iter->first == RGW_ATTR_ETAG) {
8368 handled = dump_string("etag", bl, formatter.get());
8369 } else if (iter->first == RGW_ATTR_COMPRESSION) {
8370 handled = decode_dump<RGWCompressionInfo>("compression", bl, formatter.get());
8371 } else if (iter->first == RGW_ATTR_DELETE_AT) {
8372 handled = decode_dump<utime_t>("delete_at", bl, formatter.get());
8373 }
8374
8375 if (!handled)
8376 other_attrs[iter->first] = bl;
8377 }
8378
8379 formatter->open_object_section("attrs");
8380 for (iter = other_attrs.begin(); iter != other_attrs.end(); ++iter) {
8381 dump_string(iter->first.c_str(), iter->second, formatter.get());
8382 }
8383 formatter->close_section();
8384 formatter->close_section();
8385 formatter->flush(cout);
8386 }
8387
8388 if (opt_cmd == OPT::BUCKET_CHECK) {
8389 if (check_head_obj_locator) {
8390 if (bucket_name.empty()) {
8391 cerr << "ERROR: need to specify bucket name" << std::endl;
8392 return EINVAL;
8393 }
8394 do_check_object_locator(tenant, bucket_name, fix, remove_bad, formatter.get());
8395 } else {
8396 RGWBucketAdminOp::check_index(driver, bucket_op, stream_flusher, null_yield, dpp());
8397 }
8398 }
8399
8400 if (opt_cmd == OPT::BUCKET_CHECK_OLH) {
8401 rgw::sal::RadosStore* store = dynamic_cast<rgw::sal::RadosStore*>(driver);
8402 if (!store) {
8403 cerr <<
8404 "WARNING: this command is only relevant when the cluster has a RADOS backing store." <<
8405 std::endl;
8406 return 0;
8407 }
8408 RGWBucketAdminOp::check_index_olh(store, bucket_op, stream_flusher, dpp());
8409 }
8410
8411 if (opt_cmd == OPT::BUCKET_CHECK_UNLINKED) {
8412 rgw::sal::RadosStore* store = dynamic_cast<rgw::sal::RadosStore*>(driver);
8413 if (!store) {
8414 cerr <<
8415 "WARNING: this command is only relevant when the cluster has a RADOS backing store." <<
8416 std::endl;
8417 return 0;
8418 }
8419 RGWBucketAdminOp::check_index_unlinked(store, bucket_op, stream_flusher, dpp());
8420 }
8421
8422 if (opt_cmd == OPT::BUCKET_RM) {
8423 if (!inconsistent_index) {
8424 RGWBucketAdminOp::remove_bucket(driver, bucket_op, null_yield, dpp(), bypass_gc, true);
8425 } else {
8426 if (!yes_i_really_mean_it) {
8427 cerr << "using --inconsistent_index can corrupt the bucket index " << std::endl
8428 << "do you really mean it? (requires --yes-i-really-mean-it)" << std::endl;
8429 return 1;
8430 }
8431 RGWBucketAdminOp::remove_bucket(driver, bucket_op, null_yield, dpp(), bypass_gc, false);
8432 }
8433 }
8434
8435 if (opt_cmd == OPT::GC_LIST) {
8436 int index = 0;
8437 bool truncated;
8438 bool processing_queue = false;
8439 formatter->open_array_section("entries");
8440
8441 do {
8442 list<cls_rgw_gc_obj_info> result;
8443 int ret = static_cast<rgw::sal::RadosStore*>(driver)->getRados()->list_gc_objs(&index, marker, 1000, !include_all, result, &truncated, processing_queue);
8444 if (ret < 0) {
8445 cerr << "ERROR: failed to list objs: " << cpp_strerror(-ret) << std::endl;
8446 return 1;
8447 }
8448
8449
8450 list<cls_rgw_gc_obj_info>::iterator iter;
8451 for (iter = result.begin(); iter != result.end(); ++iter) {
8452 cls_rgw_gc_obj_info& info = *iter;
8453 formatter->open_object_section("chain_info");
8454 formatter->dump_string("tag", info.tag);
8455 formatter->dump_stream("time") << info.time;
8456 formatter->open_array_section("objs");
8457 list<cls_rgw_obj>::iterator liter;
8458 cls_rgw_obj_chain& chain = info.chain;
8459 for (liter = chain.objs.begin(); liter != chain.objs.end(); ++liter) {
8460 cls_rgw_obj& obj = *liter;
8461 encode_json("obj", obj, formatter.get());
8462 }
8463 formatter->close_section(); // objs
8464 formatter->close_section(); // obj_chain
8465 formatter->flush(cout);
8466 }
8467 } while (truncated);
8468 formatter->close_section();
8469 formatter->flush(cout);
8470 }
8471
8472 if (opt_cmd == OPT::GC_PROCESS) {
8473 int ret = static_cast<rgw::sal::RadosStore*>(driver)->getRados()->process_gc(!include_all);
8474 if (ret < 0) {
8475 cerr << "ERROR: gc processing returned error: " << cpp_strerror(-ret) << std::endl;
8476 return 1;
8477 }
8478 }
8479
8480 if (opt_cmd == OPT::LC_LIST) {
8481 formatter->open_array_section("lifecycle_list");
8482 vector<std::unique_ptr<rgw::sal::Lifecycle::LCEntry>> bucket_lc_map;
8483 string marker;
8484 int index{0};
8485 #define MAX_LC_LIST_ENTRIES 100
8486 if (max_entries < 0) {
8487 max_entries = MAX_LC_LIST_ENTRIES;
8488 }
8489 do {
8490 int ret = static_cast<rgw::sal::RadosStore*>(driver)->getRados()->list_lc_progress(marker, max_entries,
8491 bucket_lc_map, index);
8492 if (ret < 0) {
8493 cerr << "ERROR: failed to list objs: " << cpp_strerror(-ret)
8494 << std::endl;
8495 return 1;
8496 }
8497 for (const auto& entry : bucket_lc_map) {
8498 formatter->open_object_section("bucket_lc_info");
8499 formatter->dump_string("bucket", entry->get_bucket());
8500 formatter->dump_string("shard", entry->get_oid());
8501 char exp_buf[100];
8502 time_t t{time_t(entry->get_start_time())};
8503 if (std::strftime(
8504 exp_buf, sizeof(exp_buf),
8505 "%a, %d %b %Y %T %Z", std::gmtime(&t))) {
8506 formatter->dump_string("started", exp_buf);
8507 }
8508 string lc_status = LC_STATUS[entry->get_status()];
8509 formatter->dump_string("status", lc_status);
8510 formatter->close_section(); // objs
8511 formatter->flush(cout);
8512 }
8513 } while (!bucket_lc_map.empty());
8514
8515 formatter->close_section(); //lifecycle list
8516 formatter->flush(cout);
8517 }
8518
8519
8520 if (opt_cmd == OPT::LC_GET) {
8521 if (bucket_name.empty()) {
8522 cerr << "ERROR: bucket not specified" << std::endl;
8523 return EINVAL;
8524 }
8525
8526 RGWLifecycleConfiguration config;
8527 ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
8528 if (ret < 0) {
8529 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
8530 return -ret;
8531 }
8532
8533 auto aiter = bucket->get_attrs().find(RGW_ATTR_LC);
8534 if (aiter == bucket->get_attrs().end()) {
8535 return -ENOENT;
8536 }
8537
8538 bufferlist::const_iterator iter{&aiter->second};
8539 try {
8540 config.decode(iter);
8541 } catch (const buffer::error& e) {
8542 cerr << "ERROR: decode life cycle config failed" << std::endl;
8543 return -EIO;
8544 }
8545
8546 encode_json("result", config, formatter.get());
8547 formatter->flush(cout);
8548 }
8549
8550 if (opt_cmd == OPT::LC_PROCESS) {
8551 if ((! bucket_name.empty()) ||
8552 (! bucket_id.empty())) {
8553 int ret = init_bucket(nullptr, tenant, bucket_name, bucket_id, &bucket);
8554 if (ret < 0) {
8555 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret)
8556 << std::endl;
8557 return ret;
8558 }
8559 }
8560
8561 int ret =
8562 static_cast<rgw::sal::RadosStore*>(driver)->getRados()->process_lc(bucket);
8563 if (ret < 0) {
8564 cerr << "ERROR: lc processing returned error: " << cpp_strerror(-ret) << std::endl;
8565 return 1;
8566 }
8567 }
8568
8569 if (opt_cmd == OPT::LC_RESHARD_FIX) {
8570 ret = RGWBucketAdminOp::fix_lc_shards(driver, bucket_op, stream_flusher, dpp());
8571 if (ret < 0) {
8572 cerr << "ERROR: fixing lc shards: " << cpp_strerror(-ret) << std::endl;
8573 }
8574
8575 }
8576
8577 if (opt_cmd == OPT::ORPHANS_FIND) {
8578 if (!yes_i_really_mean_it) {
8579 cerr << "this command is now deprecated; please consider using the rgw-orphan-list tool; "
8580 << "accidental removal of active objects cannot be reversed; "
8581 << "do you really mean it? (requires --yes-i-really-mean-it)"
8582 << std::endl;
8583 return EINVAL;
8584 } else {
8585 cerr << "IMPORTANT: this command is now deprecated; please consider using the rgw-orphan-list tool"
8586 << std::endl;
8587 }
8588
8589 RGWOrphanSearch search(static_cast<rgw::sal::RadosStore*>(driver), max_concurrent_ios, orphan_stale_secs);
8590
8591 if (job_id.empty()) {
8592 cerr << "ERROR: --job-id not specified" << std::endl;
8593 return EINVAL;
8594 }
8595 if (pool_name.empty()) {
8596 cerr << "ERROR: --pool not specified" << std::endl;
8597 return EINVAL;
8598 }
8599
8600 RGWOrphanSearchInfo info;
8601
8602 info.pool = pool;
8603 info.job_name = job_id;
8604 info.num_shards = num_shards;
8605
8606 int ret = search.init(dpp(), job_id, &info, detail);
8607 if (ret < 0) {
8608 cerr << "could not init search, ret=" << ret << std::endl;
8609 return -ret;
8610 }
8611 ret = search.run(dpp());
8612 if (ret < 0) {
8613 return -ret;
8614 }
8615 }
8616
8617 if (opt_cmd == OPT::ORPHANS_FINISH) {
8618 if (!yes_i_really_mean_it) {
8619 cerr << "this command is now deprecated; please consider using the rgw-orphan-list tool; "
8620 << "accidental removal of active objects cannot be reversed; "
8621 << "do you really mean it? (requires --yes-i-really-mean-it)"
8622 << std::endl;
8623 return EINVAL;
8624 } else {
8625 cerr << "IMPORTANT: this command is now deprecated; please consider using the rgw-orphan-list tool"
8626 << std::endl;
8627 }
8628
8629 RGWOrphanSearch search(static_cast<rgw::sal::RadosStore*>(driver), max_concurrent_ios, orphan_stale_secs);
8630
8631 if (job_id.empty()) {
8632 cerr << "ERROR: --job-id not specified" << std::endl;
8633 return EINVAL;
8634 }
8635 int ret = search.init(dpp(), job_id, NULL);
8636 if (ret < 0) {
8637 if (ret == -ENOENT) {
8638 cerr << "job not found" << std::endl;
8639 }
8640 return -ret;
8641 }
8642 ret = search.finish();
8643 if (ret < 0) {
8644 return -ret;
8645 }
8646 }
8647
8648 if (opt_cmd == OPT::ORPHANS_LIST_JOBS){
8649 if (!yes_i_really_mean_it) {
8650 cerr << "this command is now deprecated; please consider using the rgw-orphan-list tool; "
8651 << "do you really mean it? (requires --yes-i-really-mean-it)"
8652 << std::endl;
8653 return EINVAL;
8654 } else {
8655 cerr << "IMPORTANT: this command is now deprecated; please consider using the rgw-orphan-list tool"
8656 << std::endl;
8657 }
8658
8659 RGWOrphanStore orphan_store(static_cast<rgw::sal::RadosStore*>(driver));
8660 int ret = orphan_store.init(dpp());
8661 if (ret < 0){
8662 cerr << "connection to cluster failed!" << std::endl;
8663 return -ret;
8664 }
8665
8666 map <string,RGWOrphanSearchState> m;
8667 ret = orphan_store.list_jobs(m);
8668 if (ret < 0) {
8669 cerr << "job list failed" << std::endl;
8670 return -ret;
8671 }
8672 formatter->open_array_section("entries");
8673 for (const auto &it: m){
8674 if (!extra_info){
8675 formatter->dump_string("job-id",it.first);
8676 } else {
8677 encode_json("orphan_search_state", it.second, formatter.get());
8678 }
8679 }
8680 formatter->close_section();
8681 formatter->flush(cout);
8682 }
8683
8684 if (opt_cmd == OPT::USER_CHECK) {
8685 check_bad_user_bucket_mapping(driver, *user.get(), fix, null_yield, dpp());
8686 }
8687
8688 if (opt_cmd == OPT::USER_STATS) {
8689 if (rgw::sal::User::empty(user)) {
8690 cerr << "ERROR: uid not specified" << std::endl;
8691 return EINVAL;
8692 }
8693 if (reset_stats) {
8694 if (!bucket_name.empty()) {
8695 cerr << "ERROR: --reset-stats does not work on buckets and "
8696 "bucket specified" << std::endl;
8697 return EINVAL;
8698 }
8699 if (sync_stats) {
8700 cerr << "ERROR: sync-stats includes the reset-stats functionality, "
8701 "so at most one of the two should be specified" << std::endl;
8702 return EINVAL;
8703 }
8704 ret = static_cast<rgw::sal::RadosStore*>(driver)->svc()->user->reset_bucket_stats(dpp(), user->get_id(), null_yield);
8705 if (ret < 0) {
8706 cerr << "ERROR: could not reset user stats: " << cpp_strerror(-ret) <<
8707 std::endl;
8708 return -ret;
8709 }
8710 }
8711
8712 if (sync_stats) {
8713 if (!bucket_name.empty()) {
8714 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
8715 if (ret < 0) {
8716 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
8717 return -ret;
8718 }
8719 ret = bucket->sync_user_stats(dpp(), null_yield);
8720 if (ret < 0) {
8721 cerr << "ERROR: could not sync bucket stats: " <<
8722 cpp_strerror(-ret) << std::endl;
8723 return -ret;
8724 }
8725 } else {
8726 int ret = rgw_user_sync_all_stats(dpp(), driver, user.get(), null_yield);
8727 if (ret < 0) {
8728 cerr << "ERROR: could not sync user stats: " <<
8729 cpp_strerror(-ret) << std::endl;
8730 return -ret;
8731 }
8732 }
8733 }
8734
8735 constexpr bool omit_utilized_stats = false;
8736 RGWStorageStats stats(omit_utilized_stats);
8737 ceph::real_time last_stats_sync;
8738 ceph::real_time last_stats_update;
8739 int ret = user->read_stats(dpp(), null_yield, &stats, &last_stats_sync, &last_stats_update);
8740 if (ret < 0) {
8741 if (ret == -ENOENT) { /* in case of ENOENT */
8742 cerr << "User has not been initialized or user does not exist" << std::endl;
8743 } else {
8744 cerr << "ERROR: can't read user: " << cpp_strerror(ret) << std::endl;
8745 }
8746 return -ret;
8747 }
8748
8749
8750 {
8751 Formatter::ObjectSection os(*formatter, "result");
8752 encode_json("stats", stats, formatter.get());
8753 utime_t last_sync_ut(last_stats_sync);
8754 encode_json("last_stats_sync", last_sync_ut, formatter.get());
8755 utime_t last_update_ut(last_stats_update);
8756 encode_json("last_stats_update", last_update_ut, formatter.get());
8757 }
8758 formatter->flush(cout);
8759 }
8760
8761 if (opt_cmd == OPT::METADATA_GET) {
8762 int ret = static_cast<rgw::sal::RadosStore*>(driver)->ctl()->meta.mgr->get(metadata_key, formatter.get(), null_yield, dpp());
8763 if (ret < 0) {
8764 cerr << "ERROR: can't get key: " << cpp_strerror(-ret) << std::endl;
8765 return -ret;
8766 }
8767
8768 formatter->flush(cout);
8769 }
8770
8771 if (opt_cmd == OPT::METADATA_PUT) {
8772 bufferlist bl;
8773 int ret = read_input(infile, bl);
8774 if (ret < 0) {
8775 cerr << "ERROR: failed to read input: " << cpp_strerror(-ret) << std::endl;
8776 return -ret;
8777 }
8778 ret = static_cast<rgw::sal::RadosStore*>(driver)->ctl()->meta.mgr->put(metadata_key, bl, null_yield, dpp(), RGWMDLogSyncType::APPLY_ALWAYS, false);
8779 if (ret < 0) {
8780 cerr << "ERROR: can't put key: " << cpp_strerror(-ret) << std::endl;
8781 return -ret;
8782 }
8783 }
8784
8785 if (opt_cmd == OPT::METADATA_RM) {
8786 int ret = static_cast<rgw::sal::RadosStore*>(driver)->ctl()->meta.mgr->remove(metadata_key, null_yield, dpp());
8787 if (ret < 0) {
8788 cerr << "ERROR: can't remove key: " << cpp_strerror(-ret) << std::endl;
8789 return -ret;
8790 }
8791 }
8792
8793 if (opt_cmd == OPT::METADATA_LIST || opt_cmd == OPT::USER_LIST) {
8794 if (opt_cmd == OPT::USER_LIST) {
8795 metadata_key = "user";
8796 }
8797 void *handle;
8798 int max = 1000;
8799 int ret = driver->meta_list_keys_init(dpp(), metadata_key, marker, &handle);
8800 if (ret < 0) {
8801 cerr << "ERROR: can't get key: " << cpp_strerror(-ret) << std::endl;
8802 return -ret;
8803 }
8804
8805 bool truncated;
8806 uint64_t count = 0;
8807
8808 if (max_entries_specified) {
8809 formatter->open_object_section("result");
8810 }
8811 formatter->open_array_section("keys");
8812
8813 uint64_t left;
8814 do {
8815 list<string> keys;
8816 left = (max_entries_specified ? max_entries - count : max);
8817 ret = driver->meta_list_keys_next(dpp(), handle, left, keys, &truncated);
8818 if (ret < 0 && ret != -ENOENT) {
8819 cerr << "ERROR: lists_keys_next(): " << cpp_strerror(-ret) << std::endl;
8820 return -ret;
8821 } if (ret != -ENOENT) {
8822 for (list<string>::iterator iter = keys.begin(); iter != keys.end(); ++iter) {
8823 formatter->dump_string("key", *iter);
8824 ++count;
8825 }
8826 formatter->flush(cout);
8827 }
8828 } while (truncated && left > 0);
8829
8830 formatter->close_section();
8831
8832 if (max_entries_specified) {
8833 encode_json("truncated", truncated, formatter.get());
8834 encode_json("count", count, formatter.get());
8835 if (truncated) {
8836 encode_json("marker", driver->meta_get_marker(handle), formatter.get());
8837 }
8838 formatter->close_section();
8839 }
8840 formatter->flush(cout);
8841
8842 driver->meta_list_keys_complete(handle);
8843 }
8844
8845 if (opt_cmd == OPT::MDLOG_LIST) {
8846 if (!start_date.empty()) {
8847 std::cerr << "start-date not allowed." << std::endl;
8848 return -EINVAL;
8849 }
8850 if (!end_date.empty()) {
8851 std::cerr << "end-date not allowed." << std::endl;
8852 return -EINVAL;
8853 }
8854 if (!end_marker.empty()) {
8855 std::cerr << "end-marker not allowed." << std::endl;
8856 return -EINVAL;
8857 }
8858 if (!start_marker.empty()) {
8859 if (marker.empty()) {
8860 marker = start_marker;
8861 } else {
8862 std::cerr << "start-marker and marker not both allowed." << std::endl;
8863 return -EINVAL;
8864 }
8865 }
8866
8867 int i = (specified_shard_id ? shard_id : 0);
8868
8869 if (period_id.empty()) {
8870 // use realm's current period
8871 RGWRealm realm;
8872 int ret = rgw::read_realm(dpp(), null_yield, cfgstore.get(),
8873 realm_id, realm_name, realm);
8874 if (ret < 0 ) {
8875 cerr << "failed to load realm: " << cpp_strerror(-ret) << std::endl;
8876 return -ret;
8877 }
8878 period_id = realm.current_period;
8879 std::cerr << "No --period given, using current period="
8880 << period_id << std::endl;
8881 }
8882 RGWMetadataLog *meta_log = static_cast<rgw::sal::RadosStore*>(driver)->svc()->mdlog->get_log(period_id);
8883
8884 formatter->open_array_section("entries");
8885 for (; i < g_ceph_context->_conf->rgw_md_log_max_shards; i++) {
8886 void *handle;
8887 list<cls_log_entry> entries;
8888
8889 meta_log->init_list_entries(i, {}, {}, marker, &handle);
8890 bool truncated;
8891 do {
8892 int ret = meta_log->list_entries(dpp(), handle, 1000, entries, NULL, &truncated);
8893 if (ret < 0) {
8894 cerr << "ERROR: meta_log->list_entries(): " << cpp_strerror(-ret) << std::endl;
8895 return -ret;
8896 }
8897
8898 for (list<cls_log_entry>::iterator iter = entries.begin(); iter != entries.end(); ++iter) {
8899 cls_log_entry& entry = *iter;
8900 static_cast<rgw::sal::RadosStore*>(driver)->ctl()->meta.mgr->dump_log_entry(entry, formatter.get());
8901 }
8902 formatter->flush(cout);
8903 } while (truncated);
8904
8905 meta_log->complete_list_entries(handle);
8906
8907 if (specified_shard_id)
8908 break;
8909 }
8910
8911
8912 formatter->close_section();
8913 formatter->flush(cout);
8914 }
8915
8916 if (opt_cmd == OPT::MDLOG_STATUS) {
8917 int i = (specified_shard_id ? shard_id : 0);
8918
8919 if (period_id.empty()) {
8920 // use realm's current period
8921 RGWRealm realm;
8922 int ret = rgw::read_realm(dpp(), null_yield, cfgstore.get(),
8923 realm_id, realm_name, realm);
8924 if (ret < 0 ) {
8925 cerr << "failed to load realm: " << cpp_strerror(-ret) << std::endl;
8926 return -ret;
8927 }
8928 period_id = realm.current_period;
8929 std::cerr << "No --period given, using current period="
8930 << period_id << std::endl;
8931 }
8932 RGWMetadataLog *meta_log = static_cast<rgw::sal::RadosStore*>(driver)->svc()->mdlog->get_log(period_id);
8933
8934 formatter->open_array_section("entries");
8935
8936 for (; i < g_ceph_context->_conf->rgw_md_log_max_shards; i++) {
8937 RGWMetadataLogInfo info;
8938 meta_log->get_info(dpp(), i, &info);
8939
8940 ::encode_json("info", info, formatter.get());
8941
8942 if (specified_shard_id)
8943 break;
8944 }
8945
8946
8947 formatter->close_section();
8948 formatter->flush(cout);
8949 }
8950
8951 if (opt_cmd == OPT::MDLOG_AUTOTRIM) {
8952 // need a full history for purging old mdlog periods
8953 static_cast<rgw::sal::RadosStore*>(driver)->svc()->mdlog->init_oldest_log_period(null_yield, dpp());
8954
8955 RGWCoroutinesManager crs(driver->ctx(), driver->get_cr_registry());
8956 RGWHTTPManager http(driver->ctx(), crs.get_completion_mgr());
8957 int ret = http.start();
8958 if (ret < 0) {
8959 cerr << "failed to initialize http client with " << cpp_strerror(ret) << std::endl;
8960 return -ret;
8961 }
8962
8963 auto num_shards = g_conf()->rgw_md_log_max_shards;
8964 auto mltcr = create_admin_meta_log_trim_cr(
8965 dpp(), static_cast<rgw::sal::RadosStore*>(driver), &http, num_shards);
8966 if (!mltcr) {
8967 cerr << "Cluster misconfigured! Unable to trim." << std::endl;
8968 return -EIO;
8969 }
8970 ret = crs.run(dpp(), mltcr);
8971 if (ret < 0) {
8972 cerr << "automated mdlog trim failed with " << cpp_strerror(ret) << std::endl;
8973 return -ret;
8974 }
8975 }
8976
8977 if (opt_cmd == OPT::MDLOG_TRIM) {
8978 if (!start_date.empty()) {
8979 std::cerr << "start-date not allowed." << std::endl;
8980 return -EINVAL;
8981 }
8982 if (!end_date.empty()) {
8983 std::cerr << "end-date not allowed." << std::endl;
8984 return -EINVAL;
8985 }
8986 if (!start_marker.empty()) {
8987 std::cerr << "start-marker not allowed." << std::endl;
8988 return -EINVAL;
8989 }
8990 if (!end_marker.empty()) {
8991 if (marker.empty()) {
8992 marker = end_marker;
8993 } else {
8994 std::cerr << "end-marker and marker not both allowed." << std::endl;
8995 return -EINVAL;
8996 }
8997 }
8998
8999 if (!specified_shard_id) {
9000 cerr << "ERROR: shard-id must be specified for trim operation" << std::endl;
9001 return EINVAL;
9002 }
9003
9004 if (marker.empty()) {
9005 cerr << "ERROR: marker must be specified for trim operation" << std::endl;
9006 return EINVAL;
9007 }
9008
9009 if (period_id.empty()) {
9010 std::cerr << "missing --period argument" << std::endl;
9011 return EINVAL;
9012 }
9013 RGWMetadataLog *meta_log = static_cast<rgw::sal::RadosStore*>(driver)->svc()->mdlog->get_log(period_id);
9014
9015 // trim until -ENODATA
9016 do {
9017 ret = meta_log->trim(dpp(), shard_id, {}, {}, {}, marker);
9018 } while (ret == 0);
9019 if (ret < 0 && ret != -ENODATA) {
9020 cerr << "ERROR: meta_log->trim(): " << cpp_strerror(-ret) << std::endl;
9021 return -ret;
9022 }
9023 }
9024
9025 if (opt_cmd == OPT::SYNC_INFO) {
9026 sync_info(opt_effective_zone_id, opt_bucket, zone_formatter.get());
9027 }
9028
9029 if (opt_cmd == OPT::SYNC_STATUS) {
9030 sync_status(formatter.get());
9031 }
9032
9033 if (opt_cmd == OPT::METADATA_SYNC_STATUS) {
9034 RGWMetaSyncStatusManager sync(static_cast<rgw::sal::RadosStore*>(driver), static_cast<rgw::sal::RadosStore*>(driver)->svc()->rados->get_async_processor());
9035
9036 int ret = sync.init(dpp());
9037 if (ret < 0) {
9038 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
9039 return -ret;
9040 }
9041
9042 rgw_meta_sync_status sync_status;
9043 ret = sync.read_sync_status(dpp(), &sync_status);
9044 if (ret < 0) {
9045 cerr << "ERROR: sync.read_sync_status() returned ret=" << ret << std::endl;
9046 return -ret;
9047 }
9048
9049 formatter->open_object_section("summary");
9050 encode_json("sync_status", sync_status, formatter.get());
9051
9052 uint64_t full_total = 0;
9053 uint64_t full_complete = 0;
9054
9055 for (auto marker_iter : sync_status.sync_markers) {
9056 full_total += marker_iter.second.total_entries;
9057 if (marker_iter.second.state == rgw_meta_sync_marker::SyncState::FullSync) {
9058 full_complete += marker_iter.second.pos;
9059 } else {
9060 full_complete += marker_iter.second.total_entries;
9061 }
9062 }
9063
9064 formatter->open_object_section("full_sync");
9065 encode_json("total", full_total, formatter.get());
9066 encode_json("complete", full_complete, formatter.get());
9067 formatter->close_section();
9068 formatter->dump_string("current_time",
9069 to_iso_8601(ceph::real_clock::now(),
9070 iso_8601_format::YMDhms));
9071 formatter->close_section();
9072
9073 formatter->flush(cout);
9074
9075 }
9076
9077 if (opt_cmd == OPT::METADATA_SYNC_INIT) {
9078 RGWMetaSyncStatusManager sync(static_cast<rgw::sal::RadosStore*>(driver), static_cast<rgw::sal::RadosStore*>(driver)->svc()->rados->get_async_processor());
9079
9080 int ret = sync.init(dpp());
9081 if (ret < 0) {
9082 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
9083 return -ret;
9084 }
9085 ret = sync.init_sync_status(dpp());
9086 if (ret < 0) {
9087 cerr << "ERROR: sync.init_sync_status() returned ret=" << ret << std::endl;
9088 return -ret;
9089 }
9090 }
9091
9092
9093 if (opt_cmd == OPT::METADATA_SYNC_RUN) {
9094 RGWMetaSyncStatusManager sync(static_cast<rgw::sal::RadosStore*>(driver), static_cast<rgw::sal::RadosStore*>(driver)->svc()->rados->get_async_processor());
9095
9096 int ret = sync.init(dpp());
9097 if (ret < 0) {
9098 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
9099 return -ret;
9100 }
9101
9102 ret = sync.run(dpp(), null_yield);
9103 if (ret < 0) {
9104 cerr << "ERROR: sync.run() returned ret=" << ret << std::endl;
9105 return -ret;
9106 }
9107 }
9108
9109 if (opt_cmd == OPT::DATA_SYNC_STATUS) {
9110 if (source_zone.empty()) {
9111 cerr << "ERROR: source zone not specified" << std::endl;
9112 return EINVAL;
9113 }
9114 RGWDataSyncStatusManager sync(static_cast<rgw::sal::RadosStore*>(driver), static_cast<rgw::sal::RadosStore*>(driver)->svc()->rados->get_async_processor(), source_zone, nullptr);
9115
9116 int ret = sync.init(dpp());
9117 if (ret < 0) {
9118 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
9119 return -ret;
9120 }
9121
9122 rgw_data_sync_status sync_status;
9123 if (specified_shard_id) {
9124 set<string> pending_buckets;
9125 set<string> recovering_buckets;
9126 rgw_data_sync_marker sync_marker;
9127 ret = sync.read_shard_status(dpp(), shard_id, pending_buckets, recovering_buckets, &sync_marker,
9128 max_entries_specified ? max_entries : 20);
9129 if (ret < 0 && ret != -ENOENT) {
9130 cerr << "ERROR: sync.read_shard_status() returned ret=" << ret << std::endl;
9131 return -ret;
9132 }
9133 formatter->open_object_section("summary");
9134 encode_json("shard_id", shard_id, formatter.get());
9135 encode_json("marker", sync_marker, formatter.get());
9136 encode_json("pending_buckets", pending_buckets, formatter.get());
9137 encode_json("recovering_buckets", recovering_buckets, formatter.get());
9138 formatter->dump_string("current_time",
9139 to_iso_8601(ceph::real_clock::now(),
9140 iso_8601_format::YMDhms));
9141 formatter->close_section();
9142 formatter->flush(cout);
9143 } else {
9144 ret = sync.read_sync_status(dpp(), &sync_status);
9145 if (ret < 0 && ret != -ENOENT) {
9146 cerr << "ERROR: sync.read_sync_status() returned ret=" << ret << std::endl;
9147 return -ret;
9148 }
9149
9150 formatter->open_object_section("summary");
9151 encode_json("sync_status", sync_status, formatter.get());
9152
9153 uint64_t full_total = 0;
9154 uint64_t full_complete = 0;
9155
9156 for (auto marker_iter : sync_status.sync_markers) {
9157 full_total += marker_iter.second.total_entries;
9158 if (marker_iter.second.state == rgw_meta_sync_marker::SyncState::FullSync) {
9159 full_complete += marker_iter.second.pos;
9160 } else {
9161 full_complete += marker_iter.second.total_entries;
9162 }
9163 }
9164
9165 formatter->open_object_section("full_sync");
9166 encode_json("total", full_total, formatter.get());
9167 encode_json("complete", full_complete, formatter.get());
9168 formatter->close_section();
9169 formatter->dump_string("current_time",
9170 to_iso_8601(ceph::real_clock::now(),
9171 iso_8601_format::YMDhms));
9172 formatter->close_section();
9173
9174 formatter->flush(cout);
9175 }
9176 }
9177
9178 if (opt_cmd == OPT::DATA_SYNC_INIT) {
9179 if (source_zone.empty()) {
9180 cerr << "ERROR: source zone not specified" << std::endl;
9181 return EINVAL;
9182 }
9183
9184 RGWDataSyncStatusManager sync(static_cast<rgw::sal::RadosStore*>(driver), static_cast<rgw::sal::RadosStore*>(driver)->svc()->rados->get_async_processor(), source_zone, nullptr);
9185
9186 int ret = sync.init(dpp());
9187 if (ret < 0) {
9188 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
9189 return -ret;
9190 }
9191
9192 ret = sync.init_sync_status(dpp());
9193 if (ret < 0) {
9194 cerr << "ERROR: sync.init_sync_status() returned ret=" << ret << std::endl;
9195 return -ret;
9196 }
9197 }
9198
9199 if (opt_cmd == OPT::DATA_SYNC_RUN) {
9200 if (source_zone.empty()) {
9201 cerr << "ERROR: source zone not specified" << std::endl;
9202 return EINVAL;
9203 }
9204
9205 RGWSyncModuleInstanceRef sync_module;
9206 int ret = static_cast<rgw::sal::RadosStore*>(driver)->svc()->sync_modules->get_manager()->create_instance(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(driver)->svc()->zone->get_zone().tier_type,
9207 static_cast<rgw::sal::RadosStore*>(driver)->svc()->zone->get_zone_params().tier_config, &sync_module);
9208 if (ret < 0) {
9209 ldpp_dout(dpp(), -1) << "ERROR: failed to init sync module instance, ret=" << ret << dendl;
9210 return ret;
9211 }
9212
9213 RGWDataSyncStatusManager sync(static_cast<rgw::sal::RadosStore*>(driver), static_cast<rgw::sal::RadosStore*>(driver)->svc()->rados->get_async_processor(), source_zone, nullptr, sync_module);
9214
9215 ret = sync.init(dpp());
9216 if (ret < 0) {
9217 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
9218 return -ret;
9219 }
9220
9221 ret = sync.run(dpp());
9222 if (ret < 0) {
9223 cerr << "ERROR: sync.run() returned ret=" << ret << std::endl;
9224 return -ret;
9225 }
9226 }
9227
9228 if (opt_cmd == OPT::BUCKET_SYNC_INIT) {
9229 if (source_zone.empty()) {
9230 cerr << "ERROR: source zone not specified" << std::endl;
9231 return EINVAL;
9232 }
9233 if (bucket_name.empty()) {
9234 cerr << "ERROR: bucket not specified" << std::endl;
9235 return EINVAL;
9236 }
9237 int ret = init_bucket_for_sync(user.get(), tenant, bucket_name, bucket_id, &bucket);
9238 if (ret < 0) {
9239 return -ret;
9240 }
9241 auto opt_sb = opt_source_bucket;
9242 if (opt_sb && opt_sb->bucket_id.empty()) {
9243 string sbid;
9244 std::unique_ptr<rgw::sal::Bucket> sbuck;
9245 int ret = init_bucket_for_sync(user.get(), opt_sb->tenant, opt_sb->name, sbid, &sbuck);
9246 if (ret < 0) {
9247 return -ret;
9248 }
9249 opt_sb = sbuck->get_key();
9250 }
9251
9252 auto sync = RGWBucketPipeSyncStatusManager::construct(
9253 dpp(), static_cast<rgw::sal::RadosStore*>(driver), source_zone, opt_sb,
9254 bucket->get_key(), extra_info ? &std::cout : nullptr);
9255
9256 if (!sync) {
9257 cerr << "ERROR: sync.init() returned error=" << sync.error() << std::endl;
9258 return -sync.error();
9259 }
9260 ret = (*sync)->init_sync_status(dpp());
9261 if (ret < 0) {
9262 cerr << "ERROR: sync.init_sync_status() returned ret=" << ret << std::endl;
9263 return -ret;
9264 }
9265 }
9266
9267 if (opt_cmd == OPT::BUCKET_SYNC_CHECKPOINT) {
9268 std::optional<rgw_zone_id> opt_source_zone;
9269 if (!source_zone.empty()) {
9270 opt_source_zone = source_zone;
9271 }
9272 if (bucket_name.empty()) {
9273 cerr << "ERROR: bucket not specified" << std::endl;
9274 return EINVAL;
9275 }
9276 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
9277 if (ret < 0) {
9278 return -ret;
9279 }
9280
9281 if (!static_cast<rgw::sal::RadosStore*>(driver)->ctl()->bucket->bucket_imports_data(bucket->get_key(), null_yield, dpp())) {
9282 std::cout << "Sync is disabled for bucket " << bucket_name << std::endl;
9283 return 0;
9284 }
9285
9286 RGWBucketSyncPolicyHandlerRef handler;
9287 ret = driver->get_sync_policy_handler(dpp(), std::nullopt, bucket->get_key(), &handler, null_yield);
9288 if (ret < 0) {
9289 std::cerr << "ERROR: failed to get policy handler for bucket ("
9290 << bucket << "): r=" << ret << ": " << cpp_strerror(-ret) << std::endl;
9291 return -ret;
9292 }
9293
9294 auto timeout_at = ceph::coarse_mono_clock::now() + opt_timeout_sec;
9295 ret = rgw_bucket_sync_checkpoint(dpp(), static_cast<rgw::sal::RadosStore*>(driver), *handler, bucket->get_info(),
9296 opt_source_zone, opt_source_bucket,
9297 opt_retry_delay_ms, timeout_at);
9298 if (ret < 0) {
9299 ldpp_dout(dpp(), -1) << "bucket sync checkpoint failed: " << cpp_strerror(ret) << dendl;
9300 return -ret;
9301 }
9302 }
9303
9304 if ((opt_cmd == OPT::BUCKET_SYNC_DISABLE) || (opt_cmd == OPT::BUCKET_SYNC_ENABLE)) {
9305 if (bucket_name.empty()) {
9306 cerr << "ERROR: bucket not specified" << std::endl;
9307 return EINVAL;
9308 }
9309 if (opt_cmd == OPT::BUCKET_SYNC_DISABLE) {
9310 bucket_op.set_sync_bucket(false);
9311 } else {
9312 bucket_op.set_sync_bucket(true);
9313 }
9314 bucket_op.set_tenant(tenant);
9315 string err_msg;
9316 ret = RGWBucketAdminOp::sync_bucket(driver, bucket_op, dpp(), &err_msg);
9317 if (ret < 0) {
9318 cerr << err_msg << std::endl;
9319 return -ret;
9320 }
9321 }
9322
9323 if (opt_cmd == OPT::BUCKET_SYNC_INFO) {
9324 if (bucket_name.empty()) {
9325 cerr << "ERROR: bucket not specified" << std::endl;
9326 return EINVAL;
9327 }
9328 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
9329 if (ret < 0) {
9330 return -ret;
9331 }
9332 bucket_sync_info(driver, bucket->get_info(), std::cout);
9333 }
9334
9335 if (opt_cmd == OPT::BUCKET_SYNC_STATUS) {
9336 if (bucket_name.empty()) {
9337 cerr << "ERROR: bucket not specified" << std::endl;
9338 return EINVAL;
9339 }
9340 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
9341 if (ret < 0) {
9342 return -ret;
9343 }
9344 bucket_sync_status(driver, bucket->get_info(), source_zone, opt_source_bucket, std::cout);
9345 }
9346
9347 if (opt_cmd == OPT::BUCKET_SYNC_MARKERS) {
9348 if (source_zone.empty()) {
9349 cerr << "ERROR: source zone not specified" << std::endl;
9350 return EINVAL;
9351 }
9352 if (bucket_name.empty()) {
9353 cerr << "ERROR: bucket not specified" << std::endl;
9354 return EINVAL;
9355 }
9356 int ret = init_bucket_for_sync(user.get(), tenant, bucket_name, bucket_id, &bucket);
9357 if (ret < 0) {
9358 return -ret;
9359 }
9360 auto sync = RGWBucketPipeSyncStatusManager::construct(
9361 dpp(), static_cast<rgw::sal::RadosStore*>(driver), source_zone,
9362 opt_source_bucket, bucket->get_key(), nullptr);
9363
9364 if (!sync) {
9365 cerr << "ERROR: sync.init() returned error=" << sync.error() << std::endl;
9366 return -sync.error();
9367 }
9368
9369 auto sync_status = (*sync)->read_sync_status(dpp());
9370 if (!sync_status) {
9371 cerr << "ERROR: sync.read_sync_status() returned error="
9372 << sync_status.error() << std::endl;
9373 return -sync_status.error();
9374 }
9375
9376 encode_json("sync_status", *sync_status, formatter.get());
9377 formatter->flush(cout);
9378 }
9379
9380 if (opt_cmd == OPT::BUCKET_SYNC_RUN) {
9381 if (source_zone.empty()) {
9382 cerr << "ERROR: source zone not specified" << std::endl;
9383 return EINVAL;
9384 }
9385 if (bucket_name.empty()) {
9386 cerr << "ERROR: bucket not specified" << std::endl;
9387 return EINVAL;
9388 }
9389 int ret = init_bucket_for_sync(user.get(), tenant, bucket_name, bucket_id, &bucket);
9390 if (ret < 0) {
9391 return -ret;
9392 }
9393 auto sync = RGWBucketPipeSyncStatusManager::construct(
9394 dpp(), static_cast<rgw::sal::RadosStore*>(driver), source_zone,
9395 opt_source_bucket, bucket->get_key(), extra_info ? &std::cout : nullptr);
9396
9397 if (!sync) {
9398 cerr << "ERROR: sync.init() returned error=" << sync.error() << std::endl;
9399 return -sync.error();
9400 }
9401
9402 ret = (*sync)->run(dpp());
9403 if (ret < 0) {
9404 cerr << "ERROR: sync.run() returned ret=" << ret << std::endl;
9405 return -ret;
9406 }
9407 }
9408
9409 if (opt_cmd == OPT::BILOG_LIST) {
9410 if (bucket_name.empty()) {
9411 cerr << "ERROR: bucket not specified" << std::endl;
9412 return EINVAL;
9413 }
9414 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
9415 if (ret < 0) {
9416 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
9417 return -ret;
9418 }
9419 formatter->open_array_section("entries");
9420 bool truncated;
9421 int count = 0;
9422 if (max_entries < 0)
9423 max_entries = 1000;
9424
9425 const auto& logs = bucket->get_info().layout.logs;
9426 auto log_layout = std::reference_wrapper{logs.back()};
9427 if (gen) {
9428 auto i = std::find_if(logs.begin(), logs.end(), rgw::matches_gen(*gen));
9429 if (i == logs.end()) {
9430 cerr << "ERROR: no log layout with gen=" << *gen << std::endl;
9431 return ENOENT;
9432 }
9433 log_layout = *i;
9434 }
9435
9436 do {
9437 list<rgw_bi_log_entry> entries;
9438 ret = static_cast<rgw::sal::RadosStore*>(driver)->svc()->bilog_rados->log_list(dpp(), bucket->get_info(), log_layout, shard_id, marker, max_entries - count, entries, &truncated);
9439 if (ret < 0) {
9440 cerr << "ERROR: list_bi_log_entries(): " << cpp_strerror(-ret) << std::endl;
9441 return -ret;
9442 }
9443
9444 count += entries.size();
9445
9446 for (list<rgw_bi_log_entry>::iterator iter = entries.begin(); iter != entries.end(); ++iter) {
9447 rgw_bi_log_entry& entry = *iter;
9448 encode_json("entry", entry, formatter.get());
9449
9450 marker = entry.id;
9451 }
9452 formatter->flush(cout);
9453 } while (truncated && count < max_entries);
9454
9455 formatter->close_section();
9456 formatter->flush(cout);
9457 }
9458
9459 if (opt_cmd == OPT::SYNC_ERROR_LIST) {
9460 if (max_entries < 0) {
9461 max_entries = 1000;
9462 }
9463 if (!start_date.empty()) {
9464 std::cerr << "start-date not allowed." << std::endl;
9465 return -EINVAL;
9466 }
9467 if (!end_date.empty()) {
9468 std::cerr << "end-date not allowed." << std::endl;
9469 return -EINVAL;
9470 }
9471 if (!end_marker.empty()) {
9472 std::cerr << "end-marker not allowed." << std::endl;
9473 return -EINVAL;
9474 }
9475 if (!start_marker.empty()) {
9476 if (marker.empty()) {
9477 marker = start_marker;
9478 } else {
9479 std::cerr << "start-marker and marker not both allowed." << std::endl;
9480 return -EINVAL;
9481 }
9482 }
9483
9484 bool truncated;
9485
9486 if (shard_id < 0) {
9487 shard_id = 0;
9488 }
9489
9490 formatter->open_array_section("entries");
9491
9492 for (; shard_id < ERROR_LOGGER_SHARDS; ++shard_id) {
9493 formatter->open_object_section("shard");
9494 encode_json("shard_id", shard_id, formatter.get());
9495 formatter->open_array_section("entries");
9496
9497 int count = 0;
9498 string oid = RGWSyncErrorLogger::get_shard_oid(RGW_SYNC_ERROR_LOG_SHARD_PREFIX, shard_id);
9499
9500 do {
9501 list<cls_log_entry> entries;
9502 ret = static_cast<rgw::sal::RadosStore*>(driver)->svc()->cls->timelog.list(dpp(), oid, {}, {}, max_entries - count, entries, marker, &marker, &truncated,
9503 null_yield);
9504 if (ret == -ENOENT) {
9505 break;
9506 }
9507 if (ret < 0) {
9508 cerr << "ERROR: svc.cls->timelog.list(): " << cpp_strerror(-ret) << std::endl;
9509 return -ret;
9510 }
9511
9512 count += entries.size();
9513
9514 for (auto& cls_entry : entries) {
9515 rgw_sync_error_info log_entry;
9516
9517 auto iter = cls_entry.data.cbegin();
9518 try {
9519 decode(log_entry, iter);
9520 } catch (buffer::error& err) {
9521 cerr << "ERROR: failed to decode log entry" << std::endl;
9522 continue;
9523 }
9524 formatter->open_object_section("entry");
9525 encode_json("id", cls_entry.id, formatter.get());
9526 encode_json("section", cls_entry.section, formatter.get());
9527 encode_json("name", cls_entry.name, formatter.get());
9528 encode_json("timestamp", cls_entry.timestamp, formatter.get());
9529 encode_json("info", log_entry, formatter.get());
9530 formatter->close_section();
9531 formatter->flush(cout);
9532 }
9533 } while (truncated && count < max_entries);
9534
9535 formatter->close_section();
9536 formatter->close_section();
9537
9538 if (specified_shard_id) {
9539 break;
9540 }
9541 }
9542
9543 formatter->close_section();
9544 formatter->flush(cout);
9545 }
9546
9547 if (opt_cmd == OPT::SYNC_ERROR_TRIM) {
9548 if (!start_date.empty()) {
9549 std::cerr << "start-date not allowed." << std::endl;
9550 return -EINVAL;
9551 }
9552 if (!end_date.empty()) {
9553 std::cerr << "end-date not allowed." << std::endl;
9554 return -EINVAL;
9555 }
9556 if (!start_marker.empty()) {
9557 std::cerr << "end-date not allowed." << std::endl;
9558 return -EINVAL;
9559 }
9560 if (!end_marker.empty()) {
9561 std::cerr << "end-date not allowed." << std::endl;
9562 return -EINVAL;
9563 }
9564
9565 if (shard_id < 0) {
9566 shard_id = 0;
9567 }
9568
9569 for (; shard_id < ERROR_LOGGER_SHARDS; ++shard_id) {
9570 ret = trim_sync_error_log(shard_id, marker, trim_delay_ms);
9571 if (ret < 0) {
9572 cerr << "ERROR: sync error trim: " << cpp_strerror(-ret) << std::endl;
9573 return -ret;
9574 }
9575 if (specified_shard_id) {
9576 break;
9577 }
9578 }
9579 }
9580
9581 if (opt_cmd == OPT::SYNC_GROUP_CREATE ||
9582 opt_cmd == OPT::SYNC_GROUP_MODIFY) {
9583 CHECK_TRUE(require_non_empty_opt(opt_group_id), "ERROR: --group-id not specified", EINVAL);
9584 CHECK_TRUE(require_opt(opt_status), "ERROR: --status is not specified (options: forbidden, allowed, enabled)", EINVAL);
9585
9586 SyncPolicyContext sync_policy_ctx(cfgstore.get(), opt_bucket);
9587 ret = sync_policy_ctx.init(zonegroup_id, zonegroup_name);
9588 if (ret < 0) {
9589 return -ret;
9590 }
9591 auto& sync_policy = sync_policy_ctx.get_policy();
9592
9593 if (opt_cmd == OPT::SYNC_GROUP_MODIFY) {
9594 auto iter = sync_policy.groups.find(*opt_group_id);
9595 if (iter == sync_policy.groups.end()) {
9596 cerr << "ERROR: could not find group '" << *opt_group_id << "'" << std::endl;
9597 return ENOENT;
9598 }
9599 }
9600
9601 auto& group = sync_policy.groups[*opt_group_id];
9602 group.id = *opt_group_id;
9603
9604 if (opt_status) {
9605 if (!group.set_status(*opt_status)) {
9606 cerr << "ERROR: unrecognized status (options: forbidden, allowed, enabled)" << std::endl;
9607 return EINVAL;
9608 }
9609 }
9610
9611 ret = sync_policy_ctx.write_policy();
9612 if (ret < 0) {
9613 return -ret;
9614 }
9615
9616 show_result(sync_policy, zone_formatter.get(), cout);
9617 }
9618
9619 if (opt_cmd == OPT::SYNC_GROUP_GET) {
9620 SyncPolicyContext sync_policy_ctx(cfgstore.get(), opt_bucket);
9621 ret = sync_policy_ctx.init(zonegroup_id, zonegroup_name);
9622 if (ret < 0) {
9623 return -ret;
9624 }
9625 auto& sync_policy = sync_policy_ctx.get_policy();
9626
9627 auto& groups = sync_policy.groups;
9628
9629 if (!opt_group_id) {
9630 show_result(groups, zone_formatter.get(), cout);
9631 } else {
9632 auto iter = sync_policy.groups.find(*opt_group_id);
9633 if (iter == sync_policy.groups.end()) {
9634 cerr << "ERROR: could not find group '" << *opt_group_id << "'" << std::endl;
9635 return ENOENT;
9636 }
9637
9638 show_result(iter->second, zone_formatter.get(), cout);
9639 }
9640 }
9641
9642 if (opt_cmd == OPT::SYNC_GROUP_REMOVE) {
9643 CHECK_TRUE(require_non_empty_opt(opt_group_id), "ERROR: --group-id not specified", EINVAL);
9644
9645 SyncPolicyContext sync_policy_ctx(cfgstore.get(), opt_bucket);
9646 ret = sync_policy_ctx.init(zonegroup_id, zonegroup_name);
9647 if (ret < 0) {
9648 return -ret;
9649 }
9650 auto& sync_policy = sync_policy_ctx.get_policy();
9651
9652 sync_policy.groups.erase(*opt_group_id);
9653
9654 ret = sync_policy_ctx.write_policy();
9655 if (ret < 0) {
9656 return -ret;
9657 }
9658
9659 {
9660 Formatter::ObjectSection os(*zone_formatter.get(), "result");
9661 encode_json("sync_policy", sync_policy, zone_formatter.get());
9662 }
9663
9664 zone_formatter->flush(cout);
9665 }
9666
9667 if (opt_cmd == OPT::SYNC_GROUP_FLOW_CREATE) {
9668 CHECK_TRUE(require_non_empty_opt(opt_group_id), "ERROR: --group-id not specified", EINVAL);
9669 CHECK_TRUE(require_non_empty_opt(opt_flow_id), "ERROR: --flow-id not specified", EINVAL);
9670 CHECK_TRUE(require_opt(opt_flow_type),
9671 "ERROR: --flow-type not specified (options: symmetrical, directional)", EINVAL);
9672 CHECK_TRUE((symmetrical_flow_opt(*opt_flow_type) ||
9673 directional_flow_opt(*opt_flow_type)),
9674 "ERROR: --flow-type invalid (options: symmetrical, directional)", EINVAL);
9675
9676 SyncPolicyContext sync_policy_ctx(cfgstore.get(), opt_bucket);
9677 ret = sync_policy_ctx.init(zonegroup_id, zonegroup_name);
9678 if (ret < 0) {
9679 return -ret;
9680 }
9681 auto& sync_policy = sync_policy_ctx.get_policy();
9682
9683 auto iter = sync_policy.groups.find(*opt_group_id);
9684 if (iter == sync_policy.groups.end()) {
9685 cerr << "ERROR: could not find group '" << *opt_group_id << "'" << std::endl;
9686 return ENOENT;
9687 }
9688
9689 auto& group = iter->second;
9690
9691 if (symmetrical_flow_opt(*opt_flow_type)) {
9692 CHECK_TRUE(require_non_empty_opt(opt_zone_ids), "ERROR: --zones not provided for symmetrical flow, or is empty", EINVAL);
9693
9694 rgw_sync_symmetric_group *flow_group;
9695
9696 group.data_flow.find_or_create_symmetrical(*opt_flow_id, &flow_group);
9697
9698 for (auto& z : *opt_zone_ids) {
9699 flow_group->zones.insert(z);
9700 }
9701 } else { /* directional */
9702 CHECK_TRUE(require_non_empty_opt(opt_source_zone_id), "ERROR: --source-zone not provided for directional flow rule, or is empty", EINVAL);
9703 CHECK_TRUE(require_non_empty_opt(opt_dest_zone_id), "ERROR: --dest-zone not provided for directional flow rule, or is empty", EINVAL);
9704
9705 rgw_sync_directional_rule *flow_rule;
9706
9707 group.data_flow.find_or_create_directional(*opt_source_zone_id, *opt_dest_zone_id, &flow_rule);
9708 }
9709
9710 ret = sync_policy_ctx.write_policy();
9711 if (ret < 0) {
9712 return -ret;
9713 }
9714
9715 show_result(sync_policy, zone_formatter.get(), cout);
9716 }
9717
9718 if (opt_cmd == OPT::SYNC_GROUP_FLOW_REMOVE) {
9719 CHECK_TRUE(require_non_empty_opt(opt_group_id), "ERROR: --group-id not specified", EINVAL);
9720 CHECK_TRUE(require_non_empty_opt(opt_flow_id), "ERROR: --flow-id not specified", EINVAL);
9721 CHECK_TRUE(require_opt(opt_flow_type),
9722 "ERROR: --flow-type not specified (options: symmetrical, directional)", EINVAL);
9723 CHECK_TRUE((symmetrical_flow_opt(*opt_flow_type) ||
9724 directional_flow_opt(*opt_flow_type)),
9725 "ERROR: --flow-type invalid (options: symmetrical, directional)", EINVAL);
9726
9727 SyncPolicyContext sync_policy_ctx(cfgstore.get(), opt_bucket);
9728 ret = sync_policy_ctx.init(zonegroup_id, zonegroup_name);
9729 if (ret < 0) {
9730 return -ret;
9731 }
9732 auto& sync_policy = sync_policy_ctx.get_policy();
9733
9734 auto iter = sync_policy.groups.find(*opt_group_id);
9735 if (iter == sync_policy.groups.end()) {
9736 cerr << "ERROR: could not find group '" << *opt_group_id << "'" << std::endl;
9737 return ENOENT;
9738 }
9739
9740 auto& group = iter->second;
9741
9742 if (symmetrical_flow_opt(*opt_flow_type)) {
9743 group.data_flow.remove_symmetrical(*opt_flow_id, opt_zone_ids);
9744 } else { /* directional */
9745 CHECK_TRUE(require_non_empty_opt(opt_source_zone_id), "ERROR: --source-zone not provided for directional flow rule, or is empty", EINVAL);
9746 CHECK_TRUE(require_non_empty_opt(opt_dest_zone_id), "ERROR: --dest-zone not provided for directional flow rule, or is empty", EINVAL);
9747
9748 group.data_flow.remove_directional(*opt_source_zone_id, *opt_dest_zone_id);
9749 }
9750
9751 ret = sync_policy_ctx.write_policy();
9752 if (ret < 0) {
9753 return -ret;
9754 }
9755
9756 show_result(sync_policy, zone_formatter.get(), cout);
9757 }
9758
9759 if (opt_cmd == OPT::SYNC_GROUP_PIPE_CREATE ||
9760 opt_cmd == OPT::SYNC_GROUP_PIPE_MODIFY) {
9761 CHECK_TRUE(require_non_empty_opt(opt_group_id), "ERROR: --group-id not specified", EINVAL);
9762 CHECK_TRUE(require_non_empty_opt(opt_pipe_id), "ERROR: --pipe-id not specified", EINVAL);
9763 if (opt_cmd == OPT::SYNC_GROUP_PIPE_CREATE) {
9764 CHECK_TRUE(require_non_empty_opt(opt_source_zone_ids), "ERROR: --source-zones not provided or is empty; should be list of zones or '*'", EINVAL);
9765 CHECK_TRUE(require_non_empty_opt(opt_dest_zone_ids), "ERROR: --dest-zones not provided or is empty; should be list of zones or '*'", EINVAL);
9766 }
9767
9768 SyncPolicyContext sync_policy_ctx(cfgstore.get(), opt_bucket);
9769 ret = sync_policy_ctx.init(zonegroup_id, zonegroup_name);
9770 if (ret < 0) {
9771 return -ret;
9772 }
9773 auto& sync_policy = sync_policy_ctx.get_policy();
9774
9775 auto iter = sync_policy.groups.find(*opt_group_id);
9776 if (iter == sync_policy.groups.end()) {
9777 cerr << "ERROR: could not find group '" << *opt_group_id << "'" << std::endl;
9778 return ENOENT;
9779 }
9780
9781 auto& group = iter->second;
9782
9783 rgw_sync_bucket_pipes *pipe;
9784
9785 if (opt_cmd == OPT::SYNC_GROUP_PIPE_CREATE) {
9786 group.find_pipe(*opt_pipe_id, true, &pipe);
9787 } else {
9788 if (!group.find_pipe(*opt_pipe_id, false, &pipe)) {
9789 cerr << "ERROR: could not find pipe '" << *opt_pipe_id << "'" << std::endl;
9790 return ENOENT;
9791 }
9792 }
9793
9794 if (opt_source_zone_ids) {
9795 pipe->source.add_zones(*opt_source_zone_ids);
9796 }
9797 pipe->source.set_bucket(opt_source_tenant,
9798 opt_source_bucket_name,
9799 opt_source_bucket_id);
9800 if (opt_dest_zone_ids) {
9801 pipe->dest.add_zones(*opt_dest_zone_ids);
9802 }
9803 pipe->dest.set_bucket(opt_dest_tenant,
9804 opt_dest_bucket_name,
9805 opt_dest_bucket_id);
9806
9807 pipe->params.source.filter.set_prefix(opt_prefix, !!opt_prefix_rm);
9808 pipe->params.source.filter.set_tags(tags_add, tags_rm);
9809 if (opt_dest_owner) {
9810 pipe->params.dest.set_owner(*opt_dest_owner);
9811 }
9812 if (opt_storage_class) {
9813 pipe->params.dest.set_storage_class(*opt_storage_class);
9814 }
9815 if (opt_priority) {
9816 pipe->params.priority = *opt_priority;
9817 }
9818 if (opt_mode) {
9819 if (*opt_mode == "system") {
9820 pipe->params.mode = rgw_sync_pipe_params::MODE_SYSTEM;
9821 } else if (*opt_mode == "user") {
9822 pipe->params.mode = rgw_sync_pipe_params::MODE_USER;
9823 } else {
9824 cerr << "ERROR: bad mode value: should be one of the following: system, user" << std::endl;
9825 return EINVAL;
9826 }
9827 }
9828
9829 if (!rgw::sal::User::empty(user)) {
9830 pipe->params.user = user->get_id();
9831 } else if (pipe->params.user.empty()) {
9832 auto owner = sync_policy_ctx.get_owner();
9833 if (owner) {
9834 pipe->params.user = *owner;
9835 }
9836 }
9837
9838 ret = sync_policy_ctx.write_policy();
9839 if (ret < 0) {
9840 return -ret;
9841 }
9842
9843 show_result(sync_policy, zone_formatter.get(), cout);
9844 }
9845
9846 if (opt_cmd == OPT::SYNC_GROUP_PIPE_REMOVE) {
9847 CHECK_TRUE(require_non_empty_opt(opt_group_id), "ERROR: --group-id not specified", EINVAL);
9848 CHECK_TRUE(require_non_empty_opt(opt_pipe_id), "ERROR: --pipe-id not specified", EINVAL);
9849
9850 SyncPolicyContext sync_policy_ctx(cfgstore.get(), opt_bucket);
9851 ret = sync_policy_ctx.init(zonegroup_id, zonegroup_name);
9852 if (ret < 0) {
9853 return -ret;
9854 }
9855 auto& sync_policy = sync_policy_ctx.get_policy();
9856
9857 auto iter = sync_policy.groups.find(*opt_group_id);
9858 if (iter == sync_policy.groups.end()) {
9859 cerr << "ERROR: could not find group '" << *opt_group_id << "'" << std::endl;
9860 return ENOENT;
9861 }
9862
9863 auto& group = iter->second;
9864
9865 rgw_sync_bucket_pipes *pipe;
9866
9867 if (!group.find_pipe(*opt_pipe_id, false, &pipe)) {
9868 cerr << "ERROR: could not find pipe '" << *opt_pipe_id << "'" << std::endl;
9869 return ENOENT;
9870 }
9871
9872 if (opt_source_zone_ids) {
9873 pipe->source.remove_zones(*opt_source_zone_ids);
9874 }
9875
9876 pipe->source.remove_bucket(opt_source_tenant,
9877 opt_source_bucket_name,
9878 opt_source_bucket_id);
9879 if (opt_dest_zone_ids) {
9880 pipe->dest.remove_zones(*opt_dest_zone_ids);
9881 }
9882 pipe->dest.remove_bucket(opt_dest_tenant,
9883 opt_dest_bucket_name,
9884 opt_dest_bucket_id);
9885
9886 if (!(opt_source_zone_ids ||
9887 opt_source_tenant ||
9888 opt_source_bucket ||
9889 opt_source_bucket_id ||
9890 opt_dest_zone_ids ||
9891 opt_dest_tenant ||
9892 opt_dest_bucket ||
9893 opt_dest_bucket_id)) {
9894 group.remove_pipe(*opt_pipe_id);
9895 }
9896
9897 ret = sync_policy_ctx.write_policy();
9898 if (ret < 0) {
9899 return -ret;
9900 }
9901
9902 show_result(sync_policy, zone_formatter.get(), cout);
9903 }
9904
9905 if (opt_cmd == OPT::SYNC_POLICY_GET) {
9906 SyncPolicyContext sync_policy_ctx(cfgstore.get(), opt_bucket);
9907 ret = sync_policy_ctx.init(zonegroup_id, zonegroup_name);
9908 if (ret < 0) {
9909 return -ret;
9910 }
9911 auto& sync_policy = sync_policy_ctx.get_policy();
9912
9913 show_result(sync_policy, zone_formatter.get(), cout);
9914 }
9915
9916 if (opt_cmd == OPT::BILOG_TRIM) {
9917 if (bucket_name.empty()) {
9918 cerr << "ERROR: bucket not specified" << std::endl;
9919 return EINVAL;
9920 }
9921 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
9922 if (ret < 0) {
9923 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
9924 return -ret;
9925 }
9926
9927 if (!gen) {
9928 gen = 0;
9929 }
9930 ret = bilog_trim(dpp(), static_cast<rgw::sal::RadosStore*>(driver),
9931 bucket->get_info(), *gen,
9932 shard_id, start_marker, end_marker);
9933 if (ret < 0) {
9934 cerr << "ERROR: trim_bi_log_entries(): " << cpp_strerror(-ret) << std::endl;
9935 return -ret;
9936 }
9937 }
9938
9939 if (opt_cmd == OPT::BILOG_STATUS) {
9940 if (bucket_name.empty()) {
9941 cerr << "ERROR: bucket not specified" << std::endl;
9942 return EINVAL;
9943 }
9944 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
9945 if (ret < 0) {
9946 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
9947 return -ret;
9948 }
9949 map<int, string> markers;
9950 const auto& logs = bucket->get_info().layout.logs;
9951 auto log_layout = std::reference_wrapper{logs.back()};
9952 if (gen) {
9953 auto i = std::find_if(logs.begin(), logs.end(), rgw::matches_gen(*gen));
9954 if (i == logs.end()) {
9955 cerr << "ERROR: no log layout with gen=" << *gen << std::endl;
9956 return ENOENT;
9957 }
9958 log_layout = *i;
9959 }
9960
9961 ret = static_cast<rgw::sal::RadosStore*>(driver)->svc()->bilog_rados->get_log_status(dpp(), bucket->get_info(), log_layout, shard_id,
9962 &markers, null_yield);
9963 if (ret < 0) {
9964 cerr << "ERROR: get_bi_log_status(): " << cpp_strerror(-ret) << std::endl;
9965 return -ret;
9966 }
9967 formatter->open_object_section("entries");
9968 encode_json("markers", markers, formatter.get());
9969 formatter->dump_string("current_time",
9970 to_iso_8601(ceph::real_clock::now(),
9971 iso_8601_format::YMDhms));
9972 formatter->close_section();
9973 formatter->flush(cout);
9974 }
9975
9976 if (opt_cmd == OPT::BILOG_AUTOTRIM) {
9977 RGWCoroutinesManager crs(driver->ctx(), driver->get_cr_registry());
9978 RGWHTTPManager http(driver->ctx(), crs.get_completion_mgr());
9979 int ret = http.start();
9980 if (ret < 0) {
9981 cerr << "failed to initialize http client with " << cpp_strerror(ret) << std::endl;
9982 return -ret;
9983 }
9984
9985 rgw::BucketTrimConfig config;
9986 configure_bucket_trim(driver->ctx(), config);
9987
9988 rgw::BucketTrimManager trim(static_cast<rgw::sal::RadosStore*>(driver), config);
9989 ret = trim.init();
9990 if (ret < 0) {
9991 cerr << "trim manager init failed with " << cpp_strerror(ret) << std::endl;
9992 return -ret;
9993 }
9994 ret = crs.run(dpp(), trim.create_admin_bucket_trim_cr(&http));
9995 if (ret < 0) {
9996 cerr << "automated bilog trim failed with " << cpp_strerror(ret) << std::endl;
9997 return -ret;
9998 }
9999 }
10000
10001 if (opt_cmd == OPT::DATALOG_LIST) {
10002 formatter->open_array_section("entries");
10003 bool truncated;
10004 int count = 0;
10005 if (max_entries < 0)
10006 max_entries = 1000;
10007 if (!start_date.empty()) {
10008 std::cerr << "start-date not allowed." << std::endl;
10009 return -EINVAL;
10010 }
10011 if (!end_date.empty()) {
10012 std::cerr << "end-date not allowed." << std::endl;
10013 return -EINVAL;
10014 }
10015 if (!end_marker.empty()) {
10016 std::cerr << "end-marker not allowed." << std::endl;
10017 return -EINVAL;
10018 }
10019 if (!start_marker.empty()) {
10020 if (marker.empty()) {
10021 marker = start_marker;
10022 } else {
10023 std::cerr << "start-marker and marker not both allowed." << std::endl;
10024 return -EINVAL;
10025 }
10026 }
10027
10028 auto datalog_svc = static_cast<rgw::sal::RadosStore*>(driver)->svc()->datalog_rados;
10029 RGWDataChangesLog::LogMarker log_marker;
10030
10031 do {
10032 std::vector<rgw_data_change_log_entry> entries;
10033 if (specified_shard_id) {
10034 ret = datalog_svc->list_entries(dpp(), shard_id, max_entries - count,
10035 entries, marker,
10036 &marker, &truncated,
10037 null_yield);
10038 } else {
10039 ret = datalog_svc->list_entries(dpp(), max_entries - count, entries,
10040 log_marker, &truncated, null_yield);
10041 }
10042 if (ret < 0) {
10043 cerr << "ERROR: datalog_svc->list_entries(): " << cpp_strerror(-ret) << std::endl;
10044 return -ret;
10045 }
10046
10047 count += entries.size();
10048
10049 for (const auto& entry : entries) {
10050 if (!extra_info) {
10051 encode_json("entry", entry.entry, formatter.get());
10052 } else {
10053 encode_json("entry", entry, formatter.get());
10054 }
10055 }
10056 formatter.get()->flush(cout);
10057 } while (truncated && count < max_entries);
10058
10059 formatter->close_section();
10060 formatter->flush(cout);
10061 }
10062
10063 if (opt_cmd == OPT::DATALOG_STATUS) {
10064 int i = (specified_shard_id ? shard_id : 0);
10065
10066 formatter->open_array_section("entries");
10067 for (; i < g_ceph_context->_conf->rgw_data_log_num_shards; i++) {
10068 list<cls_log_entry> entries;
10069
10070 RGWDataChangesLogInfo info;
10071 static_cast<rgw::sal::RadosStore*>(driver)->svc()->
10072 datalog_rados->get_info(dpp(), i, &info, null_yield);
10073
10074 ::encode_json("info", info, formatter.get());
10075
10076 if (specified_shard_id)
10077 break;
10078 }
10079
10080 formatter->close_section();
10081 formatter->flush(cout);
10082 }
10083
10084 if (opt_cmd == OPT::DATALOG_AUTOTRIM) {
10085 RGWCoroutinesManager crs(driver->ctx(), driver->get_cr_registry());
10086 RGWHTTPManager http(driver->ctx(), crs.get_completion_mgr());
10087 int ret = http.start();
10088 if (ret < 0) {
10089 cerr << "failed to initialize http client with " << cpp_strerror(ret) << std::endl;
10090 return -ret;
10091 }
10092
10093 auto num_shards = g_conf()->rgw_data_log_num_shards;
10094 std::vector<std::string> markers(num_shards);
10095 ret = crs.run(dpp(), create_admin_data_log_trim_cr(dpp(), static_cast<rgw::sal::RadosStore*>(driver), &http, num_shards, markers));
10096 if (ret < 0) {
10097 cerr << "automated datalog trim failed with " << cpp_strerror(ret) << std::endl;
10098 return -ret;
10099 }
10100 }
10101
10102 if (opt_cmd == OPT::DATALOG_TRIM) {
10103 if (!start_date.empty()) {
10104 std::cerr << "start-date not allowed." << std::endl;
10105 return -EINVAL;
10106 }
10107 if (!end_date.empty()) {
10108 std::cerr << "end-date not allowed." << std::endl;
10109 return -EINVAL;
10110 }
10111 if (!start_marker.empty()) {
10112 std::cerr << "start-marker not allowed." << std::endl;
10113 return -EINVAL;
10114 }
10115 if (!end_marker.empty()) {
10116 if (marker.empty()) {
10117 marker = end_marker;
10118 } else {
10119 std::cerr << "end-marker and marker not both allowed." << std::endl;
10120 return -EINVAL;
10121 }
10122 }
10123
10124 if (!specified_shard_id) {
10125 cerr << "ERROR: requires a --shard-id" << std::endl;
10126 return EINVAL;
10127 }
10128
10129 if (marker.empty()) {
10130 cerr << "ERROR: requires a --marker" << std::endl;
10131 return EINVAL;
10132 }
10133
10134 auto datalog = static_cast<rgw::sal::RadosStore*>(driver)->svc()->datalog_rados;
10135 ret = datalog->trim_entries(dpp(), shard_id, marker, null_yield);
10136
10137 if (ret < 0 && ret != -ENODATA) {
10138 cerr << "ERROR: trim_entries(): " << cpp_strerror(-ret) << std::endl;
10139 return -ret;
10140 }
10141 }
10142
10143 if (opt_cmd == OPT::DATALOG_TYPE) {
10144 if (!opt_log_type) {
10145 std::cerr << "log-type not specified." << std::endl;
10146 return -EINVAL;
10147 }
10148 auto datalog = static_cast<rgw::sal::RadosStore*>(driver)->svc()->datalog_rados;
10149 ret = datalog->change_format(dpp(), *opt_log_type, null_yield);
10150 if (ret < 0) {
10151 cerr << "ERROR: change_format(): " << cpp_strerror(-ret) << std::endl;
10152 return -ret;
10153 }
10154 }
10155
10156 if (opt_cmd == OPT::DATALOG_PRUNE) {
10157 auto datalog = static_cast<rgw::sal::RadosStore*>(driver)->svc()->datalog_rados;
10158 std::optional<uint64_t> through;
10159 ret = datalog->trim_generations(dpp(), through, null_yield);
10160
10161 if (ret < 0) {
10162 cerr << "ERROR: trim_generations(): " << cpp_strerror(-ret) << std::endl;
10163 return -ret;
10164 }
10165
10166 if (through) {
10167 std::cout << "Pruned " << *through << " empty generations." << std::endl;
10168 } else {
10169 std::cout << "No empty generations." << std::endl;
10170 }
10171 }
10172
10173 bool quota_op = (opt_cmd == OPT::QUOTA_SET || opt_cmd == OPT::QUOTA_ENABLE || opt_cmd == OPT::QUOTA_DISABLE);
10174
10175 if (quota_op) {
10176 if (bucket_name.empty() && rgw::sal::User::empty(user)) {
10177 cerr << "ERROR: bucket name or uid is required for quota operation" << std::endl;
10178 return EINVAL;
10179 }
10180
10181 if (!bucket_name.empty()) {
10182 if (!quota_scope.empty() && quota_scope != "bucket") {
10183 cerr << "ERROR: invalid quota scope specification." << std::endl;
10184 return EINVAL;
10185 }
10186 set_bucket_quota(driver, opt_cmd, tenant, bucket_name,
10187 max_size, max_objects, have_max_size, have_max_objects);
10188 } else if (!rgw::sal::User::empty(user)) {
10189 if (quota_scope == "bucket") {
10190 return set_user_bucket_quota(opt_cmd, ruser, user_op, max_size, max_objects, have_max_size, have_max_objects);
10191 } else if (quota_scope == "user") {
10192 return set_user_quota(opt_cmd, ruser, user_op, max_size, max_objects, have_max_size, have_max_objects);
10193 } else {
10194 cerr << "ERROR: invalid quota scope specification. Please specify either --quota-scope=bucket, or --quota-scope=user" << std::endl;
10195 return EINVAL;
10196 }
10197 }
10198 }
10199
10200 bool ratelimit_op_set = (opt_cmd == OPT::RATELIMIT_SET || opt_cmd == OPT::RATELIMIT_ENABLE || opt_cmd == OPT::RATELIMIT_DISABLE);
10201 bool ratelimit_op_get = opt_cmd == OPT::RATELIMIT_GET;
10202 if (ratelimit_op_set) {
10203 if (bucket_name.empty() && rgw::sal::User::empty(user)) {
10204 cerr << "ERROR: bucket name or uid is required for ratelimit operation" << std::endl;
10205 return EINVAL;
10206 }
10207
10208 if (!bucket_name.empty()) {
10209 if (!ratelimit_scope.empty() && ratelimit_scope != "bucket") {
10210 cerr << "ERROR: invalid ratelimit scope specification. (bucket scope is not bucket but bucket has been specified)" << std::endl;
10211 return EINVAL;
10212 }
10213 return set_bucket_ratelimit(driver, opt_cmd, tenant, bucket_name,
10214 max_read_ops, max_write_ops,
10215 max_read_bytes, max_write_bytes,
10216 have_max_read_ops, have_max_write_ops,
10217 have_max_read_bytes, have_max_write_bytes);
10218 } else if (!rgw::sal::User::empty(user)) {
10219 } if (ratelimit_scope == "user") {
10220 return set_user_ratelimit(opt_cmd, user, max_read_ops, max_write_ops,
10221 max_read_bytes, max_write_bytes,
10222 have_max_read_ops, have_max_write_ops,
10223 have_max_read_bytes, have_max_write_bytes);
10224 } else {
10225 cerr << "ERROR: invalid ratelimit scope specification. Please specify either --ratelimit-scope=bucket, or --ratelimit-scope=user" << std::endl;
10226 return EINVAL;
10227 }
10228 }
10229
10230 if (ratelimit_op_get) {
10231 if (bucket_name.empty() && rgw::sal::User::empty(user)) {
10232 cerr << "ERROR: bucket name or uid is required for ratelimit operation" << std::endl;
10233 return EINVAL;
10234 }
10235
10236 if (!bucket_name.empty()) {
10237 if (!ratelimit_scope.empty() && ratelimit_scope != "bucket") {
10238 cerr << "ERROR: invalid ratelimit scope specification. (bucket scope is not bucket but bucket has been specified)" << std::endl;
10239 return EINVAL;
10240 }
10241 return show_bucket_ratelimit(driver, tenant, bucket_name, formatter.get());
10242 } else if (!rgw::sal::User::empty(user)) {
10243 } if (ratelimit_scope == "user") {
10244 return show_user_ratelimit(user, formatter.get());
10245 } else {
10246 cerr << "ERROR: invalid ratelimit scope specification. Please specify either --ratelimit-scope=bucket, or --ratelimit-scope=user" << std::endl;
10247 return EINVAL;
10248 }
10249 }
10250
10251 if (opt_cmd == OPT::MFA_CREATE) {
10252 rados::cls::otp::otp_info_t config;
10253
10254 if (rgw::sal::User::empty(user)) {
10255 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
10256 return EINVAL;
10257 }
10258
10259 if (totp_serial.empty()) {
10260 cerr << "ERROR: TOTP device serial number was not provided (via --totp-serial)" << std::endl;
10261 return EINVAL;
10262 }
10263
10264 if (totp_seed.empty()) {
10265 cerr << "ERROR: TOTP device seed was not provided (via --totp-seed)" << std::endl;
10266 return EINVAL;
10267 }
10268
10269
10270 rados::cls::otp::SeedType seed_type;
10271 if (totp_seed_type == "hex") {
10272 seed_type = rados::cls::otp::OTP_SEED_HEX;
10273 } else if (totp_seed_type == "base32") {
10274 seed_type = rados::cls::otp::OTP_SEED_BASE32;
10275 } else {
10276 cerr << "ERROR: invalid seed type: " << totp_seed_type << std::endl;
10277 return EINVAL;
10278 }
10279
10280 config.id = totp_serial;
10281 config.seed = totp_seed;
10282 config.seed_type = seed_type;
10283
10284 if (totp_seconds > 0) {
10285 config.step_size = totp_seconds;
10286 }
10287
10288 if (totp_window > 0) {
10289 config.window = totp_window;
10290 }
10291
10292 real_time mtime = real_clock::now();
10293 string oid = static_cast<rgw::sal::RadosStore*>(driver)->svc()->cls->mfa.get_mfa_oid(user->get_id());
10294
10295 int ret = static_cast<rgw::sal::RadosStore*>(driver)->ctl()->meta.mgr->mutate(RGWSI_MetaBackend_OTP::get_meta_key(user->get_id()),
10296 mtime, &objv_tracker,
10297 null_yield, dpp(),
10298 MDLOG_STATUS_WRITE,
10299 [&] {
10300 return static_cast<rgw::sal::RadosStore*>(driver)->svc()->cls->mfa.create_mfa(dpp(), user->get_id(), config, &objv_tracker, mtime, null_yield);
10301 });
10302 if (ret < 0) {
10303 cerr << "MFA creation failed, error: " << cpp_strerror(-ret) << std::endl;
10304 return -ret;
10305 }
10306
10307 RGWUserInfo& user_info = user_op.get_user_info();
10308 user_info.mfa_ids.insert(totp_serial);
10309 user_op.set_mfa_ids(user_info.mfa_ids);
10310 string err;
10311 ret = ruser.modify(dpp(), user_op, null_yield, &err);
10312 if (ret < 0) {
10313 cerr << "ERROR: failed storing user info, error: " << err << std::endl;
10314 return -ret;
10315 }
10316 }
10317
10318 if (opt_cmd == OPT::MFA_REMOVE) {
10319 if (rgw::sal::User::empty(user)) {
10320 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
10321 return EINVAL;
10322 }
10323
10324 if (totp_serial.empty()) {
10325 cerr << "ERROR: TOTP device serial number was not provided (via --totp-serial)" << std::endl;
10326 return EINVAL;
10327 }
10328
10329 real_time mtime = real_clock::now();
10330
10331 int ret = static_cast<rgw::sal::RadosStore*>(driver)->ctl()->meta.mgr->mutate(RGWSI_MetaBackend_OTP::get_meta_key(user->get_id()),
10332 mtime, &objv_tracker,
10333 null_yield, dpp(),
10334 MDLOG_STATUS_WRITE,
10335 [&] {
10336 return static_cast<rgw::sal::RadosStore*>(driver)->svc()->cls->mfa.remove_mfa(dpp(), user->get_id(), totp_serial, &objv_tracker, mtime, null_yield);
10337 });
10338 if (ret < 0) {
10339 cerr << "MFA removal failed, error: " << cpp_strerror(-ret) << std::endl;
10340 return -ret;
10341 }
10342
10343 RGWUserInfo& user_info = user_op.get_user_info();
10344 user_info.mfa_ids.erase(totp_serial);
10345 user_op.set_mfa_ids(user_info.mfa_ids);
10346 string err;
10347 ret = ruser.modify(dpp(), user_op, null_yield, &err);
10348 if (ret < 0) {
10349 cerr << "ERROR: failed storing user info, error: " << err << std::endl;
10350 return -ret;
10351 }
10352 }
10353
10354 if (opt_cmd == OPT::MFA_GET) {
10355 if (rgw::sal::User::empty(user)) {
10356 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
10357 return EINVAL;
10358 }
10359
10360 if (totp_serial.empty()) {
10361 cerr << "ERROR: TOTP device serial number was not provided (via --totp-serial)" << std::endl;
10362 return EINVAL;
10363 }
10364
10365 rados::cls::otp::otp_info_t result;
10366 int ret = static_cast<rgw::sal::RadosStore*>(driver)->svc()->cls->mfa.get_mfa(dpp(), user->get_id(), totp_serial, &result, null_yield);
10367 if (ret < 0) {
10368 if (ret == -ENOENT || ret == -ENODATA) {
10369 cerr << "MFA serial id not found" << std::endl;
10370 } else {
10371 cerr << "MFA retrieval failed, error: " << cpp_strerror(-ret) << std::endl;
10372 }
10373 return -ret;
10374 }
10375 formatter->open_object_section("result");
10376 encode_json("entry", result, formatter.get());
10377 formatter->close_section();
10378 formatter->flush(cout);
10379 }
10380
10381 if (opt_cmd == OPT::MFA_LIST) {
10382 if (rgw::sal::User::empty(user)) {
10383 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
10384 return EINVAL;
10385 }
10386
10387 list<rados::cls::otp::otp_info_t> result;
10388 int ret = static_cast<rgw::sal::RadosStore*>(driver)->svc()->cls->mfa.list_mfa(dpp(), user->get_id(), &result, null_yield);
10389 if (ret < 0 && ret != -ENOENT) {
10390 cerr << "MFA listing failed, error: " << cpp_strerror(-ret) << std::endl;
10391 return -ret;
10392 }
10393 formatter->open_object_section("result");
10394 encode_json("entries", result, formatter.get());
10395 formatter->close_section();
10396 formatter->flush(cout);
10397 }
10398
10399 if (opt_cmd == OPT::MFA_CHECK) {
10400 if (rgw::sal::User::empty(user)) {
10401 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
10402 return EINVAL;
10403 }
10404
10405 if (totp_serial.empty()) {
10406 cerr << "ERROR: TOTP device serial number was not provided (via --totp-serial)" << std::endl;
10407 return EINVAL;
10408 }
10409
10410 if (totp_pin.empty()) {
10411 cerr << "ERROR: TOTP device serial number was not provided (via --totp-pin)" << std::endl;
10412 return EINVAL;
10413 }
10414
10415 list<rados::cls::otp::otp_info_t> result;
10416 int ret = static_cast<rgw::sal::RadosStore*>(driver)->svc()->cls->mfa.check_mfa(dpp(), user->get_id(), totp_serial, totp_pin.front(), null_yield);
10417 if (ret < 0) {
10418 cerr << "MFA check failed, error: " << cpp_strerror(-ret) << std::endl;
10419 return -ret;
10420 }
10421
10422 cout << "ok" << std::endl;
10423 }
10424
10425 if (opt_cmd == OPT::MFA_RESYNC) {
10426 if (rgw::sal::User::empty(user)) {
10427 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
10428 return EINVAL;
10429 }
10430
10431 if (totp_serial.empty()) {
10432 cerr << "ERROR: TOTP device serial number was not provided (via --totp-serial)" << std::endl;
10433 return EINVAL;
10434 }
10435
10436 if (totp_pin.size() != 2) {
10437 cerr << "ERROR: missing two --totp-pin params (--totp-pin=<first> --totp-pin=<second>)" << std::endl;
10438 return EINVAL;
10439 }
10440
10441 rados::cls::otp::otp_info_t config;
10442 int ret = static_cast<rgw::sal::RadosStore*>(driver)->svc()->cls->mfa.get_mfa(dpp(), user->get_id(), totp_serial, &config, null_yield);
10443 if (ret < 0) {
10444 if (ret == -ENOENT || ret == -ENODATA) {
10445 cerr << "MFA serial id not found" << std::endl;
10446 } else {
10447 cerr << "MFA retrieval failed, error: " << cpp_strerror(-ret) << std::endl;
10448 }
10449 return -ret;
10450 }
10451
10452 ceph::real_time now;
10453
10454 ret = static_cast<rgw::sal::RadosStore*>(driver)->svc()->cls->mfa.otp_get_current_time(dpp(), user->get_id(), &now, null_yield);
10455 if (ret < 0) {
10456 cerr << "ERROR: failed to fetch current time from osd: " << cpp_strerror(-ret) << std::endl;
10457 return -ret;
10458 }
10459 time_t time_ofs;
10460
10461 ret = scan_totp(driver->ctx(), now, config, totp_pin, &time_ofs);
10462 if (ret < 0) {
10463 if (ret == -ENOENT) {
10464 cerr << "failed to resync, TOTP values not found in range" << std::endl;
10465 } else {
10466 cerr << "ERROR: failed to scan for TOTP values: " << cpp_strerror(-ret) << std::endl;
10467 }
10468 return -ret;
10469 }
10470
10471 config.time_ofs = time_ofs;
10472
10473 /* now update the backend */
10474 real_time mtime = real_clock::now();
10475
10476 ret = static_cast<rgw::sal::RadosStore*>(driver)->ctl()->meta.mgr->mutate(RGWSI_MetaBackend_OTP::get_meta_key(user->get_id()),
10477 mtime, &objv_tracker,
10478 null_yield, dpp(),
10479 MDLOG_STATUS_WRITE,
10480 [&] {
10481 return static_cast<rgw::sal::RadosStore*>(driver)->svc()->cls->mfa.create_mfa(dpp(), user->get_id(), config, &objv_tracker, mtime, null_yield);
10482 });
10483 if (ret < 0) {
10484 cerr << "MFA update failed, error: " << cpp_strerror(-ret) << std::endl;
10485 return -ret;
10486 }
10487
10488 }
10489
10490 if (opt_cmd == OPT::RESHARD_STALE_INSTANCES_LIST) {
10491 if (!static_cast<rgw::sal::RadosStore*>(driver)->svc()->zone->can_reshard() && !yes_i_really_mean_it) {
10492 cerr << "Resharding disabled in a multisite env, stale instances unlikely from resharding" << std::endl;
10493 cerr << "These instances may not be safe to delete." << std::endl;
10494 cerr << "Use --yes-i-really-mean-it to force displaying these instances." << std::endl;
10495 return EINVAL;
10496 }
10497
10498 ret = RGWBucketAdminOp::list_stale_instances(driver, bucket_op, stream_flusher, dpp());
10499 if (ret < 0) {
10500 cerr << "ERROR: listing stale instances" << cpp_strerror(-ret) << std::endl;
10501 }
10502 }
10503
10504 if (opt_cmd == OPT::RESHARD_STALE_INSTANCES_DELETE) {
10505 if (!static_cast<rgw::sal::RadosStore*>(driver)->svc()->zone->can_reshard()) {
10506 cerr << "Resharding disabled in a multisite env. Stale instances are not safe to be deleted." << std::endl;
10507 return EINVAL;
10508 }
10509
10510 ret = RGWBucketAdminOp::clear_stale_instances(driver, bucket_op, stream_flusher, dpp());
10511 if (ret < 0) {
10512 cerr << "ERROR: deleting stale instances" << cpp_strerror(-ret) << std::endl;
10513 }
10514 }
10515
10516 if (opt_cmd == OPT::PUBSUB_NOTIFICATION_LIST) {
10517 if (bucket_name.empty()) {
10518 cerr << "ERROR: bucket name was not provided (via --bucket)" << std::endl;
10519 return EINVAL;
10520 }
10521
10522 RGWPubSub ps(driver, tenant);
10523
10524 rgw_pubsub_bucket_topics result;
10525 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
10526 if (ret < 0) {
10527 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
10528 return -ret;
10529 }
10530
10531 const RGWPubSub::Bucket b(ps, bucket.get());
10532 ret = b.get_topics(dpp(), result, null_yield);
10533 if (ret < 0 && ret != -ENOENT) {
10534 cerr << "ERROR: could not get topics: " << cpp_strerror(-ret) << std::endl;
10535 return -ret;
10536 }
10537 encode_json("result", result, formatter.get());
10538 formatter->flush(cout);
10539 }
10540
10541 if (opt_cmd == OPT::PUBSUB_TOPIC_LIST) {
10542 RGWPubSub ps(driver, tenant);
10543
10544 rgw_pubsub_topics result;
10545 int ret = ps.get_topics(dpp(), result, null_yield);
10546 if (ret < 0 && ret != -ENOENT) {
10547 cerr << "ERROR: could not get topics: " << cpp_strerror(-ret) << std::endl;
10548 return -ret;
10549 }
10550 encode_json("result", result, formatter.get());
10551 formatter->flush(cout);
10552 }
10553
10554 if (opt_cmd == OPT::PUBSUB_TOPIC_GET) {
10555 if (topic_name.empty()) {
10556 cerr << "ERROR: topic name was not provided (via --topic)" << std::endl;
10557 return EINVAL;
10558 }
10559
10560 RGWPubSub ps(driver, tenant);
10561
10562 rgw_pubsub_topic topic;
10563 ret = ps.get_topic(dpp(), topic_name, topic, null_yield);
10564 if (ret < 0) {
10565 cerr << "ERROR: could not get topic: " << cpp_strerror(-ret) << std::endl;
10566 return -ret;
10567 }
10568 encode_json("topic", topic, formatter.get());
10569 formatter->flush(cout);
10570 }
10571
10572 if (opt_cmd == OPT::PUBSUB_NOTIFICATION_GET) {
10573 if (notification_id.empty()) {
10574 cerr << "ERROR: notification-id was not provided (via --notification-id)" << std::endl;
10575 return EINVAL;
10576 }
10577 if (bucket_name.empty()) {
10578 cerr << "ERROR: bucket name was not provided (via --bucket)" << std::endl;
10579 return EINVAL;
10580 }
10581
10582 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
10583 if (ret < 0) {
10584 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
10585 return -ret;
10586 }
10587
10588 RGWPubSub ps(driver, tenant);
10589
10590 rgw_pubsub_bucket_topics bucket_topics;
10591 const RGWPubSub::Bucket b(ps, bucket.get());
10592 ret = b.get_topics(dpp(), bucket_topics, null_yield);
10593 if (ret < 0 && ret != -ENOENT) {
10594 cerr << "ERROR: could not get bucket notifications: " << cpp_strerror(-ret) << std::endl;
10595 return -ret;
10596 }
10597
10598 rgw_pubsub_topic_filter bucket_topic;
10599 ret = b.get_notification_by_id(dpp(), notification_id, bucket_topic, null_yield);
10600 if (ret < 0) {
10601 cerr << "ERROR: could not get notification: " << cpp_strerror(-ret) << std::endl;
10602 return -ret;
10603 }
10604 encode_json("notification", bucket_topic, formatter.get());
10605 formatter->flush(cout);
10606 }
10607
10608 if (opt_cmd == OPT::PUBSUB_TOPIC_RM) {
10609 if (topic_name.empty()) {
10610 cerr << "ERROR: topic name was not provided (via --topic)" << std::endl;
10611 return EINVAL;
10612 }
10613
10614 ret = rgw::notify::remove_persistent_topic(dpp(), static_cast<rgw::sal::RadosStore*>(driver)->getRados()->get_notif_pool_ctx(), topic_name, null_yield);
10615 if (ret < 0) {
10616 cerr << "ERROR: could not remove persistent topic: " << cpp_strerror(-ret) << std::endl;
10617 return -ret;
10618 }
10619
10620 RGWPubSub ps(driver, tenant);
10621
10622 ret = ps.remove_topic(dpp(), topic_name, null_yield);
10623 if (ret < 0) {
10624 cerr << "ERROR: could not remove topic: " << cpp_strerror(-ret) << std::endl;
10625 return -ret;
10626 }
10627 }
10628
10629 if (opt_cmd == OPT::PUBSUB_NOTIFICATION_RM) {
10630 if (bucket_name.empty()) {
10631 cerr << "ERROR: bucket name was not provided (via --bucket)" << std::endl;
10632 return EINVAL;
10633 }
10634
10635 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
10636 if (ret < 0) {
10637 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
10638 return -ret;
10639 }
10640
10641 RGWPubSub ps(driver, tenant);
10642
10643 rgw_pubsub_bucket_topics bucket_topics;
10644 const RGWPubSub::Bucket b(ps, bucket.get());
10645 ret = b.get_topics(dpp(), bucket_topics, null_yield);
10646 if (ret < 0 && ret != -ENOENT) {
10647 cerr << "ERROR: could not get bucket notifications: " << cpp_strerror(-ret) << std::endl;
10648 return -ret;
10649 }
10650
10651 rgw_pubsub_topic_filter bucket_topic;
10652 if(notification_id.empty()) {
10653 ret = b.remove_notifications(dpp(), null_yield);
10654 } else {
10655 ret = b.remove_notification_by_id(dpp(), notification_id, null_yield);
10656 }
10657 }
10658
10659 if (opt_cmd == OPT::SCRIPT_PUT) {
10660 if (!str_script_ctx) {
10661 cerr << "ERROR: context was not provided (via --context)" << std::endl;
10662 return EINVAL;
10663 }
10664 if (infile.empty()) {
10665 cerr << "ERROR: infile was not provided (via --infile)" << std::endl;
10666 return EINVAL;
10667 }
10668 bufferlist bl;
10669 auto rc = read_input(infile, bl);
10670 if (rc < 0) {
10671 cerr << "ERROR: failed to read script: '" << infile << "'. error: " << rc << std::endl;
10672 return -rc;
10673 }
10674 const std::string script = bl.to_str();
10675 std::string err_msg;
10676 if (!rgw::lua::verify(script, err_msg)) {
10677 cerr << "ERROR: script: '" << infile << "' has error: " << std::endl << err_msg << std::endl;
10678 return EINVAL;
10679 }
10680 const rgw::lua::context script_ctx = rgw::lua::to_context(*str_script_ctx);
10681 if (script_ctx == rgw::lua::context::none) {
10682 cerr << "ERROR: invalid script context: " << *str_script_ctx << ". must be one of: " << LUA_CONTEXT_LIST << std::endl;
10683 return EINVAL;
10684 }
10685 if (script_ctx == rgw::lua::context::background && !tenant.empty()) {
10686 cerr << "ERROR: cannot specify tenant in background context" << std::endl;
10687 return EINVAL;
10688 }
10689 auto lua_manager = driver->get_lua_manager();
10690 rc = rgw::lua::write_script(dpp(), lua_manager.get(), tenant, null_yield, script_ctx, script);
10691 if (rc < 0) {
10692 cerr << "ERROR: failed to put script. error: " << rc << std::endl;
10693 return -rc;
10694 }
10695 }
10696
10697 if (opt_cmd == OPT::SCRIPT_GET) {
10698 if (!str_script_ctx) {
10699 cerr << "ERROR: context was not provided (via --context)" << std::endl;
10700 return EINVAL;
10701 }
10702 const rgw::lua::context script_ctx = rgw::lua::to_context(*str_script_ctx);
10703 if (script_ctx == rgw::lua::context::none) {
10704 cerr << "ERROR: invalid script context: " << *str_script_ctx << ". must be one of: " << LUA_CONTEXT_LIST << std::endl;
10705 return EINVAL;
10706 }
10707 auto lua_manager = driver->get_lua_manager();
10708 std::string script;
10709 const auto rc = rgw::lua::read_script(dpp(), lua_manager.get(), tenant, null_yield, script_ctx, script);
10710 if (rc == -ENOENT) {
10711 std::cout << "no script exists for context: " << *str_script_ctx <<
10712 (tenant.empty() ? "" : (" in tenant: " + tenant)) << std::endl;
10713 } else if (rc < 0) {
10714 cerr << "ERROR: failed to read script. error: " << rc << std::endl;
10715 return -rc;
10716 } else {
10717 std::cout << script << std::endl;
10718 }
10719 }
10720
10721 if (opt_cmd == OPT::SCRIPT_RM) {
10722 if (!str_script_ctx) {
10723 cerr << "ERROR: context was not provided (via --context)" << std::endl;
10724 return EINVAL;
10725 }
10726 const rgw::lua::context script_ctx = rgw::lua::to_context(*str_script_ctx);
10727 if (script_ctx == rgw::lua::context::none) {
10728 cerr << "ERROR: invalid script context: " << *str_script_ctx << ". must be one of: " << LUA_CONTEXT_LIST << std::endl;
10729 return EINVAL;
10730 }
10731 auto lua_manager = driver->get_lua_manager();
10732 const auto rc = rgw::lua::delete_script(dpp(), lua_manager.get(), tenant, null_yield, script_ctx);
10733 if (rc < 0) {
10734 cerr << "ERROR: failed to remove script. error: " << rc << std::endl;
10735 return -rc;
10736 }
10737 }
10738
10739 if (opt_cmd == OPT::SCRIPT_PACKAGE_ADD) {
10740 #ifdef WITH_RADOSGW_LUA_PACKAGES
10741 if (!script_package) {
10742 cerr << "ERROR: lua package name was not provided (via --package)" << std::endl;
10743 return EINVAL;
10744 }
10745 const auto rc = rgw::lua::add_package(dpp(), driver, null_yield, *script_package, bool(allow_compilation));
10746 if (rc < 0) {
10747 cerr << "ERROR: failed to add lua package: " << script_package << " .error: " << rc << std::endl;
10748 return -rc;
10749 }
10750 #else
10751 cerr << "ERROR: adding lua packages is not permitted" << std::endl;
10752 return EPERM;
10753 #endif
10754 }
10755
10756 if (opt_cmd == OPT::SCRIPT_PACKAGE_RM) {
10757 #ifdef WITH_RADOSGW_LUA_PACKAGES
10758 if (!script_package) {
10759 cerr << "ERROR: lua package name was not provided (via --package)" << std::endl;
10760 return EINVAL;
10761 }
10762 const auto rc = rgw::lua::remove_package(dpp(), driver, null_yield, *script_package);
10763 if (rc == -ENOENT) {
10764 cerr << "WARNING: package " << script_package << " did not exists or already removed" << std::endl;
10765 return 0;
10766 }
10767 if (rc < 0) {
10768 cerr << "ERROR: failed to remove lua package: " << script_package << " .error: " << rc << std::endl;
10769 return -rc;
10770 }
10771 #else
10772 cerr << "ERROR: removing lua packages in not permitted" << std::endl;
10773 return EPERM;
10774 #endif
10775 }
10776
10777 if (opt_cmd == OPT::SCRIPT_PACKAGE_LIST) {
10778 #ifdef WITH_RADOSGW_LUA_PACKAGES
10779 rgw::lua::packages_t packages;
10780 const auto rc = rgw::lua::list_packages(dpp(), driver, null_yield, packages);
10781 if (rc == -ENOENT) {
10782 std::cout << "no lua packages in allowlist" << std::endl;
10783 } else if (rc < 0) {
10784 cerr << "ERROR: failed to read lua packages allowlist. error: " << rc << std::endl;
10785 return rc;
10786 } else {
10787 for (const auto& package : packages) {
10788 std::cout << package << std::endl;
10789 }
10790 }
10791 #else
10792 cerr << "ERROR: listing lua packages in not permitted" << std::endl;
10793 return EPERM;
10794 #endif
10795 }
10796
10797 return 0;
10798 }
10799