]> git.proxmox.com Git - ceph.git/blob - ceph/src/rgw/rgw_admin.cc
import quincy beta 17.1.0
[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/optional.hpp>
10
11 extern "C" {
12 #include <liboath/oath.h>
13 }
14
15 #include "auth/Crypto.h"
16 #include "compressor/Compressor.h"
17
18 #include "common/armor.h"
19 #include "common/ceph_json.h"
20 #include "common/config.h"
21 #include "common/ceph_argparse.h"
22 #include "common/Formatter.h"
23 #include "common/errno.h"
24 #include "common/safe_io.h"
25
26 #include "include/util.h"
27
28 #include "cls/rgw/cls_rgw_types.h"
29 #include "cls/rgw/cls_rgw_client.h"
30
31 #include "global/global_init.h"
32
33 #include "include/utime.h"
34 #include "include/str_list.h"
35
36 #include "rgw_user.h"
37 #include "rgw_bucket.h"
38 #include "rgw_otp.h"
39 #include "rgw_rados.h"
40 #include "rgw_acl.h"
41 #include "rgw_acl_s3.h"
42 #include "rgw_datalog.h"
43 #include "rgw_lc.h"
44 #include "rgw_log.h"
45 #include "rgw_formats.h"
46 #include "rgw_usage.h"
47 #include "rgw_orphan.h"
48 #include "rgw_sync.h"
49 #include "rgw_trim_bilog.h"
50 #include "rgw_trim_datalog.h"
51 #include "rgw_trim_mdlog.h"
52 #include "rgw_data_sync.h"
53 #include "rgw_rest_conn.h"
54 #include "rgw_realm_watcher.h"
55 #include "rgw_role.h"
56 #include "rgw_reshard.h"
57 #include "rgw_http_client_curl.h"
58 #include "rgw_zone.h"
59 #include "rgw_pubsub.h"
60 #include "rgw_bucket_sync.h"
61 #include "rgw_sync_checkpoint.h"
62 #include "rgw_lua.h"
63
64 #include "services/svc_sync_modules.h"
65 #include "services/svc_cls.h"
66 #include "services/svc_bilog_rados.h"
67 #include "services/svc_mdlog.h"
68 #include "services/svc_meta_be_otp.h"
69 #include "services/svc_zone.h"
70
71 #define dout_context g_ceph_context
72 #define dout_subsys ceph_subsys_rgw
73
74 #define SECRET_KEY_LEN 40
75 #define PUBLIC_ID_LEN 20
76
77 using namespace std;
78
79 static rgw::sal::Store* store = NULL;
80
81 static const DoutPrefixProvider* dpp() {
82 struct GlobalPrefix : public DoutPrefixProvider {
83 CephContext *get_cct() const override { return dout_context; }
84 unsigned get_subsys() const override { return dout_subsys; }
85 std::ostream& gen_prefix(std::ostream& out) const override { return out; }
86 };
87 static GlobalPrefix global_dpp;
88 return &global_dpp;
89 }
90
91 #define CHECK_TRUE(x, msg, err) \
92 do { \
93 if (!x) { \
94 cerr << msg << std::endl; \
95 return err; \
96 } \
97 } while (0)
98
99 #define CHECK_SUCCESS(x, msg) \
100 do { \
101 int _x_val = (x); \
102 if (_x_val < 0) { \
103 cerr << msg << ": " << cpp_strerror(-_x_val) << std::endl; \
104 return _x_val; \
105 } \
106 } while (0)
107
108 void usage()
109 {
110 cout << "usage: radosgw-admin <cmd> [options...]" << std::endl;
111 cout << "commands:\n";
112 cout << " user create create a new user\n" ;
113 cout << " user modify modify user\n";
114 cout << " user info get user info\n";
115 cout << " user rename rename user\n";
116 cout << " user rm remove user\n";
117 cout << " user suspend suspend a user\n";
118 cout << " user enable re-enable user after suspension\n";
119 cout << " user check check user info\n";
120 cout << " user stats show user stats as accounted by quota subsystem\n";
121 cout << " user list list users\n";
122 cout << " caps add add user capabilities\n";
123 cout << " caps rm remove user capabilities\n";
124 cout << " subuser create create a new subuser\n" ;
125 cout << " subuser modify modify subuser\n";
126 cout << " subuser rm remove subuser\n";
127 cout << " key create create access key\n";
128 cout << " key rm remove access key\n";
129 cout << " bucket list list buckets (specify --allow-unordered for\n";
130 cout << " faster, unsorted listing)\n";
131 cout << " bucket limit check show bucket sharding stats\n";
132 cout << " bucket link link bucket to specified user\n";
133 cout << " bucket unlink unlink bucket from specified user\n";
134 cout << " bucket stats returns bucket statistics\n";
135 cout << " bucket rm remove bucket\n";
136 cout << " bucket check check bucket index\n";
137 cout << " bucket chown link bucket to specified user and update its object ACLs\n";
138 cout << " bucket reshard reshard bucket\n";
139 cout << " bucket rewrite rewrite all objects in the specified bucket\n";
140 cout << " bucket sync checkpoint poll a bucket's sync status until it catches up to its remote\n";
141 cout << " bucket sync disable disable bucket sync\n";
142 cout << " bucket sync enable enable bucket sync\n";
143 cout << " bucket radoslist list rados objects backing bucket's objects\n";
144 cout << " bi get retrieve bucket index object entries\n";
145 cout << " bi put store bucket index object entries\n";
146 cout << " bi list list raw bucket index entries\n";
147 cout << " bi purge purge bucket index entries\n";
148 cout << " object rm remove object\n";
149 cout << " object put put object\n";
150 cout << " object stat stat an object for its metadata\n";
151 cout << " object unlink unlink object from bucket index\n";
152 cout << " object rewrite rewrite the specified object\n";
153 cout << " objects expire run expired objects cleanup\n";
154 cout << " objects expire-stale list list stale expired objects (caused by reshard)\n";
155 cout << " objects expire-stale rm remove stale expired objects\n";
156 cout << " period rm remove a period\n";
157 cout << " period get get period info\n";
158 cout << " period get-current get current period info\n";
159 cout << " period pull pull a period\n";
160 cout << " period push push a period\n";
161 cout << " period list list all periods\n";
162 cout << " period update update the staging period\n";
163 cout << " period commit commit the staging period\n";
164 cout << " quota set set quota params\n";
165 cout << " quota enable enable quota\n";
166 cout << " quota disable disable quota\n";
167 cout << " ratelimit get get ratelimit params\n";
168 cout << " ratelimit set set ratelimit params\n";
169 cout << " ratelimit enable enable ratelimit\n";
170 cout << " ratelimit disable disable ratelimit\n";
171 cout << " global quota get view global quota params\n";
172 cout << " global quota set set global quota params\n";
173 cout << " global quota enable enable a global quota\n";
174 cout << " global quota disable disable a global quota\n";
175 cout << " global ratelimit get view global ratelimit params\n";
176 cout << " global ratelimit set set global ratelimit params\n";
177 cout << " global ratelimit enable enable a ratelimit quota\n";
178 cout << " global ratelimit disable disable a ratelimit quota\n";
179 cout << " realm create create a new realm\n";
180 cout << " realm rm remove a realm\n";
181 cout << " realm get show realm info\n";
182 cout << " realm get-default get default realm name\n";
183 cout << " realm list list realms\n";
184 cout << " realm list-periods list all realm periods\n";
185 cout << " realm rename rename a realm\n";
186 cout << " realm set set realm info (requires infile)\n";
187 cout << " realm default set realm as default\n";
188 cout << " realm pull pull a realm and its current period\n";
189 cout << " zonegroup add add a zone to a zonegroup\n";
190 cout << " zonegroup create create a new zone group info\n";
191 cout << " zonegroup default set default zone group\n";
192 cout << " zonegroup delete delete a zone group info\n";
193 cout << " zonegroup get show zone group info\n";
194 cout << " zonegroup modify modify an existing zonegroup\n";
195 cout << " zonegroup set set zone group info (requires infile)\n";
196 cout << " zonegroup rm remove a zone from a zonegroup\n";
197 cout << " zonegroup rename rename a zone group\n";
198 cout << " zonegroup list list all zone groups set on this cluster\n";
199 cout << " zonegroup placement list list zonegroup's placement targets\n";
200 cout << " zonegroup placement get get a placement target of a specific zonegroup\n";
201 cout << " zonegroup placement add add a placement target id to a zonegroup\n";
202 cout << " zonegroup placement modify modify a placement target of a specific zonegroup\n";
203 cout << " zonegroup placement rm remove a placement target from a zonegroup\n";
204 cout << " zonegroup placement default set a zonegroup's default placement target\n";
205 cout << " zone create create a new zone\n";
206 cout << " zone rm remove a zone\n";
207 cout << " zone get show zone cluster params\n";
208 cout << " zone modify modify an existing zone\n";
209 cout << " zone set set zone cluster params (requires infile)\n";
210 cout << " zone list list all zones set on this cluster\n";
211 cout << " zone rename rename a zone\n";
212 cout << " zone placement list list zone's placement targets\n";
213 cout << " zone placement get get a zone placement target\n";
214 cout << " zone placement add add a zone placement target\n";
215 cout << " zone placement modify modify a zone placement target\n";
216 cout << " zone placement rm remove a zone placement target\n";
217 cout << " metadata sync status get metadata sync status\n";
218 cout << " metadata sync init init metadata sync\n";
219 cout << " metadata sync run run metadata sync\n";
220 cout << " data sync status get data sync status of the specified source zone\n";
221 cout << " data sync init init data sync for the specified source zone\n";
222 cout << " data sync run run data sync for the specified source zone\n";
223 cout << " pool add add an existing pool for data placement\n";
224 cout << " pool rm remove an existing pool from data placement set\n";
225 cout << " pools list list placement active set\n";
226 cout << " policy read bucket/object policy\n";
227 cout << " log list list log objects\n";
228 cout << " log show dump a log from specific object or (bucket + date\n";
229 cout << " + bucket-id)\n";
230 cout << " (NOTE: required to specify formatting of date\n";
231 cout << " to \"YYYY-MM-DD-hh\")\n";
232 cout << " log rm remove log object\n";
233 cout << " usage show show usage (by user, by bucket, date range)\n";
234 cout << " usage trim trim usage (by user, by bucket, date range)\n";
235 cout << " usage clear reset all the usage stats for the cluster\n";
236 cout << " gc list dump expired garbage collection objects (specify\n";
237 cout << " --include-all to list all entries, including unexpired)\n";
238 cout << " gc process manually process garbage (specify\n";
239 cout << " --include-all to process all entries, including unexpired)\n";
240 cout << " lc list list all bucket lifecycle progress\n";
241 cout << " lc get get a lifecycle bucket configuration\n";
242 cout << " lc process manually process lifecycle\n";
243 cout << " lc reshard fix fix LC for a resharded bucket\n";
244 cout << " metadata get get metadata info\n";
245 cout << " metadata put put metadata info\n";
246 cout << " metadata rm remove metadata info\n";
247 cout << " metadata list list metadata info\n";
248 cout << " mdlog list list metadata log\n";
249 cout << " mdlog autotrim auto trim metadata log\n";
250 cout << " mdlog trim trim metadata log (use marker)\n";
251 cout << " mdlog status read metadata log status\n";
252 cout << " bilog list list bucket index log\n";
253 cout << " bilog trim trim bucket index log (use start-marker, end-marker)\n";
254 cout << " bilog status read bucket index log status\n";
255 cout << " bilog autotrim auto trim bucket index log\n";
256 cout << " datalog list list data log\n";
257 cout << " datalog trim trim data log\n";
258 cout << " datalog status read data log status\n";
259 cout << " datalog type change datalog type to --log_type={fifo,omap}\n";
260 cout << " orphans find deprecated -- init and run search for leaked rados objects (use job-id, pool)\n";
261 cout << " orphans finish deprecated -- clean up search for leaked rados objects\n";
262 cout << " orphans list-jobs deprecated -- list the current job-ids for orphans search\n";
263 cout << " * the three 'orphans' sub-commands are now deprecated; consider using the `rgw-orphan-list` tool\n";
264 cout << " role create create a AWS role for use with STS\n";
265 cout << " role delete remove a role\n";
266 cout << " role get get a role\n";
267 cout << " role list list roles with specified path prefix\n";
268 cout << " role modify modify the assume role policy of an existing role\n";
269 cout << " role-policy put add/update permission policy to role\n";
270 cout << " role-policy list list policies attached to a role\n";
271 cout << " role-policy get get the specified inline policy document embedded with the given role\n";
272 cout << " role-policy delete remove policy attached to a role\n";
273 cout << " reshard add schedule a resharding of a bucket\n";
274 cout << " reshard list list all bucket resharding or scheduled to be resharded\n";
275 cout << " reshard status read bucket resharding status\n";
276 cout << " reshard process process of scheduled reshard jobs\n";
277 cout << " reshard cancel cancel resharding a bucket\n";
278 cout << " reshard stale-instances list list stale-instances from bucket resharding\n";
279 cout << " reshard stale-instances rm cleanup stale-instances from bucket resharding\n";
280 cout << " sync error list list sync error\n";
281 cout << " sync error trim trim sync error\n";
282 cout << " mfa create create a new MFA TOTP token\n";
283 cout << " mfa list list MFA TOTP tokens\n";
284 cout << " mfa get show MFA TOTP token\n";
285 cout << " mfa remove delete MFA TOTP token\n";
286 cout << " mfa check check MFA TOTP token\n";
287 cout << " mfa resync re-sync MFA TOTP token\n";
288 cout << " topic list list bucket notifications/pubsub topics\n";
289 cout << " topic get get a bucket notifications/pubsub topic\n";
290 cout << " topic rm remove a bucket notifications/pubsub topic\n";
291 cout << " subscription get get a pubsub subscription definition\n";
292 cout << " subscription rm remove a pubsub subscription\n";
293 cout << " subscription pull show events in a pubsub subscription\n";
294 cout << " subscription ack ack (remove) an events in a pubsub subscription\n";
295 cout << " script put upload a lua script to a context\n";
296 cout << " script get get the lua script of a context\n";
297 cout << " script rm remove the lua scripts of a context\n";
298 cout << " script-package add add a lua package to the scripts allowlist\n";
299 cout << " script-package rm remove a lua package from the scripts allowlist\n";
300 cout << " script-package list get the lua packages allowlist\n";
301 cout << "options:\n";
302 cout << " --tenant=<tenant> tenant name\n";
303 cout << " --user_ns=<namespace> namespace of user (oidc in case of users authenticated with oidc provider)\n";
304 cout << " --uid=<id> user id\n";
305 cout << " --new-uid=<id> new user id\n";
306 cout << " --subuser=<name> subuser name\n";
307 cout << " --access-key=<key> S3 access key\n";
308 cout << " --email=<email> user's email address\n";
309 cout << " --secret/--secret-key=<key>\n";
310 cout << " specify secret key\n";
311 cout << " --gen-access-key generate random access key (for S3)\n";
312 cout << " --gen-secret generate random secret key\n";
313 cout << " --key-type=<type> key type, options are: swift, s3\n";
314 cout << " --temp-url-key[-2]=<key> temp url key\n";
315 cout << " --access=<access> Set access permissions for sub-user, should be one\n";
316 cout << " of read, write, readwrite, full\n";
317 cout << " --display-name=<name> user's display name\n";
318 cout << " --max-buckets max number of buckets for a user\n";
319 cout << " --admin set the admin flag on the user\n";
320 cout << " --system set the system flag on the user\n";
321 cout << " --op-mask set the op mask on the user\n";
322 cout << " --bucket=<bucket> Specify the bucket name. Also used by the quota command.\n";
323 cout << " --pool=<pool> Specify the pool name. Also used to scan for leaked rados objects.\n";
324 cout << " --object=<object> object name\n";
325 cout << " --object-version=<version> object version\n";
326 cout << " --date=<date> date in the format yyyy-mm-dd\n";
327 cout << " --start-date=<date> start date in the format yyyy-mm-dd\n";
328 cout << " --end-date=<date> end date in the format yyyy-mm-dd\n";
329 cout << " --bucket-id=<bucket-id> bucket id\n";
330 cout << " --bucket-new-name=<bucket>\n";
331 cout << " for bucket link: optional new name\n";
332 cout << " --shard-id=<shard-id> optional for: \n";
333 cout << " mdlog list\n";
334 cout << " data sync status\n";
335 cout << " required for: \n";
336 cout << " mdlog trim\n";
337 cout << " --max-entries=<entries> max entries for listing operations\n";
338 cout << " --metadata-key=<key> key to retrieve metadata from with metadata get\n";
339 cout << " --remote=<remote> zone or zonegroup id of remote gateway\n";
340 cout << " --period=<id> period id\n";
341 cout << " --url=<url> url for pushing/pulling period/realm\n";
342 cout << " --epoch=<number> period epoch\n";
343 cout << " --commit commit the period during 'period update'\n";
344 cout << " --staging get staging period info\n";
345 cout << " --master set as master\n";
346 cout << " --master-zone=<id> master zone id\n";
347 cout << " --rgw-realm=<name> realm name\n";
348 cout << " --realm-id=<id> realm id\n";
349 cout << " --realm-new-name=<name> realm new name\n";
350 cout << " --rgw-zonegroup=<name> zonegroup name\n";
351 cout << " --zonegroup-id=<id> zonegroup id\n";
352 cout << " --zonegroup-new-name=<name>\n";
353 cout << " zonegroup new name\n";
354 cout << " --rgw-zone=<name> name of zone in which radosgw is running\n";
355 cout << " --zone-id=<id> zone id\n";
356 cout << " --zone-new-name=<name> zone new name\n";
357 cout << " --source-zone specify the source zone (for data sync)\n";
358 cout << " --default set entity (realm, zonegroup, zone) as default\n";
359 cout << " --read-only set zone as read-only (when adding to zonegroup)\n";
360 cout << " --redirect-zone specify zone id to redirect when response is 404 (not found)\n";
361 cout << " --placement-id placement id for zonegroup placement commands\n";
362 cout << " --storage-class storage class for zonegroup placement commands\n";
363 cout << " --tags=<list> list of tags for zonegroup placement add and modify commands\n";
364 cout << " --tags-add=<list> list of tags to add for zonegroup placement modify command\n";
365 cout << " --tags-rm=<list> list of tags to remove for zonegroup placement modify command\n";
366 cout << " --endpoints=<list> zone endpoints\n";
367 cout << " --index-pool=<pool> placement target index pool\n";
368 cout << " --data-pool=<pool> placement target data pool\n";
369 cout << " --data-extra-pool=<pool> placement target data extra (non-ec) pool\n";
370 cout << " --placement-index-type=<type>\n";
371 cout << " placement target index type (normal, indexless, or #id)\n";
372 cout << " --compression=<type> placement target compression type (plugin name or empty/none)\n";
373 cout << " --tier-type=<type> zone tier type\n";
374 cout << " --tier-config=<k>=<v>[,...]\n";
375 cout << " set zone tier config keys, values\n";
376 cout << " --tier-config-rm=<k>[,...]\n";
377 cout << " unset zone tier config keys\n";
378 cout << " --sync-from-all[=false] set/reset whether zone syncs from all zonegroup peers\n";
379 cout << " --sync-from=[zone-name][,...]\n";
380 cout << " set list of zones to sync from\n";
381 cout << " --sync-from-rm=[zone-name][,...]\n";
382 cout << " remove zones from list of zones to sync from\n";
383 cout << " --bucket-index-max-shards override a zone/zonegroup's default bucket index shard count\n";
384 cout << " --fix besides checking bucket index, will also fix it\n";
385 cout << " --check-objects bucket check: rebuilds bucket index according to\n";
386 cout << " actual objects state\n";
387 cout << " --format=<format> specify output format for certain operations: xml,\n";
388 cout << " json\n";
389 cout << " --purge-data when specified, user removal will also purge all the\n";
390 cout << " user data\n";
391 cout << " --purge-keys when specified, subuser removal will also purge all the\n";
392 cout << " subuser keys\n";
393 cout << " --purge-objects remove a bucket's objects before deleting it\n";
394 cout << " (NOTE: required to delete a non-empty bucket)\n";
395 cout << " --sync-stats option to 'user stats', update user stats with current\n";
396 cout << " stats reported by user's buckets indexes\n";
397 cout << " --reset-stats option to 'user stats', reset stats in accordance with user buckets\n";
398 cout << " --show-config show configuration\n";
399 cout << " --show-log-entries=<flag> enable/disable dump of log entries on log show\n";
400 cout << " --show-log-sum=<flag> enable/disable dump of log summation on log show\n";
401 cout << " --skip-zero-entries log show only dumps entries that don't have zero value\n";
402 cout << " in one of the numeric field\n";
403 cout << " --infile=<file> specify a file to read in when setting data\n";
404 cout << " --categories=<list> comma separated list of categories, used in usage show\n";
405 cout << " --caps=<caps> list of caps (e.g., \"usage=read, write; user=read\")\n";
406 cout << " --op-mask=<op-mask> permission of user's operations (e.g., \"read, write, delete, *\")\n";
407 cout << " --yes-i-really-mean-it required for certain operations\n";
408 cout << " --warnings-only when specified with bucket limit check, list\n";
409 cout << " only buckets nearing or over the current max\n";
410 cout << " objects per shard value\n";
411 cout << " --bypass-gc when specified with bucket deletion, triggers\n";
412 cout << " object deletions by not involving GC\n";
413 cout << " --inconsistent-index when specified with bucket deletion and bypass-gc set to true,\n";
414 cout << " ignores bucket index consistency\n";
415 cout << " --min-rewrite-size min object size for bucket rewrite (default 4M)\n";
416 cout << " --max-rewrite-size max object size for bucket rewrite (default ULLONG_MAX)\n";
417 cout << " --min-rewrite-stripe-size min stripe size for object rewrite (default 0)\n";
418 cout << " --trim-delay-ms time interval in msec to limit the frequency of sync error log entries trimming operations,\n";
419 cout << " the trimming process will sleep the specified msec for every 1000 entries trimmed\n";
420 cout << " --max-concurrent-ios maximum concurrent ios for bucket operations (default: 32)\n";
421 cout << "\n";
422 cout << "<date> := \"YYYY-MM-DD[ hh:mm:ss]\"\n";
423 cout << "\nQuota options:\n";
424 cout << " --max-objects specify max objects (negative value to disable)\n";
425 cout << " --max-size specify max size (in B/K/M/G/T, negative value to disable)\n";
426 cout << " --quota-scope scope of quota (bucket, user)\n";
427 cout << "\nRate limiting options:\n";
428 cout << " --max-read-ops specify max requests per minute for READ ops per RGW (GET and HEAD request methods), 0 means unlimited\n";
429 cout << " --max-read-bytes specify max bytes per minute for READ ops per RGW (GET and HEAD request methods), 0 means unlimited\n";
430 cout << " --max-write-ops specify max requests per minute for WRITE ops per RGW (Not GET or HEAD request methods), 0 means unlimited\n";
431 cout << " --max-write-bytes specify max bytes per minute for WRITE ops per RGW (Not GET or HEAD request methods), 0 means unlimited\n";
432 cout << " --ratelimit-scope scope of rate limiting: bucket, user, anonymous\n";
433 cout << " anonymous can be configured only with global rate limit\n";
434 cout << "\nOrphans search options:\n";
435 cout << " --num-shards num of shards to use for keeping the temporary scan info\n";
436 cout << " --orphan-stale-secs num of seconds to wait before declaring an object to be an orphan (default: 86400)\n";
437 cout << " --job-id set the job id (for orphans find)\n";
438 cout << " --detail detailed mode, log and stat head objects as well\n";
439 cout << "\nOrphans list-jobs options:\n";
440 cout << " --extra-info provide extra info in job list\n";
441 cout << "\nRole options:\n";
442 cout << " --role-name name of the role to create\n";
443 cout << " --path path to the role\n";
444 cout << " --assume-role-policy-doc the trust relationship policy document that grants an entity permission to assume the role\n";
445 cout << " --policy-name name of the policy document\n";
446 cout << " --policy-doc permission policy document\n";
447 cout << " --path-prefix path prefix for filtering roles\n";
448 cout << "\nMFA options:\n";
449 cout << " --totp-serial a string that represents the ID of a TOTP token\n";
450 cout << " --totp-seed the secret seed that is used to calculate the TOTP\n";
451 cout << " --totp-seconds the time resolution that is being used for TOTP generation\n";
452 cout << " --totp-window the number of TOTP tokens that are checked before and after the current token when validating token\n";
453 cout << " --totp-pin the valid value of a TOTP token at a certain time\n";
454 cout << "\nBucket notifications/pubsub options:\n";
455 cout << " --topic bucket notifications/pubsub topic name\n";
456 cout << " --subscription pubsub subscription name\n";
457 cout << " --event-id event id in a pubsub subscription\n";
458 cout << "\nScript options:\n";
459 cout << " --context context in which the script runs. one of: preRequest, postRequest\n";
460 cout << " --package name of the lua package that should be added/removed to/from the allowlist\n";
461 cout << " --allow-compilation package is allowed to compile C code as part of its installation\n";
462 cout << "\nradoslist options:\n";
463 cout << " --rgw-obj-fs the field separator that will separate the rados\n";
464 cout << " object name from the rgw object name;\n";
465 cout << " additionally rados objects for incomplete\n";
466 cout << " multipart uploads will not be output\n";
467 cout << "\n";
468 generic_client_usage();
469 }
470
471
472 class SimpleCmd {
473 public:
474 struct Def {
475 string cmd;
476 std::any opt;
477 };
478
479 using Aliases = std::vector<std::set<string> >;
480 using Commands = std::vector<Def>;
481
482 private:
483 struct Node {
484 map<string, Node> next;
485 set<string> expected; /* separate un-normalized list */
486 std::any opt;
487 };
488
489 Node cmd_root;
490 map<string, string> alias_map;
491
492 string normalize_alias(const string& s) const {
493 auto iter = alias_map.find(s);
494 if (iter == alias_map.end()) {
495 return s;
496 }
497
498 return iter->second;
499 }
500 void init_alias_map(Aliases& aliases) {
501 for (auto& alias_set : aliases) {
502 std::optional<string> first;
503
504 for (auto& alias : alias_set) {
505 if (!first) {
506 first = alias;
507 } else {
508 alias_map[alias] = *first;
509 }
510 }
511 }
512 }
513
514 bool gen_next_expected(Node *node, vector<string> *expected, bool ret) {
515 for (auto& next_cmd : node->expected) {
516 expected->push_back(next_cmd);
517 }
518 return ret;
519 }
520
521 Node root;
522
523 public:
524 SimpleCmd() {}
525
526 SimpleCmd(std::optional<Commands> cmds,
527 std::optional<Aliases> aliases) {
528 if (aliases) {
529 add_aliases(*aliases);
530 }
531
532 if (cmds) {
533 add_commands(*cmds);
534 }
535 }
536
537 void add_aliases(Aliases& aliases) {
538 init_alias_map(aliases);
539 }
540
541 void add_commands(std::vector<Def>& cmds) {
542 for (auto& cmd : cmds) {
543 vector<string> words;
544 get_str_vec(cmd.cmd, " ", words);
545
546 auto node = &cmd_root;
547 for (auto& word : words) {
548 auto norm = normalize_alias(word);
549 auto parent = node;
550
551 node->expected.insert(word);
552
553 node = &node->next[norm];
554
555 if (norm == "[*]") { /* optional param at the end */
556 parent->next["*"] = *node; /* can be also looked up by '*' */
557 parent->opt = cmd.opt;
558 }
559 }
560
561 node->opt = cmd.opt;
562 }
563 }
564
565 template <class Container>
566 bool find_command(Container& args,
567 std::any *opt_cmd,
568 vector<string> *extra_args,
569 string *error,
570 vector<string> *expected) {
571 auto node = &cmd_root;
572
573 std::optional<std::any> found_opt;
574
575 for (auto& arg : args) {
576 string norm = normalize_alias(arg);
577 auto iter = node->next.find(norm);
578 if (iter == node->next.end()) {
579 iter = node->next.find("*");
580 if (iter == node->next.end()) {
581 *error = string("ERROR: Unrecognized argument: '") + arg + "'";
582 return gen_next_expected(node, expected, false);
583 }
584 extra_args->push_back(arg);
585 if (!found_opt) {
586 found_opt = node->opt;
587 }
588 }
589 node = &(iter->second);
590 }
591
592 *opt_cmd = found_opt.value_or(node->opt);
593
594 if (!opt_cmd->has_value()) {
595 *error ="ERROR: Unknown command";
596 return gen_next_expected(node, expected, false);
597 }
598
599 return true;
600 }
601 };
602
603
604 namespace rgw_admin {
605
606 enum class OPT {
607 NO_CMD,
608 USER_CREATE,
609 USER_INFO,
610 USER_MODIFY,
611 USER_RENAME,
612 USER_RM,
613 USER_SUSPEND,
614 USER_ENABLE,
615 USER_CHECK,
616 USER_STATS,
617 USER_LIST,
618 SUBUSER_CREATE,
619 SUBUSER_MODIFY,
620 SUBUSER_RM,
621 KEY_CREATE,
622 KEY_RM,
623 BUCKETS_LIST,
624 BUCKET_LIMIT_CHECK,
625 BUCKET_LINK,
626 BUCKET_UNLINK,
627 BUCKET_STATS,
628 BUCKET_CHECK,
629 BUCKET_SYNC_CHECKPOINT,
630 BUCKET_SYNC_INFO,
631 BUCKET_SYNC_STATUS,
632 BUCKET_SYNC_MARKERS,
633 BUCKET_SYNC_INIT,
634 BUCKET_SYNC_RUN,
635 BUCKET_SYNC_DISABLE,
636 BUCKET_SYNC_ENABLE,
637 BUCKET_RM,
638 BUCKET_REWRITE,
639 BUCKET_RESHARD,
640 BUCKET_CHOWN,
641 BUCKET_RADOS_LIST,
642 POLICY,
643 POOL_ADD,
644 POOL_RM,
645 POOLS_LIST,
646 LOG_LIST,
647 LOG_SHOW,
648 LOG_RM,
649 USAGE_SHOW,
650 USAGE_TRIM,
651 USAGE_CLEAR,
652 OBJECT_PUT,
653 OBJECT_RM,
654 OBJECT_UNLINK,
655 OBJECT_STAT,
656 OBJECT_REWRITE,
657 OBJECTS_EXPIRE,
658 OBJECTS_EXPIRE_STALE_LIST,
659 OBJECTS_EXPIRE_STALE_RM,
660 BI_GET,
661 BI_PUT,
662 BI_LIST,
663 BI_PURGE,
664 OLH_GET,
665 OLH_READLOG,
666 QUOTA_SET,
667 QUOTA_ENABLE,
668 QUOTA_DISABLE,
669 GC_LIST,
670 GC_PROCESS,
671 LC_LIST,
672 LC_GET,
673 LC_PROCESS,
674 LC_RESHARD_FIX,
675 ORPHANS_FIND,
676 ORPHANS_FINISH,
677 ORPHANS_LIST_JOBS,
678 RATELIMIT_GET,
679 RATELIMIT_SET,
680 RATELIMIT_ENABLE,
681 RATELIMIT_DISABLE,
682 ZONEGROUP_ADD,
683 ZONEGROUP_CREATE,
684 ZONEGROUP_DEFAULT,
685 ZONEGROUP_DELETE,
686 ZONEGROUP_GET,
687 ZONEGROUP_MODIFY,
688 ZONEGROUP_SET,
689 ZONEGROUP_LIST,
690 ZONEGROUP_REMOVE,
691 ZONEGROUP_RENAME,
692 ZONEGROUP_PLACEMENT_ADD,
693 ZONEGROUP_PLACEMENT_MODIFY,
694 ZONEGROUP_PLACEMENT_RM,
695 ZONEGROUP_PLACEMENT_LIST,
696 ZONEGROUP_PLACEMENT_GET,
697 ZONEGROUP_PLACEMENT_DEFAULT,
698 ZONE_CREATE,
699 ZONE_DELETE,
700 ZONE_GET,
701 ZONE_MODIFY,
702 ZONE_SET,
703 ZONE_LIST,
704 ZONE_RENAME,
705 ZONE_DEFAULT,
706 ZONE_PLACEMENT_ADD,
707 ZONE_PLACEMENT_MODIFY,
708 ZONE_PLACEMENT_RM,
709 ZONE_PLACEMENT_LIST,
710 ZONE_PLACEMENT_GET,
711 CAPS_ADD,
712 CAPS_RM,
713 METADATA_GET,
714 METADATA_PUT,
715 METADATA_RM,
716 METADATA_LIST,
717 METADATA_SYNC_STATUS,
718 METADATA_SYNC_INIT,
719 METADATA_SYNC_RUN,
720 MDLOG_LIST,
721 MDLOG_AUTOTRIM,
722 MDLOG_TRIM,
723 MDLOG_FETCH,
724 MDLOG_STATUS,
725 SYNC_ERROR_LIST,
726 SYNC_ERROR_TRIM,
727 SYNC_GROUP_CREATE,
728 SYNC_GROUP_MODIFY,
729 SYNC_GROUP_GET,
730 SYNC_GROUP_REMOVE,
731 SYNC_GROUP_FLOW_CREATE,
732 SYNC_GROUP_FLOW_REMOVE,
733 SYNC_GROUP_PIPE_CREATE,
734 SYNC_GROUP_PIPE_MODIFY,
735 SYNC_GROUP_PIPE_REMOVE,
736 SYNC_POLICY_GET,
737 BILOG_LIST,
738 BILOG_TRIM,
739 BILOG_STATUS,
740 BILOG_AUTOTRIM,
741 DATA_SYNC_STATUS,
742 DATA_SYNC_INIT,
743 DATA_SYNC_RUN,
744 DATALOG_LIST,
745 DATALOG_STATUS,
746 DATALOG_AUTOTRIM,
747 DATALOG_TRIM,
748 DATALOG_TYPE,
749 DATALOG_PRUNE,
750 REALM_CREATE,
751 REALM_DELETE,
752 REALM_GET,
753 REALM_GET_DEFAULT,
754 REALM_LIST,
755 REALM_LIST_PERIODS,
756 REALM_RENAME,
757 REALM_SET,
758 REALM_DEFAULT,
759 REALM_PULL,
760 PERIOD_DELETE,
761 PERIOD_GET,
762 PERIOD_GET_CURRENT,
763 PERIOD_PULL,
764 PERIOD_PUSH,
765 PERIOD_LIST,
766 PERIOD_UPDATE,
767 PERIOD_COMMIT,
768 GLOBAL_QUOTA_GET,
769 GLOBAL_QUOTA_SET,
770 GLOBAL_QUOTA_ENABLE,
771 GLOBAL_QUOTA_DISABLE,
772 GLOBAL_RATELIMIT_GET,
773 GLOBAL_RATELIMIT_SET,
774 GLOBAL_RATELIMIT_ENABLE,
775 GLOBAL_RATELIMIT_DISABLE,
776 SYNC_INFO,
777 SYNC_STATUS,
778 ROLE_CREATE,
779 ROLE_DELETE,
780 ROLE_GET,
781 ROLE_MODIFY,
782 ROLE_LIST,
783 ROLE_POLICY_PUT,
784 ROLE_POLICY_LIST,
785 ROLE_POLICY_GET,
786 ROLE_POLICY_DELETE,
787 RESHARD_ADD,
788 RESHARD_LIST,
789 RESHARD_STATUS,
790 RESHARD_PROCESS,
791 RESHARD_CANCEL,
792 MFA_CREATE,
793 MFA_REMOVE,
794 MFA_GET,
795 MFA_LIST,
796 MFA_CHECK,
797 MFA_RESYNC,
798 RESHARD_STALE_INSTANCES_LIST,
799 RESHARD_STALE_INSTANCES_DELETE,
800 PUBSUB_TOPICS_LIST,
801 // TODO add "subscription list" command
802 PUBSUB_TOPIC_GET,
803 PUBSUB_TOPIC_RM,
804 PUBSUB_SUB_GET,
805 PUBSUB_SUB_RM,
806 PUBSUB_SUB_PULL,
807 PUBSUB_EVENT_RM,
808 SCRIPT_PUT,
809 SCRIPT_GET,
810 SCRIPT_RM,
811 SCRIPT_PACKAGE_ADD,
812 SCRIPT_PACKAGE_RM,
813 SCRIPT_PACKAGE_LIST
814 };
815
816 }
817
818 using namespace rgw_admin;
819
820 static SimpleCmd::Commands all_cmds = {
821 { "user create", OPT::USER_CREATE },
822 { "user info", OPT::USER_INFO },
823 { "user modify", OPT::USER_MODIFY },
824 { "user rename", OPT::USER_RENAME },
825 { "user rm", OPT::USER_RM },
826 { "user suspend", OPT::USER_SUSPEND },
827 { "user enable", OPT::USER_ENABLE },
828 { "user check", OPT::USER_CHECK },
829 { "user stats", OPT::USER_STATS },
830 { "user list", OPT::USER_LIST },
831 { "subuser create", OPT::SUBUSER_CREATE },
832 { "subuser modify", OPT::SUBUSER_MODIFY },
833 { "subuser rm", OPT::SUBUSER_RM },
834 { "key create", OPT::KEY_CREATE },
835 { "key rm", OPT::KEY_RM },
836 { "buckets list", OPT::BUCKETS_LIST },
837 { "bucket list", OPT::BUCKETS_LIST },
838 { "bucket limit check", OPT::BUCKET_LIMIT_CHECK },
839 { "bucket link", OPT::BUCKET_LINK },
840 { "bucket unlink", OPT::BUCKET_UNLINK },
841 { "bucket stats", OPT::BUCKET_STATS },
842 { "bucket check", OPT::BUCKET_CHECK },
843 { "bucket sync checkpoint", OPT::BUCKET_SYNC_CHECKPOINT },
844 { "bucket sync info", OPT::BUCKET_SYNC_INFO },
845 { "bucket sync status", OPT::BUCKET_SYNC_STATUS },
846 { "bucket sync markers", OPT::BUCKET_SYNC_MARKERS },
847 { "bucket sync init", OPT::BUCKET_SYNC_INIT },
848 { "bucket sync run", OPT::BUCKET_SYNC_RUN },
849 { "bucket sync disable", OPT::BUCKET_SYNC_DISABLE },
850 { "bucket sync enable", OPT::BUCKET_SYNC_ENABLE },
851 { "bucket rm", OPT::BUCKET_RM },
852 { "bucket rewrite", OPT::BUCKET_REWRITE },
853 { "bucket reshard", OPT::BUCKET_RESHARD },
854 { "bucket chown", OPT::BUCKET_CHOWN },
855 { "bucket radoslist", OPT::BUCKET_RADOS_LIST },
856 { "bucket rados list", OPT::BUCKET_RADOS_LIST },
857 { "policy", OPT::POLICY },
858 { "pool add", OPT::POOL_ADD },
859 { "pool rm", OPT::POOL_RM },
860 { "pool list", OPT::POOLS_LIST },
861 { "pools list", OPT::POOLS_LIST },
862 { "log list", OPT::LOG_LIST },
863 { "log show", OPT::LOG_SHOW },
864 { "log rm", OPT::LOG_RM },
865 { "usage show", OPT::USAGE_SHOW },
866 { "usage trim", OPT::USAGE_TRIM },
867 { "usage clear", OPT::USAGE_CLEAR },
868 { "object put", OPT::OBJECT_PUT },
869 { "object rm", OPT::OBJECT_RM },
870 { "object unlink", OPT::OBJECT_UNLINK },
871 { "object stat", OPT::OBJECT_STAT },
872 { "object rewrite", OPT::OBJECT_REWRITE },
873 { "objects expire", OPT::OBJECTS_EXPIRE },
874 { "objects expire-stale list", OPT::OBJECTS_EXPIRE_STALE_LIST },
875 { "objects expire-stale rm", OPT::OBJECTS_EXPIRE_STALE_RM },
876 { "bi get", OPT::BI_GET },
877 { "bi put", OPT::BI_PUT },
878 { "bi list", OPT::BI_LIST },
879 { "bi purge", OPT::BI_PURGE },
880 { "olh get", OPT::OLH_GET },
881 { "olh readlog", OPT::OLH_READLOG },
882 { "quota set", OPT::QUOTA_SET },
883 { "quota enable", OPT::QUOTA_ENABLE },
884 { "quota disable", OPT::QUOTA_DISABLE },
885 { "ratelimit get", OPT::RATELIMIT_GET },
886 { "ratelimit set", OPT::RATELIMIT_SET },
887 { "ratelimit enable", OPT::RATELIMIT_ENABLE },
888 { "ratelimit disable", OPT::RATELIMIT_DISABLE },
889 { "gc list", OPT::GC_LIST },
890 { "gc process", OPT::GC_PROCESS },
891 { "lc list", OPT::LC_LIST },
892 { "lc get", OPT::LC_GET },
893 { "lc process", OPT::LC_PROCESS },
894 { "lc reshard fix", OPT::LC_RESHARD_FIX },
895 { "orphans find", OPT::ORPHANS_FIND },
896 { "orphans finish", OPT::ORPHANS_FINISH },
897 { "orphans list jobs", OPT::ORPHANS_LIST_JOBS },
898 { "orphans list-jobs", OPT::ORPHANS_LIST_JOBS },
899 { "zonegroup add", OPT::ZONEGROUP_ADD },
900 { "zonegroup create", OPT::ZONEGROUP_CREATE },
901 { "zonegroup default", OPT::ZONEGROUP_DEFAULT },
902 { "zonegroup delete", OPT::ZONEGROUP_DELETE },
903 { "zonegroup get", OPT::ZONEGROUP_GET },
904 { "zonegroup modify", OPT::ZONEGROUP_MODIFY },
905 { "zonegroup set", OPT::ZONEGROUP_SET },
906 { "zonegroup list", OPT::ZONEGROUP_LIST },
907 { "zonegroups list", OPT::ZONEGROUP_LIST },
908 { "zonegroup remove", OPT::ZONEGROUP_REMOVE },
909 { "zonegroup remove zone", OPT::ZONEGROUP_REMOVE },
910 { "zonegroup rename", OPT::ZONEGROUP_RENAME },
911 { "zonegroup placement add", OPT::ZONEGROUP_PLACEMENT_ADD },
912 { "zonegroup placement modify", OPT::ZONEGROUP_PLACEMENT_MODIFY },
913 { "zonegroup placement rm", OPT::ZONEGROUP_PLACEMENT_RM },
914 { "zonegroup placement list", OPT::ZONEGROUP_PLACEMENT_LIST },
915 { "zonegroup placement get", OPT::ZONEGROUP_PLACEMENT_GET },
916 { "zonegroup placement default", OPT::ZONEGROUP_PLACEMENT_DEFAULT },
917 { "zone create", OPT::ZONE_CREATE },
918 { "zone delete", OPT::ZONE_DELETE },
919 { "zone get", OPT::ZONE_GET },
920 { "zone modify", OPT::ZONE_MODIFY },
921 { "zone set", OPT::ZONE_SET },
922 { "zone list", OPT::ZONE_LIST },
923 { "zones list", OPT::ZONE_LIST },
924 { "zone rename", OPT::ZONE_RENAME },
925 { "zone default", OPT::ZONE_DEFAULT },
926 { "zone placement add", OPT::ZONE_PLACEMENT_ADD },
927 { "zone placement modify", OPT::ZONE_PLACEMENT_MODIFY },
928 { "zone placement rm", OPT::ZONE_PLACEMENT_RM },
929 { "zone placement list", OPT::ZONE_PLACEMENT_LIST },
930 { "zone placement get", OPT::ZONE_PLACEMENT_GET },
931 { "caps add", OPT::CAPS_ADD },
932 { "caps rm", OPT::CAPS_RM },
933 { "metadata get [*]", OPT::METADATA_GET },
934 { "metadata put [*]", OPT::METADATA_PUT },
935 { "metadata rm [*]", OPT::METADATA_RM },
936 { "metadata list [*]", OPT::METADATA_LIST },
937 { "metadata sync status", OPT::METADATA_SYNC_STATUS },
938 { "metadata sync init", OPT::METADATA_SYNC_INIT },
939 { "metadata sync run", OPT::METADATA_SYNC_RUN },
940 { "mdlog list", OPT::MDLOG_LIST },
941 { "mdlog autotrim", OPT::MDLOG_AUTOTRIM },
942 { "mdlog trim", OPT::MDLOG_TRIM },
943 { "mdlog fetch", OPT::MDLOG_FETCH },
944 { "mdlog status", OPT::MDLOG_STATUS },
945 { "sync error list", OPT::SYNC_ERROR_LIST },
946 { "sync error trim", OPT::SYNC_ERROR_TRIM },
947 { "sync policy get", OPT::SYNC_POLICY_GET },
948 { "sync group create", OPT::SYNC_GROUP_CREATE },
949 { "sync group modify", OPT::SYNC_GROUP_MODIFY },
950 { "sync group get", OPT::SYNC_GROUP_GET },
951 { "sync group remove", OPT::SYNC_GROUP_REMOVE },
952 { "sync group flow create", OPT::SYNC_GROUP_FLOW_CREATE },
953 { "sync group flow remove", OPT::SYNC_GROUP_FLOW_REMOVE },
954 { "sync group pipe create", OPT::SYNC_GROUP_PIPE_CREATE },
955 { "sync group pipe modify", OPT::SYNC_GROUP_PIPE_MODIFY },
956 { "sync group pipe remove", OPT::SYNC_GROUP_PIPE_REMOVE },
957 { "bilog list", OPT::BILOG_LIST },
958 { "bilog trim", OPT::BILOG_TRIM },
959 { "bilog status", OPT::BILOG_STATUS },
960 { "bilog autotrim", OPT::BILOG_AUTOTRIM },
961 { "data sync status", OPT::DATA_SYNC_STATUS },
962 { "data sync init", OPT::DATA_SYNC_INIT },
963 { "data sync run", OPT::DATA_SYNC_RUN },
964 { "datalog list", OPT::DATALOG_LIST },
965 { "datalog status", OPT::DATALOG_STATUS },
966 { "datalog autotrim", OPT::DATALOG_AUTOTRIM },
967 { "datalog trim", OPT::DATALOG_TRIM },
968 { "datalog type", OPT::DATALOG_TYPE },
969 { "datalog prune", OPT::DATALOG_PRUNE },
970 { "realm create", OPT::REALM_CREATE },
971 { "realm rm", OPT::REALM_DELETE },
972 { "realm get", OPT::REALM_GET },
973 { "realm get default", OPT::REALM_GET_DEFAULT },
974 { "realm get-default", OPT::REALM_GET_DEFAULT },
975 { "realm list", OPT::REALM_LIST },
976 { "realm list periods", OPT::REALM_LIST_PERIODS },
977 { "realm list-periods", OPT::REALM_LIST_PERIODS },
978 { "realm rename", OPT::REALM_RENAME },
979 { "realm set", OPT::REALM_SET },
980 { "realm default", OPT::REALM_DEFAULT },
981 { "realm pull", OPT::REALM_PULL },
982 { "period delete", OPT::PERIOD_DELETE },
983 { "period get", OPT::PERIOD_GET },
984 { "period get-current", OPT::PERIOD_GET_CURRENT },
985 { "period get current", OPT::PERIOD_GET_CURRENT },
986 { "period pull", OPT::PERIOD_PULL },
987 { "period push", OPT::PERIOD_PUSH },
988 { "period list", OPT::PERIOD_LIST },
989 { "period update", OPT::PERIOD_UPDATE },
990 { "period commit", OPT::PERIOD_COMMIT },
991 { "global quota get", OPT::GLOBAL_QUOTA_GET },
992 { "global quota set", OPT::GLOBAL_QUOTA_SET },
993 { "global quota enable", OPT::GLOBAL_QUOTA_ENABLE },
994 { "global quota disable", OPT::GLOBAL_QUOTA_DISABLE },
995 { "global ratelimit get", OPT::GLOBAL_RATELIMIT_GET },
996 { "global ratelimit set", OPT::GLOBAL_RATELIMIT_SET },
997 { "global ratelimit enable", OPT::GLOBAL_RATELIMIT_ENABLE },
998 { "global ratelimit disable", OPT::GLOBAL_RATELIMIT_DISABLE },
999 { "sync info", OPT::SYNC_INFO },
1000 { "sync status", OPT::SYNC_STATUS },
1001 { "role create", OPT::ROLE_CREATE },
1002 { "role delete", OPT::ROLE_DELETE },
1003 { "role get", OPT::ROLE_GET },
1004 { "role modify", OPT::ROLE_MODIFY },
1005 { "role list", OPT::ROLE_LIST },
1006 { "role policy put", OPT::ROLE_POLICY_PUT },
1007 { "role-policy put", OPT::ROLE_POLICY_PUT },
1008 { "role policy list", OPT::ROLE_POLICY_LIST },
1009 { "role-policy list", OPT::ROLE_POLICY_LIST },
1010 { "role policy get", OPT::ROLE_POLICY_GET },
1011 { "role-policy get", OPT::ROLE_POLICY_GET },
1012 { "role policy delete", OPT::ROLE_POLICY_DELETE },
1013 { "role-policy delete", OPT::ROLE_POLICY_DELETE },
1014 { "reshard bucket", OPT::BUCKET_RESHARD },
1015 { "reshard add", OPT::RESHARD_ADD },
1016 { "reshard list", OPT::RESHARD_LIST },
1017 { "reshard status", OPT::RESHARD_STATUS },
1018 { "reshard process", OPT::RESHARD_PROCESS },
1019 { "reshard cancel", OPT::RESHARD_CANCEL },
1020 { "mfa create", OPT::MFA_CREATE },
1021 { "mfa remove", OPT::MFA_REMOVE },
1022 { "mfa get", OPT::MFA_GET },
1023 { "mfa list", OPT::MFA_LIST },
1024 { "mfa check", OPT::MFA_CHECK },
1025 { "mfa resync", OPT::MFA_RESYNC },
1026 { "reshard stale-instances list", OPT::RESHARD_STALE_INSTANCES_LIST },
1027 { "reshard stale list", OPT::RESHARD_STALE_INSTANCES_LIST },
1028 { "reshard stale-instances delete", OPT::RESHARD_STALE_INSTANCES_DELETE },
1029 { "reshard stale delete", OPT::RESHARD_STALE_INSTANCES_DELETE },
1030 { "topic list", OPT::PUBSUB_TOPICS_LIST },
1031 { "topic get", OPT::PUBSUB_TOPIC_GET },
1032 { "topic rm", OPT::PUBSUB_TOPIC_RM },
1033 { "subscription get", OPT::PUBSUB_SUB_GET },
1034 { "subscription rm", OPT::PUBSUB_SUB_RM },
1035 { "subscription pull", OPT::PUBSUB_SUB_PULL },
1036 { "subscription ack", OPT::PUBSUB_EVENT_RM },
1037 { "script put", OPT::SCRIPT_PUT },
1038 { "script get", OPT::SCRIPT_GET },
1039 { "script rm", OPT::SCRIPT_RM },
1040 { "script-package add", OPT::SCRIPT_PACKAGE_ADD },
1041 { "script-package rm", OPT::SCRIPT_PACKAGE_RM },
1042 { "script-package list", OPT::SCRIPT_PACKAGE_LIST },
1043 };
1044
1045 static SimpleCmd::Aliases cmd_aliases = {
1046 { "delete", "del" },
1047 { "remove", "rm" },
1048 { "rename", "mv" },
1049 };
1050
1051
1052
1053 BIIndexType get_bi_index_type(const string& type_str) {
1054 if (type_str == "plain")
1055 return BIIndexType::Plain;
1056 if (type_str == "instance")
1057 return BIIndexType::Instance;
1058 if (type_str == "olh")
1059 return BIIndexType::OLH;
1060
1061 return BIIndexType::Invalid;
1062 }
1063
1064 log_type get_log_type(const string& type_str) {
1065 if (strcasecmp(type_str.c_str(), "fifo") == 0)
1066 return log_type::fifo;
1067 if (strcasecmp(type_str.c_str(), "omap") == 0)
1068 return log_type::omap;
1069
1070 return static_cast<log_type>(0xff);
1071 }
1072
1073 void dump_bi_entry(bufferlist& bl, BIIndexType index_type, Formatter *formatter)
1074 {
1075 auto iter = bl.cbegin();
1076 switch (index_type) {
1077 case BIIndexType::Plain:
1078 case BIIndexType::Instance:
1079 {
1080 rgw_bucket_dir_entry entry;
1081 decode(entry, iter);
1082 encode_json("entry", entry, formatter);
1083 }
1084 break;
1085 case BIIndexType::OLH:
1086 {
1087 rgw_bucket_olh_entry entry;
1088 decode(entry, iter);
1089 encode_json("entry", entry, formatter);
1090 }
1091 break;
1092 default:
1093 ceph_abort();
1094 break;
1095 }
1096 }
1097
1098 static void show_user_info(RGWUserInfo& info, Formatter *formatter)
1099 {
1100 encode_json("user_info", info, formatter);
1101 formatter->flush(cout);
1102 cout << std::endl;
1103 }
1104
1105 static void show_perm_policy(string perm_policy, Formatter* formatter)
1106 {
1107 formatter->open_object_section("role");
1108 formatter->dump_string("Permission policy", perm_policy);
1109 formatter->close_section();
1110 formatter->flush(cout);
1111 }
1112
1113 static void show_policy_names(std::vector<string> policy_names, Formatter* formatter)
1114 {
1115 formatter->open_array_section("PolicyNames");
1116 for (const auto& it : policy_names) {
1117 formatter->dump_string("policyname", it);
1118 }
1119 formatter->close_section();
1120 formatter->flush(cout);
1121 }
1122
1123 static void show_role_info(rgw::sal::RGWRole* role, Formatter* formatter)
1124 {
1125 formatter->open_object_section("role");
1126 role->dump(formatter);
1127 formatter->close_section();
1128 formatter->flush(cout);
1129 }
1130
1131 static void show_roles_info(vector<std::unique_ptr<rgw::sal::RGWRole>>& roles, Formatter* formatter)
1132 {
1133 formatter->open_array_section("Roles");
1134 for (const auto& it : roles) {
1135 formatter->open_object_section("role");
1136 it->dump(formatter);
1137 formatter->close_section();
1138 }
1139 formatter->close_section();
1140 formatter->flush(cout);
1141 }
1142
1143 static void show_reshard_status(
1144 const list<cls_rgw_bucket_instance_entry>& status, Formatter *formatter)
1145 {
1146 formatter->open_array_section("status");
1147 for (const auto& entry : status) {
1148 formatter->open_object_section("entry");
1149 formatter->dump_string("reshard_status", to_string(entry.reshard_status));
1150 formatter->dump_string("new_bucket_instance_id",
1151 entry.new_bucket_instance_id);
1152 formatter->dump_int("num_shards", entry.num_shards);
1153 formatter->close_section();
1154 }
1155 formatter->close_section();
1156 formatter->flush(cout);
1157 }
1158
1159 class StoreDestructor {
1160 rgw::sal::Store* store;
1161 public:
1162 explicit StoreDestructor(rgw::sal::RadosStore* _s) : store(_s) {}
1163 ~StoreDestructor() {
1164 StoreManager::close_storage(store);
1165 rgw_http_client_cleanup();
1166 }
1167 };
1168
1169 static int init_bucket(rgw::sal::User* user, const rgw_bucket& b,
1170 std::unique_ptr<rgw::sal::Bucket>* bucket)
1171 {
1172 return store->get_bucket(dpp(), nullptr, b, bucket, null_yield);
1173 }
1174
1175 static int init_bucket(rgw::sal::User* user,
1176 const string& tenant_name,
1177 const string& bucket_name,
1178 const string& bucket_id,
1179 std::unique_ptr<rgw::sal::Bucket>* bucket)
1180 {
1181 rgw_bucket b{tenant_name, bucket_name, bucket_id};
1182 return init_bucket(user, b, bucket);
1183 }
1184
1185 static int read_input(const string& infile, bufferlist& bl)
1186 {
1187 int fd = 0;
1188 if (infile.size()) {
1189 fd = open(infile.c_str(), O_RDONLY);
1190 if (fd < 0) {
1191 int err = -errno;
1192 cerr << "error reading input file " << infile << std::endl;
1193 return err;
1194 }
1195 }
1196
1197 #define READ_CHUNK 8196
1198 int r;
1199 int err;
1200
1201 do {
1202 char buf[READ_CHUNK];
1203
1204 r = safe_read(fd, buf, READ_CHUNK);
1205 if (r < 0) {
1206 err = -errno;
1207 cerr << "error while reading input" << std::endl;
1208 goto out;
1209 }
1210 bl.append(buf, r);
1211 } while (r > 0);
1212 err = 0;
1213
1214 out:
1215 if (infile.size()) {
1216 close(fd);
1217 }
1218 return err;
1219 }
1220
1221 template <class T>
1222 static int read_decode_json(const string& infile, T& t)
1223 {
1224 bufferlist bl;
1225 int ret = read_input(infile, bl);
1226 if (ret < 0) {
1227 cerr << "ERROR: failed to read input: " << cpp_strerror(-ret) << std::endl;
1228 return ret;
1229 }
1230 JSONParser p;
1231 if (!p.parse(bl.c_str(), bl.length())) {
1232 cout << "failed to parse JSON" << std::endl;
1233 return -EINVAL;
1234 }
1235
1236 try {
1237 decode_json_obj(t, &p);
1238 } catch (const JSONDecoder::err& e) {
1239 cout << "failed to decode JSON input: " << e.what() << std::endl;
1240 return -EINVAL;
1241 }
1242 return 0;
1243 }
1244
1245 template <class T, class K>
1246 static int read_decode_json(const string& infile, T& t, K *k)
1247 {
1248 bufferlist bl;
1249 int ret = read_input(infile, bl);
1250 if (ret < 0) {
1251 cerr << "ERROR: failed to read input: " << cpp_strerror(-ret) << std::endl;
1252 return ret;
1253 }
1254 JSONParser p;
1255 if (!p.parse(bl.c_str(), bl.length())) {
1256 cout << "failed to parse JSON" << std::endl;
1257 return -EINVAL;
1258 }
1259
1260 try {
1261 t.decode_json(&p, k);
1262 } catch (const JSONDecoder::err& e) {
1263 cout << "failed to decode JSON input: " << e.what() << std::endl;
1264 return -EINVAL;
1265 }
1266 return 0;
1267 }
1268
1269 template <class T>
1270 static bool decode_dump(const char *field_name, bufferlist& bl, Formatter *f)
1271 {
1272 T t;
1273
1274 auto iter = bl.cbegin();
1275
1276 try {
1277 decode(t, iter);
1278 } catch (buffer::error& err) {
1279 return false;
1280 }
1281
1282 encode_json(field_name, t, f);
1283
1284 return true;
1285 }
1286
1287 static bool dump_string(const char *field_name, bufferlist& bl, Formatter *f)
1288 {
1289 string val = bl.to_str();
1290 f->dump_string(field_name, val.c_str() /* hide encoded null termination chars */);
1291
1292 return true;
1293 }
1294
1295 bool set_ratelimit_info(RGWRateLimitInfo& ratelimit, OPT opt_cmd, int64_t max_read_ops, int64_t max_write_ops,
1296 int64_t max_read_bytes, int64_t max_write_bytes,
1297 bool have_max_read_ops, bool have_max_write_ops,
1298 bool have_max_read_bytes, bool have_max_write_bytes)
1299 {
1300 bool ratelimit_configured = true;
1301 switch (opt_cmd) {
1302 case OPT::RATELIMIT_ENABLE:
1303 case OPT::GLOBAL_RATELIMIT_ENABLE:
1304 ratelimit.enabled = true;
1305 break;
1306
1307 case OPT::RATELIMIT_SET:
1308 case OPT::GLOBAL_RATELIMIT_SET:
1309 ratelimit_configured = false;
1310 if (have_max_read_ops) {
1311 if (max_read_ops >= 0) {
1312 ratelimit.max_read_ops = max_read_ops;
1313 ratelimit_configured = true;
1314 }
1315 }
1316 if (have_max_write_ops) {
1317 if (max_write_ops >= 0) {
1318 ratelimit.max_write_ops = max_write_ops;
1319 ratelimit_configured = true;
1320 }
1321 }
1322 if (have_max_read_bytes) {
1323 if (max_read_bytes >= 0) {
1324 ratelimit.max_read_bytes = max_read_bytes;
1325 ratelimit_configured = true;
1326 }
1327 }
1328 if (have_max_write_bytes) {
1329 if (max_write_bytes >= 0) {
1330 ratelimit.max_write_bytes = max_write_bytes;
1331 ratelimit_configured = true;
1332 }
1333 }
1334 break;
1335 case OPT::RATELIMIT_DISABLE:
1336 case OPT::GLOBAL_RATELIMIT_DISABLE:
1337 ratelimit.enabled = false;
1338 break;
1339 default:
1340 break;
1341 }
1342 return ratelimit_configured;
1343 }
1344
1345 void set_quota_info(RGWQuotaInfo& quota, OPT opt_cmd, int64_t max_size, int64_t max_objects,
1346 bool have_max_size, bool have_max_objects)
1347 {
1348 switch (opt_cmd) {
1349 case OPT::QUOTA_ENABLE:
1350 case OPT::GLOBAL_QUOTA_ENABLE:
1351 quota.enabled = true;
1352
1353 // falling through on purpose
1354
1355 case OPT::QUOTA_SET:
1356 case OPT::GLOBAL_QUOTA_SET:
1357 if (have_max_objects) {
1358 if (max_objects < 0) {
1359 quota.max_objects = -1;
1360 } else {
1361 quota.max_objects = max_objects;
1362 }
1363 }
1364 if (have_max_size) {
1365 if (max_size < 0) {
1366 quota.max_size = -1;
1367 } else {
1368 quota.max_size = rgw_rounded_kb(max_size) * 1024;
1369 }
1370 }
1371 break;
1372 case OPT::QUOTA_DISABLE:
1373 case OPT::GLOBAL_QUOTA_DISABLE:
1374 quota.enabled = false;
1375 break;
1376 default:
1377 break;
1378 }
1379 }
1380
1381 int set_bucket_quota(rgw::sal::Store* store, OPT opt_cmd,
1382 const string& tenant_name, const string& bucket_name,
1383 int64_t max_size, int64_t max_objects,
1384 bool have_max_size, bool have_max_objects)
1385 {
1386 std::unique_ptr<rgw::sal::Bucket> bucket;
1387 int r = store->get_bucket(dpp(), nullptr, tenant_name, bucket_name, &bucket, null_yield);
1388 if (r < 0) {
1389 cerr << "could not get bucket info for bucket=" << bucket_name << ": " << cpp_strerror(-r) << std::endl;
1390 return -r;
1391 }
1392
1393 set_quota_info(bucket->get_info().quota, opt_cmd, max_size, max_objects, have_max_size, have_max_objects);
1394
1395 r = bucket->put_info(dpp(), false, real_time());
1396 if (r < 0) {
1397 cerr << "ERROR: failed writing bucket instance info: " << cpp_strerror(-r) << std::endl;
1398 return -r;
1399 }
1400 return 0;
1401 }
1402
1403 int set_bucket_ratelimit(rgw::sal::Store* store, OPT opt_cmd,
1404 const string& tenant_name, const string& bucket_name,
1405 int64_t max_read_ops, int64_t max_write_ops,
1406 int64_t max_read_bytes, int64_t max_write_bytes,
1407 bool have_max_read_ops, bool have_max_write_ops,
1408 bool have_max_read_bytes, bool have_max_write_bytes)
1409 {
1410 std::unique_ptr<rgw::sal::Bucket> bucket;
1411 int r = store->get_bucket(dpp(), nullptr, tenant_name, bucket_name, &bucket, null_yield);
1412 if (r < 0) {
1413 cerr << "could not get bucket info for bucket=" << bucket_name << ": " << cpp_strerror(-r) << std::endl;
1414 return -r;
1415 }
1416 RGWRateLimitInfo ratelimit_info;
1417 auto iter = bucket->get_attrs().find(RGW_ATTR_RATELIMIT);
1418 if(iter != bucket->get_attrs().end()) {
1419 try {
1420 bufferlist& bl = iter->second;
1421 auto biter = bl.cbegin();
1422 decode(ratelimit_info, biter);
1423 } catch (buffer::error& err) {
1424 ldpp_dout(dpp(), 0) << "ERROR: failed to decode rate limit" << dendl;
1425 return -EIO;
1426 }
1427 }
1428 bool ratelimit_configured = set_ratelimit_info(ratelimit_info, opt_cmd, max_read_ops, max_write_ops,
1429 max_read_bytes, max_write_bytes,
1430 have_max_read_ops, have_max_write_ops,
1431 have_max_read_bytes, have_max_write_bytes);
1432 if (!ratelimit_configured) {
1433 ldpp_dout(dpp(), 0) << "ERROR: no rate limit values have been specified" << dendl;
1434 return -EINVAL;
1435 }
1436 bufferlist bl;
1437 ratelimit_info.encode(bl);
1438 rgw::sal::Attrs attr;
1439 attr[RGW_ATTR_RATELIMIT] = bl;
1440 r = bucket->merge_and_store_attrs(dpp(), attr, null_yield);
1441 if (r < 0) {
1442 cerr << "ERROR: failed writing bucket instance info: " << cpp_strerror(-r) << std::endl;
1443 return -r;
1444 }
1445 return 0;
1446 }
1447
1448 int set_user_ratelimit(OPT opt_cmd, std::unique_ptr<rgw::sal::User>& user,
1449 int64_t max_read_ops, int64_t max_write_ops,
1450 int64_t max_read_bytes, int64_t max_write_bytes,
1451 bool have_max_read_ops, bool have_max_write_ops,
1452 bool have_max_read_bytes, bool have_max_write_bytes)
1453 {
1454 RGWRateLimitInfo ratelimit_info;
1455 user->load_user(dpp(), null_yield);
1456 auto iter = user->get_attrs().find(RGW_ATTR_RATELIMIT);
1457 if(iter != user->get_attrs().end()) {
1458 try {
1459 bufferlist& bl = iter->second;
1460 auto biter = bl.cbegin();
1461 decode(ratelimit_info, biter);
1462 } catch (buffer::error& err) {
1463 ldpp_dout(dpp(), 0) << "ERROR: failed to decode rate limit" << dendl;
1464 return -EIO;
1465 }
1466 }
1467 bool ratelimit_configured = set_ratelimit_info(ratelimit_info, opt_cmd, max_read_ops, max_write_ops,
1468 max_read_bytes, max_write_bytes,
1469 have_max_read_ops, have_max_write_ops,
1470 have_max_read_bytes, have_max_write_bytes);
1471 if (!ratelimit_configured) {
1472 ldpp_dout(dpp(), 0) << "ERROR: no rate limit values have been specified" << dendl;
1473 return -EINVAL;
1474 }
1475 bufferlist bl;
1476 ratelimit_info.encode(bl);
1477 rgw::sal::Attrs attr;
1478 attr[RGW_ATTR_RATELIMIT] = bl;
1479 int r = user->merge_and_store_attrs(dpp(), attr, null_yield);
1480 if (r < 0) {
1481 cerr << "ERROR: failed writing user instance info: " << cpp_strerror(-r) << std::endl;
1482 return -r;
1483 }
1484 return 0;
1485 }
1486
1487 int show_user_ratelimit(std::unique_ptr<rgw::sal::User>& user, Formatter *formatter)
1488 {
1489 RGWRateLimitInfo ratelimit_info;
1490 user->load_user(dpp(), null_yield);
1491 auto iter = user->get_attrs().find(RGW_ATTR_RATELIMIT);
1492 if(iter != user->get_attrs().end()) {
1493 try {
1494 bufferlist& bl = iter->second;
1495 auto biter = bl.cbegin();
1496 decode(ratelimit_info, biter);
1497 } catch (buffer::error& err) {
1498 ldpp_dout(dpp(), 0) << "ERROR: failed to decode rate limit" << dendl;
1499 return -EIO;
1500 }
1501 }
1502 formatter->open_object_section("user_ratelimit");
1503 encode_json("user_ratelimit", ratelimit_info, formatter);
1504 formatter->close_section();
1505 formatter->flush(cout);
1506 cout << std::endl;
1507 return 0;
1508 }
1509
1510 int show_bucket_ratelimit(rgw::sal::Store* store, const string& tenant_name,
1511 const string& bucket_name, Formatter *formatter)
1512 {
1513 std::unique_ptr<rgw::sal::Bucket> bucket;
1514 int r = store->get_bucket(dpp(), nullptr, tenant_name, bucket_name, &bucket, null_yield);
1515 if (r < 0) {
1516 cerr << "could not get bucket info for bucket=" << bucket_name << ": " << cpp_strerror(-r) << std::endl;
1517 return -r;
1518 }
1519 RGWRateLimitInfo ratelimit_info;
1520 auto iter = bucket->get_attrs().find(RGW_ATTR_RATELIMIT);
1521 if (iter != bucket->get_attrs().end()) {
1522 try {
1523 bufferlist& bl = iter->second;
1524 auto biter = bl.cbegin();
1525 decode(ratelimit_info, biter);
1526 } catch (buffer::error& err) {
1527 ldpp_dout(dpp(), 0) << "ERROR: failed to decode rate limit" << dendl;
1528 return -EIO;
1529 }
1530 }
1531 formatter->open_object_section("bucket_ratelimit");
1532 encode_json("bucket_ratelimit", ratelimit_info, formatter);
1533 formatter->close_section();
1534 formatter->flush(cout);
1535 cout << std::endl;
1536 return 0;
1537 }
1538 int set_user_bucket_quota(OPT opt_cmd, RGWUser& user, RGWUserAdminOpState& op_state, int64_t max_size, int64_t max_objects,
1539 bool have_max_size, bool have_max_objects)
1540 {
1541 RGWUserInfo& user_info = op_state.get_user_info();
1542
1543 set_quota_info(user_info.bucket_quota, opt_cmd, max_size, max_objects, have_max_size, have_max_objects);
1544
1545 op_state.set_bucket_quota(user_info.bucket_quota);
1546
1547 string err;
1548 int r = user.modify(dpp(), op_state, null_yield, &err);
1549 if (r < 0) {
1550 cerr << "ERROR: failed updating user info: " << cpp_strerror(-r) << ": " << err << std::endl;
1551 return -r;
1552 }
1553 return 0;
1554 }
1555
1556 int set_user_quota(OPT opt_cmd, RGWUser& user, RGWUserAdminOpState& op_state, int64_t max_size, int64_t max_objects,
1557 bool have_max_size, bool have_max_objects)
1558 {
1559 RGWUserInfo& user_info = op_state.get_user_info();
1560
1561 set_quota_info(user_info.user_quota, opt_cmd, max_size, max_objects, have_max_size, have_max_objects);
1562
1563 op_state.set_user_quota(user_info.user_quota);
1564
1565 string err;
1566 int r = user.modify(dpp(), op_state, null_yield, &err);
1567 if (r < 0) {
1568 cerr << "ERROR: failed updating user info: " << cpp_strerror(-r) << ": " << err << std::endl;
1569 return -r;
1570 }
1571 return 0;
1572 }
1573
1574 int check_min_obj_stripe_size(rgw::sal::Store* store, rgw::sal::Object* obj, uint64_t min_stripe_size, bool *need_rewrite)
1575 {
1576 RGWObjectCtx obj_ctx(store);
1577 int ret = obj->get_obj_attrs(&obj_ctx, null_yield, dpp());
1578 if (ret < 0) {
1579 ldpp_dout(dpp(), -1) << "ERROR: failed to stat object, returned error: " << cpp_strerror(-ret) << dendl;
1580 return ret;
1581 }
1582
1583 map<string, bufferlist>::iterator iter;
1584 iter = obj->get_attrs().find(RGW_ATTR_MANIFEST);
1585 if (iter == obj->get_attrs().end()) {
1586 *need_rewrite = (obj->get_obj_size() >= min_stripe_size);
1587 return 0;
1588 }
1589
1590 RGWObjManifest manifest;
1591
1592 try {
1593 bufferlist& bl = iter->second;
1594 auto biter = bl.cbegin();
1595 decode(manifest, biter);
1596 } catch (buffer::error& err) {
1597 ldpp_dout(dpp(), 0) << "ERROR: failed to decode manifest" << dendl;
1598 return -EIO;
1599 }
1600
1601 map<uint64_t, RGWObjManifestPart>& objs = manifest.get_explicit_objs();
1602 map<uint64_t, RGWObjManifestPart>::iterator oiter;
1603 for (oiter = objs.begin(); oiter != objs.end(); ++oiter) {
1604 RGWObjManifestPart& part = oiter->second;
1605
1606 if (part.size >= min_stripe_size) {
1607 *need_rewrite = true;
1608 return 0;
1609 }
1610 }
1611 *need_rewrite = false;
1612
1613 return 0;
1614 }
1615
1616
1617 int check_obj_locator_underscore(rgw::sal::Object* obj, bool fix, bool remove_bad, Formatter *f) {
1618 f->open_object_section("object");
1619 f->open_object_section("key");
1620 f->dump_string("type", "head");
1621 f->dump_string("name", obj->get_name());
1622 f->dump_string("instance", obj->get_instance());
1623 f->close_section();
1624
1625 string oid;
1626 string locator;
1627
1628 get_obj_bucket_and_oid_loc(obj->get_obj(), oid, locator);
1629
1630 f->dump_string("oid", oid);
1631 f->dump_string("locator", locator);
1632
1633 RGWObjectCtx obj_ctx(store);
1634 std::unique_ptr<rgw::sal::Object::ReadOp> read_op = obj->get_read_op(&obj_ctx);
1635
1636 int ret = read_op->prepare(null_yield, dpp());
1637 bool needs_fixing = (ret == -ENOENT);
1638
1639 f->dump_bool("needs_fixing", needs_fixing);
1640
1641 string status = (needs_fixing ? "needs_fixing" : "ok");
1642
1643 if ((needs_fixing || remove_bad) && fix) {
1644 ret = static_cast<rgw::sal::RadosStore*>(store)->getRados()->fix_head_obj_locator(dpp(), obj->get_bucket()->get_info(), needs_fixing, remove_bad, obj->get_key());
1645 if (ret < 0) {
1646 cerr << "ERROR: fix_head_object_locator() returned ret=" << ret << std::endl;
1647 goto done;
1648 }
1649 status = "fixed";
1650 }
1651
1652 done:
1653 f->dump_string("status", status);
1654
1655 f->close_section();
1656
1657 return 0;
1658 }
1659
1660 int check_obj_tail_locator_underscore(RGWBucketInfo& bucket_info, rgw_obj_key& key, bool fix, Formatter *f) {
1661 f->open_object_section("object");
1662 f->open_object_section("key");
1663 f->dump_string("type", "tail");
1664 f->dump_string("name", key.name);
1665 f->dump_string("instance", key.instance);
1666 f->close_section();
1667
1668 bool needs_fixing;
1669 string status;
1670
1671 int ret = static_cast<rgw::sal::RadosStore*>(store)->getRados()->fix_tail_obj_locator(dpp(), bucket_info, key, fix, &needs_fixing, null_yield);
1672 if (ret < 0) {
1673 cerr << "ERROR: fix_tail_object_locator_underscore() returned ret=" << ret << std::endl;
1674 status = "failed";
1675 } else {
1676 status = (needs_fixing && !fix ? "needs_fixing" : "ok");
1677 }
1678
1679 f->dump_bool("needs_fixing", needs_fixing);
1680 f->dump_string("status", status);
1681
1682 f->close_section();
1683
1684 return 0;
1685 }
1686
1687 int do_check_object_locator(const string& tenant_name, const string& bucket_name,
1688 bool fix, bool remove_bad, Formatter *f)
1689 {
1690 if (remove_bad && !fix) {
1691 cerr << "ERROR: can't have remove_bad specified without fix" << std::endl;
1692 return -EINVAL;
1693 }
1694
1695 std::unique_ptr<rgw::sal::Bucket> bucket;
1696 string bucket_id;
1697
1698 f->open_object_section("bucket");
1699 f->dump_string("bucket", bucket_name);
1700 int ret = init_bucket(nullptr, tenant_name, bucket_name, bucket_id, &bucket);
1701 if (ret < 0) {
1702 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
1703 return ret;
1704 }
1705 int count = 0;
1706
1707 int max_entries = 1000;
1708
1709 string prefix;
1710 string delim;
1711 string marker;
1712 vector<rgw_bucket_dir_entry> result;
1713 string ns;
1714
1715 rgw::sal::Bucket::ListParams params;
1716 rgw::sal::Bucket::ListResults results;
1717
1718 params.prefix = prefix;
1719 params.delim = delim;
1720 params.marker = rgw_obj_key(marker);
1721 params.ns = ns;
1722 params.enforce_ns = true;
1723 params.list_versions = true;
1724
1725 f->open_array_section("check_objects");
1726 do {
1727 ret = bucket->list(dpp(), params, max_entries - count, results, null_yield);
1728 if (ret < 0) {
1729 cerr << "ERROR: store->list_objects(): " << cpp_strerror(-ret) << std::endl;
1730 return -ret;
1731 }
1732
1733 count += results.objs.size();
1734
1735 for (vector<rgw_bucket_dir_entry>::iterator iter = results.objs.begin(); iter != results.objs.end(); ++iter) {
1736 std::unique_ptr<rgw::sal::Object> obj = bucket->get_object(iter->key);
1737
1738 if (obj->get_name()[0] == '_') {
1739 ret = check_obj_locator_underscore(obj.get(), fix, remove_bad, f);
1740
1741 if (ret >= 0) {
1742 ret = check_obj_tail_locator_underscore(bucket->get_info(), obj->get_key(), fix, f);
1743 if (ret < 0) {
1744 cerr << "ERROR: check_obj_tail_locator_underscore(): " << cpp_strerror(-ret) << std::endl;
1745 return -ret;
1746 }
1747 }
1748 }
1749 }
1750 f->flush(cout);
1751 } while (results.is_truncated && count < max_entries);
1752 f->close_section();
1753 f->close_section();
1754
1755 f->flush(cout);
1756
1757 return 0;
1758 }
1759
1760 /// search for a matching zone/zonegroup id and return a connection if found
1761 static boost::optional<RGWRESTConn> get_remote_conn(rgw::sal::RadosStore* store,
1762 const RGWZoneGroup& zonegroup,
1763 const std::string& remote)
1764 {
1765 boost::optional<RGWRESTConn> conn;
1766 if (remote == zonegroup.get_id()) {
1767 conn.emplace(store->ctx(), store->svc()->zone, remote, zonegroup.endpoints, zonegroup.api_name);
1768 } else {
1769 for (const auto& z : zonegroup.zones) {
1770 const auto& zone = z.second;
1771 if (remote == zone.id) {
1772 conn.emplace(store->ctx(), store->svc()->zone, remote, zone.endpoints, zonegroup.api_name);
1773 break;
1774 }
1775 }
1776 }
1777 return conn;
1778 }
1779
1780 /// search each zonegroup for a connection
1781 static boost::optional<RGWRESTConn> get_remote_conn(rgw::sal::RadosStore* store,
1782 const RGWPeriodMap& period_map,
1783 const std::string& remote)
1784 {
1785 boost::optional<RGWRESTConn> conn;
1786 for (const auto& zg : period_map.zonegroups) {
1787 conn = get_remote_conn(store, zg.second, remote);
1788 if (conn) {
1789 break;
1790 }
1791 }
1792 return conn;
1793 }
1794
1795 // we expect a very small response
1796 static constexpr size_t MAX_REST_RESPONSE = 128 * 1024;
1797
1798 static int send_to_remote_gateway(RGWRESTConn* conn, req_info& info,
1799 bufferlist& in_data, JSONParser& parser)
1800 {
1801 if (!conn) {
1802 return -EINVAL;
1803 }
1804
1805 ceph::bufferlist response;
1806 rgw_user user;
1807 int ret = conn->forward(dpp(), user, info, nullptr, MAX_REST_RESPONSE, &in_data, &response, null_yield);
1808
1809 int parse_ret = parser.parse(response.c_str(), response.length());
1810 if (parse_ret < 0) {
1811 cerr << "failed to parse response" << std::endl;
1812 return parse_ret;
1813 }
1814 return ret;
1815 }
1816
1817 static int send_to_url(const string& url,
1818 std::optional<string> opt_region,
1819 const string& access,
1820 const string& secret, req_info& info,
1821 bufferlist& in_data, JSONParser& parser)
1822 {
1823 if (access.empty() || secret.empty()) {
1824 cerr << "An --access-key and --secret must be provided with --url." << std::endl;
1825 return -EINVAL;
1826 }
1827 RGWAccessKey key;
1828 key.id = access;
1829 key.key = secret;
1830
1831 param_vec_t params;
1832 RGWRESTSimpleRequest req(g_ceph_context, info.method, url, NULL, &params, opt_region);
1833
1834 bufferlist response;
1835 int ret = req.forward_request(dpp(), key, info, MAX_REST_RESPONSE, &in_data, &response, null_yield);
1836
1837 int parse_ret = parser.parse(response.c_str(), response.length());
1838 if (parse_ret < 0) {
1839 cout << "failed to parse response" << std::endl;
1840 return parse_ret;
1841 }
1842 return ret;
1843 }
1844
1845 static int send_to_remote_or_url(RGWRESTConn *conn, const string& url,
1846 std::optional<string> opt_region,
1847 const string& access, const string& secret,
1848 req_info& info, bufferlist& in_data,
1849 JSONParser& parser)
1850 {
1851 if (url.empty()) {
1852 return send_to_remote_gateway(conn, info, in_data, parser);
1853 }
1854 return send_to_url(url, opt_region, access, secret, info, in_data, parser);
1855 }
1856
1857 static int commit_period(RGWRealm& realm, RGWPeriod& period,
1858 string remote, const string& url,
1859 std::optional<string> opt_region,
1860 const string& access, const string& secret,
1861 bool force)
1862 {
1863 auto& master_zone = period.get_master_zone();
1864 if (master_zone.empty()) {
1865 cerr << "cannot commit period: period does not have a master zone of a master zonegroup" << std::endl;
1866 return -EINVAL;
1867 }
1868 // are we the period's master zone?
1869 if (store->get_zone()->get_id() == master_zone) {
1870 // read the current period
1871 RGWPeriod current_period;
1872 int ret = current_period.init(dpp(), g_ceph_context,
1873 static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, realm.get_id(),
1874 null_yield);
1875 if (ret < 0) {
1876 cerr << "Error initializing current period: "
1877 << cpp_strerror(-ret) << std::endl;
1878 return ret;
1879 }
1880 // the master zone can commit locally
1881 ret = period.commit(dpp(), store, realm, current_period, cerr, null_yield, force);
1882 if (ret < 0) {
1883 cerr << "failed to commit period: " << cpp_strerror(-ret) << std::endl;
1884 }
1885 return ret;
1886 }
1887
1888 if (remote.empty() && url.empty()) {
1889 // use the new master zone's connection
1890 remote = master_zone.id;
1891 cerr << "Sending period to new master zone " << remote << std::endl;
1892 }
1893 boost::optional<RGWRESTConn> conn;
1894 RGWRESTConn *remote_conn = nullptr;
1895 if (!remote.empty()) {
1896 conn = get_remote_conn(static_cast<rgw::sal::RadosStore*>(store), period.get_map(), remote);
1897 if (!conn) {
1898 cerr << "failed to find a zone or zonegroup for remote "
1899 << remote << std::endl;
1900 return -ENOENT;
1901 }
1902 remote_conn = &*conn;
1903 }
1904
1905 // push period to the master with an empty period id
1906 period.set_id(string());
1907
1908 RGWEnv env;
1909 req_info info(g_ceph_context, &env);
1910 info.method = "POST";
1911 info.request_uri = "/admin/realm/period";
1912
1913 // json format into a bufferlist
1914 JSONFormatter jf(false);
1915 encode_json("period", period, &jf);
1916 bufferlist bl;
1917 jf.flush(bl);
1918
1919 JSONParser p;
1920 int ret = send_to_remote_or_url(remote_conn, url, opt_region, access, secret, info, bl, p);
1921 if (ret < 0) {
1922 cerr << "request failed: " << cpp_strerror(-ret) << std::endl;
1923
1924 // did we parse an error message?
1925 auto message = p.find_obj("Message");
1926 if (message) {
1927 cerr << "Reason: " << message->get_data() << std::endl;
1928 }
1929 return ret;
1930 }
1931
1932 // decode the response and store it back
1933 try {
1934 decode_json_obj(period, &p);
1935 } catch (const JSONDecoder::err& e) {
1936 cout << "failed to decode JSON input: " << e.what() << std::endl;
1937 return -EINVAL;
1938 }
1939 if (period.get_id().empty()) {
1940 cerr << "Period commit got back an empty period id" << std::endl;
1941 return -EINVAL;
1942 }
1943 // the master zone gave us back the period that it committed, so it's
1944 // safe to save it as our latest epoch
1945 ret = period.store_info(dpp(), false, null_yield);
1946 if (ret < 0) {
1947 cerr << "Error storing committed period " << period.get_id() << ": "
1948 << cpp_strerror(ret) << std::endl;
1949 return ret;
1950 }
1951 ret = period.set_latest_epoch(dpp(), null_yield, period.get_epoch());
1952 if (ret < 0) {
1953 cerr << "Error updating period epoch: " << cpp_strerror(ret) << std::endl;
1954 return ret;
1955 }
1956 ret = period.reflect(dpp(), null_yield);
1957 if (ret < 0) {
1958 cerr << "Error updating local objects: " << cpp_strerror(ret) << std::endl;
1959 return ret;
1960 }
1961 realm.notify_new_period(dpp(), period, null_yield);
1962 return ret;
1963 }
1964
1965 static int update_period(const string& realm_id, const string& realm_name,
1966 const string& period_id, const string& period_epoch,
1967 bool commit, const string& remote, const string& url,
1968 std::optional<string> opt_region,
1969 const string& access, const string& secret,
1970 Formatter *formatter, bool force)
1971 {
1972 RGWRealm realm(realm_id, realm_name);
1973 int ret = realm.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
1974 if (ret < 0 ) {
1975 cerr << "Error initializing realm " << cpp_strerror(-ret) << std::endl;
1976 return ret;
1977 }
1978 epoch_t epoch = 0;
1979 if (!period_epoch.empty()) {
1980 epoch = atoi(period_epoch.c_str());
1981 }
1982 RGWPeriod period(period_id, epoch);
1983 ret = period.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, realm.get_id(), null_yield);
1984 if (ret < 0) {
1985 cerr << "period init failed: " << cpp_strerror(-ret) << std::endl;
1986 return ret;
1987 }
1988 period.fork();
1989 ret = period.update(dpp(), null_yield);
1990 if(ret < 0) {
1991 // Dropping the error message here, as both the ret codes were handled in
1992 // period.update()
1993 return ret;
1994 }
1995 ret = period.store_info(dpp(), false, null_yield);
1996 if (ret < 0) {
1997 cerr << "failed to store period: " << cpp_strerror(-ret) << std::endl;
1998 return ret;
1999 }
2000 if (commit) {
2001 ret = commit_period(realm, period, remote, url, opt_region, access, secret, force);
2002 if (ret < 0) {
2003 cerr << "failed to commit period: " << cpp_strerror(-ret) << std::endl;
2004 return ret;
2005 }
2006 }
2007 encode_json("period", period, formatter);
2008 formatter->flush(cout);
2009 return 0;
2010 }
2011
2012 static int init_bucket_for_sync(rgw::sal::User* user,
2013 const string& tenant, const string& bucket_name,
2014 const string& bucket_id,
2015 std::unique_ptr<rgw::sal::Bucket>* bucket)
2016 {
2017 int ret = init_bucket(user, tenant, bucket_name, bucket_id, bucket);
2018 if (ret < 0) {
2019 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
2020 return ret;
2021 }
2022
2023 return 0;
2024 }
2025
2026 static int do_period_pull(RGWRESTConn *remote_conn, const string& url,
2027 std::optional<string> opt_region,
2028 const string& access_key, const string& secret_key,
2029 const string& realm_id, const string& realm_name,
2030 const string& period_id, const string& period_epoch,
2031 RGWPeriod *period)
2032 {
2033 RGWEnv env;
2034 req_info info(g_ceph_context, &env);
2035 info.method = "GET";
2036 info.request_uri = "/admin/realm/period";
2037
2038 map<string, string> &params = info.args.get_params();
2039 if (!realm_id.empty())
2040 params["realm_id"] = realm_id;
2041 if (!realm_name.empty())
2042 params["realm_name"] = realm_name;
2043 if (!period_id.empty())
2044 params["period_id"] = period_id;
2045 if (!period_epoch.empty())
2046 params["epoch"] = period_epoch;
2047
2048 bufferlist bl;
2049 JSONParser p;
2050 int ret = send_to_remote_or_url(remote_conn, url, opt_region, access_key, secret_key,
2051 info, bl, p);
2052 if (ret < 0) {
2053 cerr << "request failed: " << cpp_strerror(-ret) << std::endl;
2054 return ret;
2055 }
2056 ret = period->init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield, false);
2057 if (ret < 0) {
2058 cerr << "faile to init period " << cpp_strerror(-ret) << std::endl;
2059 return ret;
2060 }
2061 try {
2062 decode_json_obj(*period, &p);
2063 } catch (const JSONDecoder::err& e) {
2064 cout << "failed to decode JSON input: " << e.what() << std::endl;
2065 return -EINVAL;
2066 }
2067 ret = period->store_info(dpp(), false, null_yield);
2068 if (ret < 0) {
2069 cerr << "Error storing period " << period->get_id() << ": " << cpp_strerror(ret) << std::endl;
2070 }
2071 // store latest epoch (ignore errors)
2072 period->update_latest_epoch(dpp(), period->get_epoch(), null_yield);
2073 return 0;
2074 }
2075
2076 static int read_current_period_id(rgw::sal::RadosStore* store, const std::string& realm_id,
2077 const std::string& realm_name,
2078 std::string* period_id)
2079 {
2080 RGWRealm realm(realm_id, realm_name);
2081 int ret = realm.init(dpp(), g_ceph_context, store->svc()->sysobj, null_yield);
2082 if (ret < 0) {
2083 std::cerr << "failed to read realm: " << cpp_strerror(-ret) << std::endl;
2084 return ret;
2085 }
2086 *period_id = realm.get_current_period();
2087 return 0;
2088 }
2089
2090 void flush_ss(stringstream& ss, list<string>& l)
2091 {
2092 if (!ss.str().empty()) {
2093 l.push_back(ss.str());
2094 }
2095 ss.str("");
2096 }
2097
2098 stringstream& push_ss(stringstream& ss, list<string>& l, int tab = 0)
2099 {
2100 flush_ss(ss, l);
2101 if (tab > 0) {
2102 ss << setw(tab) << "" << setw(1);
2103 }
2104 return ss;
2105 }
2106
2107 static void get_md_sync_status(list<string>& status)
2108 {
2109 RGWMetaSyncStatusManager sync(static_cast<rgw::sal::RadosStore*>(store), static_cast<rgw::sal::RadosStore*>(store)->svc()->rados->get_async_processor());
2110
2111 int ret = sync.init(dpp());
2112 if (ret < 0) {
2113 status.push_back(string("failed to retrieve sync info: sync.init() failed: ") + cpp_strerror(-ret));
2114 return;
2115 }
2116
2117 rgw_meta_sync_status sync_status;
2118 ret = sync.read_sync_status(dpp(), &sync_status);
2119 if (ret < 0) {
2120 status.push_back(string("failed to read sync status: ") + cpp_strerror(-ret));
2121 return;
2122 }
2123
2124 string status_str;
2125 switch (sync_status.sync_info.state) {
2126 case rgw_meta_sync_info::StateInit:
2127 status_str = "init";
2128 break;
2129 case rgw_meta_sync_info::StateBuildingFullSyncMaps:
2130 status_str = "preparing for full sync";
2131 break;
2132 case rgw_meta_sync_info::StateSync:
2133 status_str = "syncing";
2134 break;
2135 default:
2136 status_str = "unknown";
2137 }
2138
2139 status.push_back(status_str);
2140
2141 uint64_t full_total = 0;
2142 uint64_t full_complete = 0;
2143
2144 int num_full = 0;
2145 int num_inc = 0;
2146 int total_shards = 0;
2147 set<int> shards_behind_set;
2148
2149 for (auto marker_iter : sync_status.sync_markers) {
2150 full_total += marker_iter.second.total_entries;
2151 total_shards++;
2152 if (marker_iter.second.state == rgw_meta_sync_marker::SyncState::FullSync) {
2153 num_full++;
2154 full_complete += marker_iter.second.pos;
2155 int shard_id = marker_iter.first;
2156 shards_behind_set.insert(shard_id);
2157 } else {
2158 full_complete += marker_iter.second.total_entries;
2159 }
2160 if (marker_iter.second.state == rgw_meta_sync_marker::SyncState::IncrementalSync) {
2161 num_inc++;
2162 }
2163 }
2164
2165 stringstream ss;
2166 push_ss(ss, status) << "full sync: " << num_full << "/" << total_shards << " shards";
2167
2168 if (num_full > 0) {
2169 push_ss(ss, status) << "full sync: " << full_total - full_complete << " entries to sync";
2170 }
2171
2172 push_ss(ss, status) << "incremental sync: " << num_inc << "/" << total_shards << " shards";
2173
2174 map<int, RGWMetadataLogInfo> master_shards_info;
2175 string master_period = static_cast<rgw::sal::RadosStore*>(store)->svc()->zone->get_current_period_id();
2176
2177 ret = sync.read_master_log_shards_info(dpp(), master_period, &master_shards_info);
2178 if (ret < 0) {
2179 status.push_back(string("failed to fetch master sync status: ") + cpp_strerror(-ret));
2180 return;
2181 }
2182
2183 map<int, string> shards_behind;
2184 if (sync_status.sync_info.period != master_period) {
2185 status.push_back(string("master is on a different period: master_period=" +
2186 master_period + " local_period=" + sync_status.sync_info.period));
2187 } else {
2188 for (auto local_iter : sync_status.sync_markers) {
2189 int shard_id = local_iter.first;
2190 auto iter = master_shards_info.find(shard_id);
2191
2192 if (iter == master_shards_info.end()) {
2193 /* huh? */
2194 derr << "ERROR: could not find remote sync shard status for shard_id=" << shard_id << dendl;
2195 continue;
2196 }
2197 auto master_marker = iter->second.marker;
2198 if (local_iter.second.state == rgw_meta_sync_marker::SyncState::IncrementalSync &&
2199 master_marker > local_iter.second.marker) {
2200 shards_behind[shard_id] = local_iter.second.marker;
2201 shards_behind_set.insert(shard_id);
2202 }
2203 }
2204 }
2205
2206 // fetch remote log entries to determine the oldest change
2207 std::optional<std::pair<int, ceph::real_time>> oldest;
2208 if (!shards_behind.empty()) {
2209 map<int, rgw_mdlog_shard_data> master_pos;
2210 ret = sync.read_master_log_shards_next(dpp(), sync_status.sync_info.period, shards_behind, &master_pos);
2211 if (ret < 0) {
2212 derr << "ERROR: failed to fetch master next positions (" << cpp_strerror(-ret) << ")" << dendl;
2213 } else {
2214 for (auto iter : master_pos) {
2215 rgw_mdlog_shard_data& shard_data = iter.second;
2216
2217 if (shard_data.entries.empty()) {
2218 // there aren't any entries in this shard, so we're not really behind
2219 shards_behind.erase(iter.first);
2220 shards_behind_set.erase(iter.first);
2221 } else {
2222 rgw_mdlog_entry& entry = shard_data.entries.front();
2223 if (!oldest) {
2224 oldest.emplace(iter.first, entry.timestamp);
2225 } else if (!ceph::real_clock::is_zero(entry.timestamp) && entry.timestamp < oldest->second) {
2226 oldest.emplace(iter.first, entry.timestamp);
2227 }
2228 }
2229 }
2230 }
2231 }
2232
2233 int total_behind = shards_behind.size() + (sync_status.sync_info.num_shards - num_inc);
2234 if (total_behind == 0) {
2235 push_ss(ss, status) << "metadata is caught up with master";
2236 } else {
2237 push_ss(ss, status) << "metadata is behind on " << total_behind << " shards";
2238 push_ss(ss, status) << "behind shards: " << "[" << shards_behind_set << "]";
2239 if (oldest) {
2240 push_ss(ss, status) << "oldest incremental change not applied: "
2241 << oldest->second << " [" << oldest->first << ']';
2242 }
2243 }
2244
2245 flush_ss(ss, status);
2246 }
2247
2248 static void get_data_sync_status(const rgw_zone_id& source_zone, list<string>& status, int tab)
2249 {
2250 stringstream ss;
2251
2252 RGWZone *sz;
2253
2254 if (!static_cast<rgw::sal::RadosStore*>(store)->svc()->zone->find_zone(source_zone, &sz)) {
2255 push_ss(ss, status, tab) << string("zone not found");
2256 flush_ss(ss, status);
2257 return;
2258 }
2259
2260 if (!static_cast<rgw::sal::RadosStore*>(store)->svc()->zone->zone_syncs_from(static_cast<rgw::sal::RadosStore*>(store)->svc()->zone->get_zone(), *sz)) {
2261 push_ss(ss, status, tab) << string("not syncing from zone");
2262 flush_ss(ss, status);
2263 return;
2264 }
2265 RGWDataSyncStatusManager sync(static_cast<rgw::sal::RadosStore*>(store), static_cast<rgw::sal::RadosStore*>(store)->svc()->rados->get_async_processor(), source_zone, nullptr);
2266
2267 int ret = sync.init(dpp());
2268 if (ret < 0) {
2269 push_ss(ss, status, tab) << string("failed to retrieve sync info: ") + cpp_strerror(-ret);
2270 flush_ss(ss, status);
2271 return;
2272 }
2273
2274 rgw_data_sync_status sync_status;
2275 ret = sync.read_sync_status(dpp(), &sync_status);
2276 if (ret < 0 && ret != -ENOENT) {
2277 push_ss(ss, status, tab) << string("failed read sync status: ") + cpp_strerror(-ret);
2278 return;
2279 }
2280
2281 set<int> recovering_shards;
2282 ret = sync.read_recovering_shards(dpp(), sync_status.sync_info.num_shards, recovering_shards);
2283 if (ret < 0 && ret != ENOENT) {
2284 push_ss(ss, status, tab) << string("failed read recovering shards: ") + cpp_strerror(-ret);
2285 return;
2286 }
2287
2288 string status_str;
2289 switch (sync_status.sync_info.state) {
2290 case rgw_data_sync_info::StateInit:
2291 status_str = "init";
2292 break;
2293 case rgw_data_sync_info::StateBuildingFullSyncMaps:
2294 status_str = "preparing for full sync";
2295 break;
2296 case rgw_data_sync_info::StateSync:
2297 status_str = "syncing";
2298 break;
2299 default:
2300 status_str = "unknown";
2301 }
2302
2303 push_ss(ss, status, tab) << status_str;
2304
2305 uint64_t full_total = 0;
2306 uint64_t full_complete = 0;
2307
2308 int num_full = 0;
2309 int num_inc = 0;
2310 int total_shards = 0;
2311 set<int> shards_behind_set;
2312
2313 for (auto marker_iter : sync_status.sync_markers) {
2314 full_total += marker_iter.second.total_entries;
2315 total_shards++;
2316 if (marker_iter.second.state == rgw_data_sync_marker::SyncState::FullSync) {
2317 num_full++;
2318 full_complete += marker_iter.second.pos;
2319 int shard_id = marker_iter.first;
2320 shards_behind_set.insert(shard_id);
2321 } else {
2322 full_complete += marker_iter.second.total_entries;
2323 }
2324 if (marker_iter.second.state == rgw_data_sync_marker::SyncState::IncrementalSync) {
2325 num_inc++;
2326 }
2327 }
2328
2329 push_ss(ss, status, tab) << "full sync: " << num_full << "/" << total_shards << " shards";
2330
2331 if (num_full > 0) {
2332 push_ss(ss, status, tab) << "full sync: " << full_total - full_complete << " buckets to sync";
2333 }
2334
2335 push_ss(ss, status, tab) << "incremental sync: " << num_inc << "/" << total_shards << " shards";
2336
2337 map<int, RGWDataChangesLogInfo> source_shards_info;
2338
2339 ret = sync.read_source_log_shards_info(dpp(), &source_shards_info);
2340 if (ret < 0) {
2341 push_ss(ss, status, tab) << string("failed to fetch source sync status: ") + cpp_strerror(-ret);
2342 return;
2343 }
2344
2345 map<int, string> shards_behind;
2346
2347 for (auto local_iter : sync_status.sync_markers) {
2348 int shard_id = local_iter.first;
2349 auto iter = source_shards_info.find(shard_id);
2350
2351 if (iter == source_shards_info.end()) {
2352 /* huh? */
2353 derr << "ERROR: could not find remote sync shard status for shard_id=" << shard_id << dendl;
2354 continue;
2355 }
2356 auto master_marker = iter->second.marker;
2357 if (local_iter.second.state == rgw_data_sync_marker::SyncState::IncrementalSync &&
2358 master_marker > local_iter.second.marker) {
2359 shards_behind[shard_id] = local_iter.second.marker;
2360 shards_behind_set.insert(shard_id);
2361 }
2362 }
2363
2364 int total_behind = shards_behind.size() + (sync_status.sync_info.num_shards - num_inc);
2365 int total_recovering = recovering_shards.size();
2366 if (total_behind == 0 && total_recovering == 0) {
2367 push_ss(ss, status, tab) << "data is caught up with source";
2368 } else if (total_behind > 0) {
2369 push_ss(ss, status, tab) << "data is behind on " << total_behind << " shards";
2370
2371 push_ss(ss, status, tab) << "behind shards: " << "[" << shards_behind_set << "]" ;
2372
2373 map<int, rgw_datalog_shard_data> master_pos;
2374 ret = sync.read_source_log_shards_next(dpp(), shards_behind, &master_pos);
2375 if (ret < 0) {
2376 derr << "ERROR: failed to fetch next positions (" << cpp_strerror(-ret) << ")" << dendl;
2377 } else {
2378 std::optional<std::pair<int, ceph::real_time>> oldest;
2379
2380 for (auto iter : master_pos) {
2381 rgw_datalog_shard_data& shard_data = iter.second;
2382
2383 if (!shard_data.entries.empty()) {
2384 rgw_datalog_entry& entry = shard_data.entries.front();
2385 if (!oldest) {
2386 oldest.emplace(iter.first, entry.timestamp);
2387 } else if (!ceph::real_clock::is_zero(entry.timestamp) && entry.timestamp < oldest->second) {
2388 oldest.emplace(iter.first, entry.timestamp);
2389 }
2390 }
2391 }
2392
2393 if (oldest) {
2394 push_ss(ss, status, tab) << "oldest incremental change not applied: "
2395 << oldest->second << " [" << oldest->first << ']';
2396 }
2397 }
2398 }
2399
2400 if (total_recovering > 0) {
2401 push_ss(ss, status, tab) << total_recovering << " shards are recovering";
2402 push_ss(ss, status, tab) << "recovering shards: " << "[" << recovering_shards << "]";
2403 }
2404
2405 flush_ss(ss, status);
2406 }
2407
2408 static void tab_dump(const string& header, int width, const list<string>& entries)
2409 {
2410 string s = header;
2411
2412 for (auto e : entries) {
2413 cout << std::setw(width) << s << std::setw(1) << " " << e << std::endl;
2414 s.clear();
2415 }
2416 }
2417
2418
2419 static void sync_status(Formatter *formatter)
2420 {
2421 const RGWRealm& realm = store->get_zone()->get_realm();
2422 const RGWZoneGroup& zonegroup = store->get_zone()->get_zonegroup();
2423 const RGWZone& zone = static_cast<rgw::sal::RadosStore*>(store)->svc()->zone->get_zone();
2424
2425 int width = 15;
2426
2427 cout << std::setw(width) << "realm" << std::setw(1) << " " << realm.get_id() << " (" << realm.get_name() << ")" << std::endl;
2428 cout << std::setw(width) << "zonegroup" << std::setw(1) << " " << zonegroup.get_id() << " (" << zonegroup.get_name() << ")" << std::endl;
2429 cout << std::setw(width) << "zone" << std::setw(1) << " " << zone.id << " (" << zone.name << ")" << std::endl;
2430
2431 list<string> md_status;
2432
2433 if (store->is_meta_master()) {
2434 md_status.push_back("no sync (zone is master)");
2435 } else {
2436 get_md_sync_status(md_status);
2437 }
2438
2439 tab_dump("metadata sync", width, md_status);
2440
2441 list<string> data_status;
2442
2443 auto& zone_conn_map = static_cast<rgw::sal::RadosStore*>(store)->svc()->zone->get_zone_conn_map();
2444
2445 for (auto iter : zone_conn_map) {
2446 const rgw_zone_id& source_id = iter.first;
2447 string source_str = "source: ";
2448 string s = source_str + source_id.id;
2449 RGWZone *sz;
2450 if (static_cast<rgw::sal::RadosStore*>(store)->svc()->zone->find_zone(source_id, &sz)) {
2451 s += string(" (") + sz->name + ")";
2452 }
2453 data_status.push_back(s);
2454 get_data_sync_status(source_id, data_status, source_str.size());
2455 }
2456
2457 tab_dump("data sync", width, data_status);
2458 }
2459
2460 struct indented {
2461 int w; // indent width
2462 std::string_view header;
2463 indented(int w, std::string_view header = "") : w(w), header(header) {}
2464 };
2465 std::ostream& operator<<(std::ostream& out, const indented& h) {
2466 return out << std::setw(h.w) << h.header << std::setw(1) << ' ';
2467 }
2468
2469 static int bucket_source_sync_status(const DoutPrefixProvider *dpp, rgw::sal::RadosStore* store, const RGWZone& zone,
2470 const RGWZone& source, RGWRESTConn *conn,
2471 const RGWBucketInfo& bucket_info,
2472 rgw_sync_bucket_pipe pipe,
2473 int width, std::ostream& out)
2474 {
2475 out << indented{width, "source zone"} << source.id << " (" << source.name << ")" << std::endl;
2476
2477 // syncing from this zone?
2478 if (!zone.syncs_from(source.name)) {
2479 out << indented{width} << "does not sync from zone\n";
2480 return 0;
2481 }
2482
2483 if (!pipe.source.bucket) {
2484 ldpp_dout(dpp, -1) << __func__ << "(): missing source bucket" << dendl;
2485 return -EINVAL;
2486 }
2487
2488 std::unique_ptr<rgw::sal::Bucket> source_bucket;
2489 int r = init_bucket(nullptr, *pipe.source.bucket, &source_bucket);
2490 if (r < 0) {
2491 ldpp_dout(dpp, -1) << "failed to read source bucket info: " << cpp_strerror(r) << dendl;
2492 return r;
2493 }
2494
2495 pipe.source.bucket = source_bucket->get_key();
2496 pipe.dest.bucket = bucket_info.bucket;
2497
2498 std::vector<rgw_bucket_shard_sync_info> status;
2499 r = rgw_bucket_sync_status(dpp, store, pipe, bucket_info, &source_bucket->get_info(), &status);
2500 if (r < 0) {
2501 ldpp_dout(dpp, -1) << "failed to read bucket sync status: " << cpp_strerror(r) << dendl;
2502 return r;
2503 }
2504
2505 out << indented{width, "source bucket"} << source_bucket << std::endl;
2506
2507 int num_full = 0;
2508 int num_inc = 0;
2509 uint64_t full_complete = 0;
2510 const size_t total_shards = status.size();
2511
2512 using BucketSyncState = rgw_bucket_shard_sync_info::SyncState;
2513 for (size_t shard_id = 0; shard_id < total_shards; shard_id++) {
2514 auto& m = status[shard_id];
2515 if (m.state == BucketSyncState::StateFullSync) {
2516 num_full++;
2517 full_complete += m.full_marker.count;
2518 } else if (m.state == BucketSyncState::StateIncrementalSync) {
2519 num_inc++;
2520 }
2521 }
2522
2523 out << indented{width} << "full sync: " << num_full << "/" << total_shards << " shards\n";
2524 if (num_full > 0) {
2525 out << indented{width} << "full sync: " << full_complete << " objects completed\n";
2526 }
2527 out << indented{width} << "incremental sync: " << num_inc << "/" << total_shards << " shards\n";
2528
2529 BucketIndexShardsManager remote_markers;
2530 r = rgw_read_remote_bilog_info(dpp, conn, source_bucket->get_key(), remote_markers, null_yield);
2531 if (r < 0) {
2532 ldpp_dout(dpp, -1) << "failed to read remote log: " << cpp_strerror(r) << dendl;
2533 return r;
2534 }
2535
2536 std::set<int> shards_behind;
2537 for (auto& r : remote_markers.get()) {
2538 auto shard_id = r.first;
2539 auto& m = status[shard_id];
2540 if (r.second.empty()) {
2541 continue; // empty bucket index shard
2542 }
2543 auto pos = BucketIndexShardsManager::get_shard_marker(m.inc_marker.position);
2544 if (m.state != BucketSyncState::StateIncrementalSync || pos != r.second) {
2545 shards_behind.insert(shard_id);
2546 }
2547 }
2548 if (!shards_behind.empty()) {
2549 out << indented{width} << "bucket is behind on " << shards_behind.size() << " shards\n";
2550 out << indented{width} << "behind shards: [" << shards_behind << "]\n" ;
2551 } else if (!num_full) {
2552 out << indented{width} << "bucket is caught up with source\n";
2553 }
2554 return 0;
2555 }
2556
2557 void encode_json(const char *name, const RGWBucketSyncFlowManager::pipe_set& pset, Formatter *f)
2558 {
2559 Formatter::ObjectSection top_section(*f, name);
2560 Formatter::ArraySection as(*f, "entries");
2561
2562 for (auto& pipe_handler : pset) {
2563 Formatter::ObjectSection hs(*f, "handler");
2564 encode_json("source", pipe_handler.source, f);
2565 encode_json("dest", pipe_handler.dest, f);
2566 }
2567 }
2568
2569 static std::vector<string> convert_bucket_set_to_str_vec(const std::set<rgw_bucket>& bs)
2570 {
2571 std::vector<string> result;
2572 result.reserve(bs.size());
2573 for (auto& b : bs) {
2574 result.push_back(b.get_key());
2575 }
2576 return result;
2577 }
2578
2579 static void get_hint_entities(const std::set<rgw_zone_id>& zones, const std::set<rgw_bucket>& buckets,
2580 std::set<rgw_sync_bucket_entity> *hint_entities)
2581 {
2582 for (auto& zone_id : zones) {
2583 for (auto& b : buckets) {
2584 std::unique_ptr<rgw::sal::Bucket> hint_bucket;
2585 int ret = init_bucket(nullptr, b, &hint_bucket);
2586 if (ret < 0) {
2587 ldpp_dout(dpp(), 20) << "could not init bucket info for hint bucket=" << b << " ... skipping" << dendl;
2588 continue;
2589 }
2590
2591 hint_entities->insert(rgw_sync_bucket_entity(zone_id, hint_bucket->get_key()));
2592 }
2593 }
2594 }
2595
2596 static rgw_zone_id resolve_zone_id(const string& s)
2597 {
2598 rgw_zone_id result;
2599
2600 RGWZone *zone;
2601 if (static_cast<rgw::sal::RadosStore*>(store)->svc()->zone->find_zone(s, &zone)) {
2602 return rgw_zone_id(s);
2603 }
2604 if (static_cast<rgw::sal::RadosStore*>(store)->svc()->zone->find_zone_id_by_name(s, &result)) {
2605 return result;
2606 }
2607 return rgw_zone_id(s);
2608 }
2609
2610 rgw_zone_id validate_zone_id(const rgw_zone_id& zone_id)
2611 {
2612 return resolve_zone_id(zone_id.id);
2613 }
2614
2615 static int sync_info(std::optional<rgw_zone_id> opt_target_zone, std::optional<rgw_bucket> opt_bucket, Formatter *formatter)
2616 {
2617 rgw_zone_id zone_id = opt_target_zone.value_or(store->get_zone()->get_id());
2618
2619 auto zone_policy_handler = static_cast<rgw::sal::RadosStore*>(store)->svc()->zone->get_sync_policy_handler(zone_id);
2620
2621 RGWBucketSyncPolicyHandlerRef bucket_handler;
2622
2623 std::optional<rgw_bucket> eff_bucket = opt_bucket;
2624
2625 auto handler = zone_policy_handler;
2626
2627 if (eff_bucket) {
2628 std::unique_ptr<rgw::sal::Bucket> bucket;
2629
2630 int ret = init_bucket(nullptr, *eff_bucket, &bucket);
2631 if (ret < 0 && ret != -ENOENT) {
2632 cerr << "ERROR: init_bucket failed: " << cpp_strerror(-ret) << std::endl;
2633 return ret;
2634 }
2635
2636 if (ret >= 0) {
2637 rgw::sal::Attrs attrs = bucket->get_attrs();
2638 bucket_handler.reset(handler->alloc_child(bucket->get_info(), std::move(attrs)));
2639 } else {
2640 cerr << "WARNING: bucket not found, simulating result" << std::endl;
2641 bucket_handler.reset(handler->alloc_child(*eff_bucket, nullopt));
2642 }
2643
2644 ret = bucket_handler->init(dpp(), null_yield);
2645 if (ret < 0) {
2646 cerr << "ERROR: failed to init bucket sync policy handler: " << cpp_strerror(-ret) << " (ret=" << ret << ")" << std::endl;
2647 return ret;
2648 }
2649
2650 handler = bucket_handler;
2651 }
2652
2653 std::set<rgw_sync_bucket_pipe> sources;
2654 std::set<rgw_sync_bucket_pipe> dests;
2655
2656 handler->get_pipes(&sources, &dests, std::nullopt);
2657
2658 auto source_hints_vec = convert_bucket_set_to_str_vec(handler->get_source_hints());
2659 auto target_hints_vec = convert_bucket_set_to_str_vec(handler->get_target_hints());
2660
2661 std::set<rgw_sync_bucket_pipe> resolved_sources;
2662 std::set<rgw_sync_bucket_pipe> resolved_dests;
2663
2664 rgw_sync_bucket_entity self_entity(zone_id, opt_bucket);
2665
2666 set<rgw_zone_id> source_zones;
2667 set<rgw_zone_id> target_zones;
2668
2669 zone_policy_handler->reflect(dpp(), nullptr, nullptr,
2670 nullptr, nullptr,
2671 &source_zones,
2672 &target_zones,
2673 false); /* relaxed: also get all zones that we allow to sync to/from */
2674
2675 std::set<rgw_sync_bucket_entity> hint_entities;
2676
2677 get_hint_entities(source_zones, handler->get_source_hints(), &hint_entities);
2678 get_hint_entities(target_zones, handler->get_target_hints(), &hint_entities);
2679
2680 for (auto& hint_entity : hint_entities) {
2681 if (!hint_entity.zone ||
2682 !hint_entity.bucket) {
2683 continue; /* shouldn't really happen */
2684 }
2685
2686 auto zid = validate_zone_id(*hint_entity.zone);
2687 auto& hint_bucket = *hint_entity.bucket;
2688
2689 RGWBucketSyncPolicyHandlerRef hint_bucket_handler;
2690 int r = store->get_sync_policy_handler(dpp(), zid, hint_bucket, &hint_bucket_handler, null_yield);
2691 if (r < 0) {
2692 ldpp_dout(dpp(), 20) << "could not get bucket sync policy handler for hint bucket=" << hint_bucket << " ... skipping" << dendl;
2693 continue;
2694 }
2695
2696 hint_bucket_handler->get_pipes(&resolved_dests,
2697 &resolved_sources,
2698 self_entity); /* flipping resolved dests and sources as these are
2699 relative to the remote entity */
2700 }
2701
2702 {
2703 Formatter::ObjectSection os(*formatter, "result");
2704 encode_json("sources", sources, formatter);
2705 encode_json("dests", dests, formatter);
2706 {
2707 Formatter::ObjectSection hints_section(*formatter, "hints");
2708 encode_json("sources", source_hints_vec, formatter);
2709 encode_json("dests", target_hints_vec, formatter);
2710 }
2711 {
2712 Formatter::ObjectSection resolved_hints_section(*formatter, "resolved-hints-1");
2713 encode_json("sources", resolved_sources, formatter);
2714 encode_json("dests", resolved_dests, formatter);
2715 }
2716 {
2717 Formatter::ObjectSection resolved_hints_section(*formatter, "resolved-hints");
2718 encode_json("sources", handler->get_resolved_source_hints(), formatter);
2719 encode_json("dests", handler->get_resolved_dest_hints(), formatter);
2720 }
2721 }
2722
2723 formatter->flush(cout);
2724
2725 return 0;
2726 }
2727
2728 static int bucket_sync_info(rgw::sal::RadosStore* store, const RGWBucketInfo& info,
2729 std::ostream& out)
2730 {
2731 const RGWRealm& realm = store->get_zone()->get_realm();
2732 const RGWZoneGroup& zonegroup = store->get_zone()->get_zonegroup();
2733 const RGWZone& zone = store->svc()->zone->get_zone();
2734 constexpr int width = 15;
2735
2736 out << indented{width, "realm"} << realm.get_id() << " (" << realm.get_name() << ")\n";
2737 out << indented{width, "zonegroup"} << zonegroup.get_id() << " (" << zonegroup.get_name() << ")\n";
2738 out << indented{width, "zone"} << zone.id << " (" << zone.name << ")\n";
2739 out << indented{width, "bucket"} << info.bucket << "\n\n";
2740
2741 if (!static_cast<rgw::sal::RadosStore*>(store)->ctl()->bucket->bucket_imports_data(info.bucket, null_yield, dpp())) {
2742 out << "Sync is disabled for bucket " << info.bucket.name << '\n';
2743 return 0;
2744 }
2745
2746 RGWBucketSyncPolicyHandlerRef handler;
2747
2748 int r = store->get_sync_policy_handler(dpp(), std::nullopt, info.bucket, &handler, null_yield);
2749 if (r < 0) {
2750 ldpp_dout(dpp(), -1) << "ERROR: failed to get policy handler for bucket (" << info.bucket << "): r=" << r << ": " << cpp_strerror(-r) << dendl;
2751 return r;
2752 }
2753
2754 auto& sources = handler->get_sources();
2755
2756 for (auto& m : sources) {
2757 auto& zone = m.first;
2758 out << indented{width, "source zone"} << zone << std::endl;
2759 for (auto& pipe_handler : m.second) {
2760 out << indented{width, "bucket"} << *pipe_handler.source.bucket << std::endl;
2761 }
2762 }
2763
2764 return 0;
2765 }
2766
2767 static int bucket_sync_status(rgw::sal::RadosStore* store, const RGWBucketInfo& info,
2768 const rgw_zone_id& source_zone_id,
2769 std::optional<rgw_bucket>& opt_source_bucket,
2770 std::ostream& out)
2771 {
2772 const RGWRealm& realm = store->get_zone()->get_realm();
2773 const RGWZoneGroup& zonegroup = store->get_zone()->get_zonegroup();
2774 const RGWZone& zone = static_cast<rgw::sal::RadosStore*>(store)->svc()->zone->get_zone();
2775 constexpr int width = 15;
2776
2777 out << indented{width, "realm"} << realm.get_id() << " (" << realm.get_name() << ")\n";
2778 out << indented{width, "zonegroup"} << zonegroup.get_id() << " (" << zonegroup.get_name() << ")\n";
2779 out << indented{width, "zone"} << zone.id << " (" << zone.name << ")\n";
2780 out << indented{width, "bucket"} << info.bucket << "\n\n";
2781
2782 if (!static_cast<rgw::sal::RadosStore*>(store)->ctl()->bucket->bucket_imports_data(info.bucket, null_yield, dpp())) {
2783 out << "Sync is disabled for bucket " << info.bucket.name << " or bucket has no sync sources" << std::endl;
2784 return 0;
2785 }
2786
2787 RGWBucketSyncPolicyHandlerRef handler;
2788
2789 int r = store->get_sync_policy_handler(dpp(), std::nullopt, info.bucket, &handler, null_yield);
2790 if (r < 0) {
2791 ldpp_dout(dpp(), -1) << "ERROR: failed to get policy handler for bucket (" << info.bucket << "): r=" << r << ": " << cpp_strerror(-r) << dendl;
2792 return r;
2793 }
2794
2795 auto sources = handler->get_all_sources();
2796
2797 auto& zone_conn_map = static_cast<rgw::sal::RadosStore*>(store)->svc()->zone->get_zone_conn_map();
2798 set<rgw_zone_id> zone_ids;
2799
2800 if (!source_zone_id.empty()) {
2801 auto z = zonegroup.zones.find(source_zone_id);
2802 if (z == zonegroup.zones.end()) {
2803 ldpp_dout(dpp(), -1) << "Source zone not found in zonegroup "
2804 << zonegroup.get_name() << dendl;
2805 return -EINVAL;
2806 }
2807 auto c = zone_conn_map.find(source_zone_id);
2808 if (c == zone_conn_map.end()) {
2809 ldpp_dout(dpp(), -1) << "No connection to zone " << z->second.name << dendl;
2810 return -EINVAL;
2811 }
2812 zone_ids.insert(source_zone_id);
2813 } else {
2814 for (const auto& entry : zonegroup.zones) {
2815 zone_ids.insert(entry.second.id);
2816 }
2817 }
2818
2819 for (auto& zone_id : zone_ids) {
2820 auto z = zonegroup.zones.find(zone_id.id);
2821 if (z == zonegroup.zones.end()) { /* should't happen */
2822 continue;
2823 }
2824 auto c = zone_conn_map.find(zone_id.id);
2825 if (c == zone_conn_map.end()) { /* should't happen */
2826 continue;
2827 }
2828
2829 for (auto& entry : sources) {
2830 auto& pipe = entry.second;
2831 if (opt_source_bucket &&
2832 pipe.source.bucket != opt_source_bucket) {
2833 continue;
2834 }
2835 if (pipe.source.zone.value_or(rgw_zone_id()) == z->second.id) {
2836 bucket_source_sync_status(dpp(), store, zone, z->second,
2837 c->second,
2838 info, pipe,
2839 width, out);
2840 }
2841 }
2842 }
2843
2844 return 0;
2845 }
2846
2847 static void parse_tier_config_param(const string& s, map<string, string, ltstr_nocase>& out)
2848 {
2849 int level = 0;
2850 string cur_conf;
2851 list<string> confs;
2852 for (auto c : s) {
2853 if (c == ',') {
2854 if (level == 0) {
2855 confs.push_back(cur_conf);
2856 cur_conf.clear();
2857 continue;
2858 }
2859 }
2860 if (c == '{') {
2861 ++level;
2862 } else if (c == '}') {
2863 --level;
2864 }
2865 cur_conf += c;
2866 }
2867 if (!cur_conf.empty()) {
2868 confs.push_back(cur_conf);
2869 }
2870
2871 for (auto c : confs) {
2872 ssize_t pos = c.find("=");
2873 if (pos < 0) {
2874 out[c] = "";
2875 } else {
2876 out[c.substr(0, pos)] = c.substr(pos + 1);
2877 }
2878 }
2879 }
2880
2881 static int check_pool_support_omap(const rgw_pool& pool)
2882 {
2883 librados::IoCtx io_ctx;
2884 int ret = static_cast<rgw::sal::RadosStore*>(store)->getRados()->get_rados_handle()->ioctx_create(pool.to_str().c_str(), io_ctx);
2885 if (ret < 0) {
2886 // the pool may not exist at this moment, we have no way to check if it supports omap.
2887 return 0;
2888 }
2889
2890 ret = io_ctx.omap_clear("__omap_test_not_exist_oid__");
2891 if (ret == -EOPNOTSUPP) {
2892 io_ctx.close();
2893 return ret;
2894 }
2895 io_ctx.close();
2896 return 0;
2897 }
2898
2899 int check_reshard_bucket_params(rgw::sal::RadosStore* store,
2900 const string& bucket_name,
2901 const string& tenant,
2902 const string& bucket_id,
2903 bool num_shards_specified,
2904 int num_shards,
2905 int yes_i_really_mean_it,
2906 std::unique_ptr<rgw::sal::Bucket>* bucket)
2907 {
2908 if (bucket_name.empty()) {
2909 cerr << "ERROR: bucket not specified" << std::endl;
2910 return -EINVAL;
2911 }
2912
2913 if (!num_shards_specified) {
2914 cerr << "ERROR: --num-shards not specified" << std::endl;
2915 return -EINVAL;
2916 }
2917
2918 if (num_shards > (int)static_cast<rgw::sal::RadosStore*>(store)->getRados()->get_max_bucket_shards()) {
2919 cerr << "ERROR: num_shards too high, max value: " << static_cast<rgw::sal::RadosStore*>(store)->getRados()->get_max_bucket_shards() << std::endl;
2920 return -EINVAL;
2921 }
2922
2923 if (num_shards < 0) {
2924 cerr << "ERROR: num_shards must be non-negative integer" << std::endl;
2925 return -EINVAL;
2926 }
2927
2928 int ret = init_bucket(nullptr, tenant, bucket_name, bucket_id, bucket);
2929 if (ret < 0) {
2930 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
2931 return ret;
2932 }
2933
2934 if ((*bucket)->get_info().reshard_status != cls_rgw_reshard_status::NOT_RESHARDING) {
2935 // if in_progress or done then we have an old BucketInfo
2936 cerr << "ERROR: the bucket is currently undergoing resharding and "
2937 "cannot be added to the reshard list at this time" << std::endl;
2938 return -EBUSY;
2939 }
2940
2941 int num_source_shards = ((*bucket)->get_info().layout.current_index.layout.normal.num_shards > 0 ? (*bucket)->get_info().layout.current_index.layout.normal.num_shards : 1);
2942
2943 if (num_shards <= num_source_shards && !yes_i_really_mean_it) {
2944 cerr << "num shards is less or equal to current shards count" << std::endl
2945 << "do you really mean it? (requires --yes-i-really-mean-it)" << std::endl;
2946 return -EINVAL;
2947 }
2948 return 0;
2949 }
2950
2951 static int scan_totp(CephContext *cct, ceph::real_time& now, rados::cls::otp::otp_info_t& totp, vector<string>& pins,
2952 time_t *pofs)
2953 {
2954 #define MAX_TOTP_SKEW_HOURS (24 * 7)
2955 time_t start_time = ceph::real_clock::to_time_t(now);
2956 time_t time_ofs = 0, time_ofs_abs = 0;
2957 time_t step_size = totp.step_size;
2958 if (step_size == 0) {
2959 step_size = OATH_TOTP_DEFAULT_TIME_STEP_SIZE;
2960 }
2961 uint32_t count = 0;
2962 int sign = 1;
2963
2964 uint32_t max_skew = MAX_TOTP_SKEW_HOURS * 3600;
2965
2966 while (time_ofs_abs < max_skew) {
2967 int rc = oath_totp_validate2(totp.seed_bin.c_str(), totp.seed_bin.length(),
2968 start_time,
2969 step_size,
2970 time_ofs,
2971 1,
2972 nullptr,
2973 pins[0].c_str());
2974 if (rc != OATH_INVALID_OTP) {
2975 rc = oath_totp_validate2(totp.seed_bin.c_str(), totp.seed_bin.length(),
2976 start_time,
2977 step_size,
2978 time_ofs - step_size, /* smaller time_ofs moves time forward */
2979 1,
2980 nullptr,
2981 pins[1].c_str());
2982 if (rc != OATH_INVALID_OTP) {
2983 *pofs = time_ofs - step_size + step_size * totp.window / 2;
2984 ldpp_dout(dpp(), 20) << "found at time=" << start_time - time_ofs << " time_ofs=" << time_ofs << dendl;
2985 return 0;
2986 }
2987 }
2988 sign = -sign;
2989 time_ofs_abs = (++count) * step_size;
2990 time_ofs = sign * time_ofs_abs;
2991 }
2992
2993 return -ENOENT;
2994 }
2995
2996 static int trim_sync_error_log(int shard_id, const string& marker, int delay_ms)
2997 {
2998 auto oid = RGWSyncErrorLogger::get_shard_oid(RGW_SYNC_ERROR_LOG_SHARD_PREFIX,
2999 shard_id);
3000 // call cls_log_trim() until it returns -ENODATA
3001 for (;;) {
3002 int ret = static_cast<rgw::sal::RadosStore*>(store)->svc()->cls->timelog.trim(dpp(), oid, {}, {}, {}, marker, nullptr,
3003 null_yield);
3004 if (ret == -ENODATA) {
3005 return 0;
3006 }
3007 if (ret < 0) {
3008 return ret;
3009 }
3010 if (delay_ms) {
3011 std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms));
3012 }
3013 }
3014 // unreachable
3015 }
3016
3017 const string& get_tier_type(rgw::sal::RadosStore* store) {
3018 return store->svc()->zone->get_zone().tier_type;
3019 }
3020
3021 static bool symmetrical_flow_opt(const string& opt)
3022 {
3023 return (opt == "symmetrical" || opt == "symmetric");
3024 }
3025
3026 static bool directional_flow_opt(const string& opt)
3027 {
3028 return (opt == "directional" || opt == "direction");
3029 }
3030
3031 template <class T>
3032 static bool require_opt(std::optional<T> opt, bool extra_check = true)
3033 {
3034 if (!opt || !extra_check) {
3035 return false;
3036 }
3037 return true;
3038 }
3039
3040 template <class T>
3041 static bool require_non_empty_opt(std::optional<T> opt, bool extra_check = true)
3042 {
3043 if (!opt || opt->empty() || !extra_check) {
3044 return false;
3045 }
3046 return true;
3047 }
3048
3049 template <class T>
3050 static void show_result(T& obj,
3051 Formatter *formatter,
3052 ostream& os)
3053 {
3054 encode_json("obj", obj, formatter);
3055
3056 formatter->flush(cout);
3057 }
3058
3059 void init_optional_bucket(std::optional<rgw_bucket>& opt_bucket,
3060 std::optional<string>& opt_tenant,
3061 std::optional<string>& opt_bucket_name,
3062 std::optional<string>& opt_bucket_id)
3063 {
3064 if (opt_tenant || opt_bucket_name || opt_bucket_id) {
3065 opt_bucket.emplace();
3066 if (opt_tenant) {
3067 opt_bucket->tenant = *opt_tenant;
3068 }
3069 if (opt_bucket_name) {
3070 opt_bucket->name = *opt_bucket_name;
3071 }
3072 if (opt_bucket_id) {
3073 opt_bucket->bucket_id = *opt_bucket_id;
3074 }
3075 }
3076 }
3077
3078 class SyncPolicyContext
3079 {
3080 RGWZoneGroup zonegroup;
3081
3082 std::optional<rgw_bucket> b;
3083 std::unique_ptr<rgw::sal::Bucket> bucket;
3084
3085 rgw_sync_policy_info *policy{nullptr};
3086
3087 std::optional<rgw_user> owner;
3088
3089 public:
3090 SyncPolicyContext(const string& zonegroup_id,
3091 const string& zonegroup_name,
3092 std::optional<rgw_bucket> _bucket) : zonegroup(zonegroup_id, zonegroup_name),
3093 b(_bucket) {}
3094
3095 int init() {
3096 int ret = zonegroup.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
3097 if (ret < 0) {
3098 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
3099 return ret;
3100 }
3101
3102 if (!b) {
3103 policy = &zonegroup.sync_policy;
3104 return 0;
3105 }
3106
3107 ret = init_bucket(nullptr, *b, &bucket);
3108 if (ret < 0) {
3109 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
3110 return ret;
3111 }
3112
3113 owner = bucket->get_info().owner;
3114
3115 if (!bucket->get_info().sync_policy) {
3116 rgw_sync_policy_info new_policy;
3117 bucket->get_info().set_sync_policy(std::move(new_policy));
3118 }
3119
3120 policy = &(*bucket->get_info().sync_policy);
3121
3122 return 0;
3123 }
3124
3125 int write_policy() {
3126 if (!b) {
3127 int ret = zonegroup.update(dpp(), null_yield);
3128 if (ret < 0) {
3129 cerr << "failed to update zonegroup: " << cpp_strerror(-ret) << std::endl;
3130 return -ret;
3131 }
3132 return 0;
3133 }
3134
3135 int ret = bucket->put_info(dpp(), false, real_time());
3136 if (ret < 0) {
3137 cerr << "failed to store bucket info: " << cpp_strerror(-ret) << std::endl;
3138 return -ret;
3139 }
3140
3141 return 0;
3142 }
3143
3144 rgw_sync_policy_info& get_policy() {
3145 return *policy;
3146 }
3147
3148 std::optional<rgw_user>& get_owner() {
3149 return owner;
3150 }
3151 };
3152
3153 void resolve_zone_id_opt(std::optional<string>& zone_name, std::optional<rgw_zone_id>& zone_id)
3154 {
3155 if (!zone_name || zone_id) {
3156 return;
3157 }
3158 zone_id.emplace();
3159 if (!static_cast<rgw::sal::RadosStore*>(store)->svc()->zone->find_zone_id_by_name(*zone_name, &(*zone_id))) {
3160 cerr << "WARNING: cannot find source zone id for name=" << *zone_name << std::endl;
3161 zone_id = rgw_zone_id(*zone_name);
3162 }
3163 }
3164 void resolve_zone_ids_opt(std::optional<vector<string> >& names, std::optional<vector<rgw_zone_id> >& ids)
3165 {
3166 if (!names || ids) {
3167 return;
3168 }
3169 ids.emplace();
3170 for (auto& name : *names) {
3171 rgw_zone_id zid;
3172 if (!static_cast<rgw::sal::RadosStore*>(store)->svc()->zone->find_zone_id_by_name(name, &zid)) {
3173 cerr << "WARNING: cannot find source zone id for name=" << name << std::endl;
3174 zid = rgw_zone_id(name);
3175 }
3176 ids->push_back(zid);
3177 }
3178 }
3179
3180 static vector<rgw_zone_id> zone_ids_from_str(const string& val)
3181 {
3182 vector<rgw_zone_id> result;
3183 vector<string> v;
3184 get_str_vec(val, v);
3185 for (auto& z : v) {
3186 result.push_back(rgw_zone_id(z));
3187 }
3188 return result;
3189 }
3190
3191 class JSONFormatter_PrettyZone : public JSONFormatter {
3192 class Handler : public JSONEncodeFilter::Handler<rgw_zone_id> {
3193 void encode_json(const char *name, const void *pval, ceph::Formatter *f) const override {
3194 auto zone_id = *(static_cast<const rgw_zone_id *>(pval));
3195 string zone_name;
3196 RGWZone *zone;
3197 if (static_cast<rgw::sal::RadosStore*>(store)->svc()->zone->find_zone(zone_id, &zone)) {
3198 zone_name = zone->name;
3199 } else {
3200 cerr << "WARNING: cannot find zone name for id=" << zone_id << std::endl;
3201 zone_name = zone_id.id;
3202 }
3203
3204 ::encode_json(name, zone_name, f);
3205 }
3206 } zone_id_type_handler;
3207
3208 JSONEncodeFilter encode_filter;
3209 public:
3210 JSONFormatter_PrettyZone(bool pretty_format) : JSONFormatter(pretty_format) {
3211 encode_filter.register_type(&zone_id_type_handler);
3212 }
3213
3214 void *get_external_feature_handler(const std::string& feature) override {
3215 if (feature != "JSONEncodeFilter") {
3216 return nullptr;
3217 }
3218 return &encode_filter;
3219 }
3220 };
3221
3222 static int search_entities_by_zone(rgw_zone_id zone_id,
3223 RGWRealm *prealm,
3224 RGWPeriod *pperiod,
3225 RGWZoneGroup *pzonegroup,
3226 bool *pfound)
3227 {
3228 *pfound = false;
3229
3230 auto& found = *pfound;
3231
3232 list<string> realms;
3233 int r = static_cast<rgw::sal::RadosStore*>(store)->svc()->zone->list_realms(dpp(), realms);
3234 if (r < 0) {
3235 cerr << "failed to list realms: " << cpp_strerror(-r) << std::endl;
3236 return r;
3237 }
3238
3239 for (auto& realm_name : realms) {
3240 string realm_id;
3241 string period_id;
3242 RGWRealm realm(realm_id, realm_name);
3243 r = realm.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
3244 if (r < 0) {
3245 cerr << "WARNING: can't open realm " << realm_name << ": " << cpp_strerror(-r) << " ... skipping" << std::endl;
3246 continue;
3247 }
3248 RGWPeriod period;
3249 r = realm.find_zone(dpp(), zone_id, pperiod,
3250 pzonegroup, &found, null_yield);
3251
3252 if (found) {
3253 *prealm = realm;
3254 break;
3255 }
3256 }
3257
3258 return 0;
3259 }
3260
3261 static int try_to_resolve_local_zone(string& zone_id, string& zone_name)
3262 {
3263 /* try to read zone info */
3264 RGWZoneParams zone(zone_id, zone_name);
3265 int r = zone.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
3266 if (r == -ENOENT) {
3267 ldpp_dout(dpp(), 20) << __func__ << "(): local zone not found (id=" << zone_id << ", name= " << zone_name << ")" << dendl;
3268 return r;
3269 }
3270
3271 if (r < 0) {
3272 ldpp_dout(dpp(), 0) << __func__ << "(): unable to read zone (id=" << zone_id << ", name= " << zone_name << "): " << cpp_strerror(-r) << dendl;
3273
3274 return r;
3275 }
3276
3277 zone_id = zone.get_id();
3278 zone_name = zone.get_name();
3279
3280 return 0;
3281 }
3282
3283 static void check_set_consistent(const string& resolved_param,
3284 string& param,
3285 const string& param_name)
3286 {
3287 if (!param.empty() && param != resolved_param) {
3288 ldpp_dout(dpp(), 5) << "WARNING: " << param_name << " resolve mismatch. (param=" << param << ", resolved=" << resolved_param << ")" << dendl;
3289 return;
3290 }
3291
3292 param = resolved_param;
3293 ldpp_dout(dpp(), 20) << __func__ << "(): resolved param: " << param_name << ": " << param << dendl;
3294 }
3295
3296
3297 static int try_to_resolve_local_entities(string& realm_id, string& realm_name,
3298 string& zonegroup_id, string& zonegroup_name,
3299 string& zone_id, string& zone_name)
3300 {
3301 /*
3302 * Try to figure out realm, zonegroup, and zone entities, based on provided params and local zone.
3303 *
3304 * First read the local zone info (for zone id/name). Then search existing realm and period
3305 * configuration and if found, update (but don't override) passed params.
3306 *
3307 */
3308
3309 ldpp_dout(dpp(), 20) << __func__ << "(): before: realm_id=" << realm_id << " realm_name=" << realm_name << " zonegroup_id=" << zonegroup_id << " zonegroup_name=" << zonegroup_name << " zone_id=" << zone_id << " zone_name=" << zone_name << dendl;
3310 int r = try_to_resolve_local_zone(zone_id, zone_name);
3311 if (r == -ENOENT) {
3312 /* this local zone doesn't exist, abort */
3313 return 0;
3314 }
3315 if (r < 0) {
3316 return r;
3317 }
3318
3319 if (zone_id.empty()) {
3320 /* not sure it's possible, but let's abort */
3321 return 0;
3322 }
3323
3324 bool found;
3325 RGWRealm realm;
3326 RGWPeriod period;
3327 RGWZoneGroup zonegroup;
3328 r = search_entities_by_zone(zone_id, &realm, &period, &zonegroup, &found);
3329 if (r < 0) {
3330 ldpp_dout(dpp(), 0) << "ERROR: error when searching for realm id (r=" << r << "), ignoring" << dendl;
3331 return r;
3332 }
3333
3334 if (!found) {
3335 return 0;
3336 }
3337
3338 check_set_consistent(realm.get_id(), realm_id, "realm id (--realm-id)");
3339 check_set_consistent(realm.get_name(), realm_name, "realm name (--rgw-realm)");
3340 check_set_consistent(zonegroup.get_id(), zonegroup_id, "zonegroup id (--zonegroup-id)");
3341 check_set_consistent(zonegroup.get_name(), zonegroup_name, "zonegroup name (--rgw-zonegroup)");
3342
3343 ldpp_dout(dpp(), 20) << __func__ << "(): after: realm_id=" << realm_id << " realm_name=" << realm_name << " zonegroup_id=" << zonegroup_id << " zonegroup_name=" << zonegroup_name << " zone_id=" << zone_id << " zone_name=" << zone_name << dendl;
3344
3345 return 0;
3346 }
3347
3348 static bool empty_opt(std::optional<string>& os)
3349 {
3350 return (!os || os->empty());
3351 }
3352
3353 static string safe_opt(std::optional<string>& os)
3354 {
3355 return os.value_or(string());
3356 }
3357
3358 void init_realm_param(CephContext *cct, string& var, std::optional<string>& opt_var, const string& conf_name)
3359 {
3360 var = cct->_conf.get_val<string>(conf_name);
3361 if (!var.empty()) {
3362 opt_var = var;
3363 }
3364 }
3365
3366 int main(int argc, const char **argv)
3367 {
3368 auto args = argv_to_vec(argc, argv);
3369 if (args.empty()) {
3370 cerr << argv[0] << ": -h or --help for usage" << std::endl;
3371 exit(1);
3372 }
3373 if (ceph_argparse_need_usage(args)) {
3374 usage();
3375 exit(0);
3376 }
3377
3378 auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT,
3379 CODE_ENVIRONMENT_UTILITY, 0);
3380
3381 // for region -> zonegroup conversion (must happen before common_init_finish())
3382 if (!g_conf()->rgw_region.empty() && g_conf()->rgw_zonegroup.empty()) {
3383 g_conf().set_val_or_die("rgw_zonegroup", g_conf()->rgw_region.c_str());
3384 }
3385
3386 rgw_user user_id_arg;
3387 std::unique_ptr<rgw::sal::User> user;
3388 string tenant;
3389 string user_ns;
3390 rgw_user new_user_id;
3391 std::string access_key, secret_key, user_email, display_name;
3392 std::string bucket_name, pool_name, object;
3393 rgw_pool pool;
3394 std::string date, subuser, access, format;
3395 std::string start_date, end_date;
3396 std::string key_type_str;
3397 std::string period_id, period_epoch, remote, url;
3398 std::optional<string> opt_region;
3399 std::string master_zone;
3400 std::string realm_name, realm_id, realm_new_name;
3401 std::optional<string> opt_realm_name, opt_realm_id;
3402 std::string zone_name, zone_id, zone_new_name;
3403 std::optional<string> opt_zone_name, opt_zone_id;
3404 std::string zonegroup_name, zonegroup_id, zonegroup_new_name;
3405 std::optional<string> opt_zonegroup_name, opt_zonegroup_id;
3406 std::string api_name;
3407 std::string role_name, path, assume_role_doc, policy_name, perm_policy_doc, path_prefix;
3408 std::string redirect_zone;
3409 bool redirect_zone_set = false;
3410 list<string> endpoints;
3411 int tmp_int;
3412 int sync_from_all_specified = false;
3413 bool sync_from_all = false;
3414 list<string> sync_from;
3415 list<string> sync_from_rm;
3416 int is_master_int;
3417 int set_default = 0;
3418 bool is_master = false;
3419 bool is_master_set = false;
3420 int read_only_int;
3421 bool read_only = false;
3422 int is_read_only_set = false;
3423 int commit = false;
3424 int staging = false;
3425 int key_type = KEY_TYPE_UNDEFINED;
3426 std::unique_ptr<rgw::sal::Bucket> bucket;
3427 uint32_t perm_mask = 0;
3428 RGWUserInfo info;
3429 OPT opt_cmd = OPT::NO_CMD;
3430 int gen_access_key = 0;
3431 int gen_secret_key = 0;
3432 bool set_perm = false;
3433 bool set_temp_url_key = false;
3434 map<int, string> temp_url_keys;
3435 string bucket_id;
3436 string new_bucket_name;
3437 std::unique_ptr<Formatter> formatter;
3438 std::unique_ptr<Formatter> zone_formatter;
3439 int purge_data = false;
3440 int pretty_format = false;
3441 int show_log_entries = true;
3442 int show_log_sum = true;
3443 int skip_zero_entries = false; // log show
3444 int purge_keys = false;
3445 int yes_i_really_mean_it = false;
3446 int delete_child_objects = false;
3447 int fix = false;
3448 int remove_bad = false;
3449 int check_head_obj_locator = false;
3450 int max_buckets = -1;
3451 bool max_buckets_specified = false;
3452 map<string, bool> categories;
3453 string caps;
3454 int check_objects = false;
3455 RGWBucketAdminOpState bucket_op;
3456 string infile;
3457 string metadata_key;
3458 RGWObjVersionTracker objv_tracker;
3459 string marker;
3460 string start_marker;
3461 string end_marker;
3462 int max_entries = -1;
3463 bool max_entries_specified = false;
3464 int admin = false;
3465 bool admin_specified = false;
3466 int system = false;
3467 bool system_specified = false;
3468 int shard_id = -1;
3469 bool specified_shard_id = false;
3470 string client_id;
3471 string op_id;
3472 string op_mask_str;
3473 string quota_scope;
3474 string ratelimit_scope;
3475 string object_version;
3476 string placement_id;
3477 std::optional<string> opt_storage_class;
3478 list<string> tags;
3479 list<string> tags_add;
3480 list<string> tags_rm;
3481
3482 int64_t max_objects = -1;
3483 int64_t max_size = -1;
3484 int64_t max_read_ops = 0;
3485 int64_t max_write_ops = 0;
3486 int64_t max_read_bytes = 0;
3487 int64_t max_write_bytes = 0;
3488 bool have_max_objects = false;
3489 bool have_max_size = false;
3490 bool have_max_write_ops = false;
3491 bool have_max_read_ops = false;
3492 bool have_max_write_bytes = false;
3493 bool have_max_read_bytes = false;
3494 int include_all = false;
3495 int allow_unordered = false;
3496
3497 int sync_stats = false;
3498 int reset_stats = false;
3499 int bypass_gc = false;
3500 int warnings_only = false;
3501 int inconsistent_index = false;
3502
3503 int verbose = false;
3504
3505 int extra_info = false;
3506
3507 uint64_t min_rewrite_size = 4 * 1024 * 1024;
3508 uint64_t max_rewrite_size = ULLONG_MAX;
3509 uint64_t min_rewrite_stripe_size = 0;
3510
3511 BIIndexType bi_index_type = BIIndexType::Plain;
3512 std::optional<log_type> opt_log_type;
3513
3514 string job_id;
3515 int num_shards = 0;
3516 bool num_shards_specified = false;
3517 std::optional<int> bucket_index_max_shards;
3518 int max_concurrent_ios = 32;
3519 uint64_t orphan_stale_secs = (24 * 3600);
3520 int detail = false;
3521
3522 std::string val;
3523 std::ostringstream errs;
3524 string err;
3525
3526 string source_zone_name;
3527 rgw_zone_id source_zone; /* zone id */
3528
3529 string tier_type;
3530 bool tier_type_specified = false;
3531
3532 map<string, string, ltstr_nocase> tier_config_add;
3533 map<string, string, ltstr_nocase> tier_config_rm;
3534
3535 boost::optional<string> index_pool;
3536 boost::optional<string> data_pool;
3537 boost::optional<string> data_extra_pool;
3538 rgw::BucketIndexType placement_index_type = rgw::BucketIndexType::Normal;
3539 bool index_type_specified = false;
3540
3541 boost::optional<std::string> compression_type;
3542
3543 string totp_serial;
3544 string totp_seed;
3545 string totp_seed_type = "hex";
3546 vector<string> totp_pin;
3547 int totp_seconds = 0;
3548 int totp_window = 0;
3549 int trim_delay_ms = 0;
3550
3551 string topic_name;
3552 string sub_name;
3553 string event_id;
3554
3555 std::optional<std::string> str_script_ctx;
3556 std::optional<std::string> script_package;
3557 int allow_compilation = false;
3558
3559 std::optional<string> opt_group_id;
3560 std::optional<string> opt_status;
3561 std::optional<string> opt_flow_type;
3562 std::optional<vector<string> > opt_zone_names;
3563 std::optional<vector<rgw_zone_id> > opt_zone_ids;
3564 std::optional<string> opt_flow_id;
3565 std::optional<string> opt_source_zone_name;
3566 std::optional<rgw_zone_id> opt_source_zone_id;
3567 std::optional<string> opt_dest_zone_name;
3568 std::optional<rgw_zone_id> opt_dest_zone_id;
3569 std::optional<vector<string> > opt_source_zone_names;
3570 std::optional<vector<rgw_zone_id> > opt_source_zone_ids;
3571 std::optional<vector<string> > opt_dest_zone_names;
3572 std::optional<vector<rgw_zone_id> > opt_dest_zone_ids;
3573 std::optional<string> opt_pipe_id;
3574 std::optional<rgw_bucket> opt_bucket;
3575 std::optional<string> opt_tenant;
3576 std::optional<string> opt_bucket_name;
3577 std::optional<string> opt_bucket_id;
3578 std::optional<rgw_bucket> opt_source_bucket;
3579 std::optional<string> opt_source_tenant;
3580 std::optional<string> opt_source_bucket_name;
3581 std::optional<string> opt_source_bucket_id;
3582 std::optional<rgw_bucket> opt_dest_bucket;
3583 std::optional<string> opt_dest_tenant;
3584 std::optional<string> opt_dest_bucket_name;
3585 std::optional<string> opt_dest_bucket_id;
3586 std::optional<string> opt_effective_zone_name;
3587 std::optional<rgw_zone_id> opt_effective_zone_id;
3588
3589 std::optional<string> opt_prefix;
3590 std::optional<string> opt_prefix_rm;
3591
3592 std::optional<int> opt_priority;
3593 std::optional<string> opt_mode;
3594 std::optional<rgw_user> opt_dest_owner;
3595 ceph::timespan opt_retry_delay_ms = std::chrono::milliseconds(2000);
3596 ceph::timespan opt_timeout_sec = std::chrono::seconds(60);
3597
3598 SimpleCmd cmd(all_cmds, cmd_aliases);
3599 bool raw_storage_op = false;
3600
3601 std::optional<std::string> rgw_obj_fs; // radoslist field separator
3602
3603 init_realm_param(cct.get(), realm_id, opt_realm_id, "rgw_realm_id");
3604 init_realm_param(cct.get(), zonegroup_id, opt_zonegroup_id, "rgw_zonegroup_id");
3605 init_realm_param(cct.get(), zone_id, opt_zone_id, "rgw_zone_id");
3606
3607 for (std::vector<const char*>::iterator i = args.begin(); i != args.end(); ) {
3608 if (ceph_argparse_double_dash(args, i)) {
3609 break;
3610 } else if (ceph_argparse_witharg(args, i, &val, "-i", "--uid", (char*)NULL)) {
3611 user_id_arg.from_str(val);
3612 if (user_id_arg.empty()) {
3613 cerr << "no value for uid" << std::endl;
3614 exit(1);
3615 }
3616 } else if (ceph_argparse_witharg(args, i, &val, "--new-uid", (char*)NULL)) {
3617 new_user_id.from_str(val);
3618 } else if (ceph_argparse_witharg(args, i, &val, "--tenant", (char*)NULL)) {
3619 tenant = val;
3620 opt_tenant = val;
3621 } else if (ceph_argparse_witharg(args, i, &val, "--user_ns", (char*)NULL)) {
3622 user_ns = val;
3623 } else if (ceph_argparse_witharg(args, i, &val, "--access-key", (char*)NULL)) {
3624 access_key = val;
3625 } else if (ceph_argparse_witharg(args, i, &val, "--subuser", (char*)NULL)) {
3626 subuser = val;
3627 } else if (ceph_argparse_witharg(args, i, &val, "--secret", "--secret-key", (char*)NULL)) {
3628 secret_key = val;
3629 } else if (ceph_argparse_witharg(args, i, &val, "-e", "--email", (char*)NULL)) {
3630 user_email = val;
3631 } else if (ceph_argparse_witharg(args, i, &val, "-n", "--display-name", (char*)NULL)) {
3632 display_name = val;
3633 } else if (ceph_argparse_witharg(args, i, &val, "-b", "--bucket", (char*)NULL)) {
3634 bucket_name = val;
3635 opt_bucket_name = val;
3636 } else if (ceph_argparse_witharg(args, i, &val, "-p", "--pool", (char*)NULL)) {
3637 pool_name = val;
3638 pool = rgw_pool(pool_name);
3639 } else if (ceph_argparse_witharg(args, i, &val, "-o", "--object", (char*)NULL)) {
3640 object = val;
3641 } else if (ceph_argparse_witharg(args, i, &val, "--object-version", (char*)NULL)) {
3642 object_version = val;
3643 } else if (ceph_argparse_witharg(args, i, &val, "--client-id", (char*)NULL)) {
3644 client_id = val;
3645 } else if (ceph_argparse_witharg(args, i, &val, "--op-id", (char*)NULL)) {
3646 op_id = val;
3647 } else if (ceph_argparse_witharg(args, i, &val, "--op-mask", (char*)NULL)) {
3648 op_mask_str = val;
3649 } else if (ceph_argparse_witharg(args, i, &val, "--key-type", (char*)NULL)) {
3650 key_type_str = val;
3651 if (key_type_str.compare("swift") == 0) {
3652 key_type = KEY_TYPE_SWIFT;
3653 } else if (key_type_str.compare("s3") == 0) {
3654 key_type = KEY_TYPE_S3;
3655 } else {
3656 cerr << "bad key type: " << key_type_str << std::endl;
3657 exit(1);
3658 }
3659 } else if (ceph_argparse_witharg(args, i, &val, "--job-id", (char*)NULL)) {
3660 job_id = val;
3661 } else if (ceph_argparse_binary_flag(args, i, &gen_access_key, NULL, "--gen-access-key", (char*)NULL)) {
3662 // do nothing
3663 } else if (ceph_argparse_binary_flag(args, i, &gen_secret_key, NULL, "--gen-secret", (char*)NULL)) {
3664 // do nothing
3665 } else if (ceph_argparse_binary_flag(args, i, &show_log_entries, NULL, "--show-log-entries", (char*)NULL)) {
3666 // do nothing
3667 } else if (ceph_argparse_binary_flag(args, i, &show_log_sum, NULL, "--show-log-sum", (char*)NULL)) {
3668 // do nothing
3669 } else if (ceph_argparse_binary_flag(args, i, &skip_zero_entries, NULL, "--skip-zero-entries", (char*)NULL)) {
3670 // do nothing
3671 } else if (ceph_argparse_binary_flag(args, i, &admin, NULL, "--admin", (char*)NULL)) {
3672 admin_specified = true;
3673 } else if (ceph_argparse_binary_flag(args, i, &system, NULL, "--system", (char*)NULL)) {
3674 system_specified = true;
3675 } else if (ceph_argparse_binary_flag(args, i, &verbose, NULL, "--verbose", (char*)NULL)) {
3676 // do nothing
3677 } else if (ceph_argparse_binary_flag(args, i, &staging, NULL, "--staging", (char*)NULL)) {
3678 // do nothing
3679 } else if (ceph_argparse_binary_flag(args, i, &commit, NULL, "--commit", (char*)NULL)) {
3680 // do nothing
3681 } else if (ceph_argparse_witharg(args, i, &val, "--min-rewrite-size", (char*)NULL)) {
3682 min_rewrite_size = (uint64_t)atoll(val.c_str());
3683 } else if (ceph_argparse_witharg(args, i, &val, "--max-rewrite-size", (char*)NULL)) {
3684 max_rewrite_size = (uint64_t)atoll(val.c_str());
3685 } else if (ceph_argparse_witharg(args, i, &val, "--min-rewrite-stripe-size", (char*)NULL)) {
3686 min_rewrite_stripe_size = (uint64_t)atoll(val.c_str());
3687 } else if (ceph_argparse_witharg(args, i, &val, "--max-buckets", (char*)NULL)) {
3688 max_buckets = (int)strict_strtol(val.c_str(), 10, &err);
3689 if (!err.empty()) {
3690 cerr << "ERROR: failed to parse max buckets: " << err << std::endl;
3691 return EINVAL;
3692 }
3693 max_buckets_specified = true;
3694 } else if (ceph_argparse_witharg(args, i, &val, "--max-entries", (char*)NULL)) {
3695 max_entries = (int)strict_strtol(val.c_str(), 10, &err);
3696 max_entries_specified = true;
3697 if (!err.empty()) {
3698 cerr << "ERROR: failed to parse max entries: " << err << std::endl;
3699 return EINVAL;
3700 }
3701 } else if (ceph_argparse_witharg(args, i, &val, "--max-size", (char*)NULL)) {
3702 max_size = strict_iec_cast<long long>(val, &err);
3703 if (!err.empty()) {
3704 cerr << "ERROR: failed to parse max size: " << err << std::endl;
3705 return EINVAL;
3706 }
3707 have_max_size = true;
3708 } else if (ceph_argparse_witharg(args, i, &val, "--max-objects", (char*)NULL)) {
3709 max_objects = (int64_t)strict_strtoll(val.c_str(), 10, &err);
3710 if (!err.empty()) {
3711 cerr << "ERROR: failed to parse max objects: " << err << std::endl;
3712 return EINVAL;
3713 }
3714 have_max_objects = true;
3715 } else if (ceph_argparse_witharg(args, i, &val, "--max-read-ops", (char*)NULL)) {
3716 max_read_ops = (int64_t)strict_strtoll(val.c_str(), 10, &err);
3717 if (!err.empty()) {
3718 cerr << "ERROR: failed to parse max read requests: " << err << std::endl;
3719 return EINVAL;
3720 }
3721 have_max_read_ops = true;
3722 } else if (ceph_argparse_witharg(args, i, &val, "--max-write-ops", (char*)NULL)) {
3723 max_write_ops = (int64_t)strict_strtoll(val.c_str(), 10, &err);
3724 if (!err.empty()) {
3725 cerr << "ERROR: failed to parse max write requests: " << err << std::endl;
3726 return EINVAL;
3727 }
3728 have_max_write_ops = true;
3729 } else if (ceph_argparse_witharg(args, i, &val, "--max-read-bytes", (char*)NULL)) {
3730 max_read_bytes = (int64_t)strict_strtoll(val.c_str(), 10, &err);
3731 if (!err.empty()) {
3732 cerr << "ERROR: failed to parse max read bytes: " << err << std::endl;
3733 return EINVAL;
3734 }
3735 have_max_read_bytes = true;
3736 } else if (ceph_argparse_witharg(args, i, &val, "--max-write-bytes", (char*)NULL)) {
3737 max_write_bytes = (int64_t)strict_strtoll(val.c_str(), 10, &err);
3738 if (!err.empty()) {
3739 cerr << "ERROR: failed to parse max write bytes: " << err << std::endl;
3740 return EINVAL;
3741 }
3742 have_max_write_bytes = true;
3743 } else if (ceph_argparse_witharg(args, i, &val, "--date", "--time", (char*)NULL)) {
3744 date = val;
3745 if (end_date.empty())
3746 end_date = date;
3747 } else if (ceph_argparse_witharg(args, i, &val, "--start-date", "--start-time", (char*)NULL)) {
3748 start_date = val;
3749 } else if (ceph_argparse_witharg(args, i, &val, "--end-date", "--end-time", (char*)NULL)) {
3750 end_date = val;
3751 } else if (ceph_argparse_witharg(args, i, &val, "--num-shards", (char*)NULL)) {
3752 num_shards = (int)strict_strtol(val.c_str(), 10, &err);
3753 if (!err.empty()) {
3754 cerr << "ERROR: failed to parse num shards: " << err << std::endl;
3755 return EINVAL;
3756 }
3757 num_shards_specified = true;
3758 } else if (ceph_argparse_witharg(args, i, &val, "--bucket-index-max-shards", (char*)NULL)) {
3759 bucket_index_max_shards = (int)strict_strtol(val.c_str(), 10, &err);
3760 if (!err.empty()) {
3761 cerr << "ERROR: failed to parse bucket-index-max-shards: " << err << std::endl;
3762 return EINVAL;
3763 }
3764 } else if (ceph_argparse_witharg(args, i, &val, "--max-concurrent-ios", (char*)NULL)) {
3765 max_concurrent_ios = (int)strict_strtol(val.c_str(), 10, &err);
3766 if (!err.empty()) {
3767 cerr << "ERROR: failed to parse max concurrent ios: " << err << std::endl;
3768 return EINVAL;
3769 }
3770 } else if (ceph_argparse_witharg(args, i, &val, "--orphan-stale-secs", (char*)NULL)) {
3771 orphan_stale_secs = (uint64_t)strict_strtoll(val.c_str(), 10, &err);
3772 if (!err.empty()) {
3773 cerr << "ERROR: failed to parse orphan stale secs: " << err << std::endl;
3774 return EINVAL;
3775 }
3776 } else if (ceph_argparse_witharg(args, i, &val, "--shard-id", (char*)NULL)) {
3777 shard_id = (int)strict_strtol(val.c_str(), 10, &err);
3778 if (!err.empty()) {
3779 cerr << "ERROR: failed to parse shard id: " << err << std::endl;
3780 return EINVAL;
3781 }
3782 specified_shard_id = true;
3783 } else if (ceph_argparse_witharg(args, i, &val, "--access", (char*)NULL)) {
3784 access = val;
3785 perm_mask = rgw_str_to_perm(access.c_str());
3786 set_perm = true;
3787 } else if (ceph_argparse_witharg(args, i, &val, "--temp-url-key", (char*)NULL)) {
3788 temp_url_keys[0] = val;
3789 set_temp_url_key = true;
3790 } else if (ceph_argparse_witharg(args, i, &val, "--temp-url-key2", "--temp-url-key-2", (char*)NULL)) {
3791 temp_url_keys[1] = val;
3792 set_temp_url_key = true;
3793 } else if (ceph_argparse_witharg(args, i, &val, "--bucket-id", (char*)NULL)) {
3794 bucket_id = val;
3795 opt_bucket_id = val;
3796 if (bucket_id.empty()) {
3797 cerr << "no value for bucket-id" << std::endl;
3798 exit(1);
3799 }
3800 } else if (ceph_argparse_witharg(args, i, &val, "--bucket-new-name", (char*)NULL)) {
3801 new_bucket_name = val;
3802 } else if (ceph_argparse_witharg(args, i, &val, "--format", (char*)NULL)) {
3803 format = val;
3804 } else if (ceph_argparse_witharg(args, i, &val, "--categories", (char*)NULL)) {
3805 string cat_str = val;
3806 list<string> cat_list;
3807 list<string>::iterator iter;
3808 get_str_list(cat_str, cat_list);
3809 for (iter = cat_list.begin(); iter != cat_list.end(); ++iter) {
3810 categories[*iter] = true;
3811 }
3812 } else if (ceph_argparse_binary_flag(args, i, &delete_child_objects, NULL, "--purge-objects", (char*)NULL)) {
3813 // do nothing
3814 } else if (ceph_argparse_binary_flag(args, i, &pretty_format, NULL, "--pretty-format", (char*)NULL)) {
3815 // do nothing
3816 } else if (ceph_argparse_binary_flag(args, i, &purge_data, NULL, "--purge-data", (char*)NULL)) {
3817 delete_child_objects = purge_data;
3818 } else if (ceph_argparse_binary_flag(args, i, &purge_keys, NULL, "--purge-keys", (char*)NULL)) {
3819 // do nothing
3820 } else if (ceph_argparse_binary_flag(args, i, &yes_i_really_mean_it, NULL, "--yes-i-really-mean-it", (char*)NULL)) {
3821 // do nothing
3822 } else if (ceph_argparse_binary_flag(args, i, &fix, NULL, "--fix", (char*)NULL)) {
3823 // do nothing
3824 } else if (ceph_argparse_binary_flag(args, i, &remove_bad, NULL, "--remove-bad", (char*)NULL)) {
3825 // do nothing
3826 } else if (ceph_argparse_binary_flag(args, i, &check_head_obj_locator, NULL, "--check-head-obj-locator", (char*)NULL)) {
3827 // do nothing
3828 } else if (ceph_argparse_binary_flag(args, i, &check_objects, NULL, "--check-objects", (char*)NULL)) {
3829 // do nothing
3830 } else if (ceph_argparse_binary_flag(args, i, &sync_stats, NULL, "--sync-stats", (char*)NULL)) {
3831 // do nothing
3832 } else if (ceph_argparse_binary_flag(args, i, &reset_stats, NULL, "--reset-stats", (char*)NULL)) {
3833 // do nothing
3834 } else if (ceph_argparse_binary_flag(args, i, &include_all, NULL, "--include-all", (char*)NULL)) {
3835 // do nothing
3836 } else if (ceph_argparse_binary_flag(args, i, &allow_unordered, NULL, "--allow-unordered", (char*)NULL)) {
3837 // do nothing
3838 } else if (ceph_argparse_binary_flag(args, i, &extra_info, NULL, "--extra-info", (char*)NULL)) {
3839 // do nothing
3840 } else if (ceph_argparse_binary_flag(args, i, &bypass_gc, NULL, "--bypass-gc", (char*)NULL)) {
3841 // do nothing
3842 } else if (ceph_argparse_binary_flag(args, i, &warnings_only, NULL, "--warnings-only", (char*)NULL)) {
3843 // do nothing
3844 } else if (ceph_argparse_binary_flag(args, i, &inconsistent_index, NULL, "--inconsistent-index", (char*)NULL)) {
3845 // do nothing
3846 } else if (ceph_argparse_witharg(args, i, &val, "--caps", (char*)NULL)) {
3847 caps = val;
3848 } else if (ceph_argparse_witharg(args, i, &val, "--infile", (char*)NULL)) {
3849 infile = val;
3850 } else if (ceph_argparse_witharg(args, i, &val, "--metadata-key", (char*)NULL)) {
3851 metadata_key = val;
3852 } else if (ceph_argparse_witharg(args, i, &val, "--marker", (char*)NULL)) {
3853 marker = val;
3854 } else if (ceph_argparse_witharg(args, i, &val, "--start-marker", (char*)NULL)) {
3855 start_marker = val;
3856 } else if (ceph_argparse_witharg(args, i, &val, "--end-marker", (char*)NULL)) {
3857 end_marker = val;
3858 } else if (ceph_argparse_witharg(args, i, &val, "--quota-scope", (char*)NULL)) {
3859 quota_scope = val;
3860 } else if (ceph_argparse_witharg(args, i, &val, "--ratelimit-scope", (char*)NULL)) {
3861 ratelimit_scope = val;
3862 } else if (ceph_argparse_witharg(args, i, &val, "--index-type", (char*)NULL)) {
3863 string index_type_str = val;
3864 bi_index_type = get_bi_index_type(index_type_str);
3865 if (bi_index_type == BIIndexType::Invalid) {
3866 cerr << "ERROR: invalid bucket index entry type" << std::endl;
3867 return EINVAL;
3868 }
3869 } else if (ceph_argparse_witharg(args, i, &val, "--log-type", (char*)NULL)) {
3870 string log_type_str = val;
3871 auto l = get_log_type(log_type_str);
3872 if (l == static_cast<log_type>(0xff)) {
3873 cerr << "ERROR: invalid log type" << std::endl;
3874 return EINVAL;
3875 }
3876 opt_log_type = l;
3877 } else if (ceph_argparse_binary_flag(args, i, &is_master_int, NULL, "--master", (char*)NULL)) {
3878 is_master = (bool)is_master_int;
3879 is_master_set = true;
3880 } else if (ceph_argparse_binary_flag(args, i, &set_default, NULL, "--default", (char*)NULL)) {
3881 /* do nothing */
3882 } else if (ceph_argparse_witharg(args, i, &val, "--redirect-zone", (char*)NULL)) {
3883 redirect_zone = val;
3884 redirect_zone_set = true;
3885 } else if (ceph_argparse_binary_flag(args, i, &read_only_int, NULL, "--read-only", (char*)NULL)) {
3886 read_only = (bool)read_only_int;
3887 is_read_only_set = true;
3888 } else if (ceph_argparse_witharg(args, i, &val, "--master-zone", (char*)NULL)) {
3889 master_zone = val;
3890 } else if (ceph_argparse_witharg(args, i, &val, "--period", (char*)NULL)) {
3891 period_id = val;
3892 } else if (ceph_argparse_witharg(args, i, &val, "--epoch", (char*)NULL)) {
3893 period_epoch = val;
3894 } else if (ceph_argparse_witharg(args, i, &val, "--remote", (char*)NULL)) {
3895 remote = val;
3896 } else if (ceph_argparse_witharg(args, i, &val, "--url", (char*)NULL)) {
3897 url = val;
3898 } else if (ceph_argparse_witharg(args, i, &val, "--region", (char*)NULL)) {
3899 opt_region = val;
3900 } else if (ceph_argparse_witharg(args, i, &val, "--realm-id", (char*)NULL)) {
3901 realm_id = val;
3902 opt_realm_id = val;
3903 g_conf().set_val("rgw_realm_id", val);
3904 } else if (ceph_argparse_witharg(args, i, &val, "--realm-new-name", (char*)NULL)) {
3905 realm_new_name = val;
3906 } else if (ceph_argparse_witharg(args, i, &val, "--zonegroup-id", (char*)NULL)) {
3907 zonegroup_id = val;
3908 opt_zonegroup_id = val;
3909 g_conf().set_val("rgw_zonegroup_id", val);
3910 } else if (ceph_argparse_witharg(args, i, &val, "--zonegroup-new-name", (char*)NULL)) {
3911 zonegroup_new_name = val;
3912 } else if (ceph_argparse_witharg(args, i, &val, "--placement-id", (char*)NULL)) {
3913 placement_id = val;
3914 } else if (ceph_argparse_witharg(args, i, &val, "--storage-class", (char*)NULL)) {
3915 opt_storage_class = val;
3916 } else if (ceph_argparse_witharg(args, i, &val, "--tags", (char*)NULL)) {
3917 get_str_list(val, ",", tags);
3918 } else if (ceph_argparse_witharg(args, i, &val, "--tags-add", (char*)NULL)) {
3919 get_str_list(val, ",", tags_add);
3920 } else if (ceph_argparse_witharg(args, i, &val, "--tags-rm", (char*)NULL)) {
3921 get_str_list(val, ",", tags_rm);
3922 } else if (ceph_argparse_witharg(args, i, &val, "--api-name", (char*)NULL)) {
3923 api_name = val;
3924 } else if (ceph_argparse_witharg(args, i, &val, "--zone-id", (char*)NULL)) {
3925 zone_id = val;
3926 opt_zone_id = val;
3927 g_conf().set_val("rgw_zone_id", val);
3928 } else if (ceph_argparse_witharg(args, i, &val, "--zone-new-name", (char*)NULL)) {
3929 zone_new_name = val;
3930 } else if (ceph_argparse_witharg(args, i, &val, "--endpoints", (char*)NULL)) {
3931 get_str_list(val, endpoints);
3932 } else if (ceph_argparse_witharg(args, i, &val, "--sync-from", (char*)NULL)) {
3933 get_str_list(val, sync_from);
3934 } else if (ceph_argparse_witharg(args, i, &val, "--sync-from-rm", (char*)NULL)) {
3935 get_str_list(val, sync_from_rm);
3936 } else if (ceph_argparse_binary_flag(args, i, &tmp_int, NULL, "--sync-from-all", (char*)NULL)) {
3937 sync_from_all = (bool)tmp_int;
3938 sync_from_all_specified = true;
3939 } else if (ceph_argparse_witharg(args, i, &val, "--source-zone", (char*)NULL)) {
3940 source_zone_name = val;
3941 opt_source_zone_name = val;
3942 } else if (ceph_argparse_witharg(args, i, &val, "--source-zone-id", (char*)NULL)) {
3943 opt_source_zone_id = val;
3944 } else if (ceph_argparse_witharg(args, i, &val, "--dest-zone", (char*)NULL)) {
3945 opt_dest_zone_name = val;
3946 } else if (ceph_argparse_witharg(args, i, &val, "--dest-zone-id", (char*)NULL)) {
3947 opt_dest_zone_id = val;
3948 } else if (ceph_argparse_witharg(args, i, &val, "--tier-type", (char*)NULL)) {
3949 tier_type = val;
3950 tier_type_specified = true;
3951 } else if (ceph_argparse_witharg(args, i, &val, "--tier-config", (char*)NULL)) {
3952 parse_tier_config_param(val, tier_config_add);
3953 } else if (ceph_argparse_witharg(args, i, &val, "--tier-config-rm", (char*)NULL)) {
3954 parse_tier_config_param(val, tier_config_rm);
3955 } else if (ceph_argparse_witharg(args, i, &val, "--index-pool", (char*)NULL)) {
3956 index_pool = val;
3957 } else if (ceph_argparse_witharg(args, i, &val, "--data-pool", (char*)NULL)) {
3958 data_pool = val;
3959 } else if (ceph_argparse_witharg(args, i, &val, "--data-extra-pool", (char*)NULL)) {
3960 data_extra_pool = val;
3961 } else if (ceph_argparse_witharg(args, i, &val, "--placement-index-type", (char*)NULL)) {
3962 if (val == "normal") {
3963 placement_index_type = rgw::BucketIndexType::Normal;
3964 } else if (val == "indexless") {
3965 placement_index_type = rgw::BucketIndexType::Indexless;
3966 } else {
3967 placement_index_type = (rgw::BucketIndexType)strict_strtol(val.c_str(), 10, &err);
3968 if (!err.empty()) {
3969 cerr << "ERROR: failed to parse index type index: " << err << std::endl;
3970 return EINVAL;
3971 }
3972 }
3973 index_type_specified = true;
3974 } else if (ceph_argparse_witharg(args, i, &val, "--compression", (char*)NULL)) {
3975 compression_type = val;
3976 } else if (ceph_argparse_witharg(args, i, &val, "--role-name", (char*)NULL)) {
3977 role_name = val;
3978 } else if (ceph_argparse_witharg(args, i, &val, "--path", (char*)NULL)) {
3979 path = val;
3980 } else if (ceph_argparse_witharg(args, i, &val, "--assume-role-policy-doc", (char*)NULL)) {
3981 assume_role_doc = val;
3982 } else if (ceph_argparse_witharg(args, i, &val, "--policy-name", (char*)NULL)) {
3983 policy_name = val;
3984 } else if (ceph_argparse_witharg(args, i, &val, "--policy-doc", (char*)NULL)) {
3985 perm_policy_doc = val;
3986 } else if (ceph_argparse_witharg(args, i, &val, "--path-prefix", (char*)NULL)) {
3987 path_prefix = val;
3988 } else if (ceph_argparse_witharg(args, i, &val, "--totp-serial", (char*)NULL)) {
3989 totp_serial = val;
3990 } else if (ceph_argparse_witharg(args, i, &val, "--totp-pin", (char*)NULL)) {
3991 totp_pin.push_back(val);
3992 } else if (ceph_argparse_witharg(args, i, &val, "--totp-seed", (char*)NULL)) {
3993 totp_seed = val;
3994 } else if (ceph_argparse_witharg(args, i, &val, "--totp-seed-type", (char*)NULL)) {
3995 totp_seed_type = val;
3996 } else if (ceph_argparse_witharg(args, i, &val, "--totp-seconds", (char*)NULL)) {
3997 totp_seconds = atoi(val.c_str());
3998 } else if (ceph_argparse_witharg(args, i, &val, "--totp-window", (char*)NULL)) {
3999 totp_window = atoi(val.c_str());
4000 } else if (ceph_argparse_witharg(args, i, &val, "--trim-delay-ms", (char*)NULL)) {
4001 trim_delay_ms = atoi(val.c_str());
4002 } else if (ceph_argparse_witharg(args, i, &val, "--topic", (char*)NULL)) {
4003 topic_name = val;
4004 } else if (ceph_argparse_witharg(args, i, &val, "--subscription", (char*)NULL)) {
4005 sub_name = val;
4006 } else if (ceph_argparse_witharg(args, i, &val, "--event-id", (char*)NULL)) {
4007 event_id = val;
4008 } else if (ceph_argparse_witharg(args, i, &val, "--group-id", (char*)NULL)) {
4009 opt_group_id = val;
4010 } else if (ceph_argparse_witharg(args, i, &val, "--status", (char*)NULL)) {
4011 opt_status = val;
4012 } else if (ceph_argparse_witharg(args, i, &val, "--flow-type", (char*)NULL)) {
4013 opt_flow_type = val;
4014 } else if (ceph_argparse_witharg(args, i, &val, "--zones", "--zone-names", (char*)NULL)) {
4015 vector<string> v;
4016 get_str_vec(val, v);
4017 opt_zone_names = std::move(v);
4018 } else if (ceph_argparse_witharg(args, i, &val, "--zone-ids", (char*)NULL)) {
4019 opt_zone_ids = zone_ids_from_str(val);
4020 } else if (ceph_argparse_witharg(args, i, &val, "--source-zones", "--source-zone-names", (char*)NULL)) {
4021 vector<string> v;
4022 get_str_vec(val, v);
4023 opt_source_zone_names = std::move(v);
4024 } else if (ceph_argparse_witharg(args, i, &val, "--source-zone-ids", (char*)NULL)) {
4025 opt_source_zone_ids = zone_ids_from_str(val);
4026 } else if (ceph_argparse_witharg(args, i, &val, "--dest-zones", "--dest-zone-names", (char*)NULL)) {
4027 vector<string> v;
4028 get_str_vec(val, v);
4029 opt_dest_zone_names = std::move(v);
4030 } else if (ceph_argparse_witharg(args, i, &val, "--dest-zone-ids", (char*)NULL)) {
4031 opt_dest_zone_ids = zone_ids_from_str(val);
4032 } else if (ceph_argparse_witharg(args, i, &val, "--flow-id", (char*)NULL)) {
4033 opt_flow_id = val;
4034 } else if (ceph_argparse_witharg(args, i, &val, "--pipe-id", (char*)NULL)) {
4035 opt_pipe_id = val;
4036 } else if (ceph_argparse_witharg(args, i, &val, "--source-tenant", (char*)NULL)) {
4037 opt_source_tenant = val;
4038 } else if (ceph_argparse_witharg(args, i, &val, "--source-bucket", (char*)NULL)) {
4039 opt_source_bucket_name = val;
4040 } else if (ceph_argparse_witharg(args, i, &val, "--source-bucket-id", (char*)NULL)) {
4041 opt_source_bucket_id = val;
4042 } else if (ceph_argparse_witharg(args, i, &val, "--dest-tenant", (char*)NULL)) {
4043 opt_dest_tenant = val;
4044 } else if (ceph_argparse_witharg(args, i, &val, "--dest-bucket", (char*)NULL)) {
4045 opt_dest_bucket_name = val;
4046 } else if (ceph_argparse_witharg(args, i, &val, "--dest-bucket-id", (char*)NULL)) {
4047 opt_dest_bucket_id = val;
4048 } else if (ceph_argparse_witharg(args, i, &val, "--effective-zone-name", "--effective-zone", (char*)NULL)) {
4049 opt_effective_zone_name = val;
4050 } else if (ceph_argparse_witharg(args, i, &val, "--effective-zone-id", (char*)NULL)) {
4051 opt_effective_zone_id = rgw_zone_id(val);
4052 } else if (ceph_argparse_witharg(args, i, &val, "--prefix", (char*)NULL)) {
4053 opt_prefix = val;
4054 } else if (ceph_argparse_witharg(args, i, &val, "--prefix-rm", (char*)NULL)) {
4055 opt_prefix_rm = val;
4056 } else if (ceph_argparse_witharg(args, i, &val, "--priority", (char*)NULL)) {
4057 opt_priority = atoi(val.c_str());
4058 } else if (ceph_argparse_witharg(args, i, &val, "--mode", (char*)NULL)) {
4059 opt_mode = val;
4060 } else if (ceph_argparse_witharg(args, i, &val, "--dest-owner", (char*)NULL)) {
4061 opt_dest_owner.emplace(val);
4062 opt_dest_owner = val;
4063 } else if (ceph_argparse_witharg(args, i, &val, "--retry-delay-ms", (char*)NULL)) {
4064 opt_retry_delay_ms = std::chrono::milliseconds(atoi(val.c_str()));
4065 } else if (ceph_argparse_witharg(args, i, &val, "--timeout-sec", (char*)NULL)) {
4066 opt_timeout_sec = std::chrono::seconds(atoi(val.c_str()));
4067 } else if (ceph_argparse_binary_flag(args, i, &detail, NULL, "--detail", (char*)NULL)) {
4068 // do nothing
4069 } else if (ceph_argparse_witharg(args, i, &val, "--context", (char*)NULL)) {
4070 str_script_ctx = val;
4071 } else if (ceph_argparse_witharg(args, i, &val, "--package", (char*)NULL)) {
4072 script_package = val;
4073 } else if (ceph_argparse_binary_flag(args, i, &allow_compilation, NULL, "--allow-compilation", (char*)NULL)) {
4074 // do nothing
4075 } else if (ceph_argparse_witharg(args, i, &val, "--rgw-obj-fs", (char*)NULL)) {
4076 rgw_obj_fs = val;
4077 } else if (strncmp(*i, "-", 1) == 0) {
4078 cerr << "ERROR: invalid flag " << *i << std::endl;
4079 return EINVAL;
4080 } else {
4081 ++i;
4082 }
4083 }
4084
4085 /* common_init_finish needs to be called after g_conf().set_val() */
4086 common_init_finish(g_ceph_context);
4087
4088 if (args.empty()) {
4089 usage();
4090 exit(1);
4091 }
4092 else {
4093 std::vector<string> extra_args;
4094 std::vector<string> expected;
4095
4096 std::any _opt_cmd;
4097
4098 if (!cmd.find_command(args, &_opt_cmd, &extra_args, &err, &expected)) {
4099 if (!expected.empty()) {
4100 cerr << err << std::endl;
4101 cerr << "Expected one of the following:" << std::endl;
4102 for (auto& exp : expected) {
4103 if (exp == "*" || exp == "[*]") {
4104 continue;
4105 }
4106 cerr << " " << exp << std::endl;
4107 }
4108 } else {
4109 cerr << "Command not found:";
4110 for (auto& arg : args) {
4111 cerr << " " << arg;
4112 }
4113 cerr << std::endl;
4114 }
4115 exit(1);
4116 }
4117
4118 opt_cmd = std::any_cast<OPT>(_opt_cmd);
4119
4120 /* some commands may have an optional extra param */
4121 if (!extra_args.empty()) {
4122 switch (opt_cmd) {
4123 case OPT::METADATA_GET:
4124 case OPT::METADATA_PUT:
4125 case OPT::METADATA_RM:
4126 case OPT::METADATA_LIST:
4127 metadata_key = extra_args[0];
4128 break;
4129 default:
4130 break;
4131 }
4132 }
4133
4134 // not a raw op if 'period update' needs to commit to master
4135 bool raw_period_update = opt_cmd == OPT::PERIOD_UPDATE && !commit;
4136 // not a raw op if 'period pull' needs to read zone/period configuration
4137 bool raw_period_pull = opt_cmd == OPT::PERIOD_PULL && !url.empty();
4138
4139 std::set<OPT> raw_storage_ops_list = {OPT::ZONEGROUP_ADD, OPT::ZONEGROUP_CREATE,
4140 OPT::ZONEGROUP_DELETE,
4141 OPT::ZONEGROUP_GET, OPT::ZONEGROUP_LIST,
4142 OPT::ZONEGROUP_SET, OPT::ZONEGROUP_DEFAULT,
4143 OPT::ZONEGROUP_RENAME, OPT::ZONEGROUP_MODIFY,
4144 OPT::ZONEGROUP_REMOVE,
4145 OPT::ZONEGROUP_PLACEMENT_ADD, OPT::ZONEGROUP_PLACEMENT_RM,
4146 OPT::ZONEGROUP_PLACEMENT_MODIFY, OPT::ZONEGROUP_PLACEMENT_LIST,
4147 OPT::ZONEGROUP_PLACEMENT_GET,
4148 OPT::ZONEGROUP_PLACEMENT_DEFAULT,
4149 OPT::ZONE_CREATE, OPT::ZONE_DELETE,
4150 OPT::ZONE_GET, OPT::ZONE_SET, OPT::ZONE_RENAME,
4151 OPT::ZONE_LIST, OPT::ZONE_MODIFY, OPT::ZONE_DEFAULT,
4152 OPT::ZONE_PLACEMENT_ADD, OPT::ZONE_PLACEMENT_RM,
4153 OPT::ZONE_PLACEMENT_MODIFY, OPT::ZONE_PLACEMENT_LIST,
4154 OPT::ZONE_PLACEMENT_GET,
4155 OPT::REALM_CREATE,
4156 OPT::PERIOD_DELETE, OPT::PERIOD_GET,
4157 OPT::PERIOD_GET_CURRENT, OPT::PERIOD_LIST,
4158 OPT::GLOBAL_QUOTA_GET, OPT::GLOBAL_QUOTA_SET,
4159 OPT::GLOBAL_QUOTA_ENABLE, OPT::GLOBAL_QUOTA_DISABLE,
4160 OPT::GLOBAL_RATELIMIT_GET, OPT::GLOBAL_RATELIMIT_SET,
4161 OPT::GLOBAL_RATELIMIT_ENABLE, OPT::GLOBAL_RATELIMIT_DISABLE,
4162 OPT::REALM_DELETE, OPT::REALM_GET, OPT::REALM_LIST,
4163 OPT::REALM_LIST_PERIODS,
4164 OPT::REALM_GET_DEFAULT,
4165 OPT::REALM_RENAME, OPT::REALM_SET,
4166 OPT::REALM_DEFAULT, OPT::REALM_PULL};
4167
4168 std::set<OPT> readonly_ops_list = {
4169 OPT::USER_INFO,
4170 OPT::USER_STATS,
4171 OPT::BUCKETS_LIST,
4172 OPT::BUCKET_LIMIT_CHECK,
4173 OPT::BUCKET_STATS,
4174 OPT::BUCKET_SYNC_CHECKPOINT,
4175 OPT::BUCKET_SYNC_INFO,
4176 OPT::BUCKET_SYNC_STATUS,
4177 OPT::BUCKET_SYNC_MARKERS,
4178 OPT::LOG_LIST,
4179 OPT::LOG_SHOW,
4180 OPT::USAGE_SHOW,
4181 OPT::OBJECT_STAT,
4182 OPT::BI_GET,
4183 OPT::BI_LIST,
4184 OPT::OLH_GET,
4185 OPT::OLH_READLOG,
4186 OPT::GC_LIST,
4187 OPT::LC_LIST,
4188 OPT::ORPHANS_LIST_JOBS,
4189 OPT::ZONEGROUP_GET,
4190 OPT::ZONEGROUP_LIST,
4191 OPT::ZONEGROUP_PLACEMENT_LIST,
4192 OPT::ZONEGROUP_PLACEMENT_GET,
4193 OPT::ZONE_GET,
4194 OPT::ZONE_LIST,
4195 OPT::ZONE_PLACEMENT_LIST,
4196 OPT::ZONE_PLACEMENT_GET,
4197 OPT::METADATA_GET,
4198 OPT::METADATA_LIST,
4199 OPT::METADATA_SYNC_STATUS,
4200 OPT::MDLOG_LIST,
4201 OPT::MDLOG_STATUS,
4202 OPT::SYNC_ERROR_LIST,
4203 OPT::SYNC_GROUP_GET,
4204 OPT::SYNC_POLICY_GET,
4205 OPT::BILOG_LIST,
4206 OPT::BILOG_STATUS,
4207 OPT::DATA_SYNC_STATUS,
4208 OPT::DATALOG_LIST,
4209 OPT::DATALOG_STATUS,
4210 OPT::REALM_GET,
4211 OPT::REALM_GET_DEFAULT,
4212 OPT::REALM_LIST,
4213 OPT::REALM_LIST_PERIODS,
4214 OPT::PERIOD_GET,
4215 OPT::PERIOD_GET_CURRENT,
4216 OPT::PERIOD_LIST,
4217 OPT::GLOBAL_QUOTA_GET,
4218 OPT::GLOBAL_RATELIMIT_GET,
4219 OPT::SYNC_INFO,
4220 OPT::SYNC_STATUS,
4221 OPT::ROLE_GET,
4222 OPT::ROLE_LIST,
4223 OPT::ROLE_POLICY_LIST,
4224 OPT::ROLE_POLICY_GET,
4225 OPT::RESHARD_LIST,
4226 OPT::RESHARD_STATUS,
4227 OPT::PUBSUB_TOPICS_LIST,
4228 OPT::PUBSUB_TOPIC_GET,
4229 OPT::PUBSUB_SUB_GET,
4230 OPT::PUBSUB_SUB_PULL,
4231 OPT::SCRIPT_GET,
4232 };
4233
4234 std::set<OPT> gc_ops_list = {
4235 OPT::GC_LIST,
4236 OPT::GC_PROCESS,
4237 OPT::OBJECT_RM,
4238 OPT::BUCKET_RM, // --purge-objects
4239 OPT::USER_RM, // --purge-data
4240 OPT::OBJECTS_EXPIRE,
4241 OPT::OBJECTS_EXPIRE_STALE_RM,
4242 OPT::LC_PROCESS
4243 };
4244
4245 raw_storage_op = (raw_storage_ops_list.find(opt_cmd) != raw_storage_ops_list.end() ||
4246 raw_period_update || raw_period_pull);
4247 bool need_cache = readonly_ops_list.find(opt_cmd) == readonly_ops_list.end();
4248 bool need_gc = (gc_ops_list.find(opt_cmd) != gc_ops_list.end()) && !bypass_gc;
4249
4250 if (raw_storage_op) {
4251 store = StoreManager::get_raw_storage(dpp(), g_ceph_context, "rados");
4252 } else {
4253 store = StoreManager::get_storage(dpp(), g_ceph_context, "rados", false, false, false,
4254 false, false,
4255 need_cache && g_conf()->rgw_cache_enabled, need_gc);
4256 }
4257 if (!store) {
4258 cerr << "couldn't init storage provider" << std::endl;
4259 return 5; //EIO
4260 }
4261
4262 /* Needs to be after the store is initialized. Note, user could be empty here. */
4263 user = store->get_user(user_id_arg);
4264
4265 init_optional_bucket(opt_bucket, opt_tenant,
4266 opt_bucket_name, opt_bucket_id);
4267 init_optional_bucket(opt_source_bucket, opt_source_tenant,
4268 opt_source_bucket_name, opt_source_bucket_id);
4269 init_optional_bucket(opt_dest_bucket, opt_dest_tenant,
4270 opt_dest_bucket_name, opt_dest_bucket_id);
4271
4272 if (tenant.empty()) {
4273 tenant = user->get_tenant();
4274 } else {
4275 if (rgw::sal::User::empty(user) && opt_cmd != OPT::ROLE_CREATE
4276 && opt_cmd != OPT::ROLE_DELETE
4277 && opt_cmd != OPT::ROLE_GET
4278 && opt_cmd != OPT::ROLE_MODIFY
4279 && opt_cmd != OPT::ROLE_LIST
4280 && opt_cmd != OPT::ROLE_POLICY_PUT
4281 && opt_cmd != OPT::ROLE_POLICY_LIST
4282 && opt_cmd != OPT::ROLE_POLICY_GET
4283 && opt_cmd != OPT::ROLE_POLICY_DELETE
4284 && opt_cmd != OPT::RESHARD_ADD
4285 && opt_cmd != OPT::RESHARD_CANCEL
4286 && opt_cmd != OPT::RESHARD_STATUS) {
4287 cerr << "ERROR: --tenant is set, but there's no user ID" << std::endl;
4288 return EINVAL;
4289 }
4290 user->set_tenant(tenant);
4291 }
4292 if (user_ns.empty()) {
4293 user_ns = user->get_id().ns;
4294 } else {
4295 user->set_ns(user_ns);
4296 }
4297
4298 if (!new_user_id.empty() && !tenant.empty()) {
4299 new_user_id.tenant = tenant;
4300 }
4301
4302 /* check key parameter conflict */
4303 if ((!access_key.empty()) && gen_access_key) {
4304 cerr << "ERROR: key parameter conflict, --access-key & --gen-access-key" << std::endl;
4305 return EINVAL;
4306 }
4307 if ((!secret_key.empty()) && gen_secret_key) {
4308 cerr << "ERROR: key parameter conflict, --secret & --gen-secret" << std::endl;
4309 return EINVAL;
4310 }
4311 }
4312
4313 // default to pretty json
4314 if (format.empty()) {
4315 format = "json";
4316 pretty_format = true;
4317 }
4318
4319 if (format == "xml")
4320 formatter = make_unique<XMLFormatter>(new XMLFormatter(pretty_format));
4321 else if (format == "json")
4322 formatter = make_unique<JSONFormatter>(new JSONFormatter(pretty_format));
4323 else {
4324 cerr << "unrecognized format: " << format << std::endl;
4325 exit(1);
4326 }
4327
4328 zone_formatter = std::make_unique<JSONFormatter_PrettyZone>(pretty_format);
4329
4330 realm_name = g_conf()->rgw_realm;
4331 zone_name = g_conf()->rgw_zone;
4332 zonegroup_name = g_conf()->rgw_zonegroup;
4333
4334 if (!realm_name.empty()) {
4335 opt_realm_name = realm_name;
4336 }
4337
4338 if (!zone_name.empty()) {
4339 opt_zone_name = zone_name;
4340 }
4341
4342 if (!zonegroup_name.empty()) {
4343 opt_zonegroup_name = zonegroup_name;
4344 }
4345
4346 RGWStreamFlusher stream_flusher(formatter.get(), cout);
4347
4348 RGWUserAdminOpState user_op(store);
4349 if (!user_email.empty()) {
4350 user_op.user_email_specified=true;
4351 }
4352
4353 if (!source_zone_name.empty()) {
4354 if (!static_cast<rgw::sal::RadosStore*>(store)->svc()->zone->find_zone_id_by_name(source_zone_name, &source_zone)) {
4355 cerr << "WARNING: cannot find source zone id for name=" << source_zone_name << std::endl;
4356 source_zone = source_zone_name;
4357 }
4358 }
4359
4360 rgw_http_client_init(g_ceph_context);
4361
4362 struct rgw_curl_setup {
4363 rgw_curl_setup() {
4364 rgw::curl::setup_curl(boost::none);
4365 }
4366 ~rgw_curl_setup() {
4367 rgw::curl::cleanup_curl();
4368 }
4369 } curl_cleanup;
4370
4371 oath_init();
4372
4373 StoreDestructor store_destructor(static_cast<rgw::sal::RadosStore*>(store));
4374
4375 if (raw_storage_op) {
4376 try_to_resolve_local_entities(realm_id, realm_name,
4377 zonegroup_id, zonegroup_name,
4378 zone_id, zone_name);
4379
4380
4381 switch (opt_cmd) {
4382 case OPT::PERIOD_DELETE:
4383 {
4384 if (period_id.empty()) {
4385 cerr << "missing period id" << std::endl;
4386 return EINVAL;
4387 }
4388 RGWPeriod period(period_id);
4389 int ret = period.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
4390 if (ret < 0) {
4391 cerr << "period.init failed: " << cpp_strerror(-ret) << std::endl;
4392 return -ret;
4393 }
4394 ret = period.delete_obj(dpp(), null_yield);
4395 if (ret < 0) {
4396 cerr << "ERROR: couldn't delete period: " << cpp_strerror(-ret) << std::endl;
4397 return -ret;
4398 }
4399
4400 }
4401 break;
4402 case OPT::PERIOD_GET:
4403 {
4404 epoch_t epoch = 0;
4405 if (!period_epoch.empty()) {
4406 epoch = atoi(period_epoch.c_str());
4407 }
4408 if (staging) {
4409 RGWRealm realm(realm_id, realm_name);
4410 int ret = realm.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
4411 if (ret < 0 ) {
4412 cerr << "Error initializing realm " << cpp_strerror(-ret) << std::endl;
4413 return -ret;
4414 }
4415 realm_id = realm.get_id();
4416 realm_name = realm.get_name();
4417 period_id = RGWPeriod::get_staging_id(realm_id);
4418 epoch = 1;
4419 }
4420 RGWPeriod period(period_id, epoch);
4421 int ret = period.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, realm_id,
4422 null_yield, realm_name);
4423 if (ret < 0) {
4424 cerr << "period init failed: " << cpp_strerror(-ret) << std::endl;
4425 return -ret;
4426 }
4427 encode_json("period", period, formatter.get());
4428 formatter->flush(cout);
4429 }
4430 break;
4431 case OPT::PERIOD_GET_CURRENT:
4432 {
4433 int ret = read_current_period_id(static_cast<rgw::sal::RadosStore*>(store), realm_id, realm_name, &period_id);
4434 if (ret < 0) {
4435 return -ret;
4436 }
4437 formatter->open_object_section("period_get_current");
4438 encode_json("current_period", period_id, formatter.get());
4439 formatter->close_section();
4440 formatter->flush(cout);
4441 }
4442 break;
4443 case OPT::PERIOD_LIST:
4444 {
4445 list<string> periods;
4446 int ret = static_cast<rgw::sal::RadosStore*>(store)->svc()->zone->list_periods(dpp(), periods);
4447 if (ret < 0) {
4448 cerr << "failed to list periods: " << cpp_strerror(-ret) << std::endl;
4449 return -ret;
4450 }
4451 formatter->open_object_section("periods_list");
4452 encode_json("periods", periods, formatter.get());
4453 formatter->close_section();
4454 formatter->flush(cout);
4455 }
4456 break;
4457 case OPT::PERIOD_UPDATE:
4458 {
4459 int ret = update_period(realm_id, realm_name, period_id, period_epoch,
4460 commit, remote, url, opt_region,
4461 access_key, secret_key,
4462 formatter.get(), yes_i_really_mean_it);
4463 if (ret < 0) {
4464 return -ret;
4465 }
4466 }
4467 break;
4468 case OPT::PERIOD_PULL:
4469 {
4470 boost::optional<RGWRESTConn> conn;
4471 RGWRESTConn *remote_conn = nullptr;
4472 if (url.empty()) {
4473 // load current period for endpoints
4474 RGWRealm realm(realm_id, realm_name);
4475 int ret = realm.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
4476 if (ret < 0) {
4477 cerr << "failed to init realm: " << cpp_strerror(-ret) << std::endl;
4478 return -ret;
4479 }
4480 RGWPeriod current_period(realm.get_current_period());
4481 ret = current_period.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
4482 if (ret < 0) {
4483 cerr << "failed to init current period: " << cpp_strerror(-ret) << std::endl;
4484 return -ret;
4485 }
4486 if (remote.empty()) {
4487 // use realm master zone as remote
4488 remote = current_period.get_master_zone().id;
4489 }
4490 conn = get_remote_conn(static_cast<rgw::sal::RadosStore*>(store), current_period.get_map(), remote);
4491 if (!conn) {
4492 cerr << "failed to find a zone or zonegroup for remote "
4493 << remote << std::endl;
4494 return -ENOENT;
4495 }
4496 remote_conn = &*conn;
4497 }
4498
4499 RGWPeriod period;
4500 int ret = do_period_pull(remote_conn, url, opt_region,
4501 access_key, secret_key,
4502 realm_id, realm_name, period_id, period_epoch,
4503 &period);
4504 if (ret < 0) {
4505 cerr << "period pull failed: " << cpp_strerror(-ret) << std::endl;
4506 return -ret;
4507 }
4508
4509 encode_json("period", period, formatter.get());
4510 formatter->flush(cout);
4511 }
4512 break;
4513 case OPT::GLOBAL_RATELIMIT_GET:
4514 case OPT::GLOBAL_RATELIMIT_SET:
4515 case OPT::GLOBAL_RATELIMIT_ENABLE:
4516 case OPT::GLOBAL_RATELIMIT_DISABLE:
4517 {
4518 if (realm_id.empty()) {
4519 RGWRealm realm(g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj);
4520 if (!realm_name.empty()) {
4521 // look up realm_id for the given realm_name
4522 int ret = realm.read_id(dpp(), realm_name, realm_id, null_yield);
4523 if (ret < 0) {
4524 cerr << "ERROR: failed to read realm for " << realm_name
4525 << ": " << cpp_strerror(-ret) << std::endl;
4526 return -ret;
4527 }
4528 } else {
4529 // use default realm_id when none is given
4530 int ret = realm.read_default_id(dpp(), realm_id, null_yield);
4531 if (ret < 0 && ret != -ENOENT) { // on ENOENT, use empty realm_id
4532 cerr << "ERROR: failed to read default realm: "
4533 << cpp_strerror(-ret) << std::endl;
4534 return -ret;
4535 }
4536 }
4537 }
4538
4539 RGWPeriodConfig period_config;
4540 int ret = period_config.read(dpp(), static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, realm_id, null_yield);
4541 if (ret < 0 && ret != -ENOENT) {
4542 cerr << "ERROR: failed to read period config: "
4543 << cpp_strerror(-ret) << std::endl;
4544 return -ret;
4545 }
4546 bool ratelimit_configured = true;
4547 formatter->open_object_section("period_config");
4548 if (ratelimit_scope == "bucket") {
4549 ratelimit_configured = set_ratelimit_info(period_config.bucket_ratelimit, opt_cmd,
4550 max_read_ops, max_write_ops,
4551 max_read_bytes, max_write_bytes,
4552 have_max_read_ops, have_max_write_ops,
4553 have_max_read_bytes, have_max_write_bytes);
4554 encode_json("bucket_ratelimit", period_config.bucket_ratelimit, formatter.get());
4555 } else if (ratelimit_scope == "user") {
4556 ratelimit_configured = set_ratelimit_info(period_config.user_ratelimit, opt_cmd,
4557 max_read_ops, max_write_ops,
4558 max_read_bytes, max_write_bytes,
4559 have_max_read_ops, have_max_write_ops,
4560 have_max_read_bytes, have_max_write_bytes);
4561 encode_json("user_ratelimit", period_config.user_ratelimit, formatter.get());
4562 } else if (ratelimit_scope == "anonymous") {
4563 ratelimit_configured = set_ratelimit_info(period_config.anon_ratelimit, opt_cmd,
4564 max_read_ops, max_write_ops,
4565 max_read_bytes, max_write_bytes,
4566 have_max_read_ops, have_max_write_ops,
4567 have_max_read_bytes, have_max_write_bytes);
4568 encode_json("anonymous_ratelimit", period_config.anon_ratelimit, formatter.get());
4569 } else if (ratelimit_scope.empty() && opt_cmd == OPT::GLOBAL_RATELIMIT_GET) {
4570 // if no scope is given for GET, print both
4571 encode_json("bucket_ratelimit", period_config.bucket_ratelimit, formatter.get());
4572 encode_json("user_ratelimit", period_config.user_ratelimit, formatter.get());
4573 encode_json("anonymous_ratelimit", period_config.anon_ratelimit, formatter.get());
4574 } else {
4575 cerr << "ERROR: invalid rate limit scope specification. Please specify "
4576 "either --ratelimit-scope=bucket, or --ratelimit-scope=user or --ratelimit-scope=anonymous" << std::endl;
4577 return EINVAL;
4578 }
4579 if (!ratelimit_configured) {
4580 cerr << "ERROR: no rate limit values have been specified" << std::endl;
4581 return EINVAL;
4582 }
4583
4584 formatter->close_section();
4585
4586 if (opt_cmd != OPT::GLOBAL_RATELIMIT_GET) {
4587 // write the modified period config
4588 ret = period_config.write(dpp(), static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, realm_id, null_yield);
4589 if (ret < 0) {
4590 cerr << "ERROR: failed to write period config: "
4591 << cpp_strerror(-ret) << std::endl;
4592 return -ret;
4593 }
4594 if (!realm_id.empty()) {
4595 cout << "Global ratelimit changes saved. Use 'period update' to apply "
4596 "them to the staging period, and 'period commit' to commit the "
4597 "new period." << std::endl;
4598 } else {
4599 cout << "Global ratelimit changes saved. They will take effect as "
4600 "the gateways are restarted." << std::endl;
4601 }
4602 }
4603
4604 formatter->flush(cout);
4605 }
4606 break;
4607 case OPT::GLOBAL_QUOTA_GET:
4608 case OPT::GLOBAL_QUOTA_SET:
4609 case OPT::GLOBAL_QUOTA_ENABLE:
4610 case OPT::GLOBAL_QUOTA_DISABLE:
4611 {
4612 if (realm_id.empty()) {
4613 RGWRealm realm(g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj);
4614 if (!realm_name.empty()) {
4615 // look up realm_id for the given realm_name
4616 int ret = realm.read_id(dpp(), realm_name, realm_id, null_yield);
4617 if (ret < 0) {
4618 cerr << "ERROR: failed to read realm for " << realm_name
4619 << ": " << cpp_strerror(-ret) << std::endl;
4620 return -ret;
4621 }
4622 } else {
4623 // use default realm_id when none is given
4624 int ret = realm.read_default_id(dpp(), realm_id, null_yield);
4625 if (ret < 0 && ret != -ENOENT) { // on ENOENT, use empty realm_id
4626 cerr << "ERROR: failed to read default realm: "
4627 << cpp_strerror(-ret) << std::endl;
4628 return -ret;
4629 }
4630 }
4631 }
4632
4633 RGWPeriodConfig period_config;
4634 int ret = period_config.read(dpp(), static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, realm_id, null_yield);
4635 if (ret < 0 && ret != -ENOENT) {
4636 cerr << "ERROR: failed to read period config: "
4637 << cpp_strerror(-ret) << std::endl;
4638 return -ret;
4639 }
4640
4641 formatter->open_object_section("period_config");
4642 if (quota_scope == "bucket") {
4643 set_quota_info(period_config.bucket_quota, opt_cmd,
4644 max_size, max_objects,
4645 have_max_size, have_max_objects);
4646 encode_json("bucket quota", period_config.bucket_quota, formatter.get());
4647 } else if (quota_scope == "user") {
4648 set_quota_info(period_config.user_quota, opt_cmd,
4649 max_size, max_objects,
4650 have_max_size, have_max_objects);
4651 encode_json("user quota", period_config.user_quota, formatter.get());
4652 } else if (quota_scope.empty() && opt_cmd == OPT::GLOBAL_QUOTA_GET) {
4653 // if no scope is given for GET, print both
4654 encode_json("bucket quota", period_config.bucket_quota, formatter.get());
4655 encode_json("user quota", period_config.user_quota, formatter.get());
4656 } else {
4657 cerr << "ERROR: invalid quota scope specification. Please specify "
4658 "either --quota-scope=bucket, or --quota-scope=user" << std::endl;
4659 return EINVAL;
4660 }
4661 formatter->close_section();
4662
4663 if (opt_cmd != OPT::GLOBAL_QUOTA_GET) {
4664 // write the modified period config
4665 ret = period_config.write(dpp(), static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, realm_id, null_yield);
4666 if (ret < 0) {
4667 cerr << "ERROR: failed to write period config: "
4668 << cpp_strerror(-ret) << std::endl;
4669 return -ret;
4670 }
4671 if (!realm_id.empty()) {
4672 cout << "Global quota changes saved. Use 'period update' to apply "
4673 "them to the staging period, and 'period commit' to commit the "
4674 "new period." << std::endl;
4675 } else {
4676 cout << "Global quota changes saved. They will take effect as "
4677 "the gateways are restarted." << std::endl;
4678 }
4679 }
4680
4681 formatter->flush(cout);
4682 }
4683 break;
4684 case OPT::REALM_CREATE:
4685 {
4686 if (realm_name.empty()) {
4687 cerr << "missing realm name" << std::endl;
4688 return EINVAL;
4689 }
4690
4691 RGWRealm realm(realm_name, g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj);
4692 int ret = realm.create(dpp(), null_yield);
4693 if (ret < 0) {
4694 cerr << "ERROR: couldn't create realm " << realm_name << ": " << cpp_strerror(-ret) << std::endl;
4695 return -ret;
4696 }
4697
4698 if (set_default) {
4699 ret = realm.set_as_default(dpp(), null_yield);
4700 if (ret < 0) {
4701 cerr << "failed to set realm " << realm_name << " as default: " << cpp_strerror(-ret) << std::endl;
4702 }
4703 }
4704
4705 encode_json("realm", realm, formatter.get());
4706 formatter->flush(cout);
4707 }
4708 break;
4709 case OPT::REALM_DELETE:
4710 {
4711 if (empty_opt(opt_realm_name) && empty_opt(opt_realm_id)) {
4712 cerr << "missing realm name or id" << std::endl;
4713 return EINVAL;
4714 }
4715 RGWRealm realm(safe_opt(opt_realm_id), safe_opt(opt_realm_name));
4716 int ret = realm.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
4717 if (ret < 0) {
4718 cerr << "realm.init failed: " << cpp_strerror(-ret) << std::endl;
4719 return -ret;
4720 }
4721 ret = realm.delete_obj(dpp(), null_yield);
4722 if (ret < 0) {
4723 cerr << "ERROR: couldn't : " << cpp_strerror(-ret) << std::endl;
4724 return -ret;
4725 }
4726
4727 }
4728 break;
4729 case OPT::REALM_GET:
4730 {
4731 RGWRealm realm(realm_id, realm_name);
4732 int ret = realm.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
4733 if (ret < 0) {
4734 if (ret == -ENOENT && realm_name.empty() && realm_id.empty()) {
4735 cerr << "missing realm name or id, or default realm not found" << std::endl;
4736 } else {
4737 cerr << "realm.init failed: " << cpp_strerror(-ret) << std::endl;
4738 }
4739 return -ret;
4740 }
4741 encode_json("realm", realm, formatter.get());
4742 formatter->flush(cout);
4743 }
4744 break;
4745 case OPT::REALM_GET_DEFAULT:
4746 {
4747 RGWRealm realm(g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj);
4748 string default_id;
4749 int ret = realm.read_default_id(dpp(), default_id, null_yield);
4750 if (ret == -ENOENT) {
4751 cout << "No default realm is set" << std::endl;
4752 return -ret;
4753 } else if (ret < 0) {
4754 cerr << "Error reading default realm: " << cpp_strerror(-ret) << std::endl;
4755 return -ret;
4756 }
4757 cout << "default realm: " << default_id << std::endl;
4758 }
4759 break;
4760 case OPT::REALM_LIST:
4761 {
4762 RGWRealm realm(g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj);
4763 string default_id;
4764 int ret = realm.read_default_id(dpp(), default_id, null_yield);
4765 if (ret < 0 && ret != -ENOENT) {
4766 cerr << "could not determine default realm: " << cpp_strerror(-ret) << std::endl;
4767 }
4768 list<string> realms;
4769 ret = static_cast<rgw::sal::RadosStore*>(store)->svc()->zone->list_realms(dpp(), realms);
4770 if (ret < 0) {
4771 cerr << "failed to list realms: " << cpp_strerror(-ret) << std::endl;
4772 return -ret;
4773 }
4774 formatter->open_object_section("realms_list");
4775 encode_json("default_info", default_id, formatter.get());
4776 encode_json("realms", realms, formatter.get());
4777 formatter->close_section();
4778 formatter->flush(cout);
4779 }
4780 break;
4781 case OPT::REALM_LIST_PERIODS:
4782 {
4783 int ret = read_current_period_id(static_cast<rgw::sal::RadosStore*>(store), realm_id, realm_name, &period_id);
4784 if (ret < 0) {
4785 return -ret;
4786 }
4787 list<string> periods;
4788 ret = static_cast<rgw::sal::RadosStore*>(store)->svc()->zone->list_periods(dpp(), period_id, periods, null_yield);
4789 if (ret < 0) {
4790 cerr << "list periods failed: " << cpp_strerror(-ret) << std::endl;
4791 return -ret;
4792 }
4793 formatter->open_object_section("realm_periods_list");
4794 encode_json("current_period", period_id, formatter.get());
4795 encode_json("periods", periods, formatter.get());
4796 formatter->close_section();
4797 formatter->flush(cout);
4798 }
4799 break;
4800
4801 case OPT::REALM_RENAME:
4802 {
4803 RGWRealm realm(realm_id, realm_name);
4804 if (realm_new_name.empty()) {
4805 cerr << "missing realm new name" << std::endl;
4806 return EINVAL;
4807 }
4808 if (realm_name.empty() && realm_id.empty()) {
4809 cerr << "missing realm name or id" << std::endl;
4810 return EINVAL;
4811 }
4812 int ret = realm.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
4813 if (ret < 0) {
4814 cerr << "realm.init failed: " << cpp_strerror(-ret) << std::endl;
4815 return -ret;
4816 }
4817 ret = realm.rename(dpp(), realm_new_name, null_yield);
4818 if (ret < 0) {
4819 cerr << "realm.rename failed: " << cpp_strerror(-ret) << std::endl;
4820 return -ret;
4821 }
4822 cout << "Realm name updated. Note that this change only applies to "
4823 "the current cluster, so this command must be run separately "
4824 "on each of the realm's other clusters." << std::endl;
4825 }
4826 break;
4827 case OPT::REALM_SET:
4828 {
4829 if (realm_id.empty() && realm_name.empty()) {
4830 cerr << "no realm name or id provided" << std::endl;
4831 return EINVAL;
4832 }
4833 RGWRealm realm(realm_id, realm_name);
4834 bool new_realm = false;
4835 int ret = realm.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
4836 if (ret < 0 && ret != -ENOENT) {
4837 cerr << "failed to init realm: " << cpp_strerror(-ret) << std::endl;
4838 return -ret;
4839 } else if (ret == -ENOENT) {
4840 new_realm = true;
4841 }
4842 ret = read_decode_json(infile, realm);
4843 if (ret < 0) {
4844 return 1;
4845 }
4846 if (!realm_name.empty() && realm.get_name() != realm_name) {
4847 cerr << "mismatch between --rgw-realm " << realm_name << " and json input file name " <<
4848 realm.get_name() << std::endl;
4849 return EINVAL;
4850 }
4851 /* new realm */
4852 if (new_realm) {
4853 cout << "clearing period and epoch for new realm" << std::endl;
4854 realm.clear_current_period_and_epoch();
4855 ret = realm.create(dpp(), null_yield);
4856 if (ret < 0) {
4857 cerr << "ERROR: couldn't create new realm: " << cpp_strerror(-ret) << std::endl;
4858 return 1;
4859 }
4860 } else {
4861 ret = realm.update(dpp(), null_yield);
4862 if (ret < 0) {
4863 cerr << "ERROR: couldn't store realm info: " << cpp_strerror(-ret) << std::endl;
4864 return 1;
4865 }
4866 }
4867
4868 if (set_default) {
4869 ret = realm.set_as_default(dpp(), null_yield);
4870 if (ret < 0) {
4871 cerr << "failed to set realm " << realm_name << " as default: " << cpp_strerror(-ret) << std::endl;
4872 }
4873 }
4874 encode_json("realm", realm, formatter.get());
4875 formatter->flush(cout);
4876 }
4877 break;
4878
4879 case OPT::REALM_DEFAULT:
4880 {
4881 RGWRealm realm(realm_id, realm_name);
4882 int ret = realm.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
4883 if (ret < 0) {
4884 cerr << "failed to init realm: " << cpp_strerror(-ret) << std::endl;
4885 return -ret;
4886 }
4887 ret = realm.set_as_default(dpp(), null_yield);
4888 if (ret < 0) {
4889 cerr << "failed to set realm as default: " << cpp_strerror(-ret) << std::endl;
4890 return -ret;
4891 }
4892 }
4893 break;
4894 case OPT::REALM_PULL:
4895 {
4896 if (url.empty()) {
4897 cerr << "A --url must be provided." << std::endl;
4898 return EINVAL;
4899 }
4900 RGWEnv env;
4901 req_info info(g_ceph_context, &env);
4902 info.method = "GET";
4903 info.request_uri = "/admin/realm";
4904
4905 map<string, string> &params = info.args.get_params();
4906 if (!realm_id.empty())
4907 params["id"] = realm_id;
4908 if (!realm_name.empty())
4909 params["name"] = realm_name;
4910
4911 bufferlist bl;
4912 JSONParser p;
4913 int ret = send_to_url(url, opt_region, access_key, secret_key, info, bl, p);
4914 if (ret < 0) {
4915 cerr << "request failed: " << cpp_strerror(-ret) << std::endl;
4916 if (ret == -EACCES) {
4917 cerr << "If the realm has been changed on the master zone, the "
4918 "master zone's gateway may need to be restarted to recognize "
4919 "this user." << std::endl;
4920 }
4921 return -ret;
4922 }
4923 RGWRealm realm;
4924 realm.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield, false);
4925 try {
4926 decode_json_obj(realm, &p);
4927 } catch (const JSONDecoder::err& e) {
4928 cerr << "failed to decode JSON response: " << e.what() << std::endl;
4929 return EINVAL;
4930 }
4931 RGWPeriod period;
4932 auto& current_period = realm.get_current_period();
4933 if (!current_period.empty()) {
4934 // pull the latest epoch of the realm's current period
4935 ret = do_period_pull(nullptr, url, opt_region,
4936 access_key, secret_key,
4937 realm_id, realm_name, current_period, "",
4938 &period);
4939 if (ret < 0) {
4940 cerr << "could not fetch period " << current_period << std::endl;
4941 return -ret;
4942 }
4943 }
4944 ret = realm.create(dpp(), null_yield, false);
4945 if (ret < 0 && ret != -EEXIST) {
4946 cerr << "Error storing realm " << realm.get_id() << ": "
4947 << cpp_strerror(ret) << std::endl;
4948 return -ret;
4949 } else if (ret ==-EEXIST) {
4950 ret = realm.update(dpp(), null_yield);
4951 if (ret < 0) {
4952 cerr << "Error storing realm " << realm.get_id() << ": "
4953 << cpp_strerror(ret) << std::endl;
4954 }
4955 }
4956
4957 if (set_default) {
4958 ret = realm.set_as_default(dpp(), null_yield);
4959 if (ret < 0) {
4960 cerr << "failed to set realm " << realm_name << " as default: " << cpp_strerror(-ret) << std::endl;
4961 }
4962 }
4963
4964 encode_json("realm", realm, formatter.get());
4965 formatter->flush(cout);
4966 }
4967 break;
4968
4969 case OPT::ZONEGROUP_ADD:
4970 {
4971 if (zonegroup_id.empty() && zonegroup_name.empty()) {
4972 cerr << "no zonegroup name or id provided" << std::endl;
4973 return EINVAL;
4974 }
4975
4976 RGWZoneGroup zonegroup(zonegroup_id,zonegroup_name);
4977 int ret = zonegroup.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
4978 if (ret < 0) {
4979 cerr << "failed to initialize zonegroup " << zonegroup_name << " id " << zonegroup_id << ": "
4980 << cpp_strerror(-ret) << std::endl;
4981 return -ret;
4982 }
4983 RGWZoneParams zone(zone_id, zone_name);
4984 ret = zone.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
4985 if (ret < 0) {
4986 cerr << "unable to initialize zone: " << cpp_strerror(-ret) << std::endl;
4987 return -ret;
4988 }
4989 if (zone.realm_id != zonegroup.realm_id) {
4990 zone.realm_id = zonegroup.realm_id;
4991 ret = zone.update(dpp(), null_yield);
4992 if (ret < 0) {
4993 cerr << "failed to save zone info: " << cpp_strerror(-ret) << std::endl;
4994 return -ret;
4995 }
4996 }
4997
4998 string *ptier_type = (tier_type_specified ? &tier_type : nullptr);
4999
5000 for (auto a : tier_config_add) {
5001 int r = zone.tier_config.set(a.first, a.second);
5002 if (r < 0) {
5003 cerr << "ERROR: failed to set configurable: " << a << std::endl;
5004 return EINVAL;
5005 }
5006 }
5007
5008 bool *psync_from_all = (sync_from_all_specified ? &sync_from_all : nullptr);
5009 string *predirect_zone = (redirect_zone_set ? &redirect_zone : nullptr);
5010
5011 ret = zonegroup.add_zone(dpp(), zone,
5012 (is_master_set ? &is_master : NULL),
5013 (is_read_only_set ? &read_only : NULL),
5014 endpoints, ptier_type,
5015 psync_from_all, sync_from, sync_from_rm,
5016 predirect_zone, bucket_index_max_shards,
5017 static_cast<rgw::sal::RadosStore*>(store)->svc()->sync_modules->get_manager(),
5018 null_yield);
5019 if (ret < 0) {
5020 cerr << "failed to add zone " << zone_name << " to zonegroup " << zonegroup.get_name() << ": "
5021 << cpp_strerror(-ret) << std::endl;
5022 return -ret;
5023 }
5024
5025 encode_json("zonegroup", zonegroup, formatter.get());
5026 formatter->flush(cout);
5027 }
5028 break;
5029 case OPT::ZONEGROUP_CREATE:
5030 {
5031 if (zonegroup_name.empty()) {
5032 cerr << "Missing zonegroup name" << std::endl;
5033 return EINVAL;
5034 }
5035 RGWRealm realm(realm_id, realm_name);
5036 int ret = realm.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
5037 if (ret < 0) {
5038 cerr << "failed to init realm: " << cpp_strerror(-ret) << std::endl;
5039 return -ret;
5040 }
5041
5042 RGWZoneGroup zonegroup(zonegroup_name, is_master, g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, realm.get_id(), endpoints);
5043 zonegroup.api_name = (api_name.empty() ? zonegroup_name : api_name);
5044 ret = zonegroup.create(dpp(), null_yield);
5045 if (ret < 0) {
5046 cerr << "failed to create zonegroup " << zonegroup_name << ": " << cpp_strerror(-ret) << std::endl;
5047 return -ret;
5048 }
5049
5050 if (set_default) {
5051 ret = zonegroup.set_as_default(dpp(), null_yield);
5052 if (ret < 0) {
5053 cerr << "failed to set zonegroup " << zonegroup_name << " as default: " << cpp_strerror(-ret) << std::endl;
5054 }
5055 }
5056
5057 encode_json("zonegroup", zonegroup, formatter.get());
5058 formatter->flush(cout);
5059 }
5060 break;
5061 case OPT::ZONEGROUP_DEFAULT:
5062 {
5063 if (zonegroup_id.empty() && zonegroup_name.empty()) {
5064 cerr << "no zonegroup name or id provided" << std::endl;
5065 return EINVAL;
5066 }
5067
5068 RGWZoneGroup zonegroup(zonegroup_id, zonegroup_name);
5069 int ret = zonegroup.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
5070 if (ret < 0) {
5071 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
5072 return -ret;
5073 }
5074
5075 ret = zonegroup.set_as_default(dpp(), null_yield);
5076 if (ret < 0) {
5077 cerr << "failed to set zonegroup as default: " << cpp_strerror(-ret) << std::endl;
5078 return -ret;
5079 }
5080 }
5081 break;
5082 case OPT::ZONEGROUP_DELETE:
5083 {
5084 if (empty_opt(opt_zonegroup_id) && empty_opt(opt_zonegroup_name)) {
5085 cerr << "no zonegroup name or id provided" << std::endl;
5086 return EINVAL;
5087 }
5088 RGWZoneGroup zonegroup(safe_opt(opt_zonegroup_id), safe_opt(opt_zonegroup_name));
5089 int ret = zonegroup.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj,
5090 null_yield);
5091 if (ret < 0) {
5092 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
5093 return -ret;
5094 }
5095 ret = zonegroup.delete_obj(dpp(), null_yield);
5096 if (ret < 0) {
5097 cerr << "ERROR: couldn't delete zonegroup: " << cpp_strerror(-ret) << std::endl;
5098 return -ret;
5099 }
5100 }
5101 break;
5102 case OPT::ZONEGROUP_GET:
5103 {
5104 RGWZoneGroup zonegroup(zonegroup_id, zonegroup_name);
5105 int ret = zonegroup.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
5106 if (ret < 0) {
5107 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
5108 return -ret;
5109 }
5110
5111 encode_json("zonegroup", zonegroup, formatter.get());
5112 formatter->flush(cout);
5113 }
5114 break;
5115 case OPT::ZONEGROUP_LIST:
5116 {
5117 RGWZoneGroup zonegroup;
5118 int ret = zonegroup.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj,
5119 null_yield, false);
5120 if (ret < 0) {
5121 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
5122 return -ret;
5123 }
5124
5125 list<string> zonegroups;
5126 ret = static_cast<rgw::sal::RadosStore*>(store)->svc()->zone->list_zonegroups(dpp(), zonegroups);
5127 if (ret < 0) {
5128 cerr << "failed to list zonegroups: " << cpp_strerror(-ret) << std::endl;
5129 return -ret;
5130 }
5131 string default_zonegroup;
5132 ret = zonegroup.read_default_id(dpp(), default_zonegroup, null_yield);
5133 if (ret < 0 && ret != -ENOENT) {
5134 cerr << "could not determine default zonegroup: " << cpp_strerror(-ret) << std::endl;
5135 }
5136 formatter->open_object_section("zonegroups_list");
5137 encode_json("default_info", default_zonegroup, formatter.get());
5138 encode_json("zonegroups", zonegroups, formatter.get());
5139 formatter->close_section();
5140 formatter->flush(cout);
5141 }
5142 break;
5143 case OPT::ZONEGROUP_MODIFY:
5144 {
5145 RGWZoneGroup zonegroup(zonegroup_id, zonegroup_name);
5146 int ret = zonegroup.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
5147 if (ret < 0) {
5148 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
5149 return -ret;
5150 }
5151
5152 bool need_update = false;
5153
5154 if (!master_zone.empty()) {
5155 zonegroup.master_zone = master_zone;
5156 need_update = true;
5157 }
5158
5159 if (is_master_set) {
5160 zonegroup.update_master(dpp(), is_master, null_yield);
5161 need_update = true;
5162 }
5163
5164 if (!endpoints.empty()) {
5165 zonegroup.endpoints = endpoints;
5166 need_update = true;
5167 }
5168
5169 if (!api_name.empty()) {
5170 zonegroup.api_name = api_name;
5171 need_update = true;
5172 }
5173
5174 if (!realm_id.empty()) {
5175 zonegroup.realm_id = realm_id;
5176 need_update = true;
5177 } else if (!realm_name.empty()) {
5178 // get realm id from name
5179 RGWRealm realm{g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj};
5180 ret = realm.read_id(dpp(), realm_name, zonegroup.realm_id, null_yield);
5181 if (ret < 0) {
5182 cerr << "failed to find realm by name " << realm_name << std::endl;
5183 return -ret;
5184 }
5185 need_update = true;
5186 }
5187
5188 if (bucket_index_max_shards) {
5189 for (auto& [name, zone] : zonegroup.zones) {
5190 zone.bucket_index_max_shards = *bucket_index_max_shards;
5191 }
5192 need_update = true;
5193 }
5194
5195 if (need_update) {
5196 ret = zonegroup.update(dpp(), null_yield);
5197 if (ret < 0) {
5198 cerr << "failed to update zonegroup: " << cpp_strerror(-ret) << std::endl;
5199 return -ret;
5200 }
5201 }
5202
5203 if (set_default) {
5204 ret = zonegroup.set_as_default(dpp(), null_yield);
5205 if (ret < 0) {
5206 cerr << "failed to set zonegroup " << zonegroup_name << " as default: " << cpp_strerror(-ret) << std::endl;
5207 }
5208 }
5209
5210 encode_json("zonegroup", zonegroup, formatter.get());
5211 formatter->flush(cout);
5212 }
5213 break;
5214 case OPT::ZONEGROUP_SET:
5215 {
5216 RGWRealm realm(realm_id, realm_name);
5217 int ret = realm.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
5218 bool default_realm_not_exist = (ret == -ENOENT && realm_id.empty() && realm_name.empty());
5219
5220 if (ret < 0 && !default_realm_not_exist ) {
5221 cerr << "failed to init realm: " << cpp_strerror(-ret) << std::endl;
5222 return -ret;
5223 }
5224
5225 RGWZoneGroup zonegroup;
5226 ret = zonegroup.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj,
5227 null_yield, false);
5228 if (ret < 0) {
5229 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
5230 return -ret;
5231 }
5232 ret = read_decode_json(infile, zonegroup);
5233 if (ret < 0) {
5234 return 1;
5235 }
5236 if (zonegroup.realm_id.empty() && !default_realm_not_exist) {
5237 zonegroup.realm_id = realm.get_id();
5238 }
5239 ret = zonegroup.create(dpp(), null_yield);
5240 if (ret < 0 && ret != -EEXIST) {
5241 cerr << "ERROR: couldn't create zonegroup info: " << cpp_strerror(-ret) << std::endl;
5242 return 1;
5243 } else if (ret == -EEXIST) {
5244 ret = zonegroup.update(dpp(), null_yield);
5245 if (ret < 0) {
5246 cerr << "ERROR: couldn't store zonegroup info: " << cpp_strerror(-ret) << std::endl;
5247 return 1;
5248 }
5249 }
5250
5251 if (set_default) {
5252 ret = zonegroup.set_as_default(dpp(), null_yield);
5253 if (ret < 0) {
5254 cerr << "failed to set zonegroup " << zonegroup_name << " as default: " << cpp_strerror(-ret) << std::endl;
5255 }
5256 }
5257
5258 encode_json("zonegroup", zonegroup, formatter.get());
5259 formatter->flush(cout);
5260 }
5261 break;
5262 case OPT::ZONEGROUP_REMOVE:
5263 {
5264 RGWZoneGroup zonegroup(zonegroup_id, zonegroup_name);
5265 int ret = zonegroup.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
5266 if (ret < 0) {
5267 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
5268 return -ret;
5269 }
5270
5271 if (zone_id.empty()) {
5272 if (zone_name.empty()) {
5273 cerr << "no --zone-id or --rgw-zone name provided" << std::endl;
5274 return EINVAL;
5275 }
5276 // look up zone id by name
5277 for (auto& z : zonegroup.zones) {
5278 if (zone_name == z.second.name) {
5279 zone_id = z.second.id;
5280 break;
5281 }
5282 }
5283 if (zone_id.empty()) {
5284 cerr << "zone name " << zone_name << " not found in zonegroup "
5285 << zonegroup.get_name() << std::endl;
5286 return ENOENT;
5287 }
5288 }
5289
5290 ret = zonegroup.remove_zone(dpp(), zone_id, null_yield);
5291 if (ret < 0) {
5292 cerr << "failed to remove zone: " << cpp_strerror(-ret) << std::endl;
5293 return -ret;
5294 }
5295
5296 encode_json("zonegroup", zonegroup, formatter.get());
5297 formatter->flush(cout);
5298 }
5299 break;
5300 case OPT::ZONEGROUP_RENAME:
5301 {
5302 if (zonegroup_new_name.empty()) {
5303 cerr << " missing zonegroup new name" << std::endl;
5304 return EINVAL;
5305 }
5306 if (zonegroup_id.empty() && zonegroup_name.empty()) {
5307 cerr << "no zonegroup name or id provided" << std::endl;
5308 return EINVAL;
5309 }
5310 RGWZoneGroup zonegroup(zonegroup_id, zonegroup_name);
5311 int ret = zonegroup.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
5312 if (ret < 0) {
5313 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
5314 return -ret;
5315 }
5316 ret = zonegroup.rename(dpp(), zonegroup_new_name, null_yield);
5317 if (ret < 0) {
5318 cerr << "failed to rename zonegroup: " << cpp_strerror(-ret) << std::endl;
5319 return -ret;
5320 }
5321 }
5322 break;
5323 case OPT::ZONEGROUP_PLACEMENT_LIST:
5324 {
5325 RGWZoneGroup zonegroup(zonegroup_id, zonegroup_name);
5326 int ret = zonegroup.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj,
5327 null_yield);
5328 if (ret < 0) {
5329 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
5330 return -ret;
5331 }
5332
5333 encode_json("placement_targets", zonegroup.placement_targets, formatter.get());
5334 formatter->flush(cout);
5335 }
5336 break;
5337 case OPT::ZONEGROUP_PLACEMENT_GET:
5338 {
5339 if (placement_id.empty()) {
5340 cerr << "ERROR: --placement-id not specified" << std::endl;
5341 return EINVAL;
5342 }
5343
5344 RGWZoneGroup zonegroup(zonegroup_id, zonegroup_name);
5345 int ret = zonegroup.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
5346 if (ret < 0) {
5347 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
5348 return -ret;
5349 }
5350
5351 auto p = zonegroup.placement_targets.find(placement_id);
5352 if (p == zonegroup.placement_targets.end()) {
5353 cerr << "failed to find a zonegroup placement target named '" << placement_id << "'" << std::endl;
5354 return -ENOENT;
5355 }
5356 encode_json("placement_targets", p->second, formatter.get());
5357 formatter->flush(cout);
5358 }
5359 break;
5360 case OPT::ZONEGROUP_PLACEMENT_ADD:
5361 case OPT::ZONEGROUP_PLACEMENT_MODIFY:
5362 case OPT::ZONEGROUP_PLACEMENT_RM:
5363 case OPT::ZONEGROUP_PLACEMENT_DEFAULT:
5364 {
5365 if (placement_id.empty()) {
5366 cerr << "ERROR: --placement-id not specified" << std::endl;
5367 return EINVAL;
5368 }
5369
5370 rgw_placement_rule rule;
5371 rule.from_str(placement_id);
5372
5373 if (!rule.storage_class.empty() && opt_storage_class &&
5374 rule.storage_class != *opt_storage_class) {
5375 cerr << "ERROR: provided contradicting storage class configuration" << std::endl;
5376 return EINVAL;
5377 } else if (rule.storage_class.empty()) {
5378 rule.storage_class = opt_storage_class.value_or(string());
5379 }
5380
5381 RGWZoneGroup zonegroup(zonegroup_id, zonegroup_name);
5382 int ret = zonegroup.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
5383 if (ret < 0) {
5384 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
5385 return -ret;
5386 }
5387
5388 if (opt_cmd == OPT::ZONEGROUP_PLACEMENT_ADD ||
5389 opt_cmd == OPT::ZONEGROUP_PLACEMENT_MODIFY) {
5390 RGWZoneGroupPlacementTarget& target = zonegroup.placement_targets[placement_id];
5391 if (!tags.empty()) {
5392 target.tags.clear();
5393 for (auto& t : tags) {
5394 target.tags.insert(t);
5395 }
5396 }
5397
5398 target.name = placement_id;
5399 for (auto& t : tags_rm) {
5400 target.tags.erase(t);
5401 }
5402 for (auto& t : tags_add) {
5403 target.tags.insert(t);
5404 }
5405 target.storage_classes.insert(rule.get_storage_class());
5406
5407 /* Tier options */
5408 bool tier_class = false;
5409 std::string storage_class = rule.get_storage_class();
5410 RGWZoneGroupPlacementTier t{storage_class};
5411 RGWZoneGroupPlacementTier *pt = &t;
5412
5413 auto ptiter = target.tier_targets.find(storage_class);
5414 if (ptiter != target.tier_targets.end()) {
5415 pt = &ptiter->second;
5416 tier_class = true;
5417 } else if (tier_type_specified) {
5418 if (tier_type == "cloud-s3") {
5419 /* we support only cloud-s3 tier-type for now.
5420 * Once set cant be reset. */
5421 tier_class = true;
5422 pt->tier_type = tier_type;
5423 pt->storage_class = storage_class;
5424 } else {
5425 cerr << "ERROR: Invalid tier-type specified" << std::endl;
5426 return EINVAL;
5427 }
5428 }
5429
5430 if (tier_class) {
5431 if (tier_config_add.size() > 0) {
5432 JSONFormattable tconfig;
5433 for (auto add : tier_config_add) {
5434 int r = tconfig.set(add.first, add.second);
5435 if (r < 0) {
5436 cerr << "ERROR: failed to set configurable: " << add << std::endl;
5437 return EINVAL;
5438 }
5439 }
5440 int r = pt->update_params(tconfig);
5441 if (r < 0) {
5442 cerr << "ERROR: failed to update tier_config options"<< std::endl;
5443 }
5444 }
5445 if (tier_config_rm.size() > 0) {
5446 JSONFormattable tconfig;
5447 for (auto add : tier_config_rm) {
5448 int r = tconfig.set(add.first, add.second);
5449 if (r < 0) {
5450 cerr << "ERROR: failed to set configurable: " << add << std::endl;
5451 return EINVAL;
5452 }
5453 }
5454 int r = pt->clear_params(tconfig);
5455 if (r < 0) {
5456 cerr << "ERROR: failed to update tier_config options"<< std::endl;
5457 }
5458 }
5459
5460 target.tier_targets.emplace(std::make_pair(storage_class, *pt));
5461 }
5462
5463 } else if (opt_cmd == OPT::ZONEGROUP_PLACEMENT_RM) {
5464 if (!opt_storage_class || opt_storage_class->empty()) {
5465 zonegroup.placement_targets.erase(placement_id);
5466 } else {
5467 auto iter = zonegroup.placement_targets.find(placement_id);
5468 if (iter != zonegroup.placement_targets.end()) {
5469 RGWZoneGroupPlacementTarget& info = zonegroup.placement_targets[placement_id];
5470 info.storage_classes.erase(*opt_storage_class);
5471
5472 auto ptiter = info.tier_targets.find(*opt_storage_class);
5473 if (ptiter != info.tier_targets.end()) {
5474 info.tier_targets.erase(ptiter);
5475 }
5476 }
5477 }
5478 } else if (opt_cmd == OPT::ZONEGROUP_PLACEMENT_DEFAULT) {
5479 if (!zonegroup.placement_targets.count(placement_id)) {
5480 cerr << "failed to find a zonegroup placement target named '"
5481 << placement_id << "'" << std::endl;
5482 return -ENOENT;
5483 }
5484 zonegroup.default_placement = rule;
5485 }
5486
5487 zonegroup.post_process_params(dpp(), null_yield);
5488 ret = zonegroup.update(dpp(), null_yield);
5489 if (ret < 0) {
5490 cerr << "failed to update zonegroup: " << cpp_strerror(-ret) << std::endl;
5491 return -ret;
5492 }
5493
5494 encode_json("placement_targets", zonegroup.placement_targets, formatter.get());
5495 formatter->flush(cout);
5496 }
5497 break;
5498 case OPT::ZONE_CREATE:
5499 {
5500 if (zone_name.empty()) {
5501 cerr << "zone name not provided" << std::endl;
5502 return EINVAL;
5503 }
5504 int ret;
5505 RGWZoneGroup zonegroup(zonegroup_id, zonegroup_name);
5506 /* if the user didn't provide zonegroup info , create stand alone zone */
5507 if (!zonegroup_id.empty() || !zonegroup_name.empty()) {
5508 ret = zonegroup.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
5509 if (ret < 0) {
5510 cerr << "unable to initialize zonegroup " << zonegroup_name << ": " << cpp_strerror(-ret) << std::endl;
5511 return -ret;
5512 }
5513 if (realm_id.empty() && realm_name.empty()) {
5514 realm_id = zonegroup.realm_id;
5515 }
5516 }
5517
5518 RGWZoneParams zone(zone_id, zone_name);
5519 ret = zone.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield, false);
5520 if (ret < 0) {
5521 cerr << "unable to initialize zone: " << cpp_strerror(-ret) << std::endl;
5522 return -ret;
5523 }
5524
5525 zone.system_key.id = access_key;
5526 zone.system_key.key = secret_key;
5527 zone.realm_id = realm_id;
5528 for (auto a : tier_config_add) {
5529 int r = zone.tier_config.set(a.first, a.second);
5530 if (r < 0) {
5531 cerr << "ERROR: failed to set configurable: " << a << std::endl;
5532 return EINVAL;
5533 }
5534 }
5535
5536 ret = zone.create(dpp(), null_yield);
5537 if (ret < 0) {
5538 cerr << "failed to create zone " << zone_name << ": " << cpp_strerror(-ret) << std::endl;
5539 return -ret;
5540 }
5541
5542 if (!zonegroup_id.empty() || !zonegroup_name.empty()) {
5543 string *ptier_type = (tier_type_specified ? &tier_type : nullptr);
5544 bool *psync_from_all = (sync_from_all_specified ? &sync_from_all : nullptr);
5545 string *predirect_zone = (redirect_zone_set ? &redirect_zone : nullptr);
5546 ret = zonegroup.add_zone(dpp(), zone,
5547 (is_master_set ? &is_master : NULL),
5548 (is_read_only_set ? &read_only : NULL),
5549 endpoints,
5550 ptier_type,
5551 psync_from_all,
5552 sync_from, sync_from_rm,
5553 predirect_zone, bucket_index_max_shards,
5554 static_cast<rgw::sal::RadosStore*>(store)->svc()->sync_modules->get_manager(),
5555 null_yield);
5556 if (ret < 0) {
5557 cerr << "failed to add zone " << zone_name << " to zonegroup " << zonegroup.get_name()
5558 << ": " << cpp_strerror(-ret) << std::endl;
5559 return -ret;
5560 }
5561 }
5562
5563 if (set_default) {
5564 ret = zone.set_as_default(dpp(), null_yield);
5565 if (ret < 0) {
5566 cerr << "failed to set zone " << zone_name << " as default: " << cpp_strerror(-ret) << std::endl;
5567 }
5568 }
5569
5570 encode_json("zone", zone, formatter.get());
5571 formatter->flush(cout);
5572 }
5573 break;
5574 case OPT::ZONE_DEFAULT:
5575 {
5576 if (zone_id.empty() && zone_name.empty()) {
5577 cerr << "no zone name or id provided" << std::endl;
5578 return EINVAL;
5579 }
5580 RGWZoneParams zone(zone_id, zone_name);
5581 int ret = zone.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
5582 if (ret < 0) {
5583 cerr << "unable to initialize zone: " << cpp_strerror(-ret) << std::endl;
5584 return -ret;
5585 }
5586 ret = zone.set_as_default(dpp(), null_yield);
5587 if (ret < 0) {
5588 cerr << "failed to set zone as default: " << cpp_strerror(-ret) << std::endl;
5589 return -ret;
5590 }
5591 }
5592 break;
5593 case OPT::ZONE_DELETE:
5594 {
5595 if (empty_opt(opt_zone_id) && empty_opt(opt_zone_name)) {
5596 cerr << "no zone name or id provided" << std::endl;
5597 return EINVAL;
5598 }
5599 RGWZoneParams zone(safe_opt(opt_zone_id), safe_opt(opt_zone_name));
5600 int ret = zone.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
5601 if (ret < 0) {
5602 cerr << "unable to initialize zone: " << cpp_strerror(-ret) << std::endl;
5603 return -ret;
5604 }
5605
5606 list<string> zonegroups;
5607 ret = static_cast<rgw::sal::RadosStore*>(store)->svc()->zone->list_zonegroups(dpp(), zonegroups);
5608 if (ret < 0) {
5609 cerr << "failed to list zonegroups: " << cpp_strerror(-ret) << std::endl;
5610 return -ret;
5611 }
5612
5613 for (list<string>::iterator iter = zonegroups.begin(); iter != zonegroups.end(); ++iter) {
5614 RGWZoneGroup zonegroup(string(), *iter);
5615 int ret = zonegroup.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
5616 if (ret < 0) {
5617 cerr << "WARNING: failed to initialize zonegroup " << zonegroup_name << std::endl;
5618 continue;
5619 }
5620 ret = zonegroup.remove_zone(dpp(), zone.get_id(), null_yield);
5621 if (ret < 0 && ret != -ENOENT) {
5622 cerr << "failed to remove zone " << zone.get_name() << " from zonegroup " << zonegroup.get_name() << ": "
5623 << cpp_strerror(-ret) << std::endl;
5624 }
5625 }
5626
5627 ret = zone.delete_obj(dpp(), null_yield);
5628 if (ret < 0) {
5629 cerr << "failed to delete zone " << zone.get_name() << ": " << cpp_strerror(-ret) << std::endl;
5630 return -ret;
5631 }
5632 }
5633 break;
5634 case OPT::ZONE_GET:
5635 {
5636 RGWZoneParams zone(zone_id, zone_name);
5637 int ret = zone.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
5638 if (ret < 0) {
5639 cerr << "unable to initialize zone: " << cpp_strerror(-ret) << std::endl;
5640 return -ret;
5641 }
5642 encode_json("zone", zone, formatter.get());
5643 formatter->flush(cout);
5644 }
5645 break;
5646 case OPT::ZONE_SET:
5647 {
5648 RGWZoneParams zone(zone_name);
5649 int ret = zone.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield,
5650 false);
5651 if (ret < 0) {
5652 return -ret;
5653 }
5654
5655 ret = zone.read(dpp(), null_yield);
5656 if (ret < 0 && ret != -ENOENT) {
5657 cerr << "zone.read() returned ret=" << ret << std::endl;
5658 return -ret;
5659 }
5660
5661 string orig_id = zone.get_id();
5662
5663 ret = read_decode_json(infile, zone);
5664 if (ret < 0) {
5665 return 1;
5666 }
5667
5668 if(zone.realm_id.empty()) {
5669 RGWRealm realm(realm_id, realm_name);
5670 int ret = realm.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
5671 if (ret < 0 && ret != -ENOENT) {
5672 cerr << "failed to init realm: " << cpp_strerror(-ret) << std::endl;
5673 return -ret;
5674 }
5675 zone.realm_id = realm.get_id();
5676 }
5677
5678 if( !zone_name.empty() && !zone.get_name().empty() && zone.get_name() != zone_name) {
5679 cerr << "Error: zone name " << zone_name << " is different than the zone name " << zone.get_name() << " in the provided json " << std::endl;
5680 return EINVAL;
5681 }
5682
5683 if (zone.get_name().empty()) {
5684 zone.set_name(zone_name);
5685 if (zone.get_name().empty()) {
5686 cerr << "no zone name specified" << std::endl;
5687 return EINVAL;
5688 }
5689 }
5690
5691 zone_name = zone.get_name();
5692
5693 if (zone.get_id().empty()) {
5694 zone.set_id(orig_id);
5695 }
5696
5697 if (zone.get_id().empty()) {
5698 cerr << "no zone name id the json provided, assuming old format" << std::endl;
5699 if (zone_name.empty()) {
5700 cerr << "missing zone name" << std::endl;
5701 return EINVAL;
5702 }
5703 zone.set_name(zone_name);
5704 zone.set_id(zone_name);
5705 }
5706
5707 cerr << "zone id " << zone.get_id();
5708 ret = zone.fix_pool_names(dpp(), null_yield);
5709 if (ret < 0) {
5710 cerr << "ERROR: couldn't fix zone: " << cpp_strerror(-ret) << std::endl;
5711 return -ret;
5712 }
5713 ret = zone.write(dpp(), false, null_yield);
5714 if (ret < 0) {
5715 cerr << "ERROR: couldn't create zone: " << cpp_strerror(-ret) << std::endl;
5716 return 1;
5717 }
5718
5719 if (set_default) {
5720 ret = zone.set_as_default(dpp(), null_yield);
5721 if (ret < 0) {
5722 cerr << "failed to set zone " << zone_name << " as default: " << cpp_strerror(-ret) << std::endl;
5723 }
5724 }
5725
5726 encode_json("zone", zone, formatter.get());
5727 formatter->flush(cout);
5728 }
5729 break;
5730 case OPT::ZONE_LIST:
5731 {
5732 list<string> zones;
5733 int ret = static_cast<rgw::sal::RadosStore*>(store)->svc()->zone->list_zones(dpp(), zones);
5734 if (ret < 0) {
5735 cerr << "failed to list zones: " << cpp_strerror(-ret) << std::endl;
5736 return -ret;
5737 }
5738
5739 RGWZoneParams zone;
5740 ret = zone.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield, false);
5741 if (ret < 0) {
5742 cerr << "failed to init zone: " << cpp_strerror(-ret) << std::endl;
5743 return -ret;
5744 }
5745 string default_zone;
5746 ret = zone.read_default_id(dpp(), default_zone, null_yield);
5747 if (ret < 0 && ret != -ENOENT) {
5748 cerr << "could not determine default zone: " << cpp_strerror(-ret) << std::endl;
5749 }
5750 formatter->open_object_section("zones_list");
5751 encode_json("default_info", default_zone, formatter.get());
5752 encode_json("zones", zones, formatter.get());
5753 formatter->close_section();
5754 formatter->flush(cout);
5755 }
5756 break;
5757 case OPT::ZONE_MODIFY:
5758 {
5759 RGWZoneParams zone(zone_id, zone_name);
5760 int ret = zone.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
5761 if (ret < 0) {
5762 cerr << "failed to init zone: " << cpp_strerror(-ret) << std::endl;
5763 return -ret;
5764 }
5765
5766 bool need_zone_update = false;
5767 if (!access_key.empty()) {
5768 zone.system_key.id = access_key;
5769 need_zone_update = true;
5770 }
5771
5772 if (!secret_key.empty()) {
5773 zone.system_key.key = secret_key;
5774 need_zone_update = true;
5775 }
5776
5777 if (!realm_id.empty()) {
5778 zone.realm_id = realm_id;
5779 need_zone_update = true;
5780 } else if (!realm_name.empty()) {
5781 // get realm id from name
5782 RGWRealm realm{g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj};
5783 ret = realm.read_id(dpp(), realm_name, zone.realm_id, null_yield);
5784 if (ret < 0) {
5785 cerr << "failed to find realm by name " << realm_name << std::endl;
5786 return -ret;
5787 }
5788 need_zone_update = true;
5789 }
5790
5791 if (tier_config_add.size() > 0) {
5792 for (auto add : tier_config_add) {
5793 int r = zone.tier_config.set(add.first, add.second);
5794 if (r < 0) {
5795 cerr << "ERROR: failed to set configurable: " << add << std::endl;
5796 return EINVAL;
5797 }
5798 }
5799 need_zone_update = true;
5800 }
5801
5802 for (auto rm : tier_config_rm) {
5803 if (!rm.first.empty()) { /* otherwise will remove the entire config */
5804 zone.tier_config.erase(rm.first);
5805 need_zone_update = true;
5806 }
5807 }
5808
5809 if (need_zone_update) {
5810 ret = zone.update(dpp(), null_yield);
5811 if (ret < 0) {
5812 cerr << "failed to save zone info: " << cpp_strerror(-ret) << std::endl;
5813 return -ret;
5814 }
5815 }
5816
5817 RGWZoneGroup zonegroup(zonegroup_id, zonegroup_name);
5818 ret = zonegroup.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
5819 if (ret < 0) {
5820 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
5821 return -ret;
5822 }
5823 string *ptier_type = (tier_type_specified ? &tier_type : nullptr);
5824
5825 bool *psync_from_all = (sync_from_all_specified ? &sync_from_all : nullptr);
5826 string *predirect_zone = (redirect_zone_set ? &redirect_zone : nullptr);
5827
5828 ret = zonegroup.add_zone(dpp(), zone,
5829 (is_master_set ? &is_master : NULL),
5830 (is_read_only_set ? &read_only : NULL),
5831 endpoints, ptier_type,
5832 psync_from_all, sync_from, sync_from_rm,
5833 predirect_zone, bucket_index_max_shards,
5834 static_cast<rgw::sal::RadosStore*>(store)->svc()->sync_modules->get_manager(),
5835 null_yield);
5836 if (ret < 0) {
5837 cerr << "failed to update zonegroup: " << cpp_strerror(-ret) << std::endl;
5838 return -ret;
5839 }
5840
5841 ret = zonegroup.update(dpp(), null_yield);
5842 if (ret < 0) {
5843 cerr << "failed to update zonegroup: " << cpp_strerror(-ret) << std::endl;
5844 return -ret;
5845 }
5846
5847 if (set_default) {
5848 ret = zone.set_as_default(dpp(), null_yield);
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, formatter.get());
5855 formatter->flush(cout);
5856 }
5857 break;
5858 case OPT::ZONE_RENAME:
5859 {
5860 if (zone_new_name.empty()) {
5861 cerr << " missing zone new name" << std::endl;
5862 return EINVAL;
5863 }
5864 if (zone_id.empty() && zone_name.empty()) {
5865 cerr << "no zone name or id provided" << std::endl;
5866 return EINVAL;
5867 }
5868 RGWZoneParams zone(zone_id,zone_name);
5869 int ret = zone.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
5870 if (ret < 0) {
5871 cerr << "unable to initialize zone: " << cpp_strerror(-ret) << std::endl;
5872 return -ret;
5873 }
5874 ret = zone.rename(dpp(), zone_new_name, null_yield);
5875 if (ret < 0) {
5876 cerr << "failed to rename zone " << zone_name << " to " << zone_new_name << ": " << cpp_strerror(-ret)
5877 << std::endl;
5878 return -ret;
5879 }
5880 RGWZoneGroup zonegroup(zonegroup_id, zonegroup_name);
5881 ret = zonegroup.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
5882 if (ret < 0) {
5883 cerr << "WARNING: failed to initialize zonegroup " << zonegroup_name << std::endl;
5884 } else {
5885 ret = zonegroup.rename_zone(dpp(), zone, null_yield);
5886 if (ret < 0) {
5887 cerr << "Error in zonegroup rename for " << zone_name << ": " << cpp_strerror(-ret) << std::endl;
5888 return -ret;
5889 }
5890 }
5891 }
5892 break;
5893 case OPT::ZONE_PLACEMENT_ADD:
5894 case OPT::ZONE_PLACEMENT_MODIFY:
5895 case OPT::ZONE_PLACEMENT_RM:
5896 {
5897 if (placement_id.empty()) {
5898 cerr << "ERROR: --placement-id not specified" << std::endl;
5899 return EINVAL;
5900 }
5901 // validate compression type
5902 if (compression_type && *compression_type != "random"
5903 && !Compressor::get_comp_alg_type(*compression_type)) {
5904 std::cerr << "Unrecognized compression type" << std::endl;
5905 return EINVAL;
5906 }
5907
5908 RGWZoneParams zone(zone_id, zone_name);
5909 int ret = zone.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
5910 if (ret < 0) {
5911 cerr << "failed to init zone: " << cpp_strerror(-ret) << std::endl;
5912 return -ret;
5913 }
5914
5915 if (opt_cmd == OPT::ZONE_PLACEMENT_ADD ||
5916 opt_cmd == OPT::ZONE_PLACEMENT_MODIFY) {
5917 RGWZoneGroup zonegroup(zonegroup_id, zonegroup_name);
5918 ret = zonegroup.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
5919 if (ret < 0) {
5920 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
5921 return -ret;
5922 }
5923
5924 auto ptiter = zonegroup.placement_targets.find(placement_id);
5925 if (ptiter == zonegroup.placement_targets.end()) {
5926 cerr << "ERROR: placement id '" << placement_id << "' is not configured in zonegroup placement targets" << std::endl;
5927 return EINVAL;
5928 }
5929
5930 string storage_class = rgw_placement_rule::get_canonical_storage_class(opt_storage_class.value_or(string()));
5931 if (ptiter->second.storage_classes.find(storage_class) == ptiter->second.storage_classes.end()) {
5932 cerr << "ERROR: storage class '" << storage_class << "' is not defined in zonegroup '" << placement_id << "' placement target" << std::endl;
5933 return EINVAL;
5934 }
5935 if (ptiter->second.tier_targets.find(storage_class) != ptiter->second.tier_targets.end()) {
5936 cerr << "ERROR: storage class '" << storage_class << "' is of tier type in zonegroup '" << placement_id << "' placement target" << std::endl;
5937 return EINVAL;
5938 }
5939
5940 RGWZonePlacementInfo& info = zone.placement_pools[placement_id];
5941
5942 string opt_index_pool = index_pool.value_or(string());
5943 string opt_data_pool = data_pool.value_or(string());
5944
5945 if (!opt_index_pool.empty()) {
5946 info.index_pool = opt_index_pool;
5947 }
5948
5949 if (info.index_pool.empty()) {
5950 cerr << "ERROR: index pool not configured, need to specify --index-pool" << std::endl;
5951 return EINVAL;
5952 }
5953
5954 if (opt_data_pool.empty()) {
5955 const RGWZoneStorageClass *porig_sc{nullptr};
5956 if (info.storage_classes.find(storage_class, &porig_sc)) {
5957 if (porig_sc->data_pool) {
5958 opt_data_pool = porig_sc->data_pool->to_str();
5959 }
5960 }
5961 if (opt_data_pool.empty()) {
5962 cerr << "ERROR: data pool not configured, need to specify --data-pool" << std::endl;
5963 return EINVAL;
5964 }
5965 }
5966
5967 rgw_pool dp = opt_data_pool;
5968 info.storage_classes.set_storage_class(storage_class, &dp, compression_type.get_ptr());
5969
5970 if (data_extra_pool) {
5971 info.data_extra_pool = *data_extra_pool;
5972 }
5973 if (index_type_specified) {
5974 info.index_type = placement_index_type;
5975 }
5976
5977 ret = check_pool_support_omap(info.get_data_extra_pool());
5978 if (ret < 0) {
5979 cerr << "ERROR: the data extra (non-ec) pool '" << info.get_data_extra_pool()
5980 << "' does not support omap" << std::endl;
5981 return ret;
5982 }
5983 } else if (opt_cmd == OPT::ZONE_PLACEMENT_RM) {
5984 if (!opt_storage_class ||
5985 opt_storage_class->empty()) {
5986 zone.placement_pools.erase(placement_id);
5987 } else {
5988 auto iter = zone.placement_pools.find(placement_id);
5989 if (iter != zone.placement_pools.end()) {
5990 RGWZonePlacementInfo& info = zone.placement_pools[placement_id];
5991 info.storage_classes.remove_storage_class(*opt_storage_class);
5992 }
5993 }
5994 }
5995
5996 ret = zone.update(dpp(), null_yield);
5997 if (ret < 0) {
5998 cerr << "failed to save zone info: " << cpp_strerror(-ret) << std::endl;
5999 return -ret;
6000 }
6001
6002 encode_json("zone", zone, formatter.get());
6003 formatter->flush(cout);
6004 }
6005 break;
6006 case OPT::ZONE_PLACEMENT_LIST:
6007 {
6008 RGWZoneParams zone(zone_id, zone_name);
6009 int ret = zone.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
6010 if (ret < 0) {
6011 cerr << "unable to initialize zone: " << cpp_strerror(-ret) << std::endl;
6012 return -ret;
6013 }
6014 encode_json("placement_pools", zone.placement_pools, formatter.get());
6015 formatter->flush(cout);
6016 }
6017 break;
6018 case OPT::ZONE_PLACEMENT_GET:
6019 {
6020 if (placement_id.empty()) {
6021 cerr << "ERROR: --placement-id not specified" << std::endl;
6022 return EINVAL;
6023 }
6024
6025 RGWZoneParams zone(zone_id, zone_name);
6026 int ret = zone.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
6027 if (ret < 0) {
6028 cerr << "unable to initialize zone: " << cpp_strerror(-ret) << std::endl;
6029 return -ret;
6030 }
6031 auto p = zone.placement_pools.find(placement_id);
6032 if (p == zone.placement_pools.end()) {
6033 cerr << "ERROR: zone placement target '" << placement_id << "' not found" << std::endl;
6034 return -ENOENT;
6035 }
6036 encode_json("placement_pools", p->second, formatter.get());
6037 formatter->flush(cout);
6038 }
6039 default:
6040 break;
6041 }
6042 return 0;
6043 }
6044
6045 resolve_zone_id_opt(opt_effective_zone_name, opt_effective_zone_id);
6046 resolve_zone_id_opt(opt_source_zone_name, opt_source_zone_id);
6047 resolve_zone_id_opt(opt_dest_zone_name, opt_dest_zone_id);
6048 resolve_zone_ids_opt(opt_zone_names, opt_zone_ids);
6049 resolve_zone_ids_opt(opt_source_zone_names, opt_source_zone_ids);
6050 resolve_zone_ids_opt(opt_dest_zone_names, opt_dest_zone_ids);
6051
6052 bool non_master_cmd = (!store->is_meta_master() && !yes_i_really_mean_it);
6053 std::set<OPT> non_master_ops_list = {OPT::USER_CREATE, OPT::USER_RM,
6054 OPT::USER_MODIFY, OPT::USER_ENABLE,
6055 OPT::USER_SUSPEND, OPT::SUBUSER_CREATE,
6056 OPT::SUBUSER_MODIFY, OPT::SUBUSER_RM,
6057 OPT::BUCKET_LINK, OPT::BUCKET_UNLINK,
6058 OPT::BUCKET_RESHARD, OPT::BUCKET_RM,
6059 OPT::BUCKET_CHOWN, OPT::METADATA_PUT,
6060 OPT::METADATA_RM, OPT::RESHARD_CANCEL,
6061 OPT::RESHARD_ADD, OPT::MFA_CREATE,
6062 OPT::MFA_REMOVE, OPT::MFA_RESYNC,
6063 OPT::CAPS_ADD, OPT::CAPS_RM};
6064
6065 bool print_warning_message = (non_master_ops_list.find(opt_cmd) != non_master_ops_list.end() &&
6066 non_master_cmd);
6067
6068 if (print_warning_message) {
6069 cerr << "Please run the command on master zone. Performing this operation on non-master zone leads to inconsistent metadata between zones" << std::endl;
6070 cerr << "Are you sure you want to go ahead? (requires --yes-i-really-mean-it)" << std::endl;
6071 return EINVAL;
6072 }
6073
6074 if (!rgw::sal::User::empty(user)) {
6075 user_op.set_user_id(user->get_id());
6076 bucket_op.set_user_id(user->get_id());
6077 }
6078
6079 if (!display_name.empty())
6080 user_op.set_display_name(display_name);
6081
6082 if (!user_email.empty())
6083 user_op.set_user_email(user_email);
6084
6085 if (!rgw::sal::User::empty(user)) {
6086 user_op.set_new_user_id(new_user_id);
6087 }
6088
6089 if (!access_key.empty())
6090 user_op.set_access_key(access_key);
6091
6092 if (!secret_key.empty())
6093 user_op.set_secret_key(secret_key);
6094
6095 if (!subuser.empty())
6096 user_op.set_subuser(subuser);
6097
6098 if (!caps.empty())
6099 user_op.set_caps(caps);
6100
6101 user_op.set_purge_data(purge_data);
6102
6103 if (purge_keys)
6104 user_op.set_purge_keys();
6105
6106 if (gen_access_key)
6107 user_op.set_generate_key();
6108
6109 if (gen_secret_key)
6110 user_op.set_gen_secret(); // assume that a key pair should be created
6111
6112 if (max_buckets_specified)
6113 user_op.set_max_buckets(max_buckets);
6114
6115 if (admin_specified)
6116 user_op.set_admin(admin);
6117
6118 if (system_specified)
6119 user_op.set_system(system);
6120
6121 if (set_perm)
6122 user_op.set_perm(perm_mask);
6123
6124 if (set_temp_url_key) {
6125 map<int, string>::iterator iter = temp_url_keys.begin();
6126 for (; iter != temp_url_keys.end(); ++iter) {
6127 user_op.set_temp_url_key(iter->second, iter->first);
6128 }
6129 }
6130
6131 if (!op_mask_str.empty()) {
6132 uint32_t op_mask;
6133 int ret = rgw_parse_op_type_list(op_mask_str, &op_mask);
6134 if (ret < 0) {
6135 cerr << "failed to parse op_mask: " << cpp_strerror(-ret) << std::endl;
6136 return -ret;
6137 }
6138
6139 user_op.set_op_mask(op_mask);
6140 }
6141
6142 if (key_type != KEY_TYPE_UNDEFINED)
6143 user_op.set_key_type(key_type);
6144
6145 // set suspension operation parameters
6146 if (opt_cmd == OPT::USER_ENABLE)
6147 user_op.set_suspension(false);
6148 else if (opt_cmd == OPT::USER_SUSPEND)
6149 user_op.set_suspension(true);
6150
6151 if (!placement_id.empty() ||
6152 (opt_storage_class && !opt_storage_class->empty())) {
6153 rgw_placement_rule target_rule;
6154 target_rule.name = placement_id;
6155 target_rule.storage_class = *opt_storage_class;
6156 if (!store->get_zone()->get_params().valid_placement(target_rule)) {
6157 cerr << "NOTICE: invalid dest placement: " << target_rule.to_str() << std::endl;
6158 return EINVAL;
6159 }
6160 user_op.set_default_placement(target_rule);
6161 }
6162
6163 if (!tags.empty()) {
6164 user_op.set_placement_tags(tags);
6165 }
6166
6167 // RGWUser to use for user operations
6168 RGWUser ruser;
6169 int ret = 0;
6170 if (!(rgw::sal::User::empty(user) && access_key.empty()) || !subuser.empty()) {
6171 ret = ruser.init(dpp(), store, user_op, null_yield);
6172 if (ret < 0) {
6173 cerr << "user.init failed: " << cpp_strerror(-ret) << std::endl;
6174 return -ret;
6175 }
6176 }
6177
6178 /* populate bucket operation */
6179 bucket_op.set_bucket_name(bucket_name);
6180 bucket_op.set_object(object);
6181 bucket_op.set_check_objects(check_objects);
6182 bucket_op.set_delete_children(delete_child_objects);
6183 bucket_op.set_fix_index(fix);
6184 bucket_op.set_max_aio(max_concurrent_ios);
6185
6186 // required to gather errors from operations
6187 std::string err_msg;
6188
6189 bool output_user_info = true;
6190
6191 switch (opt_cmd) {
6192 case OPT::USER_INFO:
6193 if (rgw::sal::User::empty(user) && access_key.empty()) {
6194 cerr << "ERROR: --uid or --access-key required" << std::endl;
6195 return EINVAL;
6196 }
6197 break;
6198 case OPT::USER_CREATE:
6199 if (!user_op.has_existing_user()) {
6200 user_op.set_generate_key(); // generate a new key by default
6201 }
6202 ret = ruser.add(dpp(), user_op, null_yield, &err_msg);
6203 if (ret < 0) {
6204 cerr << "could not create user: " << err_msg << std::endl;
6205 if (ret == -ERR_INVALID_TENANT_NAME)
6206 ret = -EINVAL;
6207
6208 return -ret;
6209 }
6210 if (!subuser.empty()) {
6211 ret = ruser.subusers.add(dpp(),user_op, null_yield, &err_msg);
6212 if (ret < 0) {
6213 cerr << "could not create subuser: " << err_msg << std::endl;
6214 return -ret;
6215 }
6216 }
6217 break;
6218 case OPT::USER_RM:
6219 ret = ruser.remove(dpp(), user_op, null_yield, &err_msg);
6220 if (ret < 0) {
6221 cerr << "could not remove user: " << err_msg << std::endl;
6222 return -ret;
6223 }
6224
6225 output_user_info = false;
6226 break;
6227 case OPT::USER_RENAME:
6228 if (yes_i_really_mean_it) {
6229 user_op.set_overwrite_new_user(true);
6230 }
6231 ret = ruser.rename(user_op, null_yield, dpp(), &err_msg);
6232 if (ret < 0) {
6233 if (ret == -EEXIST) {
6234 err_msg += ". to overwrite this user, add --yes-i-really-mean-it";
6235 }
6236 cerr << "could not rename user: " << err_msg << std::endl;
6237 return -ret;
6238 }
6239
6240 break;
6241 case OPT::USER_ENABLE:
6242 case OPT::USER_SUSPEND:
6243 case OPT::USER_MODIFY:
6244 ret = ruser.modify(dpp(), user_op, null_yield, &err_msg);
6245 if (ret < 0) {
6246 cerr << "could not modify user: " << err_msg << std::endl;
6247 return -ret;
6248 }
6249
6250 break;
6251 case OPT::SUBUSER_CREATE:
6252 ret = ruser.subusers.add(dpp(), user_op, null_yield, &err_msg);
6253 if (ret < 0) {
6254 cerr << "could not create subuser: " << err_msg << std::endl;
6255 return -ret;
6256 }
6257
6258 break;
6259 case OPT::SUBUSER_MODIFY:
6260 ret = ruser.subusers.modify(dpp(), user_op, null_yield, &err_msg);
6261 if (ret < 0) {
6262 cerr << "could not modify subuser: " << err_msg << std::endl;
6263 return -ret;
6264 }
6265
6266 break;
6267 case OPT::SUBUSER_RM:
6268 ret = ruser.subusers.remove(dpp(), user_op, null_yield, &err_msg);
6269 if (ret < 0) {
6270 cerr << "could not remove subuser: " << err_msg << std::endl;
6271 return -ret;
6272 }
6273
6274 break;
6275 case OPT::CAPS_ADD:
6276 ret = ruser.caps.add(dpp(), user_op, null_yield, &err_msg);
6277 if (ret < 0) {
6278 cerr << "could not add caps: " << err_msg << std::endl;
6279 return -ret;
6280 }
6281
6282 break;
6283 case OPT::CAPS_RM:
6284 ret = ruser.caps.remove(dpp(), user_op, null_yield, &err_msg);
6285 if (ret < 0) {
6286 cerr << "could not remove caps: " << err_msg << std::endl;
6287 return -ret;
6288 }
6289
6290 break;
6291 case OPT::KEY_CREATE:
6292 ret = ruser.keys.add(dpp(), user_op, null_yield, &err_msg);
6293 if (ret < 0) {
6294 cerr << "could not create key: " << err_msg << std::endl;
6295 return -ret;
6296 }
6297
6298 break;
6299 case OPT::KEY_RM:
6300 ret = ruser.keys.remove(dpp(), user_op, null_yield, &err_msg);
6301 if (ret < 0) {
6302 cerr << "could not remove key: " << err_msg << std::endl;
6303 return -ret;
6304 }
6305 break;
6306 case OPT::PERIOD_PUSH:
6307 {
6308 RGWEnv env;
6309 req_info info(g_ceph_context, &env);
6310 info.method = "POST";
6311 info.request_uri = "/admin/realm/period";
6312
6313 map<string, string> &params = info.args.get_params();
6314 if (!realm_id.empty())
6315 params["realm_id"] = realm_id;
6316 if (!realm_name.empty())
6317 params["realm_name"] = realm_name;
6318 if (!period_id.empty())
6319 params["period_id"] = period_id;
6320 if (!period_epoch.empty())
6321 params["epoch"] = period_epoch;
6322
6323 // load the period
6324 RGWPeriod period(period_id);
6325 int ret = period.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
6326 if (ret < 0) {
6327 cerr << "period init failed: " << cpp_strerror(-ret) << std::endl;
6328 return -ret;
6329 }
6330 // json format into a bufferlist
6331 JSONFormatter jf(false);
6332 encode_json("period", period, &jf);
6333 bufferlist bl;
6334 jf.flush(bl);
6335
6336 JSONParser p;
6337 ret = send_to_remote_or_url(nullptr, url, opt_region,
6338 access_key, secret_key,
6339 info, bl, p);
6340 if (ret < 0) {
6341 cerr << "request failed: " << cpp_strerror(-ret) << std::endl;
6342 return -ret;
6343 }
6344 }
6345 return 0;
6346 case OPT::PERIOD_UPDATE:
6347 {
6348 int ret = update_period(realm_id, realm_name, period_id, period_epoch,
6349 commit, remote, url, opt_region,
6350 access_key, secret_key,
6351 formatter.get(), yes_i_really_mean_it);
6352 if (ret < 0) {
6353 return -ret;
6354 }
6355 }
6356 return 0;
6357 case OPT::PERIOD_COMMIT:
6358 {
6359 // read realm and staging period
6360 RGWRealm realm(realm_id, realm_name);
6361 int ret = realm.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, null_yield);
6362 if (ret < 0) {
6363 cerr << "Error initializing realm: " << cpp_strerror(-ret) << std::endl;
6364 return -ret;
6365 }
6366 RGWPeriod period(RGWPeriod::get_staging_id(realm.get_id()), 1);
6367 ret = period.init(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->sysobj, realm.get_id(), null_yield);
6368 if (ret < 0) {
6369 cerr << "period init failed: " << cpp_strerror(-ret) << std::endl;
6370 return -ret;
6371 }
6372 ret = commit_period(realm, period, remote, url, opt_region, access_key, secret_key,
6373 yes_i_really_mean_it);
6374 if (ret < 0) {
6375 cerr << "failed to commit period: " << cpp_strerror(-ret) << std::endl;
6376 return -ret;
6377 }
6378
6379 encode_json("period", period, formatter.get());
6380 formatter->flush(cout);
6381 }
6382 return 0;
6383 case OPT::ROLE_CREATE:
6384 {
6385 if (role_name.empty()) {
6386 cerr << "ERROR: role name is empty" << std::endl;
6387 return -EINVAL;
6388 }
6389
6390 if (assume_role_doc.empty()) {
6391 cerr << "ERROR: assume role policy document is empty" << std::endl;
6392 return -EINVAL;
6393 }
6394 bufferlist bl = bufferlist::static_from_string(assume_role_doc);
6395 try {
6396 const rgw::IAM::Policy p(g_ceph_context, tenant, bl);
6397 } catch (rgw::IAM::PolicyParseException& e) {
6398 cerr << "failed to parse policy: " << e.what() << std::endl;
6399 return -EINVAL;
6400 }
6401 std::unique_ptr<rgw::sal::RGWRole> role = store->get_role(role_name, tenant, path, assume_role_doc);
6402 ret = role->create(dpp(), true, null_yield);
6403 if (ret < 0) {
6404 return -ret;
6405 }
6406 show_role_info(role.get(), formatter.get());
6407 return 0;
6408 }
6409 case OPT::ROLE_DELETE:
6410 {
6411 if (role_name.empty()) {
6412 cerr << "ERROR: empty role name" << std::endl;
6413 return -EINVAL;
6414 }
6415 std::unique_ptr<rgw::sal::RGWRole> role = store->get_role(role_name, tenant);
6416 ret = role->delete_obj(dpp(), null_yield);
6417 if (ret < 0) {
6418 return -ret;
6419 }
6420 cout << "role: " << role_name << " successfully deleted" << std::endl;
6421 return 0;
6422 }
6423 case OPT::ROLE_GET:
6424 {
6425 if (role_name.empty()) {
6426 cerr << "ERROR: empty role name" << std::endl;
6427 return -EINVAL;
6428 }
6429 std::unique_ptr<rgw::sal::RGWRole> role = store->get_role(role_name, tenant);
6430 ret = role->get(dpp(), null_yield);
6431 if (ret < 0) {
6432 return -ret;
6433 }
6434 show_role_info(role.get(), formatter.get());
6435 return 0;
6436 }
6437 case OPT::ROLE_MODIFY:
6438 {
6439 if (role_name.empty()) {
6440 cerr << "ERROR: role name is empty" << std::endl;
6441 return -EINVAL;
6442 }
6443
6444 if (assume_role_doc.empty()) {
6445 cerr << "ERROR: assume role policy document is empty" << std::endl;
6446 return -EINVAL;
6447 }
6448
6449 bufferlist bl = bufferlist::static_from_string(assume_role_doc);
6450 try {
6451 const rgw::IAM::Policy p(g_ceph_context, tenant, bl);
6452 } catch (rgw::IAM::PolicyParseException& e) {
6453 cerr << "failed to parse policy: " << e.what() << std::endl;
6454 return -EINVAL;
6455 }
6456
6457 std::unique_ptr<rgw::sal::RGWRole> role = store->get_role(role_name, tenant);
6458 ret = role->get(dpp(), null_yield);
6459 if (ret < 0) {
6460 return -ret;
6461 }
6462 role->update_trust_policy(assume_role_doc);
6463 ret = role->update(dpp(), null_yield);
6464 if (ret < 0) {
6465 return -ret;
6466 }
6467 cout << "Assume role policy document updated successfully for role: " << role_name << std::endl;
6468 return 0;
6469 }
6470 case OPT::ROLE_LIST:
6471 {
6472 vector<std::unique_ptr<rgw::sal::RGWRole>> result;
6473 ret = store->get_roles(dpp(), null_yield, path_prefix, tenant, result);
6474 if (ret < 0) {
6475 return -ret;
6476 }
6477 show_roles_info(result, formatter.get());
6478 return 0;
6479 }
6480 case OPT::ROLE_POLICY_PUT:
6481 {
6482 if (role_name.empty()) {
6483 cerr << "role name is empty" << std::endl;
6484 return -EINVAL;
6485 }
6486
6487 if (policy_name.empty()) {
6488 cerr << "policy name is empty" << std::endl;
6489 return -EINVAL;
6490 }
6491
6492 if (perm_policy_doc.empty()) {
6493 cerr << "permission policy document is empty" << std::endl;
6494 return -EINVAL;
6495 }
6496
6497 bufferlist bl = bufferlist::static_from_string(perm_policy_doc);
6498 try {
6499 const rgw::IAM::Policy p(g_ceph_context, tenant, bl);
6500 } catch (rgw::IAM::PolicyParseException& e) {
6501 cerr << "failed to parse perm policy: " << e.what() << std::endl;
6502 return -EINVAL;
6503 }
6504
6505 std::unique_ptr<rgw::sal::RGWRole> role = store->get_role(role_name, tenant);
6506 ret = role->get(dpp(), null_yield);
6507 if (ret < 0) {
6508 return -ret;
6509 }
6510 role->set_perm_policy(policy_name, perm_policy_doc);
6511 ret = role->update(dpp(), null_yield);
6512 if (ret < 0) {
6513 return -ret;
6514 }
6515 cout << "Permission policy attached successfully" << std::endl;
6516 return 0;
6517 }
6518 case OPT::ROLE_POLICY_LIST:
6519 {
6520 if (role_name.empty()) {
6521 cerr << "ERROR: Role name is empty" << std::endl;
6522 return -EINVAL;
6523 }
6524 std::unique_ptr<rgw::sal::RGWRole> role = store->get_role(role_name, tenant);
6525 ret = role->get(dpp(), null_yield);
6526 if (ret < 0) {
6527 return -ret;
6528 }
6529 std::vector<string> policy_names = role->get_role_policy_names();
6530 show_policy_names(policy_names, formatter.get());
6531 return 0;
6532 }
6533 case OPT::ROLE_POLICY_GET:
6534 {
6535 if (role_name.empty()) {
6536 cerr << "ERROR: role name is empty" << std::endl;
6537 return -EINVAL;
6538 }
6539
6540 if (policy_name.empty()) {
6541 cerr << "ERROR: policy name is empty" << std::endl;
6542 return -EINVAL;
6543 }
6544 std::unique_ptr<rgw::sal::RGWRole> role = store->get_role(role_name, tenant);
6545 int ret = role->get(dpp(), null_yield);
6546 if (ret < 0) {
6547 return -ret;
6548 }
6549 string perm_policy;
6550 ret = role->get_role_policy(dpp(), policy_name, perm_policy);
6551 if (ret < 0) {
6552 return -ret;
6553 }
6554 show_perm_policy(perm_policy, formatter.get());
6555 return 0;
6556 }
6557 case OPT::ROLE_POLICY_DELETE:
6558 {
6559 if (role_name.empty()) {
6560 cerr << "ERROR: role name is empty" << std::endl;
6561 return -EINVAL;
6562 }
6563
6564 if (policy_name.empty()) {
6565 cerr << "ERROR: policy name is empty" << std::endl;
6566 return -EINVAL;
6567 }
6568 std::unique_ptr<rgw::sal::RGWRole> role = store->get_role(role_name, tenant);
6569 ret = role->get(dpp(), null_yield);
6570 if (ret < 0) {
6571 return -ret;
6572 }
6573 ret = role->delete_policy(dpp(), policy_name);
6574 if (ret < 0) {
6575 return -ret;
6576 }
6577 ret = role->update(dpp(), null_yield);
6578 if (ret < 0) {
6579 return -ret;
6580 }
6581 cout << "Policy: " << policy_name << " successfully deleted for role: "
6582 << role_name << std::endl;
6583 return 0;
6584 }
6585 default:
6586 output_user_info = false;
6587 }
6588
6589 // output the result of a user operation
6590 if (output_user_info) {
6591 ret = ruser.info(info, &err_msg);
6592 if (ret < 0) {
6593 cerr << "could not fetch user info: " << err_msg << std::endl;
6594 return -ret;
6595 }
6596 show_user_info(info, formatter.get());
6597 }
6598
6599 if (opt_cmd == OPT::POLICY) {
6600 if (format == "xml") {
6601 int ret = RGWBucketAdminOp::dump_s3_policy(store, bucket_op, cout, dpp());
6602 if (ret < 0) {
6603 cerr << "ERROR: failed to get policy: " << cpp_strerror(-ret) << std::endl;
6604 return -ret;
6605 }
6606 } else {
6607 int ret = RGWBucketAdminOp::get_policy(store, bucket_op, stream_flusher, dpp());
6608 if (ret < 0) {
6609 cerr << "ERROR: failed to get policy: " << cpp_strerror(-ret) << std::endl;
6610 return -ret;
6611 }
6612 }
6613 }
6614
6615 if (opt_cmd == OPT::BUCKET_LIMIT_CHECK) {
6616 void *handle;
6617 std::list<std::string> user_ids;
6618 metadata_key = "user";
6619 int max = 1000;
6620
6621 bool truncated;
6622
6623 if (!rgw::sal::User::empty(user)) {
6624 user_ids.push_back(user->get_id().id);
6625 ret =
6626 RGWBucketAdminOp::limit_check(store, bucket_op, user_ids, stream_flusher,
6627 null_yield, dpp(), warnings_only);
6628 } else {
6629 /* list users in groups of max-keys, then perform user-bucket
6630 * limit-check on each group */
6631 ret = store->meta_list_keys_init(dpp(), metadata_key, string(), &handle);
6632 if (ret < 0) {
6633 cerr << "ERROR: buckets limit check can't get user metadata_key: "
6634 << cpp_strerror(-ret) << std::endl;
6635 return -ret;
6636 }
6637
6638 do {
6639 ret = store->meta_list_keys_next(dpp(), handle, max, user_ids,
6640 &truncated);
6641 if (ret < 0 && ret != -ENOENT) {
6642 cerr << "ERROR: buckets limit check lists_keys_next(): "
6643 << cpp_strerror(-ret) << std::endl;
6644 break;
6645 } else {
6646 /* ok, do the limit checks for this group */
6647 ret =
6648 RGWBucketAdminOp::limit_check(store, bucket_op, user_ids, stream_flusher,
6649 null_yield, dpp(), warnings_only);
6650 if (ret < 0)
6651 break;
6652 }
6653 user_ids.clear();
6654 } while (truncated);
6655 store->meta_list_keys_complete(handle);
6656 }
6657 return -ret;
6658 } /* OPT::BUCKET_LIMIT_CHECK */
6659
6660 if (opt_cmd == OPT::BUCKETS_LIST) {
6661 if (bucket_name.empty()) {
6662 if (!rgw::sal::User::empty(user)) {
6663 if (!user_op.has_existing_user()) {
6664 cerr << "ERROR: could not find user: " << user << std::endl;
6665 return -ENOENT;
6666 }
6667 }
6668 RGWBucketAdminOp::info(store, bucket_op, stream_flusher, null_yield, dpp());
6669 } else {
6670 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
6671 if (ret < 0) {
6672 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
6673 return -ret;
6674 }
6675 formatter->open_array_section("entries");
6676
6677 int count = 0;
6678
6679 static constexpr int MAX_PAGINATE_SIZE = 10000;
6680 static constexpr int DEFAULT_MAX_ENTRIES = 1000;
6681
6682 if (max_entries < 0) {
6683 max_entries = DEFAULT_MAX_ENTRIES;
6684 }
6685 const int paginate_size = std::min(max_entries, MAX_PAGINATE_SIZE);
6686
6687 string prefix;
6688 string delim;
6689 string ns;
6690
6691 rgw::sal::Bucket::ListParams params;
6692 rgw::sal::Bucket::ListResults results;
6693
6694 params.prefix = prefix;
6695 params.delim = delim;
6696 params.marker = rgw_obj_key(marker);
6697 params.ns = ns;
6698 params.enforce_ns = false;
6699 params.list_versions = true;
6700 params.allow_unordered = bool(allow_unordered);
6701
6702 do {
6703 const int remaining = max_entries - count;
6704 ret = bucket->list(dpp(), params, std::min(remaining, paginate_size), results,
6705 null_yield);
6706 if (ret < 0) {
6707 cerr << "ERROR: store->list_objects(): " << cpp_strerror(-ret) << std::endl;
6708 return -ret;
6709 }
6710
6711 count += results.objs.size();
6712
6713 for (const auto& entry : results.objs) {
6714 encode_json("entry", entry, formatter.get());
6715 }
6716 formatter->flush(cout);
6717 } while (results.is_truncated && count < max_entries);
6718
6719 formatter->close_section();
6720 formatter->flush(cout);
6721 } /* have bucket_name */
6722 } /* OPT::BUCKETS_LIST */
6723
6724 if (opt_cmd == OPT::BUCKET_RADOS_LIST) {
6725 RGWRadosList lister(static_cast<rgw::sal::RadosStore*>(store),
6726 max_concurrent_ios, orphan_stale_secs, tenant);
6727 if (rgw_obj_fs) {
6728 lister.set_field_separator(*rgw_obj_fs);
6729 }
6730
6731 if (bucket_name.empty()) {
6732 ret = lister.run(dpp());
6733 } else {
6734 ret = lister.run(dpp(), bucket_name);
6735 }
6736
6737 if (ret < 0) {
6738 std::cerr <<
6739 "ERROR: bucket radoslist failed to finish before " <<
6740 "encountering error: " << cpp_strerror(-ret) << std::endl;
6741 std::cerr << "************************************"
6742 "************************************" << std::endl;
6743 std::cerr << "WARNING: THE RESULTS ARE NOT RELIABLE AND SHOULD NOT " <<
6744 "BE USED IN DELETING ORPHANS" << std::endl;
6745 std::cerr << "************************************"
6746 "************************************" << std::endl;
6747 return -ret;
6748 }
6749 }
6750
6751 if (opt_cmd == OPT::BUCKET_STATS) {
6752 if (bucket_name.empty() && !bucket_id.empty()) {
6753 rgw_bucket bucket;
6754 if (!rgw_find_bucket_by_id(dpp(), store->ctx(), store, marker, bucket_id, &bucket)) {
6755 cerr << "failure: no such bucket id" << std::endl;
6756 return -ENOENT;
6757 }
6758 bucket_op.set_tenant(bucket.tenant);
6759 bucket_op.set_bucket_name(bucket.name);
6760 }
6761 bucket_op.set_fetch_stats(true);
6762
6763 int r = RGWBucketAdminOp::info(store, bucket_op, stream_flusher, null_yield, dpp());
6764 if (r < 0) {
6765 cerr << "failure: " << cpp_strerror(-r) << ": " << err << std::endl;
6766 return -r;
6767 }
6768 }
6769
6770 if (opt_cmd == OPT::BUCKET_LINK) {
6771 bucket_op.set_bucket_id(bucket_id);
6772 bucket_op.set_new_bucket_name(new_bucket_name);
6773 string err;
6774 int r = RGWBucketAdminOp::link(store, bucket_op, dpp(), &err);
6775 if (r < 0) {
6776 cerr << "failure: " << cpp_strerror(-r) << ": " << err << std::endl;
6777 return -r;
6778 }
6779 }
6780
6781 if (opt_cmd == OPT::BUCKET_UNLINK) {
6782 int r = RGWBucketAdminOp::unlink(store, bucket_op, dpp());
6783 if (r < 0) {
6784 cerr << "failure: " << cpp_strerror(-r) << std::endl;
6785 return -r;
6786 }
6787 }
6788
6789 if (opt_cmd == OPT::BUCKET_CHOWN) {
6790 if (bucket_name.empty()) {
6791 cerr << "ERROR: bucket name not specified" << std::endl;
6792 return EINVAL;
6793 }
6794
6795 bucket_op.set_bucket_name(bucket_name);
6796 bucket_op.set_new_bucket_name(new_bucket_name);
6797 string err;
6798 string marker;
6799
6800 int r = RGWBucketAdminOp::chown(store, bucket_op, marker, dpp(), &err);
6801 if (r < 0) {
6802 cerr << "failure: " << cpp_strerror(-r) << ": " << err << std::endl;
6803 return -r;
6804 }
6805 }
6806
6807 if (opt_cmd == OPT::LOG_LIST) {
6808 // filter by date?
6809 if (date.size() && date.size() != 10) {
6810 cerr << "bad date format for '" << date << "', expect YYYY-MM-DD" << std::endl;
6811 return EINVAL;
6812 }
6813
6814 formatter->reset();
6815 formatter->open_array_section("logs");
6816 RGWAccessHandle h;
6817 int r = static_cast<rgw::sal::RadosStore*>(store)->getRados()->log_list_init(dpp(), date, &h);
6818 if (r == -ENOENT) {
6819 // no logs.
6820 } else {
6821 if (r < 0) {
6822 cerr << "log list: error " << r << std::endl;
6823 return -r;
6824 }
6825 while (true) {
6826 string name;
6827 int r = static_cast<rgw::sal::RadosStore*>(store)->getRados()->log_list_next(h, &name);
6828 if (r == -ENOENT)
6829 break;
6830 if (r < 0) {
6831 cerr << "log list: error " << r << std::endl;
6832 return -r;
6833 }
6834 formatter->dump_string("object", name);
6835 }
6836 }
6837 formatter->close_section();
6838 formatter->flush(cout);
6839 cout << std::endl;
6840 }
6841
6842 if (opt_cmd == OPT::LOG_SHOW || opt_cmd == OPT::LOG_RM) {
6843 if (object.empty() && (date.empty() || bucket_name.empty() || bucket_id.empty())) {
6844 cerr << "specify an object or a date, bucket and bucket-id" << std::endl;
6845 exit(1);
6846 }
6847
6848 string oid;
6849 if (!object.empty()) {
6850 oid = object;
6851 } else {
6852 oid = date;
6853 oid += "-";
6854 oid += bucket_id;
6855 oid += "-";
6856 oid += bucket_name;
6857 }
6858
6859 if (opt_cmd == OPT::LOG_SHOW) {
6860 RGWAccessHandle h;
6861
6862 int r = static_cast<rgw::sal::RadosStore*>(store)->getRados()->log_show_init(dpp(), oid, &h);
6863 if (r < 0) {
6864 cerr << "error opening log " << oid << ": " << cpp_strerror(-r) << std::endl;
6865 return -r;
6866 }
6867
6868 formatter->reset();
6869 formatter->open_object_section("log");
6870
6871 struct rgw_log_entry entry;
6872
6873 // peek at first entry to get bucket metadata
6874 r = static_cast<rgw::sal::RadosStore*>(store)->getRados()->log_show_next(dpp(), h, &entry);
6875 if (r < 0) {
6876 cerr << "error reading log " << oid << ": " << cpp_strerror(-r) << std::endl;
6877 return -r;
6878 }
6879 formatter->dump_string("bucket_id", entry.bucket_id);
6880 formatter->dump_string("bucket_owner", entry.bucket_owner.to_str());
6881 formatter->dump_string("bucket", entry.bucket);
6882
6883 uint64_t agg_time = 0;
6884 uint64_t agg_bytes_sent = 0;
6885 uint64_t agg_bytes_received = 0;
6886 uint64_t total_entries = 0;
6887
6888 if (show_log_entries)
6889 formatter->open_array_section("log_entries");
6890
6891 do {
6892 using namespace std::chrono;
6893 uint64_t total_time = duration_cast<milliseconds>(entry.total_time).count();
6894
6895 agg_time += total_time;
6896 agg_bytes_sent += entry.bytes_sent;
6897 agg_bytes_received += entry.bytes_received;
6898 total_entries++;
6899
6900 if (skip_zero_entries && entry.bytes_sent == 0 &&
6901 entry.bytes_received == 0)
6902 goto next;
6903
6904 if (show_log_entries) {
6905
6906 rgw_format_ops_log_entry(entry, formatter.get());
6907 formatter->flush(cout);
6908 }
6909 next:
6910 r = static_cast<rgw::sal::RadosStore*>(store)->getRados()->log_show_next(dpp(), h, &entry);
6911 } while (r > 0);
6912
6913 if (r < 0) {
6914 cerr << "error reading log " << oid << ": " << cpp_strerror(-r) << std::endl;
6915 return -r;
6916 }
6917 if (show_log_entries)
6918 formatter->close_section();
6919
6920 if (show_log_sum) {
6921 formatter->open_object_section("log_sum");
6922 formatter->dump_int("bytes_sent", agg_bytes_sent);
6923 formatter->dump_int("bytes_received", agg_bytes_received);
6924 formatter->dump_int("total_time", agg_time);
6925 formatter->dump_int("total_entries", total_entries);
6926 formatter->close_section();
6927 }
6928 formatter->close_section();
6929 formatter->flush(cout);
6930 cout << std::endl;
6931 }
6932 if (opt_cmd == OPT::LOG_RM) {
6933 int r = static_cast<rgw::sal::RadosStore*>(store)->getRados()->log_remove(dpp(), oid);
6934 if (r < 0) {
6935 cerr << "error removing log " << oid << ": " << cpp_strerror(-r) << std::endl;
6936 return -r;
6937 }
6938 }
6939 }
6940
6941 if (opt_cmd == OPT::POOL_ADD) {
6942 if (pool_name.empty()) {
6943 cerr << "need to specify pool to add!" << std::endl;
6944 exit(1);
6945 }
6946
6947 int ret = static_cast<rgw::sal::RadosStore*>(store)->svc()->zone->add_bucket_placement(dpp(), pool, null_yield);
6948 if (ret < 0)
6949 cerr << "failed to add bucket placement: " << cpp_strerror(-ret) << std::endl;
6950 }
6951
6952 if (opt_cmd == OPT::POOL_RM) {
6953 if (pool_name.empty()) {
6954 cerr << "need to specify pool to remove!" << std::endl;
6955 exit(1);
6956 }
6957
6958 int ret = static_cast<rgw::sal::RadosStore*>(store)->svc()->zone->remove_bucket_placement(dpp(), pool, null_yield);
6959 if (ret < 0)
6960 cerr << "failed to remove bucket placement: " << cpp_strerror(-ret) << std::endl;
6961 }
6962
6963 if (opt_cmd == OPT::POOLS_LIST) {
6964 set<rgw_pool> pools;
6965 int ret = static_cast<rgw::sal::RadosStore*>(store)->svc()->zone->list_placement_set(dpp(), pools, null_yield);
6966 if (ret < 0) {
6967 cerr << "could not list placement set: " << cpp_strerror(-ret) << std::endl;
6968 return -ret;
6969 }
6970 formatter->reset();
6971 formatter->open_array_section("pools");
6972 for (auto siter = pools.begin(); siter != pools.end(); ++siter) {
6973 formatter->open_object_section("pool");
6974 formatter->dump_string("name", siter->to_str());
6975 formatter->close_section();
6976 }
6977 formatter->close_section();
6978 formatter->flush(cout);
6979 cout << std::endl;
6980 }
6981
6982 if (opt_cmd == OPT::USAGE_SHOW) {
6983 uint64_t start_epoch = 0;
6984 uint64_t end_epoch = (uint64_t)-1;
6985
6986 int ret;
6987
6988 if (!start_date.empty()) {
6989 ret = utime_t::parse_date(start_date, &start_epoch, NULL);
6990 if (ret < 0) {
6991 cerr << "ERROR: failed to parse start date" << std::endl;
6992 return 1;
6993 }
6994 }
6995 if (!end_date.empty()) {
6996 ret = utime_t::parse_date(end_date, &end_epoch, NULL);
6997 if (ret < 0) {
6998 cerr << "ERROR: failed to parse end date" << std::endl;
6999 return 1;
7000 }
7001 }
7002
7003
7004 if (!bucket_name.empty()) {
7005 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
7006 if (ret < 0) {
7007 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7008 return -ret;
7009 }
7010 }
7011 ret = RGWUsage::show(dpp(), store, user.get(), bucket.get(), start_epoch,
7012 end_epoch, show_log_entries, show_log_sum, &categories,
7013 stream_flusher);
7014 if (ret < 0) {
7015 cerr << "ERROR: failed to show usage" << std::endl;
7016 return 1;
7017 }
7018 }
7019
7020 if (opt_cmd == OPT::USAGE_TRIM) {
7021 if (rgw::sal::User::empty(user) && bucket_name.empty() &&
7022 start_date.empty() && end_date.empty() && !yes_i_really_mean_it) {
7023 cerr << "usage trim without user/date/bucket specified will remove *all* users data" << std::endl;
7024 cerr << "do you really mean it? (requires --yes-i-really-mean-it)" << std::endl;
7025 return 1;
7026 }
7027 int ret;
7028 uint64_t start_epoch = 0;
7029 uint64_t end_epoch = (uint64_t)-1;
7030
7031
7032 if (!start_date.empty()) {
7033 ret = utime_t::parse_date(start_date, &start_epoch, NULL);
7034 if (ret < 0) {
7035 cerr << "ERROR: failed to parse start date" << std::endl;
7036 return 1;
7037 }
7038 }
7039
7040 if (!end_date.empty()) {
7041 ret = utime_t::parse_date(end_date, &end_epoch, NULL);
7042 if (ret < 0) {
7043 cerr << "ERROR: failed to parse end date" << std::endl;
7044 return 1;
7045 }
7046 }
7047
7048 if (!bucket_name.empty()) {
7049 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
7050 if (ret < 0) {
7051 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7052 return -ret;
7053 }
7054 }
7055 ret = RGWUsage::trim(dpp(), store, user.get(), bucket.get(), start_epoch, end_epoch);
7056 if (ret < 0) {
7057 cerr << "ERROR: read_usage() returned ret=" << ret << std::endl;
7058 return 1;
7059 }
7060 }
7061
7062 if (opt_cmd == OPT::USAGE_CLEAR) {
7063 if (!yes_i_really_mean_it) {
7064 cerr << "usage clear would remove *all* users usage data for all time" << std::endl;
7065 cerr << "do you really mean it? (requires --yes-i-really-mean-it)" << std::endl;
7066 return 1;
7067 }
7068
7069 ret = RGWUsage::clear(dpp(), store);
7070 if (ret < 0) {
7071 return ret;
7072 }
7073 }
7074
7075
7076 if (opt_cmd == OPT::OLH_GET || opt_cmd == OPT::OLH_READLOG) {
7077 if (bucket_name.empty()) {
7078 cerr << "ERROR: bucket not specified" << std::endl;
7079 return EINVAL;
7080 }
7081 if (object.empty()) {
7082 cerr << "ERROR: object not specified" << std::endl;
7083 return EINVAL;
7084 }
7085 }
7086
7087 if (opt_cmd == OPT::OLH_GET) {
7088 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
7089 if (ret < 0) {
7090 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7091 return -ret;
7092 }
7093 RGWOLHInfo olh;
7094 rgw_obj obj(bucket->get_key(), object);
7095 ret = static_cast<rgw::sal::RadosStore*>(store)->getRados()->get_olh(dpp(), bucket->get_info(), obj, &olh);
7096 if (ret < 0) {
7097 cerr << "ERROR: failed reading olh: " << cpp_strerror(-ret) << std::endl;
7098 return -ret;
7099 }
7100 encode_json("olh", olh, formatter.get());
7101 formatter->flush(cout);
7102 }
7103
7104 if (opt_cmd == OPT::OLH_READLOG) {
7105 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
7106 if (ret < 0) {
7107 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7108 return -ret;
7109 }
7110 map<uint64_t, vector<rgw_bucket_olh_log_entry> > log;
7111 bool is_truncated;
7112
7113 RGWObjectCtx rctx(store);
7114 std::unique_ptr<rgw::sal::Object> obj = bucket->get_object(object);
7115
7116 RGWObjState *state;
7117
7118 ret = obj->get_obj_state(dpp(), &rctx, &state, null_yield);
7119 if (ret < 0) {
7120 return -ret;
7121 }
7122
7123 ret = static_cast<rgw::sal::RadosStore*>(store)->getRados()->bucket_index_read_olh_log(dpp(), bucket->get_info(), *state, obj->get_obj(), 0, &log, &is_truncated);
7124 if (ret < 0) {
7125 cerr << "ERROR: failed reading olh: " << cpp_strerror(-ret) << std::endl;
7126 return -ret;
7127 }
7128 formatter->open_object_section("result");
7129 encode_json("is_truncated", is_truncated, formatter.get());
7130 encode_json("log", log, formatter.get());
7131 formatter->close_section();
7132 formatter->flush(cout);
7133 }
7134
7135 if (opt_cmd == OPT::BI_GET) {
7136 if (bucket_name.empty()) {
7137 cerr << "ERROR: bucket name not specified" << std::endl;
7138 return EINVAL;
7139 }
7140 if (object.empty()) {
7141 cerr << "ERROR: object not specified" << std::endl;
7142 return EINVAL;
7143 }
7144 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
7145 if (ret < 0) {
7146 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7147 return -ret;
7148 }
7149 rgw_obj obj(bucket->get_key(), object);
7150 if (!object_version.empty()) {
7151 obj.key.set_instance(object_version);
7152 }
7153
7154 rgw_cls_bi_entry entry;
7155
7156 ret = static_cast<rgw::sal::RadosStore*>(store)->getRados()->bi_get(dpp(), bucket->get_info(), obj, bi_index_type, &entry);
7157 if (ret < 0) {
7158 cerr << "ERROR: bi_get(): " << cpp_strerror(-ret) << std::endl;
7159 return -ret;
7160 }
7161
7162 encode_json("entry", entry, formatter.get());
7163 formatter->flush(cout);
7164 }
7165
7166 if (opt_cmd == OPT::BI_PUT) {
7167 if (bucket_name.empty()) {
7168 cerr << "ERROR: bucket name not specified" << std::endl;
7169 return EINVAL;
7170 }
7171 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
7172 if (ret < 0) {
7173 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7174 return -ret;
7175 }
7176
7177 rgw_cls_bi_entry entry;
7178 cls_rgw_obj_key key;
7179 ret = read_decode_json(infile, entry, &key);
7180 if (ret < 0) {
7181 return 1;
7182 }
7183
7184 rgw_obj obj(bucket->get_key(), key);
7185
7186 ret = static_cast<rgw::sal::RadosStore*>(store)->getRados()->bi_put(dpp(), bucket->get_key(), obj, entry);
7187 if (ret < 0) {
7188 cerr << "ERROR: bi_put(): " << cpp_strerror(-ret) << std::endl;
7189 return -ret;
7190 }
7191 }
7192
7193 if (opt_cmd == OPT::BI_LIST) {
7194 if (bucket_name.empty()) {
7195 cerr << "ERROR: bucket name not specified" << std::endl;
7196 return EINVAL;
7197 }
7198 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
7199 if (ret < 0) {
7200 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7201 return -ret;
7202 }
7203
7204 list<rgw_cls_bi_entry> entries;
7205 bool is_truncated;
7206 if (max_entries < 0) {
7207 max_entries = 1000;
7208 }
7209
7210 int max_shards = (bucket->get_info().layout.current_index.layout.normal.num_shards > 0 ? bucket->get_info().layout.current_index.layout.normal.num_shards : 1);
7211
7212 formatter->open_array_section("entries");
7213
7214 int i = (specified_shard_id ? shard_id : 0);
7215 for (; i < max_shards; i++) {
7216 RGWRados::BucketShard bs(static_cast<rgw::sal::RadosStore*>(store)->getRados());
7217 int shard_id = (bucket->get_info().layout.current_index.layout.normal.num_shards > 0 ? i : -1);
7218
7219 int ret = bs.init(bucket->get_key(), shard_id, bucket->get_info().layout.current_index, nullptr /* no RGWBucketInfo */, dpp());
7220 marker.clear();
7221
7222 if (ret < 0) {
7223 cerr << "ERROR: bs.init(bucket=" << bucket << ", shard=" << shard_id << "): " << cpp_strerror(-ret) << std::endl;
7224 return -ret;
7225 }
7226
7227 do {
7228 entries.clear();
7229 // if object is specified, we use that as a filter to only retrieve some some entries
7230 ret = static_cast<rgw::sal::RadosStore*>(store)->getRados()->bi_list(bs, object, marker, max_entries, &entries, &is_truncated);
7231 if (ret < 0) {
7232 cerr << "ERROR: bi_list(): " << cpp_strerror(-ret) << std::endl;
7233 return -ret;
7234 }
7235
7236 list<rgw_cls_bi_entry>::iterator iter;
7237 for (iter = entries.begin(); iter != entries.end(); ++iter) {
7238 rgw_cls_bi_entry& entry = *iter;
7239 encode_json("entry", entry, formatter.get());
7240 marker = entry.idx;
7241 }
7242 formatter->flush(cout);
7243 } while (is_truncated);
7244 formatter->flush(cout);
7245
7246 if (specified_shard_id)
7247 break;
7248 }
7249 formatter->close_section();
7250 formatter->flush(cout);
7251 }
7252
7253 if (opt_cmd == OPT::BI_PURGE) {
7254 if (bucket_name.empty()) {
7255 cerr << "ERROR: bucket name not specified" << std::endl;
7256 return EINVAL;
7257 }
7258 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
7259 if (ret < 0) {
7260 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7261 return -ret;
7262 }
7263
7264 std::unique_ptr<rgw::sal::Bucket> cur_bucket;
7265 ret = init_bucket(user.get(), tenant, bucket_name, string(), &cur_bucket);
7266 if (ret == -ENOENT) {
7267 // no bucket entrypoint
7268 } else if (ret < 0) {
7269 cerr << "ERROR: could not init current bucket info for bucket_name=" << bucket_name << ": " << cpp_strerror(-ret) << std::endl;
7270 return -ret;
7271 } else if (cur_bucket->get_bucket_id() == bucket->get_bucket_id() &&
7272 !yes_i_really_mean_it) {
7273 cerr << "specified bucket instance points to a current bucket instance" << std::endl;
7274 cerr << "do you really mean it? (requires --yes-i-really-mean-it)" << std::endl;
7275 return EINVAL;
7276 }
7277
7278 ret = bucket->purge_instance(dpp());
7279 if (ret < 0) {
7280 return -ret;
7281 }
7282 }
7283
7284 if (opt_cmd == OPT::OBJECT_PUT) {
7285 if (bucket_name.empty()) {
7286 cerr << "ERROR: bucket not specified" << std::endl;
7287 return EINVAL;
7288 }
7289 if (object.empty()) {
7290 cerr << "ERROR: object not specified" << std::endl;
7291 return EINVAL;
7292 }
7293
7294 RGWDataAccess data_access(store);
7295 rgw_obj_key key(object, object_version);
7296
7297 RGWDataAccess::BucketRef b;
7298 RGWDataAccess::ObjectRef obj;
7299
7300 int ret = data_access.get_bucket(dpp(), tenant, bucket_name, bucket_id, &b, null_yield);
7301 if (ret < 0) {
7302 cerr << "ERROR: failed to init bucket: " << cpp_strerror(-ret) << std::endl;
7303 return -ret;
7304 }
7305
7306 ret = b->get_object(key, &obj);
7307 if (ret < 0) {
7308 cerr << "ERROR: failed to get object: " << cpp_strerror(-ret) << std::endl;
7309 return -ret;
7310 }
7311
7312 bufferlist bl;
7313 ret = read_input(infile, bl);
7314 if (ret < 0) {
7315 cerr << "ERROR: failed to read input: " << cpp_strerror(-ret) << std::endl;
7316 }
7317
7318 map<string, bufferlist> attrs;
7319 ret = obj->put(bl, attrs, dpp(), null_yield);
7320 if (ret < 0) {
7321 cerr << "ERROR: put object returned error: " << cpp_strerror(-ret) << std::endl;
7322 }
7323 }
7324
7325 if (opt_cmd == OPT::OBJECT_RM) {
7326 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
7327 if (ret < 0) {
7328 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7329 return -ret;
7330 }
7331 rgw_obj_key key(object, object_version);
7332 ret = rgw_remove_object(dpp(), store, bucket.get(), key);
7333
7334 if (ret < 0) {
7335 cerr << "ERROR: object remove returned: " << cpp_strerror(-ret) << std::endl;
7336 return -ret;
7337 }
7338 }
7339
7340 if (opt_cmd == OPT::OBJECT_REWRITE) {
7341 if (bucket_name.empty()) {
7342 cerr << "ERROR: bucket not specified" << std::endl;
7343 return EINVAL;
7344 }
7345 if (object.empty()) {
7346 cerr << "ERROR: object not specified" << std::endl;
7347 return EINVAL;
7348 }
7349
7350 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
7351 if (ret < 0) {
7352 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7353 return -ret;
7354 }
7355
7356 std::unique_ptr<rgw::sal::Object> obj = bucket->get_object(object);
7357 obj->set_instance(object_version);
7358 bool need_rewrite = true;
7359 if (min_rewrite_stripe_size > 0) {
7360 ret = check_min_obj_stripe_size(store, obj.get(), min_rewrite_stripe_size, &need_rewrite);
7361 if (ret < 0) {
7362 ldpp_dout(dpp(), 0) << "WARNING: check_min_obj_stripe_size failed, r=" << ret << dendl;
7363 }
7364 }
7365 if (need_rewrite) {
7366 ret = static_cast<rgw::sal::RadosStore*>(store)->getRados()->rewrite_obj(obj.get(), dpp(), null_yield);
7367 if (ret < 0) {
7368 cerr << "ERROR: object rewrite returned: " << cpp_strerror(-ret) << std::endl;
7369 return -ret;
7370 }
7371 } else {
7372 ldpp_dout(dpp(), 20) << "skipped object" << dendl;
7373 }
7374 }
7375
7376 if (opt_cmd == OPT::OBJECTS_EXPIRE) {
7377 if (!static_cast<rgw::sal::RadosStore*>(store)->getRados()->process_expire_objects(dpp())) {
7378 cerr << "ERROR: process_expire_objects() processing returned error." << std::endl;
7379 return 1;
7380 }
7381 }
7382
7383 if (opt_cmd == OPT::OBJECTS_EXPIRE_STALE_LIST) {
7384 ret = RGWBucketAdminOp::fix_obj_expiry(store, bucket_op, stream_flusher, dpp(), true);
7385 if (ret < 0) {
7386 cerr << "ERROR: listing returned " << cpp_strerror(-ret) << std::endl;
7387 return -ret;
7388 }
7389 }
7390
7391 if (opt_cmd == OPT::OBJECTS_EXPIRE_STALE_RM) {
7392 ret = RGWBucketAdminOp::fix_obj_expiry(store, bucket_op, stream_flusher, dpp(), false);
7393 if (ret < 0) {
7394 cerr << "ERROR: removing returned " << cpp_strerror(-ret) << std::endl;
7395 return -ret;
7396 }
7397 }
7398
7399 if (opt_cmd == OPT::BUCKET_REWRITE) {
7400 if (bucket_name.empty()) {
7401 cerr << "ERROR: bucket not specified" << std::endl;
7402 return EINVAL;
7403 }
7404
7405 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
7406 if (ret < 0) {
7407 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7408 return -ret;
7409 }
7410
7411 uint64_t start_epoch = 0;
7412 uint64_t end_epoch = 0;
7413
7414 if (!end_date.empty()) {
7415 int ret = utime_t::parse_date(end_date, &end_epoch, NULL);
7416 if (ret < 0) {
7417 cerr << "ERROR: failed to parse end date" << std::endl;
7418 return EINVAL;
7419 }
7420 }
7421 if (!start_date.empty()) {
7422 int ret = utime_t::parse_date(start_date, &start_epoch, NULL);
7423 if (ret < 0) {
7424 cerr << "ERROR: failed to parse start date" << std::endl;
7425 return EINVAL;
7426 }
7427 }
7428
7429 bool is_truncated = true;
7430 bool cls_filtered = true;
7431
7432 rgw_obj_index_key marker;
7433 string empty_prefix;
7434 string empty_delimiter;
7435
7436 formatter->open_object_section("result");
7437 formatter->dump_string("bucket", bucket_name);
7438 formatter->open_array_section("objects");
7439
7440 constexpr uint32_t NUM_ENTRIES = 1000;
7441 uint16_t expansion_factor = 1;
7442 while (is_truncated) {
7443 RGWRados::ent_map_t result;
7444 result.reserve(NUM_ENTRIES);
7445
7446 int r = static_cast<rgw::sal::RadosStore*>(store)->getRados()->cls_bucket_list_ordered(
7447 dpp(), bucket->get_info(), RGW_NO_SHARD,
7448 marker, empty_prefix, empty_delimiter,
7449 NUM_ENTRIES, true, expansion_factor,
7450 result, &is_truncated, &cls_filtered, &marker,
7451 null_yield,
7452 rgw_bucket_object_check_filter);
7453 if (r < 0 && r != -ENOENT) {
7454 cerr << "ERROR: failed operation r=" << r << std::endl;
7455 } else if (r == -ENOENT) {
7456 break;
7457 }
7458
7459 if (result.size() < NUM_ENTRIES / 8) {
7460 ++expansion_factor;
7461 } else if (result.size() > NUM_ENTRIES * 7 / 8 &&
7462 expansion_factor > 1) {
7463 --expansion_factor;
7464 }
7465
7466 for (auto iter = result.begin(); iter != result.end(); ++iter) {
7467 rgw_obj_key key = iter->second.key;
7468 rgw_bucket_dir_entry& entry = iter->second;
7469
7470 formatter->open_object_section("object");
7471 formatter->dump_string("name", key.name);
7472 formatter->dump_string("instance", key.instance);
7473 formatter->dump_int("size", entry.meta.size);
7474 utime_t ut(entry.meta.mtime);
7475 ut.gmtime(formatter->dump_stream("mtime"));
7476
7477 if ((entry.meta.size < min_rewrite_size) ||
7478 (entry.meta.size > max_rewrite_size) ||
7479 (start_epoch > 0 && start_epoch > (uint64_t)ut.sec()) ||
7480 (end_epoch > 0 && end_epoch < (uint64_t)ut.sec())) {
7481 formatter->dump_string("status", "Skipped");
7482 } else {
7483 std::unique_ptr<rgw::sal::Object> obj = bucket->get_object(key);
7484
7485 bool need_rewrite = true;
7486 if (min_rewrite_stripe_size > 0) {
7487 r = check_min_obj_stripe_size(store, obj.get(), min_rewrite_stripe_size, &need_rewrite);
7488 if (r < 0) {
7489 ldpp_dout(dpp(), 0) << "WARNING: check_min_obj_stripe_size failed, r=" << r << dendl;
7490 }
7491 }
7492 if (!need_rewrite) {
7493 formatter->dump_string("status", "Skipped");
7494 } else {
7495 r = static_cast<rgw::sal::RadosStore*>(store)->getRados()->rewrite_obj(obj.get(), dpp(), null_yield);
7496 if (r == 0) {
7497 formatter->dump_string("status", "Success");
7498 } else {
7499 formatter->dump_string("status", cpp_strerror(-r));
7500 }
7501 }
7502 }
7503 formatter->dump_int("flags", entry.flags);
7504
7505 formatter->close_section();
7506 formatter->flush(cout);
7507 }
7508 }
7509 formatter->close_section();
7510 formatter->close_section();
7511 formatter->flush(cout);
7512 }
7513
7514 if (opt_cmd == OPT::BUCKET_RESHARD) {
7515 int ret = check_reshard_bucket_params(static_cast<rgw::sal::RadosStore*>(store),
7516 bucket_name,
7517 tenant,
7518 bucket_id,
7519 num_shards_specified,
7520 num_shards,
7521 yes_i_really_mean_it,
7522 &bucket);
7523 if (ret < 0) {
7524 return ret;
7525 }
7526
7527 RGWBucketReshard br(static_cast<rgw::sal::RadosStore*>(store), bucket->get_info(), bucket->get_attrs(), nullptr /* no callback */);
7528
7529 #define DEFAULT_RESHARD_MAX_ENTRIES 1000
7530 if (max_entries < 1) {
7531 max_entries = DEFAULT_RESHARD_MAX_ENTRIES;
7532 }
7533
7534 return br.execute(num_shards, max_entries, dpp(),
7535 verbose, &cout, formatter.get());
7536 }
7537
7538 if (opt_cmd == OPT::RESHARD_ADD) {
7539 int ret = check_reshard_bucket_params(static_cast<rgw::sal::RadosStore*>(store),
7540 bucket_name,
7541 tenant,
7542 bucket_id,
7543 num_shards_specified,
7544 num_shards,
7545 yes_i_really_mean_it,
7546 &bucket);
7547 if (ret < 0) {
7548 return ret;
7549 }
7550
7551 int num_source_shards = (bucket->get_info().layout.current_index.layout.normal.num_shards > 0 ? bucket->get_info().layout.current_index.layout.normal.num_shards : 1);
7552
7553 RGWReshard reshard(static_cast<rgw::sal::RadosStore*>(store), dpp());
7554 cls_rgw_reshard_entry entry;
7555 entry.time = real_clock::now();
7556 entry.tenant = tenant;
7557 entry.bucket_name = bucket_name;
7558 entry.bucket_id = bucket->get_info().bucket.bucket_id;
7559 entry.old_num_shards = num_source_shards;
7560 entry.new_num_shards = num_shards;
7561
7562 return reshard.add(dpp(), entry);
7563 }
7564
7565 if (opt_cmd == OPT::RESHARD_LIST) {
7566 list<cls_rgw_reshard_entry> entries;
7567 int ret;
7568 int count = 0;
7569 if (max_entries < 0) {
7570 max_entries = 1000;
7571 }
7572
7573 int num_logshards =
7574 store->ctx()->_conf.get_val<uint64_t>("rgw_reshard_num_logs");
7575
7576 RGWReshard reshard(static_cast<rgw::sal::RadosStore*>(store), dpp());
7577
7578 formatter->open_array_section("reshard");
7579 for (int i = 0; i < num_logshards; i++) {
7580 bool is_truncated = true;
7581 string marker;
7582 do {
7583 entries.clear();
7584 ret = reshard.list(dpp(), i, marker, max_entries - count, entries, &is_truncated);
7585 if (ret < 0) {
7586 cerr << "Error listing resharding buckets: " << cpp_strerror(-ret) << std::endl;
7587 return ret;
7588 }
7589 for (auto iter=entries.begin(); iter != entries.end(); ++iter) {
7590 cls_rgw_reshard_entry& entry = *iter;
7591 encode_json("entry", entry, formatter.get());
7592 entry.get_key(&marker);
7593 }
7594 count += entries.size();
7595 formatter->flush(cout);
7596 } while (is_truncated && count < max_entries);
7597
7598 if (count >= max_entries) {
7599 break;
7600 }
7601 }
7602
7603 formatter->close_section();
7604 formatter->flush(cout);
7605 return 0;
7606 }
7607
7608 if (opt_cmd == OPT::RESHARD_STATUS) {
7609 if (bucket_name.empty()) {
7610 cerr << "ERROR: bucket not specified" << std::endl;
7611 return EINVAL;
7612 }
7613
7614 ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
7615 if (ret < 0) {
7616 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7617 return -ret;
7618 }
7619
7620 RGWBucketReshard br(static_cast<rgw::sal::RadosStore*>(store), bucket->get_info(), bucket->get_attrs(), nullptr /* no callback */);
7621 list<cls_rgw_bucket_instance_entry> status;
7622 int r = br.get_status(dpp(), &status);
7623 if (r < 0) {
7624 cerr << "ERROR: could not get resharding status for bucket " <<
7625 bucket_name << std::endl;
7626 return -r;
7627 }
7628
7629 show_reshard_status(status, formatter.get());
7630 }
7631
7632 if (opt_cmd == OPT::RESHARD_PROCESS) {
7633 RGWReshard reshard(static_cast<rgw::sal::RadosStore*>(store), true, &cout);
7634
7635 int ret = reshard.process_all_logshards(dpp());
7636 if (ret < 0) {
7637 cerr << "ERROR: failed to process reshard logs, error=" << cpp_strerror(-ret) << std::endl;
7638 return -ret;
7639 }
7640 }
7641
7642 if (opt_cmd == OPT::RESHARD_CANCEL) {
7643 if (bucket_name.empty()) {
7644 cerr << "ERROR: bucket not specified" << std::endl;
7645 return EINVAL;
7646 }
7647
7648 bool bucket_initable = true;
7649 ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
7650 if (ret < 0) {
7651 if (yes_i_really_mean_it) {
7652 bucket_initable = false;
7653 } else {
7654 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) <<
7655 "; if you want to cancel the reshard request nonetheless, please "
7656 "use the --yes-i-really-mean-it option" << std::endl;
7657 return -ret;
7658 }
7659 }
7660
7661 if (bucket_initable) {
7662 // we did not encounter an error, so let's work with the bucket
7663 RGWBucketReshard br(static_cast<rgw::sal::RadosStore*>(store), bucket->get_info(), bucket->get_attrs(),
7664 nullptr /* no callback */);
7665 int ret = br.cancel(dpp());
7666 if (ret < 0) {
7667 if (ret == -EBUSY) {
7668 cerr << "There is ongoing resharding, please retry after " <<
7669 store->ctx()->_conf.get_val<uint64_t>(
7670 "rgw_reshard_bucket_lock_duration") <<
7671 " seconds " << std::endl;
7672 } else {
7673 cerr << "Error canceling bucket " << bucket_name <<
7674 " resharding: " << cpp_strerror(-ret) << std::endl;
7675 }
7676 return ret;
7677 }
7678 }
7679
7680 RGWReshard reshard(static_cast<rgw::sal::RadosStore*>(store), dpp());
7681
7682 cls_rgw_reshard_entry entry;
7683 entry.tenant = tenant;
7684 entry.bucket_name = bucket_name;
7685 //entry.bucket_id = bucket_id;
7686
7687 ret = reshard.remove(dpp(), entry);
7688 if (ret < 0 && ret != -ENOENT) {
7689 cerr << "Error in updating reshard log with bucket " <<
7690 bucket_name << ": " << cpp_strerror(-ret) << std::endl;
7691 return ret;
7692 }
7693 } // OPT_RESHARD_CANCEL
7694
7695 if (opt_cmd == OPT::OBJECT_UNLINK) {
7696 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
7697 if (ret < 0) {
7698 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7699 return -ret;
7700 }
7701 list<rgw_obj_index_key> oid_list;
7702 rgw_obj_key key(object, object_version);
7703 rgw_obj_index_key index_key;
7704 key.get_index_key(&index_key);
7705 oid_list.push_back(index_key);
7706 ret = bucket->remove_objs_from_index(dpp(), oid_list);
7707 if (ret < 0) {
7708 cerr << "ERROR: remove_obj_from_index() returned error: " << cpp_strerror(-ret) << std::endl;
7709 return 1;
7710 }
7711 }
7712
7713 if (opt_cmd == OPT::OBJECT_STAT) {
7714 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
7715 if (ret < 0) {
7716 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7717 return -ret;
7718 }
7719 std::unique_ptr<rgw::sal::Object> obj = bucket->get_object(object);
7720 obj->set_instance(object_version);
7721
7722 RGWObjectCtx obj_ctx(store);
7723
7724 ret = obj->get_obj_attrs(&obj_ctx, null_yield, dpp());
7725 if (ret < 0) {
7726 cerr << "ERROR: failed to stat object, returned error: " << cpp_strerror(-ret) << std::endl;
7727 return 1;
7728 }
7729 formatter->open_object_section("object_metadata");
7730 formatter->dump_string("name", object);
7731 formatter->dump_unsigned("size", obj->get_obj_size());
7732
7733 map<string, bufferlist>::iterator iter;
7734 map<string, bufferlist> other_attrs;
7735 for (iter = obj->get_attrs().begin(); iter != obj->get_attrs().end(); ++iter) {
7736 bufferlist& bl = iter->second;
7737 bool handled = false;
7738 if (iter->first == RGW_ATTR_MANIFEST) {
7739 handled = decode_dump<RGWObjManifest>("manifest", bl, formatter.get());
7740 } else if (iter->first == RGW_ATTR_ACL) {
7741 handled = decode_dump<RGWAccessControlPolicy>("policy", bl, formatter.get());
7742 } else if (iter->first == RGW_ATTR_ID_TAG) {
7743 handled = dump_string("tag", bl, formatter.get());
7744 } else if (iter->first == RGW_ATTR_ETAG) {
7745 handled = dump_string("etag", bl, formatter.get());
7746 } else if (iter->first == RGW_ATTR_COMPRESSION) {
7747 handled = decode_dump<RGWCompressionInfo>("compression", bl, formatter.get());
7748 } else if (iter->first == RGW_ATTR_DELETE_AT) {
7749 handled = decode_dump<utime_t>("delete_at", bl, formatter.get());
7750 }
7751
7752 if (!handled)
7753 other_attrs[iter->first] = bl;
7754 }
7755
7756 formatter->open_object_section("attrs");
7757 for (iter = other_attrs.begin(); iter != other_attrs.end(); ++iter) {
7758 dump_string(iter->first.c_str(), iter->second, formatter.get());
7759 }
7760 formatter->close_section();
7761 formatter->close_section();
7762 formatter->flush(cout);
7763 }
7764
7765 if (opt_cmd == OPT::BUCKET_CHECK) {
7766 if (check_head_obj_locator) {
7767 if (bucket_name.empty()) {
7768 cerr << "ERROR: need to specify bucket name" << std::endl;
7769 return EINVAL;
7770 }
7771 do_check_object_locator(tenant, bucket_name, fix, remove_bad, formatter.get());
7772 } else {
7773 RGWBucketAdminOp::check_index(store, bucket_op, stream_flusher, null_yield, dpp());
7774 }
7775 }
7776
7777 if (opt_cmd == OPT::BUCKET_RM) {
7778 if (!inconsistent_index) {
7779 RGWBucketAdminOp::remove_bucket(store, bucket_op, null_yield, dpp(), bypass_gc, true);
7780 } else {
7781 if (!yes_i_really_mean_it) {
7782 cerr << "using --inconsistent_index can corrupt the bucket index " << std::endl
7783 << "do you really mean it? (requires --yes-i-really-mean-it)" << std::endl;
7784 return 1;
7785 }
7786 RGWBucketAdminOp::remove_bucket(store, bucket_op, null_yield, dpp(), bypass_gc, false);
7787 }
7788 }
7789
7790 if (opt_cmd == OPT::GC_LIST) {
7791 int index = 0;
7792 bool truncated;
7793 bool processing_queue = false;
7794 formatter->open_array_section("entries");
7795
7796 do {
7797 list<cls_rgw_gc_obj_info> result;
7798 int ret = static_cast<rgw::sal::RadosStore*>(store)->getRados()->list_gc_objs(&index, marker, 1000, !include_all, result, &truncated, processing_queue);
7799 if (ret < 0) {
7800 cerr << "ERROR: failed to list objs: " << cpp_strerror(-ret) << std::endl;
7801 return 1;
7802 }
7803
7804
7805 list<cls_rgw_gc_obj_info>::iterator iter;
7806 for (iter = result.begin(); iter != result.end(); ++iter) {
7807 cls_rgw_gc_obj_info& info = *iter;
7808 formatter->open_object_section("chain_info");
7809 formatter->dump_string("tag", info.tag);
7810 formatter->dump_stream("time") << info.time;
7811 formatter->open_array_section("objs");
7812 list<cls_rgw_obj>::iterator liter;
7813 cls_rgw_obj_chain& chain = info.chain;
7814 for (liter = chain.objs.begin(); liter != chain.objs.end(); ++liter) {
7815 cls_rgw_obj& obj = *liter;
7816 encode_json("obj", obj, formatter.get());
7817 }
7818 formatter->close_section(); // objs
7819 formatter->close_section(); // obj_chain
7820 formatter->flush(cout);
7821 }
7822 } while (truncated);
7823 formatter->close_section();
7824 formatter->flush(cout);
7825 }
7826
7827 if (opt_cmd == OPT::GC_PROCESS) {
7828 int ret = static_cast<rgw::sal::RadosStore*>(store)->getRados()->process_gc(!include_all);
7829 if (ret < 0) {
7830 cerr << "ERROR: gc processing returned error: " << cpp_strerror(-ret) << std::endl;
7831 return 1;
7832 }
7833 }
7834
7835 if (opt_cmd == OPT::LC_LIST) {
7836 formatter->open_array_section("lifecycle_list");
7837 vector<rgw::sal::Lifecycle::LCEntry> bucket_lc_map;
7838 string marker;
7839 int index{0};
7840 #define MAX_LC_LIST_ENTRIES 100
7841 if (max_entries < 0) {
7842 max_entries = MAX_LC_LIST_ENTRIES;
7843 }
7844 do {
7845 int ret = static_cast<rgw::sal::RadosStore*>(store)->getRados()->list_lc_progress(marker, max_entries,
7846 bucket_lc_map, index);
7847 if (ret < 0) {
7848 cerr << "ERROR: failed to list objs: " << cpp_strerror(-ret)
7849 << std::endl;
7850 return 1;
7851 }
7852 for (const auto& entry : bucket_lc_map) {
7853 formatter->open_object_section("bucket_lc_info");
7854 formatter->dump_string("bucket", entry.bucket);
7855 char exp_buf[100];
7856 time_t t{time_t(entry.start_time)};
7857 if (std::strftime(
7858 exp_buf, sizeof(exp_buf),
7859 "%a, %d %b %Y %T %Z", std::gmtime(&t))) {
7860 formatter->dump_string("started", exp_buf);
7861 }
7862 string lc_status = LC_STATUS[entry.status];
7863 formatter->dump_string("status", lc_status);
7864 formatter->close_section(); // objs
7865 formatter->flush(cout);
7866 }
7867 } while (!bucket_lc_map.empty());
7868
7869 formatter->close_section(); //lifecycle list
7870 formatter->flush(cout);
7871 }
7872
7873
7874 if (opt_cmd == OPT::LC_GET) {
7875 if (bucket_name.empty()) {
7876 cerr << "ERROR: bucket not specified" << std::endl;
7877 return EINVAL;
7878 }
7879
7880 RGWLifecycleConfiguration config;
7881 ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
7882 if (ret < 0) {
7883 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7884 return -ret;
7885 }
7886
7887 auto aiter = bucket->get_attrs().find(RGW_ATTR_LC);
7888 if (aiter == bucket->get_attrs().end()) {
7889 return -ENOENT;
7890 }
7891
7892 bufferlist::const_iterator iter{&aiter->second};
7893 try {
7894 config.decode(iter);
7895 } catch (const buffer::error& e) {
7896 cerr << "ERROR: decode life cycle config failed" << std::endl;
7897 return -EIO;
7898 }
7899
7900 encode_json("result", config, formatter.get());
7901 formatter->flush(cout);
7902 }
7903
7904 if (opt_cmd == OPT::LC_PROCESS) {
7905 if ((! bucket_name.empty()) ||
7906 (! bucket_id.empty())) {
7907 int ret = init_bucket(nullptr, tenant, bucket_name, bucket_id, &bucket);
7908 if (ret < 0) {
7909 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret)
7910 << std::endl;
7911 return ret;
7912 }
7913 }
7914
7915 int ret =
7916 static_cast<rgw::sal::RadosStore*>(store)->getRados()->process_lc(bucket);
7917 if (ret < 0) {
7918 cerr << "ERROR: lc processing returned error: " << cpp_strerror(-ret) << std::endl;
7919 return 1;
7920 }
7921 }
7922
7923 if (opt_cmd == OPT::LC_RESHARD_FIX) {
7924 ret = RGWBucketAdminOp::fix_lc_shards(store, bucket_op, stream_flusher, dpp());
7925 if (ret < 0) {
7926 cerr << "ERROR: fixing lc shards: " << cpp_strerror(-ret) << std::endl;
7927 }
7928
7929 }
7930
7931 if (opt_cmd == OPT::ORPHANS_FIND) {
7932 if (!yes_i_really_mean_it) {
7933 cerr << "this command is now deprecated; please consider using the rgw-orphan-list tool; "
7934 << "accidental removal of active objects cannot be reversed; "
7935 << "do you really mean it? (requires --yes-i-really-mean-it)"
7936 << std::endl;
7937 return EINVAL;
7938 } else {
7939 cerr << "IMPORTANT: this command is now deprecated; please consider using the rgw-orphan-list tool"
7940 << std::endl;
7941 }
7942
7943 RGWOrphanSearch search(static_cast<rgw::sal::RadosStore*>(store), max_concurrent_ios, orphan_stale_secs);
7944
7945 if (job_id.empty()) {
7946 cerr << "ERROR: --job-id not specified" << std::endl;
7947 return EINVAL;
7948 }
7949 if (pool_name.empty()) {
7950 cerr << "ERROR: --pool not specified" << std::endl;
7951 return EINVAL;
7952 }
7953
7954 RGWOrphanSearchInfo info;
7955
7956 info.pool = pool;
7957 info.job_name = job_id;
7958 info.num_shards = num_shards;
7959
7960 int ret = search.init(dpp(), job_id, &info, detail);
7961 if (ret < 0) {
7962 cerr << "could not init search, ret=" << ret << std::endl;
7963 return -ret;
7964 }
7965 ret = search.run(dpp());
7966 if (ret < 0) {
7967 return -ret;
7968 }
7969 }
7970
7971 if (opt_cmd == OPT::ORPHANS_FINISH) {
7972 if (!yes_i_really_mean_it) {
7973 cerr << "this command is now deprecated; please consider using the rgw-orphan-list tool; "
7974 << "accidental removal of active objects cannot be reversed; "
7975 << "do you really mean it? (requires --yes-i-really-mean-it)"
7976 << std::endl;
7977 return EINVAL;
7978 } else {
7979 cerr << "IMPORTANT: this command is now deprecated; please consider using the rgw-orphan-list tool"
7980 << std::endl;
7981 }
7982
7983 RGWOrphanSearch search(static_cast<rgw::sal::RadosStore*>(store), max_concurrent_ios, orphan_stale_secs);
7984
7985 if (job_id.empty()) {
7986 cerr << "ERROR: --job-id not specified" << std::endl;
7987 return EINVAL;
7988 }
7989 int ret = search.init(dpp(), job_id, NULL);
7990 if (ret < 0) {
7991 if (ret == -ENOENT) {
7992 cerr << "job not found" << std::endl;
7993 }
7994 return -ret;
7995 }
7996 ret = search.finish();
7997 if (ret < 0) {
7998 return -ret;
7999 }
8000 }
8001
8002 if (opt_cmd == OPT::ORPHANS_LIST_JOBS){
8003 if (!yes_i_really_mean_it) {
8004 cerr << "this command is now deprecated; please consider using the rgw-orphan-list tool; "
8005 << "do you really mean it? (requires --yes-i-really-mean-it)"
8006 << std::endl;
8007 return EINVAL;
8008 } else {
8009 cerr << "IMPORTANT: this command is now deprecated; please consider using the rgw-orphan-list tool"
8010 << std::endl;
8011 }
8012
8013 RGWOrphanStore orphan_store(static_cast<rgw::sal::RadosStore*>(store));
8014 int ret = orphan_store.init(dpp());
8015 if (ret < 0){
8016 cerr << "connection to cluster failed!" << std::endl;
8017 return -ret;
8018 }
8019
8020 map <string,RGWOrphanSearchState> m;
8021 ret = orphan_store.list_jobs(m);
8022 if (ret < 0) {
8023 cerr << "job list failed" << std::endl;
8024 return -ret;
8025 }
8026 formatter->open_array_section("entries");
8027 for (const auto &it: m){
8028 if (!extra_info){
8029 formatter->dump_string("job-id",it.first);
8030 } else {
8031 encode_json("orphan_search_state", it.second, formatter.get());
8032 }
8033 }
8034 formatter->close_section();
8035 formatter->flush(cout);
8036 }
8037
8038 if (opt_cmd == OPT::USER_CHECK) {
8039 check_bad_user_bucket_mapping(store, user.get(), fix, null_yield, dpp());
8040 }
8041
8042 if (opt_cmd == OPT::USER_STATS) {
8043 if (rgw::sal::User::empty(user)) {
8044 cerr << "ERROR: uid not specified" << std::endl;
8045 return EINVAL;
8046 }
8047 if (reset_stats) {
8048 if (!bucket_name.empty()) {
8049 cerr << "ERROR: --reset-stats does not work on buckets and "
8050 "bucket specified" << std::endl;
8051 return EINVAL;
8052 }
8053 if (sync_stats) {
8054 cerr << "ERROR: sync-stats includes the reset-stats functionality, "
8055 "so at most one of the two should be specified" << std::endl;
8056 return EINVAL;
8057 }
8058 ret = static_cast<rgw::sal::RadosStore*>(store)->ctl()->user->reset_stats(dpp(), user->get_id(), null_yield);
8059 if (ret < 0) {
8060 cerr << "ERROR: could not reset user stats: " << cpp_strerror(-ret) <<
8061 std::endl;
8062 return -ret;
8063 }
8064 }
8065
8066 if (sync_stats) {
8067 if (!bucket_name.empty()) {
8068 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
8069 if (ret < 0) {
8070 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
8071 return -ret;
8072 }
8073 ret = bucket->sync_user_stats(dpp(), null_yield);
8074 if (ret < 0) {
8075 cerr << "ERROR: could not sync bucket stats: " <<
8076 cpp_strerror(-ret) << std::endl;
8077 return -ret;
8078 }
8079 } else {
8080 int ret = rgw_user_sync_all_stats(dpp(), store, user.get(), null_yield);
8081 if (ret < 0) {
8082 cerr << "ERROR: could not sync user stats: " <<
8083 cpp_strerror(-ret) << std::endl;
8084 return -ret;
8085 }
8086 }
8087 }
8088
8089 constexpr bool omit_utilized_stats = false;
8090 RGWStorageStats stats(omit_utilized_stats);
8091 ceph::real_time last_stats_sync;
8092 ceph::real_time last_stats_update;
8093 int ret = static_cast<rgw::sal::RadosStore*>(store)->ctl()->user->read_stats(dpp(), user->get_id(), &stats, null_yield,
8094 &last_stats_sync,
8095 &last_stats_update);
8096 if (ret < 0) {
8097 if (ret == -ENOENT) { /* in case of ENOENT */
8098 cerr << "User has not been initialized or user does not exist" << std::endl;
8099 } else {
8100 cerr << "ERROR: can't read user: " << cpp_strerror(ret) << std::endl;
8101 }
8102 return -ret;
8103 }
8104
8105
8106 {
8107 Formatter::ObjectSection os(*formatter, "result");
8108 encode_json("stats", stats, formatter.get());
8109 utime_t last_sync_ut(last_stats_sync);
8110 encode_json("last_stats_sync", last_sync_ut, formatter.get());
8111 utime_t last_update_ut(last_stats_update);
8112 encode_json("last_stats_update", last_update_ut, formatter.get());
8113 }
8114 formatter->flush(cout);
8115 }
8116
8117 if (opt_cmd == OPT::METADATA_GET) {
8118 int ret = static_cast<rgw::sal::RadosStore*>(store)->ctl()->meta.mgr->get(metadata_key, formatter.get(), null_yield, dpp());
8119 if (ret < 0) {
8120 cerr << "ERROR: can't get key: " << cpp_strerror(-ret) << std::endl;
8121 return -ret;
8122 }
8123
8124 formatter->flush(cout);
8125 }
8126
8127 if (opt_cmd == OPT::METADATA_PUT) {
8128 bufferlist bl;
8129 int ret = read_input(infile, bl);
8130 if (ret < 0) {
8131 cerr << "ERROR: failed to read input: " << cpp_strerror(-ret) << std::endl;
8132 return -ret;
8133 }
8134 ret = static_cast<rgw::sal::RadosStore*>(store)->ctl()->meta.mgr->put(metadata_key, bl, null_yield, dpp(), RGWMDLogSyncType::APPLY_ALWAYS, false);
8135 if (ret < 0) {
8136 cerr << "ERROR: can't put key: " << cpp_strerror(-ret) << std::endl;
8137 return -ret;
8138 }
8139 }
8140
8141 if (opt_cmd == OPT::METADATA_RM) {
8142 int ret = static_cast<rgw::sal::RadosStore*>(store)->ctl()->meta.mgr->remove(metadata_key, null_yield, dpp());
8143 if (ret < 0) {
8144 cerr << "ERROR: can't remove key: " << cpp_strerror(-ret) << std::endl;
8145 return -ret;
8146 }
8147 }
8148
8149 if (opt_cmd == OPT::METADATA_LIST || opt_cmd == OPT::USER_LIST) {
8150 if (opt_cmd == OPT::USER_LIST) {
8151 metadata_key = "user";
8152 }
8153 void *handle;
8154 int max = 1000;
8155 int ret = store->meta_list_keys_init(dpp(), metadata_key, marker, &handle);
8156 if (ret < 0) {
8157 cerr << "ERROR: can't get key: " << cpp_strerror(-ret) << std::endl;
8158 return -ret;
8159 }
8160
8161 bool truncated;
8162 uint64_t count = 0;
8163
8164 if (max_entries_specified) {
8165 formatter->open_object_section("result");
8166 }
8167 formatter->open_array_section("keys");
8168
8169 uint64_t left;
8170 do {
8171 list<string> keys;
8172 left = (max_entries_specified ? max_entries - count : max);
8173 ret = store->meta_list_keys_next(dpp(), handle, left, keys, &truncated);
8174 if (ret < 0 && ret != -ENOENT) {
8175 cerr << "ERROR: lists_keys_next(): " << cpp_strerror(-ret) << std::endl;
8176 return -ret;
8177 } if (ret != -ENOENT) {
8178 for (list<string>::iterator iter = keys.begin(); iter != keys.end(); ++iter) {
8179 formatter->dump_string("key", *iter);
8180 ++count;
8181 }
8182 formatter->flush(cout);
8183 }
8184 } while (truncated && left > 0);
8185
8186 formatter->close_section();
8187
8188 if (max_entries_specified) {
8189 encode_json("truncated", truncated, formatter.get());
8190 encode_json("count", count, formatter.get());
8191 if (truncated) {
8192 encode_json("marker", store->meta_get_marker(handle), formatter.get());
8193 }
8194 formatter->close_section();
8195 }
8196 formatter->flush(cout);
8197
8198 store->meta_list_keys_complete(handle);
8199 }
8200
8201 if (opt_cmd == OPT::MDLOG_LIST) {
8202 if (!start_date.empty()) {
8203 std::cerr << "start-date not allowed." << std::endl;
8204 return -EINVAL;
8205 }
8206 if (!end_date.empty()) {
8207 std::cerr << "end-date not allowed." << std::endl;
8208 return -EINVAL;
8209 }
8210 if (!end_marker.empty()) {
8211 std::cerr << "end-marker not allowed." << std::endl;
8212 return -EINVAL;
8213 }
8214 if (!start_marker.empty()) {
8215 if (marker.empty()) {
8216 marker = start_marker;
8217 } else {
8218 std::cerr << "start-marker and marker not both allowed." << std::endl;
8219 return -EINVAL;
8220 }
8221 }
8222
8223 int i = (specified_shard_id ? shard_id : 0);
8224
8225 if (period_id.empty()) {
8226 int ret = read_current_period_id(static_cast<rgw::sal::RadosStore*>(store), realm_id, realm_name, &period_id);
8227 if (ret < 0) {
8228 return -ret;
8229 }
8230 std::cerr << "No --period given, using current period="
8231 << period_id << std::endl;
8232 }
8233 RGWMetadataLog *meta_log = static_cast<rgw::sal::RadosStore*>(store)->svc()->mdlog->get_log(period_id);
8234
8235 formatter->open_array_section("entries");
8236 for (; i < g_ceph_context->_conf->rgw_md_log_max_shards; i++) {
8237 void *handle;
8238 list<cls_log_entry> entries;
8239
8240 meta_log->init_list_entries(i, {}, {}, marker, &handle);
8241 bool truncated;
8242 do {
8243 int ret = meta_log->list_entries(dpp(), handle, 1000, entries, NULL, &truncated);
8244 if (ret < 0) {
8245 cerr << "ERROR: meta_log->list_entries(): " << cpp_strerror(-ret) << std::endl;
8246 return -ret;
8247 }
8248
8249 for (list<cls_log_entry>::iterator iter = entries.begin(); iter != entries.end(); ++iter) {
8250 cls_log_entry& entry = *iter;
8251 static_cast<rgw::sal::RadosStore*>(store)->ctl()->meta.mgr->dump_log_entry(entry, formatter.get());
8252 }
8253 formatter->flush(cout);
8254 } while (truncated);
8255
8256 meta_log->complete_list_entries(handle);
8257
8258 if (specified_shard_id)
8259 break;
8260 }
8261
8262
8263 formatter->close_section();
8264 formatter->flush(cout);
8265 }
8266
8267 if (opt_cmd == OPT::MDLOG_STATUS) {
8268 int i = (specified_shard_id ? shard_id : 0);
8269
8270 if (period_id.empty()) {
8271 int ret = read_current_period_id(static_cast<rgw::sal::RadosStore*>(store), realm_id, realm_name, &period_id);
8272 if (ret < 0) {
8273 return -ret;
8274 }
8275 std::cerr << "No --period given, using current period="
8276 << period_id << std::endl;
8277 }
8278 RGWMetadataLog *meta_log = static_cast<rgw::sal::RadosStore*>(store)->svc()->mdlog->get_log(period_id);
8279
8280 formatter->open_array_section("entries");
8281
8282 for (; i < g_ceph_context->_conf->rgw_md_log_max_shards; i++) {
8283 RGWMetadataLogInfo info;
8284 meta_log->get_info(dpp(), i, &info);
8285
8286 ::encode_json("info", info, formatter.get());
8287
8288 if (specified_shard_id)
8289 break;
8290 }
8291
8292
8293 formatter->close_section();
8294 formatter->flush(cout);
8295 }
8296
8297 if (opt_cmd == OPT::MDLOG_AUTOTRIM) {
8298 // need a full history for purging old mdlog periods
8299 static_cast<rgw::sal::RadosStore*>(store)->svc()->mdlog->init_oldest_log_period(null_yield, dpp());
8300
8301 RGWCoroutinesManager crs(store->ctx(), store->get_cr_registry());
8302 RGWHTTPManager http(store->ctx(), crs.get_completion_mgr());
8303 int ret = http.start();
8304 if (ret < 0) {
8305 cerr << "failed to initialize http client with " << cpp_strerror(ret) << std::endl;
8306 return -ret;
8307 }
8308
8309 auto num_shards = g_conf()->rgw_md_log_max_shards;
8310 auto mltcr = create_admin_meta_log_trim_cr(
8311 dpp(), static_cast<rgw::sal::RadosStore*>(store), &http, num_shards);
8312 if (!mltcr) {
8313 cerr << "Cluster misconfigured! Unable to trim." << std::endl;
8314 return -EIO;
8315 }
8316 ret = crs.run(dpp(), mltcr);
8317 if (ret < 0) {
8318 cerr << "automated mdlog trim failed with " << cpp_strerror(ret) << std::endl;
8319 return -ret;
8320 }
8321 }
8322
8323 if (opt_cmd == OPT::MDLOG_TRIM) {
8324 if (!start_date.empty()) {
8325 std::cerr << "start-date not allowed." << std::endl;
8326 return -EINVAL;
8327 }
8328 if (!end_date.empty()) {
8329 std::cerr << "end-date not allowed." << std::endl;
8330 return -EINVAL;
8331 }
8332 if (!start_marker.empty()) {
8333 std::cerr << "start-marker not allowed." << std::endl;
8334 return -EINVAL;
8335 }
8336 if (!end_marker.empty()) {
8337 if (marker.empty()) {
8338 marker = end_marker;
8339 } else {
8340 std::cerr << "end-marker and marker not both allowed." << std::endl;
8341 return -EINVAL;
8342 }
8343 }
8344
8345 if (!specified_shard_id) {
8346 cerr << "ERROR: shard-id must be specified for trim operation" << std::endl;
8347 return EINVAL;
8348 }
8349
8350 if (marker.empty()) {
8351 cerr << "ERROR: marker must be specified for trim operation" << std::endl;
8352 return EINVAL;
8353 }
8354
8355 if (period_id.empty()) {
8356 std::cerr << "missing --period argument" << std::endl;
8357 return EINVAL;
8358 }
8359 RGWMetadataLog *meta_log = static_cast<rgw::sal::RadosStore*>(store)->svc()->mdlog->get_log(period_id);
8360
8361 // trim until -ENODATA
8362 do {
8363 ret = meta_log->trim(dpp(), shard_id, {}, {}, {}, marker);
8364 } while (ret == 0);
8365 if (ret < 0 && ret != -ENODATA) {
8366 cerr << "ERROR: meta_log->trim(): " << cpp_strerror(-ret) << std::endl;
8367 return -ret;
8368 }
8369 }
8370
8371 if (opt_cmd == OPT::SYNC_INFO) {
8372 sync_info(opt_effective_zone_id, opt_bucket, zone_formatter.get());
8373 }
8374
8375 if (opt_cmd == OPT::SYNC_STATUS) {
8376 sync_status(formatter.get());
8377 }
8378
8379 if (opt_cmd == OPT::METADATA_SYNC_STATUS) {
8380 RGWMetaSyncStatusManager sync(static_cast<rgw::sal::RadosStore*>(store), static_cast<rgw::sal::RadosStore*>(store)->svc()->rados->get_async_processor());
8381
8382 int ret = sync.init(dpp());
8383 if (ret < 0) {
8384 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
8385 return -ret;
8386 }
8387
8388 rgw_meta_sync_status sync_status;
8389 ret = sync.read_sync_status(dpp(), &sync_status);
8390 if (ret < 0) {
8391 cerr << "ERROR: sync.read_sync_status() returned ret=" << ret << std::endl;
8392 return -ret;
8393 }
8394
8395 formatter->open_object_section("summary");
8396 encode_json("sync_status", sync_status, formatter.get());
8397
8398 uint64_t full_total = 0;
8399 uint64_t full_complete = 0;
8400
8401 for (auto marker_iter : sync_status.sync_markers) {
8402 full_total += marker_iter.second.total_entries;
8403 if (marker_iter.second.state == rgw_meta_sync_marker::SyncState::FullSync) {
8404 full_complete += marker_iter.second.pos;
8405 } else {
8406 full_complete += marker_iter.second.total_entries;
8407 }
8408 }
8409
8410 formatter->open_object_section("full_sync");
8411 encode_json("total", full_total, formatter.get());
8412 encode_json("complete", full_complete, formatter.get());
8413 formatter->close_section();
8414 formatter->close_section();
8415
8416 formatter->flush(cout);
8417
8418 }
8419
8420 if (opt_cmd == OPT::METADATA_SYNC_INIT) {
8421 RGWMetaSyncStatusManager sync(static_cast<rgw::sal::RadosStore*>(store), static_cast<rgw::sal::RadosStore*>(store)->svc()->rados->get_async_processor());
8422
8423 int ret = sync.init(dpp());
8424 if (ret < 0) {
8425 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
8426 return -ret;
8427 }
8428 ret = sync.init_sync_status(dpp());
8429 if (ret < 0) {
8430 cerr << "ERROR: sync.init_sync_status() returned ret=" << ret << std::endl;
8431 return -ret;
8432 }
8433 }
8434
8435
8436 if (opt_cmd == OPT::METADATA_SYNC_RUN) {
8437 RGWMetaSyncStatusManager sync(static_cast<rgw::sal::RadosStore*>(store), static_cast<rgw::sal::RadosStore*>(store)->svc()->rados->get_async_processor());
8438
8439 int ret = sync.init(dpp());
8440 if (ret < 0) {
8441 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
8442 return -ret;
8443 }
8444
8445 ret = sync.run(dpp(), null_yield);
8446 if (ret < 0) {
8447 cerr << "ERROR: sync.run() returned ret=" << ret << std::endl;
8448 return -ret;
8449 }
8450 }
8451
8452 if (opt_cmd == OPT::DATA_SYNC_STATUS) {
8453 if (source_zone.empty()) {
8454 cerr << "ERROR: source zone not specified" << std::endl;
8455 return EINVAL;
8456 }
8457 RGWDataSyncStatusManager sync(static_cast<rgw::sal::RadosStore*>(store), static_cast<rgw::sal::RadosStore*>(store)->svc()->rados->get_async_processor(), source_zone, nullptr);
8458
8459 int ret = sync.init(dpp());
8460 if (ret < 0) {
8461 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
8462 return -ret;
8463 }
8464
8465 rgw_data_sync_status sync_status;
8466 if (specified_shard_id) {
8467 set<string> pending_buckets;
8468 set<string> recovering_buckets;
8469 rgw_data_sync_marker sync_marker;
8470 ret = sync.read_shard_status(dpp(), shard_id, pending_buckets, recovering_buckets, &sync_marker,
8471 max_entries_specified ? max_entries : 20);
8472 if (ret < 0 && ret != -ENOENT) {
8473 cerr << "ERROR: sync.read_shard_status() returned ret=" << ret << std::endl;
8474 return -ret;
8475 }
8476 formatter->open_object_section("summary");
8477 encode_json("shard_id", shard_id, formatter.get());
8478 encode_json("marker", sync_marker, formatter.get());
8479 encode_json("pending_buckets", pending_buckets, formatter.get());
8480 encode_json("recovering_buckets", recovering_buckets, formatter.get());
8481 formatter->close_section();
8482 formatter->flush(cout);
8483 } else {
8484 ret = sync.read_sync_status(dpp(), &sync_status);
8485 if (ret < 0 && ret != -ENOENT) {
8486 cerr << "ERROR: sync.read_sync_status() returned ret=" << ret << std::endl;
8487 return -ret;
8488 }
8489
8490 formatter->open_object_section("summary");
8491 encode_json("sync_status", sync_status, formatter.get());
8492
8493 uint64_t full_total = 0;
8494 uint64_t full_complete = 0;
8495
8496 for (auto marker_iter : sync_status.sync_markers) {
8497 full_total += marker_iter.second.total_entries;
8498 if (marker_iter.second.state == rgw_meta_sync_marker::SyncState::FullSync) {
8499 full_complete += marker_iter.second.pos;
8500 } else {
8501 full_complete += marker_iter.second.total_entries;
8502 }
8503 }
8504
8505 formatter->open_object_section("full_sync");
8506 encode_json("total", full_total, formatter.get());
8507 encode_json("complete", full_complete, formatter.get());
8508 formatter->close_section();
8509 formatter->close_section();
8510
8511 formatter->flush(cout);
8512 }
8513 }
8514
8515 if (opt_cmd == OPT::DATA_SYNC_INIT) {
8516 if (source_zone.empty()) {
8517 cerr << "ERROR: source zone not specified" << std::endl;
8518 return EINVAL;
8519 }
8520
8521 RGWDataSyncStatusManager sync(static_cast<rgw::sal::RadosStore*>(store), static_cast<rgw::sal::RadosStore*>(store)->svc()->rados->get_async_processor(), source_zone, nullptr);
8522
8523 int ret = sync.init(dpp());
8524 if (ret < 0) {
8525 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
8526 return -ret;
8527 }
8528
8529 ret = sync.init_sync_status(dpp());
8530 if (ret < 0) {
8531 cerr << "ERROR: sync.init_sync_status() returned ret=" << ret << std::endl;
8532 return -ret;
8533 }
8534 }
8535
8536 if (opt_cmd == OPT::DATA_SYNC_RUN) {
8537 if (source_zone.empty()) {
8538 cerr << "ERROR: source zone not specified" << std::endl;
8539 return EINVAL;
8540 }
8541
8542 RGWSyncModuleInstanceRef sync_module;
8543 int ret = static_cast<rgw::sal::RadosStore*>(store)->svc()->sync_modules->get_manager()->create_instance(dpp(), g_ceph_context, static_cast<rgw::sal::RadosStore*>(store)->svc()->zone->get_zone().tier_type,
8544 store->get_zone()->get_params().tier_config, &sync_module);
8545 if (ret < 0) {
8546 ldpp_dout(dpp(), -1) << "ERROR: failed to init sync module instance, ret=" << ret << dendl;
8547 return ret;
8548 }
8549
8550 RGWDataSyncStatusManager sync(static_cast<rgw::sal::RadosStore*>(store), static_cast<rgw::sal::RadosStore*>(store)->svc()->rados->get_async_processor(), source_zone, nullptr, sync_module);
8551
8552 ret = sync.init(dpp());
8553 if (ret < 0) {
8554 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
8555 return -ret;
8556 }
8557
8558 ret = sync.run(dpp());
8559 if (ret < 0) {
8560 cerr << "ERROR: sync.run() returned ret=" << ret << std::endl;
8561 return -ret;
8562 }
8563 }
8564
8565 if (opt_cmd == OPT::BUCKET_SYNC_INIT) {
8566 if (source_zone.empty()) {
8567 cerr << "ERROR: source zone not specified" << std::endl;
8568 return EINVAL;
8569 }
8570 if (bucket_name.empty()) {
8571 cerr << "ERROR: bucket not specified" << std::endl;
8572 return EINVAL;
8573 }
8574 int ret = init_bucket_for_sync(user.get(), tenant, bucket_name, bucket_id, &bucket);
8575 if (ret < 0) {
8576 return -ret;
8577 }
8578 auto opt_sb = opt_source_bucket;
8579 if (opt_sb && opt_sb->bucket_id.empty()) {
8580 string sbid;
8581 std::unique_ptr<rgw::sal::Bucket> sbuck;
8582 int ret = init_bucket_for_sync(user.get(), opt_sb->tenant, opt_sb->name, sbid, &sbuck);
8583 if (ret < 0) {
8584 return -ret;
8585 }
8586 opt_sb = sbuck->get_key();
8587 }
8588
8589 RGWBucketPipeSyncStatusManager sync(static_cast<rgw::sal::RadosStore*>(store), source_zone, opt_sb, bucket->get_key());
8590
8591 ret = sync.init(dpp());
8592 if (ret < 0) {
8593 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
8594 return -ret;
8595 }
8596 ret = sync.init_sync_status(dpp());
8597 if (ret < 0) {
8598 cerr << "ERROR: sync.init_sync_status() returned ret=" << ret << std::endl;
8599 return -ret;
8600 }
8601 }
8602
8603 if (opt_cmd == OPT::BUCKET_SYNC_CHECKPOINT) {
8604 std::optional<rgw_zone_id> opt_source_zone;
8605 if (!source_zone.empty()) {
8606 opt_source_zone = source_zone;
8607 }
8608 if (bucket_name.empty()) {
8609 cerr << "ERROR: bucket not specified" << std::endl;
8610 return EINVAL;
8611 }
8612 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
8613 if (ret < 0) {
8614 return -ret;
8615 }
8616
8617 if (!static_cast<rgw::sal::RadosStore*>(store)->ctl()->bucket->bucket_imports_data(bucket->get_key(), null_yield, dpp())) {
8618 std::cout << "Sync is disabled for bucket " << bucket_name << std::endl;
8619 return 0;
8620 }
8621
8622 RGWBucketSyncPolicyHandlerRef handler;
8623 ret = store->get_sync_policy_handler(dpp(), std::nullopt, bucket->get_key(), &handler, null_yield);
8624 if (ret < 0) {
8625 std::cerr << "ERROR: failed to get policy handler for bucket ("
8626 << bucket << "): r=" << ret << ": " << cpp_strerror(-ret) << std::endl;
8627 return -ret;
8628 }
8629
8630 auto timeout_at = ceph::coarse_mono_clock::now() + opt_timeout_sec;
8631 ret = rgw_bucket_sync_checkpoint(dpp(), static_cast<rgw::sal::RadosStore*>(store), *handler, bucket->get_info(),
8632 opt_source_zone, opt_source_bucket,
8633 opt_retry_delay_ms, timeout_at);
8634 if (ret < 0) {
8635 ldpp_dout(dpp(), -1) << "bucket sync checkpoint failed: " << cpp_strerror(ret) << dendl;
8636 return -ret;
8637 }
8638 }
8639
8640 if ((opt_cmd == OPT::BUCKET_SYNC_DISABLE) || (opt_cmd == OPT::BUCKET_SYNC_ENABLE)) {
8641 if (bucket_name.empty()) {
8642 cerr << "ERROR: bucket not specified" << std::endl;
8643 return EINVAL;
8644 }
8645 if (opt_cmd == OPT::BUCKET_SYNC_DISABLE) {
8646 bucket_op.set_sync_bucket(false);
8647 } else {
8648 bucket_op.set_sync_bucket(true);
8649 }
8650 bucket_op.set_tenant(tenant);
8651 string err_msg;
8652 ret = RGWBucketAdminOp::sync_bucket(store, bucket_op, dpp(), &err_msg);
8653 if (ret < 0) {
8654 cerr << err_msg << std::endl;
8655 return -ret;
8656 }
8657 }
8658
8659 if (opt_cmd == OPT::BUCKET_SYNC_INFO) {
8660 if (bucket_name.empty()) {
8661 cerr << "ERROR: bucket not specified" << std::endl;
8662 return EINVAL;
8663 }
8664 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
8665 if (ret < 0) {
8666 return -ret;
8667 }
8668 bucket_sync_info(static_cast<rgw::sal::RadosStore*>(store), bucket->get_info(), std::cout);
8669 }
8670
8671 if (opt_cmd == OPT::BUCKET_SYNC_STATUS) {
8672 if (bucket_name.empty()) {
8673 cerr << "ERROR: bucket not specified" << std::endl;
8674 return EINVAL;
8675 }
8676 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
8677 if (ret < 0) {
8678 return -ret;
8679 }
8680 bucket_sync_status(static_cast<rgw::sal::RadosStore*>(store), bucket->get_info(), source_zone, opt_source_bucket, std::cout);
8681 }
8682
8683 if (opt_cmd == OPT::BUCKET_SYNC_MARKERS) {
8684 if (source_zone.empty()) {
8685 cerr << "ERROR: source zone not specified" << std::endl;
8686 return EINVAL;
8687 }
8688 if (bucket_name.empty()) {
8689 cerr << "ERROR: bucket not specified" << std::endl;
8690 return EINVAL;
8691 }
8692 int ret = init_bucket_for_sync(user.get(), tenant, bucket_name, bucket_id, &bucket);
8693 if (ret < 0) {
8694 return -ret;
8695 }
8696 RGWBucketPipeSyncStatusManager sync(static_cast<rgw::sal::RadosStore*>(store), source_zone, opt_source_bucket, bucket->get_key());
8697
8698 ret = sync.init(dpp());
8699 if (ret < 0) {
8700 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
8701 return -ret;
8702 }
8703 ret = sync.read_sync_status(dpp());
8704 if (ret < 0) {
8705 cerr << "ERROR: sync.read_sync_status() returned ret=" << ret << std::endl;
8706 return -ret;
8707 }
8708
8709 map<int, rgw_bucket_shard_sync_info>& sync_status = sync.get_sync_status();
8710
8711 encode_json("sync_status", sync_status, formatter.get());
8712 formatter->flush(cout);
8713 }
8714
8715 if (opt_cmd == OPT::BUCKET_SYNC_RUN) {
8716 if (source_zone.empty()) {
8717 cerr << "ERROR: source zone not specified" << std::endl;
8718 return EINVAL;
8719 }
8720 if (bucket_name.empty()) {
8721 cerr << "ERROR: bucket not specified" << std::endl;
8722 return EINVAL;
8723 }
8724 int ret = init_bucket_for_sync(user.get(), tenant, bucket_name, bucket_id, &bucket);
8725 if (ret < 0) {
8726 return -ret;
8727 }
8728 RGWBucketPipeSyncStatusManager sync(static_cast<rgw::sal::RadosStore*>(store), source_zone, opt_source_bucket, bucket->get_key());
8729
8730 ret = sync.init(dpp());
8731 if (ret < 0) {
8732 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
8733 return -ret;
8734 }
8735
8736 ret = sync.run(dpp());
8737 if (ret < 0) {
8738 cerr << "ERROR: sync.run() returned ret=" << ret << std::endl;
8739 return -ret;
8740 }
8741 }
8742
8743 if (opt_cmd == OPT::BILOG_LIST) {
8744 if (bucket_name.empty()) {
8745 cerr << "ERROR: bucket not specified" << std::endl;
8746 return EINVAL;
8747 }
8748 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
8749 if (ret < 0) {
8750 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
8751 return -ret;
8752 }
8753 formatter->open_array_section("entries");
8754 bool truncated;
8755 int count = 0;
8756 if (max_entries < 0)
8757 max_entries = 1000;
8758
8759 do {
8760 list<rgw_bi_log_entry> entries;
8761 ret = static_cast<rgw::sal::RadosStore*>(store)->svc()->bilog_rados->log_list(dpp(), bucket->get_info(), shard_id, marker, max_entries - count, entries, &truncated);
8762 if (ret < 0) {
8763 cerr << "ERROR: list_bi_log_entries(): " << cpp_strerror(-ret) << std::endl;
8764 return -ret;
8765 }
8766
8767 count += entries.size();
8768
8769 for (list<rgw_bi_log_entry>::iterator iter = entries.begin(); iter != entries.end(); ++iter) {
8770 rgw_bi_log_entry& entry = *iter;
8771 encode_json("entry", entry, formatter.get());
8772
8773 marker = entry.id;
8774 }
8775 formatter->flush(cout);
8776 } while (truncated && count < max_entries);
8777
8778 formatter->close_section();
8779 formatter->flush(cout);
8780 }
8781
8782 if (opt_cmd == OPT::SYNC_ERROR_LIST) {
8783 if (max_entries < 0) {
8784 max_entries = 1000;
8785 }
8786 if (!start_date.empty()) {
8787 std::cerr << "start-date not allowed." << std::endl;
8788 return -EINVAL;
8789 }
8790 if (!end_date.empty()) {
8791 std::cerr << "end-date not allowed." << std::endl;
8792 return -EINVAL;
8793 }
8794 if (!end_marker.empty()) {
8795 std::cerr << "end-marker not allowed." << std::endl;
8796 return -EINVAL;
8797 }
8798 if (!start_marker.empty()) {
8799 if (marker.empty()) {
8800 marker = start_marker;
8801 } else {
8802 std::cerr << "start-marker and marker not both allowed." << std::endl;
8803 return -EINVAL;
8804 }
8805 }
8806
8807 bool truncated;
8808
8809 if (shard_id < 0) {
8810 shard_id = 0;
8811 }
8812
8813 formatter->open_array_section("entries");
8814
8815 for (; shard_id < ERROR_LOGGER_SHARDS; ++shard_id) {
8816 formatter->open_object_section("shard");
8817 encode_json("shard_id", shard_id, formatter.get());
8818 formatter->open_array_section("entries");
8819
8820 int count = 0;
8821 string oid = RGWSyncErrorLogger::get_shard_oid(RGW_SYNC_ERROR_LOG_SHARD_PREFIX, shard_id);
8822
8823 do {
8824 list<cls_log_entry> entries;
8825 ret = static_cast<rgw::sal::RadosStore*>(store)->svc()->cls->timelog.list(dpp(), oid, {}, {}, max_entries - count, entries, marker, &marker, &truncated,
8826 null_yield);
8827 if (ret == -ENOENT) {
8828 break;
8829 }
8830 if (ret < 0) {
8831 cerr << "ERROR: svc.cls->timelog.list(): " << cpp_strerror(-ret) << std::endl;
8832 return -ret;
8833 }
8834
8835 count += entries.size();
8836
8837 for (auto& cls_entry : entries) {
8838 rgw_sync_error_info log_entry;
8839
8840 auto iter = cls_entry.data.cbegin();
8841 try {
8842 decode(log_entry, iter);
8843 } catch (buffer::error& err) {
8844 cerr << "ERROR: failed to decode log entry" << std::endl;
8845 continue;
8846 }
8847 formatter->open_object_section("entry");
8848 encode_json("id", cls_entry.id, formatter.get());
8849 encode_json("section", cls_entry.section, formatter.get());
8850 encode_json("name", cls_entry.name, formatter.get());
8851 encode_json("timestamp", cls_entry.timestamp, formatter.get());
8852 encode_json("info", log_entry, formatter.get());
8853 formatter->close_section();
8854 formatter->flush(cout);
8855 }
8856 } while (truncated && count < max_entries);
8857
8858 formatter->close_section();
8859 formatter->close_section();
8860
8861 if (specified_shard_id) {
8862 break;
8863 }
8864 }
8865
8866 formatter->close_section();
8867 formatter->flush(cout);
8868 }
8869
8870 if (opt_cmd == OPT::SYNC_ERROR_TRIM) {
8871 if (!start_date.empty()) {
8872 std::cerr << "start-date not allowed." << std::endl;
8873 return -EINVAL;
8874 }
8875 if (!end_date.empty()) {
8876 std::cerr << "end-date not allowed." << std::endl;
8877 return -EINVAL;
8878 }
8879 if (!start_marker.empty()) {
8880 std::cerr << "end-date not allowed." << std::endl;
8881 return -EINVAL;
8882 }
8883 if (!end_marker.empty()) {
8884 std::cerr << "end-date not allowed." << std::endl;
8885 return -EINVAL;
8886 }
8887
8888 if (shard_id < 0) {
8889 shard_id = 0;
8890 }
8891
8892 for (; shard_id < ERROR_LOGGER_SHARDS; ++shard_id) {
8893 ret = trim_sync_error_log(shard_id, marker, trim_delay_ms);
8894 if (ret < 0) {
8895 cerr << "ERROR: sync error trim: " << cpp_strerror(-ret) << std::endl;
8896 return -ret;
8897 }
8898 if (specified_shard_id) {
8899 break;
8900 }
8901 }
8902 }
8903
8904 if (opt_cmd == OPT::SYNC_GROUP_CREATE ||
8905 opt_cmd == OPT::SYNC_GROUP_MODIFY) {
8906 CHECK_TRUE(require_opt(opt_group_id), "ERROR: --group-id not specified", EINVAL);
8907 CHECK_TRUE(require_opt(opt_status), "ERROR: --status is not specified (options: forbidden, allowed, enabled)", EINVAL);
8908
8909 SyncPolicyContext sync_policy_ctx(zonegroup_id, zonegroup_name, opt_bucket);
8910 ret = sync_policy_ctx.init();
8911 if (ret < 0) {
8912 return -ret;
8913 }
8914 auto& sync_policy = sync_policy_ctx.get_policy();
8915
8916 if (opt_cmd == OPT::SYNC_GROUP_MODIFY) {
8917 auto iter = sync_policy.groups.find(*opt_group_id);
8918 if (iter == sync_policy.groups.end()) {
8919 cerr << "ERROR: could not find group '" << *opt_group_id << "'" << std::endl;
8920 return ENOENT;
8921 }
8922 }
8923
8924 auto& group = sync_policy.groups[*opt_group_id];
8925 group.id = *opt_group_id;
8926
8927 if (opt_status) {
8928 if (!group.set_status(*opt_status)) {
8929 cerr << "ERROR: unrecognized status (options: forbidden, allowed, enabled)" << std::endl;
8930 return EINVAL;
8931 }
8932 }
8933
8934 ret = sync_policy_ctx.write_policy();
8935 if (ret < 0) {
8936 return -ret;
8937 }
8938
8939 show_result(sync_policy, zone_formatter.get(), cout);
8940 }
8941
8942 if (opt_cmd == OPT::SYNC_GROUP_GET) {
8943 SyncPolicyContext sync_policy_ctx(zonegroup_id, zonegroup_name, opt_bucket);
8944 ret = sync_policy_ctx.init();
8945 if (ret < 0) {
8946 return -ret;
8947 }
8948 auto& sync_policy = sync_policy_ctx.get_policy();
8949
8950 auto& groups = sync_policy.groups;
8951
8952 if (!opt_group_id) {
8953 show_result(groups, zone_formatter.get(), cout);
8954 } else {
8955 auto iter = sync_policy.groups.find(*opt_group_id);
8956 if (iter == sync_policy.groups.end()) {
8957 cerr << "ERROR: could not find group '" << *opt_group_id << "'" << std::endl;
8958 return ENOENT;
8959 }
8960
8961 show_result(iter->second, zone_formatter.get(), cout);
8962 }
8963 }
8964
8965 if (opt_cmd == OPT::SYNC_GROUP_REMOVE) {
8966 CHECK_TRUE(require_opt(opt_group_id), "ERROR: --group-id not specified", EINVAL);
8967
8968 SyncPolicyContext sync_policy_ctx(zonegroup_id, zonegroup_name, opt_bucket);
8969 ret = sync_policy_ctx.init();
8970 if (ret < 0) {
8971 return -ret;
8972 }
8973 auto& sync_policy = sync_policy_ctx.get_policy();
8974
8975 sync_policy.groups.erase(*opt_group_id);
8976
8977 ret = sync_policy_ctx.write_policy();
8978 if (ret < 0) {
8979 return -ret;
8980 }
8981
8982 {
8983 Formatter::ObjectSection os(*zone_formatter.get(), "result");
8984 encode_json("sync_policy", sync_policy, zone_formatter.get());
8985 }
8986
8987 zone_formatter->flush(cout);
8988 }
8989
8990 if (opt_cmd == OPT::SYNC_GROUP_FLOW_CREATE) {
8991 CHECK_TRUE(require_opt(opt_group_id), "ERROR: --group-id not specified", EINVAL);
8992 CHECK_TRUE(require_opt(opt_flow_id), "ERROR: --flow-id not specified", EINVAL);
8993 CHECK_TRUE(require_opt(opt_flow_type,
8994 (symmetrical_flow_opt(*opt_flow_type) ||
8995 directional_flow_opt(*opt_flow_type))),
8996 "ERROR: --flow-type not specified or invalid (options: symmetrical, directional)", EINVAL);
8997
8998 SyncPolicyContext sync_policy_ctx(zonegroup_id, zonegroup_name, opt_bucket);
8999 ret = sync_policy_ctx.init();
9000 if (ret < 0) {
9001 return -ret;
9002 }
9003 auto& sync_policy = sync_policy_ctx.get_policy();
9004
9005 auto iter = sync_policy.groups.find(*opt_group_id);
9006 if (iter == sync_policy.groups.end()) {
9007 cerr << "ERROR: could not find group '" << *opt_group_id << "'" << std::endl;
9008 return ENOENT;
9009 }
9010
9011 auto& group = iter->second;
9012
9013 if (symmetrical_flow_opt(*opt_flow_type)) {
9014 CHECK_TRUE(require_non_empty_opt(opt_zone_ids), "ERROR: --zones not provided for symmetrical flow, or is empty", EINVAL);
9015
9016 rgw_sync_symmetric_group *flow_group;
9017
9018 group.data_flow.find_or_create_symmetrical(*opt_flow_id, &flow_group);
9019
9020 for (auto& z : *opt_zone_ids) {
9021 flow_group->zones.insert(z);
9022 }
9023 } else { /* directional */
9024 CHECK_TRUE(require_non_empty_opt(opt_source_zone_id), "ERROR: --source-zone not provided for directional flow rule, or is empty", EINVAL);
9025 CHECK_TRUE(require_non_empty_opt(opt_dest_zone_id), "ERROR: --dest-zone not provided for directional flow rule, or is empty", EINVAL);
9026
9027 rgw_sync_directional_rule *flow_rule;
9028
9029 group.data_flow.find_or_create_directional(*opt_source_zone_id, *opt_dest_zone_id, &flow_rule);
9030 }
9031
9032 ret = sync_policy_ctx.write_policy();
9033 if (ret < 0) {
9034 return -ret;
9035 }
9036
9037 show_result(sync_policy, zone_formatter.get(), cout);
9038 }
9039
9040 if (opt_cmd == OPT::SYNC_GROUP_FLOW_REMOVE) {
9041 CHECK_TRUE(require_opt(opt_group_id), "ERROR: --group-id not specified", EINVAL);
9042 CHECK_TRUE(require_opt(opt_flow_id), "ERROR: --flow-id not specified", EINVAL);
9043 CHECK_TRUE(require_opt(opt_flow_type,
9044 (symmetrical_flow_opt(*opt_flow_type) ||
9045 directional_flow_opt(*opt_flow_type))),
9046 "ERROR: --flow-type not specified or invalid (options: symmetrical, directional)", EINVAL);
9047
9048 SyncPolicyContext sync_policy_ctx(zonegroup_id, zonegroup_name, opt_bucket);
9049 ret = sync_policy_ctx.init();
9050 if (ret < 0) {
9051 return -ret;
9052 }
9053 auto& sync_policy = sync_policy_ctx.get_policy();
9054
9055 auto iter = sync_policy.groups.find(*opt_group_id);
9056 if (iter == sync_policy.groups.end()) {
9057 cerr << "ERROR: could not find group '" << *opt_group_id << "'" << std::endl;
9058 return ENOENT;
9059 }
9060
9061 auto& group = iter->second;
9062
9063 if (symmetrical_flow_opt(*opt_flow_type)) {
9064 group.data_flow.remove_symmetrical(*opt_flow_id, opt_zone_ids);
9065 } else { /* directional */
9066 CHECK_TRUE(require_non_empty_opt(opt_source_zone_id), "ERROR: --source-zone not provided for directional flow rule, or is empty", EINVAL);
9067 CHECK_TRUE(require_non_empty_opt(opt_dest_zone_id), "ERROR: --dest-zone not provided for directional flow rule, or is empty", EINVAL);
9068
9069 group.data_flow.remove_directional(*opt_source_zone_id, *opt_dest_zone_id);
9070 }
9071
9072 ret = sync_policy_ctx.write_policy();
9073 if (ret < 0) {
9074 return -ret;
9075 }
9076
9077 show_result(sync_policy, zone_formatter.get(), cout);
9078 }
9079
9080 if (opt_cmd == OPT::SYNC_GROUP_PIPE_CREATE ||
9081 opt_cmd == OPT::SYNC_GROUP_PIPE_MODIFY) {
9082 CHECK_TRUE(require_opt(opt_group_id), "ERROR: --group-id not specified", EINVAL);
9083 CHECK_TRUE(require_opt(opt_pipe_id), "ERROR: --pipe-id not specified", EINVAL);
9084 if (opt_cmd == OPT::SYNC_GROUP_PIPE_CREATE) {
9085 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);
9086 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);
9087 }
9088
9089 SyncPolicyContext sync_policy_ctx(zonegroup_id, zonegroup_name, opt_bucket);
9090 ret = sync_policy_ctx.init();
9091 if (ret < 0) {
9092 return -ret;
9093 }
9094 auto& sync_policy = sync_policy_ctx.get_policy();
9095
9096 auto iter = sync_policy.groups.find(*opt_group_id);
9097 if (iter == sync_policy.groups.end()) {
9098 cerr << "ERROR: could not find group '" << *opt_group_id << "'" << std::endl;
9099 return ENOENT;
9100 }
9101
9102 auto& group = iter->second;
9103
9104 rgw_sync_bucket_pipes *pipe;
9105
9106 if (opt_cmd == OPT::SYNC_GROUP_PIPE_CREATE) {
9107 group.find_pipe(*opt_pipe_id, true, &pipe);
9108 } else {
9109 if (!group.find_pipe(*opt_pipe_id, false, &pipe)) {
9110 cerr << "ERROR: could not find pipe '" << *opt_pipe_id << "'" << std::endl;
9111 return ENOENT;
9112 }
9113 }
9114
9115 pipe->source.add_zones(*opt_source_zone_ids);
9116 pipe->source.set_bucket(opt_source_tenant,
9117 opt_source_bucket_name,
9118 opt_source_bucket_id);
9119 pipe->dest.add_zones(*opt_dest_zone_ids);
9120 pipe->dest.set_bucket(opt_dest_tenant,
9121 opt_dest_bucket_name,
9122 opt_dest_bucket_id);
9123
9124 pipe->params.source.filter.set_prefix(opt_prefix, !!opt_prefix_rm);
9125 pipe->params.source.filter.set_tags(tags_add, tags_rm);
9126 if (opt_dest_owner) {
9127 pipe->params.dest.set_owner(*opt_dest_owner);
9128 }
9129 if (opt_storage_class) {
9130 pipe->params.dest.set_storage_class(*opt_storage_class);
9131 }
9132 if (opt_priority) {
9133 pipe->params.priority = *opt_priority;
9134 }
9135 if (opt_mode) {
9136 if (*opt_mode == "system") {
9137 pipe->params.mode = rgw_sync_pipe_params::MODE_SYSTEM;
9138 } else if (*opt_mode == "user") {
9139 pipe->params.mode = rgw_sync_pipe_params::MODE_USER;
9140 } else {
9141 cerr << "ERROR: bad mode value: should be one of the following: system, user" << std::endl;
9142 return EINVAL;
9143 }
9144 }
9145
9146 if (!rgw::sal::User::empty(user)) {
9147 pipe->params.user = user->get_id();
9148 } else if (pipe->params.user.empty()) {
9149 auto owner = sync_policy_ctx.get_owner();
9150 if (owner) {
9151 pipe->params.user = *owner;
9152 }
9153 }
9154
9155 ret = sync_policy_ctx.write_policy();
9156 if (ret < 0) {
9157 return -ret;
9158 }
9159
9160 show_result(sync_policy, zone_formatter.get(), cout);
9161 }
9162
9163 if (opt_cmd == OPT::SYNC_GROUP_PIPE_REMOVE) {
9164 CHECK_TRUE(require_opt(opt_group_id), "ERROR: --group-id not specified", EINVAL);
9165 CHECK_TRUE(require_opt(opt_pipe_id), "ERROR: --pipe-id not specified", EINVAL);
9166
9167 SyncPolicyContext sync_policy_ctx(zonegroup_id, zonegroup_name, opt_bucket);
9168 ret = sync_policy_ctx.init();
9169 if (ret < 0) {
9170 return -ret;
9171 }
9172 auto& sync_policy = sync_policy_ctx.get_policy();
9173
9174 auto iter = sync_policy.groups.find(*opt_group_id);
9175 if (iter == sync_policy.groups.end()) {
9176 cerr << "ERROR: could not find group '" << *opt_group_id << "'" << std::endl;
9177 return ENOENT;
9178 }
9179
9180 auto& group = iter->second;
9181
9182 rgw_sync_bucket_pipes *pipe;
9183
9184 if (!group.find_pipe(*opt_pipe_id, false, &pipe)) {
9185 cerr << "ERROR: could not find pipe '" << *opt_pipe_id << "'" << std::endl;
9186 return ENOENT;
9187 }
9188
9189 if (opt_source_zone_ids) {
9190 pipe->source.remove_zones(*opt_source_zone_ids);
9191 }
9192
9193 pipe->source.remove_bucket(opt_source_tenant,
9194 opt_source_bucket_name,
9195 opt_source_bucket_id);
9196 if (opt_dest_zone_ids) {
9197 pipe->dest.remove_zones(*opt_dest_zone_ids);
9198 }
9199 pipe->dest.remove_bucket(opt_dest_tenant,
9200 opt_dest_bucket_name,
9201 opt_dest_bucket_id);
9202
9203 if (!(opt_source_zone_ids ||
9204 opt_source_tenant ||
9205 opt_source_bucket ||
9206 opt_source_bucket_id ||
9207 opt_dest_zone_ids ||
9208 opt_dest_tenant ||
9209 opt_dest_bucket ||
9210 opt_dest_bucket_id)) {
9211 group.remove_pipe(*opt_pipe_id);
9212 }
9213
9214 ret = sync_policy_ctx.write_policy();
9215 if (ret < 0) {
9216 return -ret;
9217 }
9218
9219 show_result(sync_policy, zone_formatter.get(), cout);
9220 }
9221
9222 if (opt_cmd == OPT::SYNC_POLICY_GET) {
9223 SyncPolicyContext sync_policy_ctx(zonegroup_id, zonegroup_name, opt_bucket);
9224 ret = sync_policy_ctx.init();
9225 if (ret < 0) {
9226 return -ret;
9227 }
9228 auto& sync_policy = sync_policy_ctx.get_policy();
9229
9230 show_result(sync_policy, zone_formatter.get(), cout);
9231 }
9232
9233 if (opt_cmd == OPT::BILOG_TRIM) {
9234 if (bucket_name.empty()) {
9235 cerr << "ERROR: bucket not specified" << std::endl;
9236 return EINVAL;
9237 }
9238 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
9239 if (ret < 0) {
9240 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
9241 return -ret;
9242 }
9243 ret = static_cast<rgw::sal::RadosStore*>(store)->svc()->bilog_rados->log_trim(dpp(), bucket->get_info(), shard_id, start_marker, end_marker);
9244 if (ret < 0) {
9245 cerr << "ERROR: trim_bi_log_entries(): " << cpp_strerror(-ret) << std::endl;
9246 return -ret;
9247 }
9248 }
9249
9250 if (opt_cmd == OPT::BILOG_STATUS) {
9251 if (bucket_name.empty()) {
9252 cerr << "ERROR: bucket not specified" << std::endl;
9253 return EINVAL;
9254 }
9255 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
9256 if (ret < 0) {
9257 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
9258 return -ret;
9259 }
9260 map<int, string> markers;
9261 ret = static_cast<rgw::sal::RadosStore*>(store)->svc()->bilog_rados->get_log_status(dpp(), bucket->get_info(), shard_id,
9262 &markers, null_yield);
9263 if (ret < 0) {
9264 cerr << "ERROR: get_bi_log_status(): " << cpp_strerror(-ret) << std::endl;
9265 return -ret;
9266 }
9267 formatter->open_object_section("entries");
9268 encode_json("markers", markers, formatter.get());
9269 formatter->close_section();
9270 formatter->flush(cout);
9271 }
9272
9273 if (opt_cmd == OPT::BILOG_AUTOTRIM) {
9274 RGWCoroutinesManager crs(store->ctx(), store->get_cr_registry());
9275 RGWHTTPManager http(store->ctx(), crs.get_completion_mgr());
9276 int ret = http.start();
9277 if (ret < 0) {
9278 cerr << "failed to initialize http client with " << cpp_strerror(ret) << std::endl;
9279 return -ret;
9280 }
9281
9282 rgw::BucketTrimConfig config;
9283 configure_bucket_trim(store->ctx(), config);
9284
9285 rgw::BucketTrimManager trim(static_cast<rgw::sal::RadosStore*>(store), config);
9286 ret = trim.init();
9287 if (ret < 0) {
9288 cerr << "trim manager init failed with " << cpp_strerror(ret) << std::endl;
9289 return -ret;
9290 }
9291 ret = crs.run(dpp(), trim.create_admin_bucket_trim_cr(&http));
9292 if (ret < 0) {
9293 cerr << "automated bilog trim failed with " << cpp_strerror(ret) << std::endl;
9294 return -ret;
9295 }
9296 }
9297
9298 if (opt_cmd == OPT::DATALOG_LIST) {
9299 formatter->open_array_section("entries");
9300 bool truncated;
9301 int count = 0;
9302 if (max_entries < 0)
9303 max_entries = 1000;
9304 if (!start_date.empty()) {
9305 std::cerr << "start-date not allowed." << std::endl;
9306 return -EINVAL;
9307 }
9308 if (!end_date.empty()) {
9309 std::cerr << "end-date not allowed." << std::endl;
9310 return -EINVAL;
9311 }
9312 if (!end_marker.empty()) {
9313 std::cerr << "end-marker not allowed." << std::endl;
9314 return -EINVAL;
9315 }
9316 if (!start_marker.empty()) {
9317 if (marker.empty()) {
9318 marker = start_marker;
9319 } else {
9320 std::cerr << "start-marker and marker not both allowed." << std::endl;
9321 return -EINVAL;
9322 }
9323 }
9324
9325 auto datalog_svc = static_cast<rgw::sal::RadosStore*>(store)->svc()->datalog_rados;
9326 RGWDataChangesLog::LogMarker log_marker;
9327
9328 do {
9329 std::vector<rgw_data_change_log_entry> entries;
9330 if (specified_shard_id) {
9331 ret = datalog_svc->list_entries(dpp(), shard_id, max_entries - count,
9332 entries, marker,
9333 &marker, &truncated);
9334 } else {
9335 ret = datalog_svc->list_entries(dpp(), max_entries - count, entries,
9336 log_marker, &truncated);
9337 }
9338 if (ret < 0) {
9339 cerr << "ERROR: datalog_svc->list_entries(): " << cpp_strerror(-ret) << std::endl;
9340 return -ret;
9341 }
9342
9343 count += entries.size();
9344
9345 for (const auto& entry : entries) {
9346 if (!extra_info) {
9347 encode_json("entry", entry.entry, formatter.get());
9348 } else {
9349 encode_json("entry", entry, formatter.get());
9350 }
9351 }
9352 formatter.get()->flush(cout);
9353 } while (truncated && count < max_entries);
9354
9355 formatter->close_section();
9356 formatter->flush(cout);
9357 }
9358
9359 if (opt_cmd == OPT::DATALOG_STATUS) {
9360 int i = (specified_shard_id ? shard_id : 0);
9361
9362 formatter->open_array_section("entries");
9363 for (; i < g_ceph_context->_conf->rgw_data_log_num_shards; i++) {
9364 list<cls_log_entry> entries;
9365
9366 RGWDataChangesLogInfo info;
9367 static_cast<rgw::sal::RadosStore*>(store)->svc()->datalog_rados->get_info(dpp(), i, &info);
9368
9369 ::encode_json("info", info, formatter.get());
9370
9371 if (specified_shard_id)
9372 break;
9373 }
9374
9375 formatter->close_section();
9376 formatter->flush(cout);
9377 }
9378
9379 if (opt_cmd == OPT::DATALOG_AUTOTRIM) {
9380 RGWCoroutinesManager crs(store->ctx(), store->get_cr_registry());
9381 RGWHTTPManager http(store->ctx(), crs.get_completion_mgr());
9382 int ret = http.start();
9383 if (ret < 0) {
9384 cerr << "failed to initialize http client with " << cpp_strerror(ret) << std::endl;
9385 return -ret;
9386 }
9387
9388 auto num_shards = g_conf()->rgw_data_log_num_shards;
9389 std::vector<std::string> markers(num_shards);
9390 ret = crs.run(dpp(), create_admin_data_log_trim_cr(dpp(), static_cast<rgw::sal::RadosStore*>(store), &http, num_shards, markers));
9391 if (ret < 0) {
9392 cerr << "automated datalog trim failed with " << cpp_strerror(ret) << std::endl;
9393 return -ret;
9394 }
9395 }
9396
9397 if (opt_cmd == OPT::DATALOG_TRIM) {
9398 if (!start_date.empty()) {
9399 std::cerr << "start-date not allowed." << std::endl;
9400 return -EINVAL;
9401 }
9402 if (!end_date.empty()) {
9403 std::cerr << "end-date not allowed." << std::endl;
9404 return -EINVAL;
9405 }
9406 if (!start_marker.empty()) {
9407 std::cerr << "start-marker not allowed." << std::endl;
9408 return -EINVAL;
9409 }
9410 if (!end_marker.empty()) {
9411 if (marker.empty()) {
9412 marker = end_marker;
9413 } else {
9414 std::cerr << "end-marker and marker not both allowed." << std::endl;
9415 return -EINVAL;
9416 }
9417 }
9418
9419 if (!specified_shard_id) {
9420 cerr << "ERROR: requires a --shard-id" << std::endl;
9421 return EINVAL;
9422 }
9423
9424 if (marker.empty()) {
9425 cerr << "ERROR: requires a --marker" << std::endl;
9426 return EINVAL;
9427 }
9428
9429 auto datalog = static_cast<rgw::sal::RadosStore*>(store)->svc()->datalog_rados;
9430 ret = datalog->trim_entries(dpp(), shard_id, marker);
9431
9432 if (ret < 0 && ret != -ENODATA) {
9433 cerr << "ERROR: trim_entries(): " << cpp_strerror(-ret) << std::endl;
9434 return -ret;
9435 }
9436 }
9437
9438 if (opt_cmd == OPT::DATALOG_TYPE) {
9439 if (!opt_log_type) {
9440 std::cerr << "log-type not specified." << std::endl;
9441 return -EINVAL;
9442 }
9443 auto datalog = static_cast<rgw::sal::RadosStore*>(store)->svc()->datalog_rados;
9444 ret = datalog->change_format(dpp(), *opt_log_type, null_yield);
9445 if (ret < 0) {
9446 cerr << "ERROR: change_format(): " << cpp_strerror(-ret) << std::endl;
9447 return -ret;
9448 }
9449 }
9450
9451 if (opt_cmd == OPT::DATALOG_PRUNE) {
9452 auto datalog = static_cast<rgw::sal::RadosStore*>(store)->svc()->datalog_rados;
9453 std::optional<uint64_t> through;
9454 ret = datalog->trim_generations(dpp(), through);
9455
9456 if (ret < 0) {
9457 cerr << "ERROR: trim_generations(): " << cpp_strerror(-ret) << std::endl;
9458 return -ret;
9459 }
9460
9461 if (through) {
9462 std::cout << "Pruned " << *through << " empty generations." << std::endl;
9463 } else {
9464 std::cout << "No empty generations." << std::endl;
9465 }
9466 }
9467
9468 bool quota_op = (opt_cmd == OPT::QUOTA_SET || opt_cmd == OPT::QUOTA_ENABLE || opt_cmd == OPT::QUOTA_DISABLE);
9469
9470 if (quota_op) {
9471 if (bucket_name.empty() && rgw::sal::User::empty(user)) {
9472 cerr << "ERROR: bucket name or uid is required for quota operation" << std::endl;
9473 return EINVAL;
9474 }
9475
9476 if (!bucket_name.empty()) {
9477 if (!quota_scope.empty() && quota_scope != "bucket") {
9478 cerr << "ERROR: invalid quota scope specification." << std::endl;
9479 return EINVAL;
9480 }
9481 set_bucket_quota(store, opt_cmd, tenant, bucket_name,
9482 max_size, max_objects, have_max_size, have_max_objects);
9483 } else if (!rgw::sal::User::empty(user)) {
9484 if (quota_scope == "bucket") {
9485 return set_user_bucket_quota(opt_cmd, ruser, user_op, max_size, max_objects, have_max_size, have_max_objects);
9486 } else if (quota_scope == "user") {
9487 return set_user_quota(opt_cmd, ruser, user_op, max_size, max_objects, have_max_size, have_max_objects);
9488 } else {
9489 cerr << "ERROR: invalid quota scope specification. Please specify either --quota-scope=bucket, or --quota-scope=user" << std::endl;
9490 return EINVAL;
9491 }
9492 }
9493 }
9494
9495 bool ratelimit_op_set = (opt_cmd == OPT::RATELIMIT_SET || opt_cmd == OPT::RATELIMIT_ENABLE || opt_cmd == OPT::RATELIMIT_DISABLE);
9496 bool ratelimit_op_get = opt_cmd == OPT::RATELIMIT_GET;
9497 if (ratelimit_op_set) {
9498 if (bucket_name.empty() && rgw::sal::User::empty(user)) {
9499 cerr << "ERROR: bucket name or uid is required for ratelimit operation" << std::endl;
9500 return EINVAL;
9501 }
9502
9503 if (!bucket_name.empty()) {
9504 if (!ratelimit_scope.empty() && ratelimit_scope != "bucket") {
9505 cerr << "ERROR: invalid ratelimit scope specification. (bucket scope is not bucket but bucket has been specified)" << std::endl;
9506 return EINVAL;
9507 }
9508 return set_bucket_ratelimit(store, opt_cmd, tenant, bucket_name,
9509 max_read_ops, max_write_ops,
9510 max_read_bytes, max_write_bytes,
9511 have_max_read_ops, have_max_write_ops,
9512 have_max_read_bytes, have_max_write_bytes);
9513 } else if (!rgw::sal::User::empty(user)) {
9514 } if (ratelimit_scope == "user") {
9515 return set_user_ratelimit(opt_cmd, user, max_read_ops, max_write_ops,
9516 max_read_bytes, max_write_bytes,
9517 have_max_read_ops, have_max_write_ops,
9518 have_max_read_bytes, have_max_write_bytes);
9519 } else {
9520 cerr << "ERROR: invalid ratelimit scope specification. Please specify either --ratelimit-scope=bucket, or --ratelimit-scope=user" << std::endl;
9521 return EINVAL;
9522 }
9523 }
9524
9525 if (ratelimit_op_get) {
9526 if (bucket_name.empty() && rgw::sal::User::empty(user)) {
9527 cerr << "ERROR: bucket name or uid is required for ratelimit operation" << std::endl;
9528 return EINVAL;
9529 }
9530
9531 if (!bucket_name.empty()) {
9532 if (!ratelimit_scope.empty() && ratelimit_scope != "bucket") {
9533 cerr << "ERROR: invalid ratelimit scope specification. (bucket scope is not bucket but bucket has been specified)" << std::endl;
9534 return EINVAL;
9535 }
9536 return show_bucket_ratelimit(store, tenant, bucket_name, formatter.get());
9537 } else if (!rgw::sal::User::empty(user)) {
9538 } if (ratelimit_scope == "user") {
9539 return show_user_ratelimit(user, formatter.get());
9540 } else {
9541 cerr << "ERROR: invalid ratelimit scope specification. Please specify either --ratelimit-scope=bucket, or --ratelimit-scope=user" << std::endl;
9542 return EINVAL;
9543 }
9544 }
9545
9546 if (opt_cmd == OPT::MFA_CREATE) {
9547 rados::cls::otp::otp_info_t config;
9548
9549 if (rgw::sal::User::empty(user)) {
9550 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
9551 return EINVAL;
9552 }
9553
9554 if (totp_serial.empty()) {
9555 cerr << "ERROR: TOTP device serial number was not provided (via --totp-serial)" << std::endl;
9556 return EINVAL;
9557 }
9558
9559 if (totp_seed.empty()) {
9560 cerr << "ERROR: TOTP device seed was not provided (via --totp-seed)" << std::endl;
9561 return EINVAL;
9562 }
9563
9564
9565 rados::cls::otp::SeedType seed_type;
9566 if (totp_seed_type == "hex") {
9567 seed_type = rados::cls::otp::OTP_SEED_HEX;
9568 } else if (totp_seed_type == "base32") {
9569 seed_type = rados::cls::otp::OTP_SEED_BASE32;
9570 } else {
9571 cerr << "ERROR: invalid seed type: " << totp_seed_type << std::endl;
9572 return EINVAL;
9573 }
9574
9575 config.id = totp_serial;
9576 config.seed = totp_seed;
9577 config.seed_type = seed_type;
9578
9579 if (totp_seconds > 0) {
9580 config.step_size = totp_seconds;
9581 }
9582
9583 if (totp_window > 0) {
9584 config.window = totp_window;
9585 }
9586
9587 real_time mtime = real_clock::now();
9588 string oid = static_cast<rgw::sal::RadosStore*>(store)->svc()->cls->mfa.get_mfa_oid(user->get_id());
9589
9590 int ret = static_cast<rgw::sal::RadosStore*>(store)->ctl()->meta.mgr->mutate(RGWSI_MetaBackend_OTP::get_meta_key(user->get_id()),
9591 mtime, &objv_tracker,
9592 null_yield, dpp(),
9593 MDLOG_STATUS_WRITE,
9594 [&] {
9595 return static_cast<rgw::sal::RadosStore*>(store)->svc()->cls->mfa.create_mfa(dpp(), user->get_id(), config, &objv_tracker, mtime, null_yield);
9596 });
9597 if (ret < 0) {
9598 cerr << "MFA creation failed, error: " << cpp_strerror(-ret) << std::endl;
9599 return -ret;
9600 }
9601
9602 RGWUserInfo& user_info = user_op.get_user_info();
9603 user_info.mfa_ids.insert(totp_serial);
9604 user_op.set_mfa_ids(user_info.mfa_ids);
9605 string err;
9606 ret = ruser.modify(dpp(), user_op, null_yield, &err);
9607 if (ret < 0) {
9608 cerr << "ERROR: failed storing user info, error: " << err << std::endl;
9609 return -ret;
9610 }
9611 }
9612
9613 if (opt_cmd == OPT::MFA_REMOVE) {
9614 if (rgw::sal::User::empty(user)) {
9615 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
9616 return EINVAL;
9617 }
9618
9619 if (totp_serial.empty()) {
9620 cerr << "ERROR: TOTP device serial number was not provided (via --totp-serial)" << std::endl;
9621 return EINVAL;
9622 }
9623
9624 real_time mtime = real_clock::now();
9625
9626 int ret = static_cast<rgw::sal::RadosStore*>(store)->ctl()->meta.mgr->mutate(RGWSI_MetaBackend_OTP::get_meta_key(user->get_id()),
9627 mtime, &objv_tracker,
9628 null_yield, dpp(),
9629 MDLOG_STATUS_WRITE,
9630 [&] {
9631 return static_cast<rgw::sal::RadosStore*>(store)->svc()->cls->mfa.remove_mfa(dpp(), user->get_id(), totp_serial, &objv_tracker, mtime, null_yield);
9632 });
9633 if (ret < 0) {
9634 cerr << "MFA removal failed, error: " << cpp_strerror(-ret) << std::endl;
9635 return -ret;
9636 }
9637
9638 RGWUserInfo& user_info = user_op.get_user_info();
9639 user_info.mfa_ids.erase(totp_serial);
9640 user_op.set_mfa_ids(user_info.mfa_ids);
9641 string err;
9642 ret = ruser.modify(dpp(), user_op, null_yield, &err);
9643 if (ret < 0) {
9644 cerr << "ERROR: failed storing user info, error: " << err << std::endl;
9645 return -ret;
9646 }
9647 }
9648
9649 if (opt_cmd == OPT::MFA_GET) {
9650 if (rgw::sal::User::empty(user)) {
9651 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
9652 return EINVAL;
9653 }
9654
9655 if (totp_serial.empty()) {
9656 cerr << "ERROR: TOTP device serial number was not provided (via --totp-serial)" << std::endl;
9657 return EINVAL;
9658 }
9659
9660 rados::cls::otp::otp_info_t result;
9661 int ret = static_cast<rgw::sal::RadosStore*>(store)->svc()->cls->mfa.get_mfa(dpp(), user->get_id(), totp_serial, &result, null_yield);
9662 if (ret < 0) {
9663 if (ret == -ENOENT || ret == -ENODATA) {
9664 cerr << "MFA serial id not found" << std::endl;
9665 } else {
9666 cerr << "MFA retrieval failed, error: " << cpp_strerror(-ret) << std::endl;
9667 }
9668 return -ret;
9669 }
9670 formatter->open_object_section("result");
9671 encode_json("entry", result, formatter.get());
9672 formatter->close_section();
9673 formatter->flush(cout);
9674 }
9675
9676 if (opt_cmd == OPT::MFA_LIST) {
9677 if (rgw::sal::User::empty(user)) {
9678 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
9679 return EINVAL;
9680 }
9681
9682 list<rados::cls::otp::otp_info_t> result;
9683 int ret = static_cast<rgw::sal::RadosStore*>(store)->svc()->cls->mfa.list_mfa(dpp(), user->get_id(), &result, null_yield);
9684 if (ret < 0) {
9685 cerr << "MFA listing failed, error: " << cpp_strerror(-ret) << std::endl;
9686 return -ret;
9687 }
9688 formatter->open_object_section("result");
9689 encode_json("entries", result, formatter.get());
9690 formatter->close_section();
9691 formatter->flush(cout);
9692 }
9693
9694 if (opt_cmd == OPT::MFA_CHECK) {
9695 if (rgw::sal::User::empty(user)) {
9696 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
9697 return EINVAL;
9698 }
9699
9700 if (totp_serial.empty()) {
9701 cerr << "ERROR: TOTP device serial number was not provided (via --totp-serial)" << std::endl;
9702 return EINVAL;
9703 }
9704
9705 if (totp_pin.empty()) {
9706 cerr << "ERROR: TOTP device serial number was not provided (via --totp-pin)" << std::endl;
9707 return EINVAL;
9708 }
9709
9710 list<rados::cls::otp::otp_info_t> result;
9711 int ret = static_cast<rgw::sal::RadosStore*>(store)->svc()->cls->mfa.check_mfa(dpp(), user->get_id(), totp_serial, totp_pin.front(), null_yield);
9712 if (ret < 0) {
9713 cerr << "MFA check failed, error: " << cpp_strerror(-ret) << std::endl;
9714 return -ret;
9715 }
9716
9717 cout << "ok" << std::endl;
9718 }
9719
9720 if (opt_cmd == OPT::MFA_RESYNC) {
9721 if (rgw::sal::User::empty(user)) {
9722 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
9723 return EINVAL;
9724 }
9725
9726 if (totp_serial.empty()) {
9727 cerr << "ERROR: TOTP device serial number was not provided (via --totp-serial)" << std::endl;
9728 return EINVAL;
9729 }
9730
9731 if (totp_pin.size() != 2) {
9732 cerr << "ERROR: missing two --totp-pin params (--totp-pin=<first> --totp-pin=<second>)" << std::endl;
9733 return EINVAL;
9734 }
9735
9736 rados::cls::otp::otp_info_t config;
9737 int ret = static_cast<rgw::sal::RadosStore*>(store)->svc()->cls->mfa.get_mfa(dpp(), user->get_id(), totp_serial, &config, null_yield);
9738 if (ret < 0) {
9739 if (ret == -ENOENT || ret == -ENODATA) {
9740 cerr << "MFA serial id not found" << std::endl;
9741 } else {
9742 cerr << "MFA retrieval failed, error: " << cpp_strerror(-ret) << std::endl;
9743 }
9744 return -ret;
9745 }
9746
9747 ceph::real_time now;
9748
9749 ret = static_cast<rgw::sal::RadosStore*>(store)->svc()->cls->mfa.otp_get_current_time(dpp(), user->get_id(), &now, null_yield);
9750 if (ret < 0) {
9751 cerr << "ERROR: failed to fetch current time from osd: " << cpp_strerror(-ret) << std::endl;
9752 return -ret;
9753 }
9754 time_t time_ofs;
9755
9756 ret = scan_totp(store->ctx(), now, config, totp_pin, &time_ofs);
9757 if (ret < 0) {
9758 if (ret == -ENOENT) {
9759 cerr << "failed to resync, TOTP values not found in range" << std::endl;
9760 } else {
9761 cerr << "ERROR: failed to scan for TOTP values: " << cpp_strerror(-ret) << std::endl;
9762 }
9763 return -ret;
9764 }
9765
9766 config.time_ofs = time_ofs;
9767
9768 /* now update the backend */
9769 real_time mtime = real_clock::now();
9770
9771 ret = static_cast<rgw::sal::RadosStore*>(store)->ctl()->meta.mgr->mutate(RGWSI_MetaBackend_OTP::get_meta_key(user->get_id()),
9772 mtime, &objv_tracker,
9773 null_yield, dpp(),
9774 MDLOG_STATUS_WRITE,
9775 [&] {
9776 return static_cast<rgw::sal::RadosStore*>(store)->svc()->cls->mfa.create_mfa(dpp(), user->get_id(), config, &objv_tracker, mtime, null_yield);
9777 });
9778 if (ret < 0) {
9779 cerr << "MFA update failed, error: " << cpp_strerror(-ret) << std::endl;
9780 return -ret;
9781 }
9782
9783 }
9784
9785 if (opt_cmd == OPT::RESHARD_STALE_INSTANCES_LIST) {
9786 if (!static_cast<rgw::sal::RadosStore*>(store)->svc()->zone->can_reshard() && !yes_i_really_mean_it) {
9787 cerr << "Resharding disabled in a multisite env, stale instances unlikely from resharding" << std::endl;
9788 cerr << "These instances may not be safe to delete." << std::endl;
9789 cerr << "Use --yes-i-really-mean-it to force displaying these instances." << std::endl;
9790 return EINVAL;
9791 }
9792
9793 ret = RGWBucketAdminOp::list_stale_instances(store, bucket_op, stream_flusher, dpp());
9794 if (ret < 0) {
9795 cerr << "ERROR: listing stale instances" << cpp_strerror(-ret) << std::endl;
9796 }
9797 }
9798
9799 if (opt_cmd == OPT::RESHARD_STALE_INSTANCES_DELETE) {
9800 if (!static_cast<rgw::sal::RadosStore*>(store)->svc()->zone->can_reshard()) {
9801 cerr << "Resharding disabled in a multisite env. Stale instances are not safe to be deleted." << std::endl;
9802 return EINVAL;
9803 }
9804
9805 ret = RGWBucketAdminOp::clear_stale_instances(store, bucket_op, stream_flusher, dpp());
9806 if (ret < 0) {
9807 cerr << "ERROR: deleting stale instances" << cpp_strerror(-ret) << std::endl;
9808 }
9809 }
9810
9811 if (opt_cmd == OPT::PUBSUB_TOPICS_LIST) {
9812
9813 RGWPubSub ps(static_cast<rgw::sal::RadosStore*>(store), tenant);
9814
9815 if (!bucket_name.empty()) {
9816 rgw_pubsub_bucket_topics result;
9817 int ret = init_bucket(user.get(), tenant, bucket_name, bucket_id, &bucket);
9818 if (ret < 0) {
9819 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
9820 return -ret;
9821 }
9822
9823 auto b = ps.get_bucket(bucket->get_key());
9824 ret = b->get_topics(&result);
9825 if (ret < 0) {
9826 cerr << "ERROR: could not get topics: " << cpp_strerror(-ret) << std::endl;
9827 return -ret;
9828 }
9829 encode_json("result", result, formatter.get());
9830 } else {
9831 rgw_pubsub_topics result;
9832 int ret = ps.get_topics(&result);
9833 if (ret < 0) {
9834 cerr << "ERROR: could not get topics: " << cpp_strerror(-ret) << std::endl;
9835 return -ret;
9836 }
9837 encode_json("result", result, formatter.get());
9838 }
9839 formatter->flush(cout);
9840 }
9841
9842 if (opt_cmd == OPT::PUBSUB_TOPIC_GET) {
9843 if (topic_name.empty()) {
9844 cerr << "ERROR: topic name was not provided (via --topic)" << std::endl;
9845 return EINVAL;
9846 }
9847
9848 RGWPubSub ps(static_cast<rgw::sal::RadosStore*>(store), tenant);
9849
9850 rgw_pubsub_topic_subs topic;
9851 ret = ps.get_topic(topic_name, &topic);
9852 if (ret < 0) {
9853 cerr << "ERROR: could not get topic: " << cpp_strerror(-ret) << std::endl;
9854 return -ret;
9855 }
9856 encode_json("topic", topic, formatter.get());
9857 formatter->flush(cout);
9858 }
9859
9860 if (opt_cmd == OPT::PUBSUB_TOPIC_RM) {
9861 if (topic_name.empty()) {
9862 cerr << "ERROR: topic name was not provided (via --topic)" << std::endl;
9863 return EINVAL;
9864 }
9865
9866 RGWPubSub ps(static_cast<rgw::sal::RadosStore*>(store), tenant);
9867
9868 ret = ps.remove_topic(dpp(), topic_name, null_yield);
9869 if (ret < 0) {
9870 cerr << "ERROR: could not remove topic: " << cpp_strerror(-ret) << std::endl;
9871 return -ret;
9872 }
9873 }
9874
9875 if (opt_cmd == OPT::PUBSUB_SUB_GET) {
9876 if (get_tier_type(static_cast<rgw::sal::RadosStore*>(store)) != "pubsub") {
9877 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
9878 return EINVAL;
9879 }
9880 if (sub_name.empty()) {
9881 cerr << "ERROR: subscription name was not provided (via --subscription)" << std::endl;
9882 return EINVAL;
9883 }
9884
9885 RGWPubSub ps(static_cast<rgw::sal::RadosStore*>(store), tenant);
9886
9887 rgw_pubsub_sub_config sub_conf;
9888
9889 auto sub = ps.get_sub(sub_name);
9890 ret = sub->get_conf(&sub_conf);
9891 if (ret < 0) {
9892 cerr << "ERROR: could not get subscription info: " << cpp_strerror(-ret) << std::endl;
9893 return -ret;
9894 }
9895 encode_json("sub", sub_conf, formatter.get());
9896 formatter->flush(cout);
9897 }
9898
9899 if (opt_cmd == OPT::PUBSUB_SUB_RM) {
9900 if (get_tier_type(static_cast<rgw::sal::RadosStore*>(store)) != "pubsub") {
9901 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
9902 return EINVAL;
9903 }
9904 if (sub_name.empty()) {
9905 cerr << "ERROR: subscription name was not provided (via --subscription)" << std::endl;
9906 return EINVAL;
9907 }
9908
9909 RGWPubSub ps(static_cast<rgw::sal::RadosStore*>(store), tenant);
9910
9911 auto sub = ps.get_sub(sub_name);
9912 ret = sub->unsubscribe(dpp(), topic_name, null_yield);
9913 if (ret < 0) {
9914 cerr << "ERROR: could not get subscription info: " << cpp_strerror(-ret) << std::endl;
9915 return -ret;
9916 }
9917 }
9918
9919 if (opt_cmd == OPT::PUBSUB_SUB_PULL) {
9920 if (get_tier_type(static_cast<rgw::sal::RadosStore*>(store)) != "pubsub") {
9921 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
9922 return EINVAL;
9923 }
9924 if (sub_name.empty()) {
9925 cerr << "ERROR: subscription name was not provided (via --subscription)" << std::endl;
9926 return EINVAL;
9927 }
9928
9929 RGWPubSub ps(static_cast<rgw::sal::RadosStore*>(store), tenant);
9930
9931 if (!max_entries_specified) {
9932 max_entries = RGWPubSub::Sub::DEFAULT_MAX_EVENTS;
9933 }
9934 auto sub = ps.get_sub_with_events(sub_name);
9935 ret = sub->list_events(dpp(), marker, max_entries);
9936 if (ret < 0) {
9937 cerr << "ERROR: could not list events: " << cpp_strerror(-ret) << std::endl;
9938 return -ret;
9939 }
9940 encode_json("result", *sub, formatter.get());
9941 formatter->flush(cout);
9942 }
9943
9944 if (opt_cmd == OPT::PUBSUB_EVENT_RM) {
9945 if (get_tier_type(static_cast<rgw::sal::RadosStore*>(store)) != "pubsub") {
9946 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
9947 return EINVAL;
9948 }
9949 if (sub_name.empty()) {
9950 cerr << "ERROR: subscription name was not provided (via --subscription)" << std::endl;
9951 return EINVAL;
9952 }
9953 if (event_id.empty()) {
9954 cerr << "ERROR: event id was not provided (via --event-id)" << std::endl;
9955 return EINVAL;
9956 }
9957
9958 RGWPubSub ps(static_cast<rgw::sal::RadosStore*>(store), tenant);
9959
9960 auto sub = ps.get_sub_with_events(sub_name);
9961 ret = sub->remove_event(dpp(), event_id);
9962 if (ret < 0) {
9963 cerr << "ERROR: could not remove event: " << cpp_strerror(-ret) << std::endl;
9964 return -ret;
9965 }
9966 }
9967
9968 if (opt_cmd == OPT::SCRIPT_PUT) {
9969 if (!str_script_ctx) {
9970 cerr << "ERROR: context was not provided (via --context)" << std::endl;
9971 return EINVAL;
9972 }
9973 if (infile.empty()) {
9974 cerr << "ERROR: infile was not provided (via --infile)" << std::endl;
9975 return EINVAL;
9976 }
9977 bufferlist bl;
9978 auto rc = read_input(infile, bl);
9979 if (rc < 0) {
9980 cerr << "ERROR: failed to read script: '" << infile << "'. error: " << rc << std::endl;
9981 return -rc;
9982 }
9983 const std::string script = bl.to_str();
9984 std::string err_msg;
9985 if (!rgw::lua::verify(script, err_msg)) {
9986 cerr << "ERROR: script: '" << infile << "' has error: " << std::endl << err_msg << std::endl;
9987 return EINVAL;
9988 }
9989 const rgw::lua::context script_ctx = rgw::lua::to_context(*str_script_ctx);
9990 if (script_ctx == rgw::lua::context::none) {
9991 cerr << "ERROR: invalid script context: " << *str_script_ctx << ". must be one of: preRequest, postRequest" << std::endl;
9992 return EINVAL;
9993 }
9994 rc = rgw::lua::write_script(dpp(), store, tenant, null_yield, script_ctx, script);
9995 if (rc < 0) {
9996 cerr << "ERROR: failed to put script. error: " << rc << std::endl;
9997 return -rc;
9998 }
9999 }
10000
10001 if (opt_cmd == OPT::SCRIPT_GET) {
10002 if (!str_script_ctx) {
10003 cerr << "ERROR: context was not provided (via --context)" << std::endl;
10004 return EINVAL;
10005 }
10006 const rgw::lua::context script_ctx = rgw::lua::to_context(*str_script_ctx);
10007 if (script_ctx == rgw::lua::context::none) {
10008 cerr << "ERROR: invalid script context: " << *str_script_ctx << ". must be one of: preRequest, postRequest" << std::endl;
10009 return EINVAL;
10010 }
10011 std::string script;
10012 const auto rc = rgw::lua::read_script(dpp(), store, tenant, null_yield, script_ctx, script);
10013 if (rc == -ENOENT) {
10014 std::cout << "no script exists for context: " << *str_script_ctx <<
10015 (tenant.empty() ? "" : (" in tenant: " + tenant)) << std::endl;
10016 } else if (rc < 0) {
10017 cerr << "ERROR: failed to read script. error: " << rc << std::endl;
10018 return -rc;
10019 } else {
10020 std::cout << script << std::endl;
10021 }
10022 }
10023
10024 if (opt_cmd == OPT::SCRIPT_RM) {
10025 if (!str_script_ctx) {
10026 cerr << "ERROR: context was not provided (via --context)" << std::endl;
10027 return EINVAL;
10028 }
10029 const rgw::lua::context script_ctx = rgw::lua::to_context(*str_script_ctx);
10030 if (script_ctx == rgw::lua::context::none) {
10031 cerr << "ERROR: invalid script context: " << *str_script_ctx << ". must be one of: preRequest, postRequest" << std::endl;
10032 return EINVAL;
10033 }
10034 const auto rc = rgw::lua::delete_script(dpp(), store, tenant, null_yield, script_ctx);
10035 if (rc < 0) {
10036 cerr << "ERROR: failed to remove script. error: " << rc << std::endl;
10037 return -rc;
10038 }
10039 }
10040
10041 if (opt_cmd == OPT::SCRIPT_PACKAGE_ADD) {
10042 #ifdef WITH_RADOSGW_LUA_PACKAGES
10043 if (!script_package) {
10044 cerr << "ERROR: lua package name was not provided (via --package)" << std::endl;
10045 return EINVAL;
10046 }
10047 const auto rc = rgw::lua::add_package(dpp(), static_cast<rgw::sal::RadosStore*>(store), null_yield, *script_package, bool(allow_compilation));
10048 if (rc < 0) {
10049 cerr << "ERROR: failed to add lua package: " << script_package << " .error: " << rc << std::endl;
10050 return -rc;
10051 }
10052 #else
10053 cerr << "ERROR: adding lua packages is not permitted" << std::endl;
10054 return EPERM;
10055 #endif
10056 }
10057
10058 if (opt_cmd == OPT::SCRIPT_PACKAGE_RM) {
10059 #ifdef WITH_RADOSGW_LUA_PACKAGES
10060 if (!script_package) {
10061 cerr << "ERROR: lua package name was not provided (via --package)" << std::endl;
10062 return EINVAL;
10063 }
10064 const auto rc = rgw::lua::remove_package(dpp(), static_cast<rgw::sal::RadosStore*>(store), null_yield, *script_package);
10065 if (rc == -ENOENT) {
10066 cerr << "WARNING: package " << script_package << " did not exists or already removed" << std::endl;
10067 return 0;
10068 }
10069 if (rc < 0) {
10070 cerr << "ERROR: failed to remove lua package: " << script_package << " .error: " << rc << std::endl;
10071 return -rc;
10072 }
10073 #else
10074 cerr << "ERROR: removing lua packages in not permitted" << std::endl;
10075 return EPERM;
10076 #endif
10077 }
10078
10079 if (opt_cmd == OPT::SCRIPT_PACKAGE_LIST) {
10080 #ifdef WITH_RADOSGW_LUA_PACKAGES
10081 rgw::lua::packages_t packages;
10082 const auto rc = rgw::lua::list_packages(dpp(), static_cast<rgw::sal::RadosStore*>(store), null_yield, packages);
10083 if (rc == -ENOENT) {
10084 std::cout << "no lua packages in allowlist" << std::endl;
10085 } else if (rc < 0) {
10086 cerr << "ERROR: failed to read lua packages allowlist. error: " << rc << std::endl;
10087 return rc;
10088 } else {
10089 for (const auto& package : packages) {
10090 std::cout << package << std::endl;
10091 }
10092 }
10093 #else
10094 cerr << "ERROR: listing lua packages in not permitted" << std::endl;
10095 return EPERM;
10096 #endif
10097 }
10098
10099 return 0;
10100 }
10101