]> git.proxmox.com Git - ceph.git/blob - ceph/src/rgw/rgw_admin.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / rgw / rgw_admin.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
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_client.h"
29
30 #include "global/global_init.h"
31
32 #include "include/utime.h"
33 #include "include/str_list.h"
34
35 #include "rgw_user.h"
36 #include "rgw_bucket.h"
37 #include "rgw_otp.h"
38 #include "rgw_rados.h"
39 #include "rgw_acl.h"
40 #include "rgw_acl_s3.h"
41 #include "rgw_lc.h"
42 #include "rgw_log.h"
43 #include "rgw_formats.h"
44 #include "rgw_usage.h"
45 #include "rgw_orphan.h"
46 #include "rgw_sync.h"
47 #include "rgw_sync_log_trim.h"
48 #include "rgw_data_sync.h"
49 #include "rgw_rest_conn.h"
50 #include "rgw_realm_watcher.h"
51 #include "rgw_role.h"
52 #include "rgw_reshard.h"
53 #include "rgw_http_client_curl.h"
54 #include "rgw_zone.h"
55 #include "rgw_pubsub.h"
56 #include "rgw_sync_module_pubsub.h"
57
58 #include "services/svc_sync_modules.h"
59
60 #define dout_context g_ceph_context
61 #define dout_subsys ceph_subsys_rgw
62
63 #define SECRET_KEY_LEN 40
64 #define PUBLIC_ID_LEN 20
65
66 static RGWRados *store = NULL;
67
68 static const DoutPrefixProvider* dpp() {
69 struct GlobalPrefix : public DoutPrefixProvider {
70 CephContext *get_cct() const override { return store->ctx(); }
71 unsigned get_subsys() const override { return dout_subsys; }
72 std::ostream& gen_prefix(std::ostream& out) const override { return out; }
73 };
74 static GlobalPrefix global_dpp;
75 return &global_dpp;
76 }
77
78 void usage()
79 {
80 cout << "usage: radosgw-admin <cmd> [options...]" << std::endl;
81 cout << "commands:\n";
82 cout << " user create create a new user\n" ;
83 cout << " user modify modify user\n";
84 cout << " user info get user info\n";
85 cout << " user rm remove user\n";
86 cout << " user suspend suspend a user\n";
87 cout << " user enable re-enable user after suspension\n";
88 cout << " user check check user info\n";
89 cout << " user stats show user stats as accounted by quota subsystem\n";
90 cout << " user list list users\n";
91 cout << " caps add add user capabilities\n";
92 cout << " caps rm remove user capabilities\n";
93 cout << " subuser create create a new subuser\n" ;
94 cout << " subuser modify modify subuser\n";
95 cout << " subuser rm remove subuser\n";
96 cout << " key create create access key\n";
97 cout << " key rm remove access key\n";
98 cout << " bucket list list buckets\n";
99 cout << " bucket limit check show bucket sharding stats\n";
100 cout << " bucket link link bucket to specified user\n";
101 cout << " bucket unlink unlink bucket from specified user\n";
102 cout << " bucket stats returns bucket statistics\n";
103 cout << " bucket rm remove bucket\n";
104 cout << " bucket check check bucket index\n";
105 cout << " bucket reshard reshard bucket\n";
106 cout << " bucket rewrite rewrite all objects in the specified bucket\n";
107 cout << " bucket sync disable disable bucket sync\n";
108 cout << " bucket sync enable enable bucket sync\n";
109 cout << " bi get retrieve bucket index object entries\n";
110 cout << " bi put store bucket index object entries\n";
111 cout << " bi list list raw bucket index entries\n";
112 cout << " bi purge purge bucket index entries\n";
113 cout << " object rm remove object\n";
114 cout << " object put put object\n";
115 cout << " object stat stat an object for its metadata\n";
116 cout << " object unlink unlink object from bucket index\n";
117 cout << " object rewrite rewrite the specified object\n";
118 cout << " objects expire run expired objects cleanup\n";
119 cout << " period rm remove a period\n";
120 cout << " period get get period info\n";
121 cout << " period get-current get current period info\n";
122 cout << " period pull pull a period\n";
123 cout << " period push push a period\n";
124 cout << " period list list all periods\n";
125 cout << " period update update the staging period\n";
126 cout << " period commit commit the staging period\n";
127 cout << " quota set set quota params\n";
128 cout << " quota enable enable quota\n";
129 cout << " quota disable disable quota\n";
130 cout << " global quota get view global quota params\n";
131 cout << " global quota set set global quota params\n";
132 cout << " global quota enable enable a global quota\n";
133 cout << " global quota disable disable a global quota\n";
134 cout << " realm create create a new realm\n";
135 cout << " realm rm remove a realm\n";
136 cout << " realm get show realm info\n";
137 cout << " realm get-default get default realm name\n";
138 cout << " realm list list realms\n";
139 cout << " realm list-periods list all realm periods\n";
140 cout << " realm rename rename a realm\n";
141 cout << " realm set set realm info (requires infile)\n";
142 cout << " realm default set realm as default\n";
143 cout << " realm pull pull a realm and its current period\n";
144 cout << " zonegroup add add a zone to a zonegroup\n";
145 cout << " zonegroup create create a new zone group info\n";
146 cout << " zonegroup default set default zone group\n";
147 cout << " zonegroup rm remove a zone group info\n";
148 cout << " zonegroup get show zone group info\n";
149 cout << " zonegroup modify modify an existing zonegroup\n";
150 cout << " zonegroup set set zone group info (requires infile)\n";
151 cout << " zonegroup rm remove a zone from a zonegroup\n";
152 cout << " zonegroup rename rename a zone group\n";
153 cout << " zonegroup list list all zone groups set on this cluster\n";
154 cout << " zonegroup placement list list zonegroup's placement targets\n";
155 cout << " zonegroup placement add add a placement target id to a zonegroup\n";
156 cout << " zonegroup placement modify modify a placement target of a specific zonegroup\n";
157 cout << " zonegroup placement rm remove a placement target from a zonegroup\n";
158 cout << " zonegroup placement default set a zonegroup's default placement target\n";
159 cout << " zone create create a new zone\n";
160 cout << " zone rm remove a zone\n";
161 cout << " zone get show zone cluster params\n";
162 cout << " zone modify modify an existing zone\n";
163 cout << " zone set set zone cluster params (requires infile)\n";
164 cout << " zone list list all zones set on this cluster\n";
165 cout << " zone rename rename a zone\n";
166 cout << " zone placement list list zone's placement targets\n";
167 cout << " zone placement add add a zone placement target\n";
168 cout << " zone placement modify modify a zone placement target\n";
169 cout << " zone placement rm remove a zone placement target\n";
170 cout << " metadata sync status get metadata sync status\n";
171 cout << " metadata sync init init metadata sync\n";
172 cout << " metadata sync run run metadata sync\n";
173 cout << " data sync status get data sync status of the specified source zone\n";
174 cout << " data sync init init data sync for the specified source zone\n";
175 cout << " data sync run run data sync for the specified source zone\n";
176 cout << " pool add add an existing pool for data placement\n";
177 cout << " pool rm remove an existing pool from data placement set\n";
178 cout << " pools list list placement active set\n";
179 cout << " policy read bucket/object policy\n";
180 cout << " log list list log objects\n";
181 cout << " log show dump a log from specific object or (bucket + date\n";
182 cout << " + bucket-id)\n";
183 cout << " (NOTE: required to specify formatting of date\n";
184 cout << " to \"YYYY-MM-DD-hh\")\n";
185 cout << " log rm remove log object\n";
186 cout << " usage show show usage (by user, by bucket, date range)\n";
187 cout << " usage trim trim usage (by user, by bucket, date range)\n";
188 cout << " usage clear reset all the usage stats for the cluster\n";
189 cout << " gc list dump expired garbage collection objects (specify\n";
190 cout << " --include-all to list all entries, including unexpired)\n";
191 cout << " gc process manually process garbage (specify\n";
192 cout << " --include-all to process all entries, including unexpired)\n";
193 cout << " lc list list all bucket lifecycle progress\n";
194 cout << " lc get get a lifecycle bucket configuration\n";
195 cout << " lc process manually process lifecycle\n";
196 cout << " lc reshard fix fix LC for a resharded bucket\n";
197 cout << " metadata get get metadata info\n";
198 cout << " metadata put put metadata info\n";
199 cout << " metadata rm remove metadata info\n";
200 cout << " metadata list list metadata info\n";
201 cout << " mdlog list list metadata log\n";
202 cout << " mdlog trim trim metadata log (use start-date, end-date or\n";
203 cout << " start-marker, end-marker)\n";
204 cout << " mdlog status read metadata log status\n";
205 cout << " bilog list list bucket index log\n";
206 cout << " bilog trim trim bucket index log (use start-marker, end-marker)\n";
207 cout << " datalog list list data log\n";
208 cout << " datalog trim trim data log\n";
209 cout << " datalog status read data log status\n";
210 cout << " orphans find init and run search for leaked rados objects (use job-id, pool)\n";
211 cout << " orphans finish clean up search for leaked rados objects\n";
212 cout << " orphans list-jobs list the current job-ids for orphans search\n";
213 cout << " role create create a AWS role for use with STS\n";
214 cout << " role rm remove a role\n";
215 cout << " role get get a role\n";
216 cout << " role list list roles with specified path prefix\n";
217 cout << " role modify modify the assume role policy of an existing role\n";
218 cout << " role-policy put add/update permission policy to role\n";
219 cout << " role-policy list list policies attached to a role\n";
220 cout << " role-policy get get the specified inline policy document embedded with the given role\n";
221 cout << " role-policy rm remove policy attached to a role\n";
222 cout << " reshard add schedule a resharding of a bucket\n";
223 cout << " reshard list list all bucket resharding or scheduled to be resharded\n";
224 cout << " reshard status read bucket resharding status\n";
225 cout << " reshard process process of scheduled reshard jobs\n";
226 cout << " reshard cancel cancel resharding a bucket\n";
227 cout << " reshard stale-instances list list stale-instances from bucket resharding\n";
228 cout << " reshard stale-instances rm cleanup stale-instances from bucket resharding\n";
229 cout << " sync error list list sync error\n";
230 cout << " sync error trim trim sync error\n";
231 cout << " mfa create create a new MFA TOTP token\n";
232 cout << " mfa list list MFA TOTP tokens\n";
233 cout << " mfa get show MFA TOTP token\n";
234 cout << " mfa remove delete MFA TOTP token\n";
235 cout << " mfa check check MFA TOTP token\n";
236 cout << " mfa resync re-sync MFA TOTP token\n";
237 cout << "options:\n";
238 cout << " --tenant=<tenant> tenant name\n";
239 cout << " --uid=<id> user id\n";
240 cout << " --subuser=<name> subuser name\n";
241 cout << " --access-key=<key> S3 access key\n";
242 cout << " --email=<email> user's email address\n";
243 cout << " --secret/--secret-key=<key>\n";
244 cout << " specify secret key\n";
245 cout << " --gen-access-key generate random access key (for S3)\n";
246 cout << " --gen-secret generate random secret key\n";
247 cout << " --key-type=<type> key type, options are: swift, s3\n";
248 cout << " --temp-url-key[-2]=<key> temp url key\n";
249 cout << " --access=<access> Set access permissions for sub-user, should be one\n";
250 cout << " of read, write, readwrite, full\n";
251 cout << " --display-name=<name> user's display name\n";
252 cout << " --max-buckets max number of buckets for a user\n";
253 cout << " --admin set the admin flag on the user\n";
254 cout << " --system set the system flag on the user\n";
255 cout << " --op-mask set the op mask on the user\n";
256 cout << " --bucket=<bucket> Specify the bucket name. Also used by the quota command.\n";
257 cout << " --pool=<pool> Specify the pool name. Also used to scan for leaked rados objects.\n";
258 cout << " --object=<object> object name\n";
259 cout << " --date=<date> date in the format yyyy-mm-dd\n";
260 cout << " --start-date=<date> start date in the format yyyy-mm-dd\n";
261 cout << " --end-date=<date> end date in the format yyyy-mm-dd\n";
262 cout << " --bucket-id=<bucket-id> bucket id\n";
263 cout << " --shard-id=<shard-id> optional for: \n";
264 cout << " mdlog list\n";
265 cout << " data sync status\n";
266 cout << " required for: \n";
267 cout << " mdlog trim\n";
268 cout << " --max-entries=<entries> max entries for listing operations\n";
269 cout << " --metadata-key=<key> key to retrieve metadata from with metadata get\n";
270 cout << " --remote=<remote> zone or zonegroup id of remote gateway\n";
271 cout << " --period=<id> period id\n";
272 cout << " --url=<url> url for pushing/pulling period/realm\n";
273 cout << " --epoch=<number> period epoch\n";
274 cout << " --commit commit the period during 'period update'\n";
275 cout << " --staging get staging period info\n";
276 cout << " --master set as master\n";
277 cout << " --master-zone=<id> master zone id\n";
278 cout << " --rgw-realm=<name> realm name\n";
279 cout << " --realm-id=<id> realm id\n";
280 cout << " --realm-new-name=<name> realm new name\n";
281 cout << " --rgw-zonegroup=<name> zonegroup name\n";
282 cout << " --zonegroup-id=<id> zonegroup id\n";
283 cout << " --zonegroup-new-name=<name>\n";
284 cout << " zonegroup new name\n";
285 cout << " --rgw-zone=<name> name of zone in which radosgw is running\n";
286 cout << " --zone-id=<id> zone id\n";
287 cout << " --zone-new-name=<name> zone new name\n";
288 cout << " --source-zone specify the source zone (for data sync)\n";
289 cout << " --default set entity (realm, zonegroup, zone) as default\n";
290 cout << " --read-only set zone as read-only (when adding to zonegroup)\n";
291 cout << " --redirect-zone specify zone id to redirect when response is 404 (not found)\n";
292 cout << " --placement-id placement id for zonegroup placement commands\n";
293 cout << " --storage-class storage class for zonegroup placement commands\n";
294 cout << " --tags=<list> list of tags for zonegroup placement add and modify commands\n";
295 cout << " --tags-add=<list> list of tags to add for zonegroup placement modify command\n";
296 cout << " --tags-rm=<list> list of tags to remove for zonegroup placement modify command\n";
297 cout << " --endpoints=<list> zone endpoints\n";
298 cout << " --index-pool=<pool> placement target index pool\n";
299 cout << " --data-pool=<pool> placement target data pool\n";
300 cout << " --data-extra-pool=<pool> placement target data extra (non-ec) pool\n";
301 cout << " --placement-index-type=<type>\n";
302 cout << " placement target index type (normal, indexless, or #id)\n";
303 cout << " --compression=<type> placement target compression type (plugin name or empty/none)\n";
304 cout << " --tier-type=<type> zone tier type\n";
305 cout << " --tier-config=<k>=<v>[,...]\n";
306 cout << " set zone tier config keys, values\n";
307 cout << " --tier-config-rm=<k>[,...]\n";
308 cout << " unset zone tier config keys\n";
309 cout << " --sync-from-all[=false] set/reset whether zone syncs from all zonegroup peers\n";
310 cout << " --sync-from=[zone-name][,...]\n";
311 cout << " set list of zones to sync from\n";
312 cout << " --sync-from-rm=[zone-name][,...]\n";
313 cout << " remove zones from list of zones to sync from\n";
314 cout << " --fix besides checking bucket index, will also fix it\n";
315 cout << " --check-objects bucket check: rebuilds bucket index according to\n";
316 cout << " actual objects state\n";
317 cout << " --format=<format> specify output format for certain operations: xml,\n";
318 cout << " json\n";
319 cout << " --purge-data when specified, user removal will also purge all the\n";
320 cout << " user data\n";
321 cout << " --purge-keys when specified, subuser removal will also purge all the\n";
322 cout << " subuser keys\n";
323 cout << " --purge-objects remove a bucket's objects before deleting it\n";
324 cout << " (NOTE: required to delete a non-empty bucket)\n";
325 cout << " --sync-stats option to 'user stats', update user stats with current\n";
326 cout << " stats reported by user's buckets indexes\n";
327 cout << " --reset-stats option to 'user stats', reset stats in accordance with user buckets\n";
328 cout << " --show-log-entries=<flag> enable/disable dump of log entries on log show\n";
329 cout << " --show-log-sum=<flag> enable/disable dump of log summation on log show\n";
330 cout << " --skip-zero-entries log show only dumps entries that don't have zero value\n";
331 cout << " in one of the numeric field\n";
332 cout << " --infile=<file> specify a file to read in when setting data\n";
333 cout << " --categories=<list> comma separated list of categories, used in usage show\n";
334 cout << " --caps=<caps> list of caps (e.g., \"usage=read, write; user=read\")\n";
335 cout << " --yes-i-really-mean-it required for certain operations\n";
336 cout << " --warnings-only when specified with bucket limit check, list\n";
337 cout << " only buckets nearing or over the current max\n";
338 cout << " objects per shard value\n";
339 cout << " --bypass-gc when specified with bucket deletion, triggers\n";
340 cout << " object deletions by not involving GC\n";
341 cout << " --inconsistent-index when specified with bucket deletion and bypass-gc set to true,\n";
342 cout << " ignores bucket index consistency\n";
343 cout << " --min-rewrite-size min object size for bucket rewrite (default 4M)\n";
344 cout << " --max-rewrite-size max object size for bucket rewrite (default ULLONG_MAX)\n";
345 cout << " --min-rewrite-stripe-size min stripe size for object rewrite (default 0)\n";
346 cout << " --trim-delay-ms time interval in msec to limit the frequency of sync error log entries trimming operations,\n";
347 cout << " the trimming process will sleep the specified msec for every 1000 entries trimmed\n";
348 cout << "\n";
349 cout << "<date> := \"YYYY-MM-DD[ hh:mm:ss]\"\n";
350 cout << "\nQuota options:\n";
351 cout << " --max-objects specify max objects (negative value to disable)\n";
352 cout << " --max-size specify max size (in B/K/M/G/T, negative value to disable)\n";
353 cout << " --quota-scope scope of quota (bucket, user)\n";
354 cout << "\nOrphans search options:\n";
355 cout << " --num-shards num of shards to use for keeping the temporary scan info\n";
356 cout << " --orphan-stale-secs num of seconds to wait before declaring an object to be an orphan (default: 86400)\n";
357 cout << " --job-id set the job id (for orphans find)\n";
358 cout << " --max-concurrent-ios maximum concurrent ios for orphans find (default: 32)\n";
359 cout << " --detail detailed mode, log and stat head objects as well\n";
360 cout << "\nOrphans list-jobs options:\n";
361 cout << " --extra-info provide extra info in job list\n";
362 cout << "\nRole options:\n";
363 cout << " --role-name name of the role to create\n";
364 cout << " --path path to the role\n";
365 cout << " --assume-role-policy-doc the trust relationship policy document that grants an entity permission to assume the role\n";
366 cout << " --policy-name name of the policy document\n";
367 cout << " --policy-doc permission policy document\n";
368 cout << " --path-prefix path prefix for filtering roles\n";
369 cout << "\nMFA options:\n";
370 cout << " --totp-serial a string that represents the ID of a TOTP token\n";
371 cout << " --totp-seed the secret seed that is used to calculate the TOTP\n";
372 cout << " --totp-seconds the time resolution that is being used for TOTP generation\n";
373 cout << " --totp-window the number of TOTP tokens that are checked before and after the current token when validating token\n";
374 cout << " --totp-pin the valid value of a TOTP token at a certain time\n";
375 cout << "\n";
376 generic_client_usage();
377 }
378
379 enum {
380 OPT_NO_CMD = 0,
381 OPT_USER_CREATE,
382 OPT_USER_INFO,
383 OPT_USER_MODIFY,
384 OPT_USER_RM,
385 OPT_USER_SUSPEND,
386 OPT_USER_ENABLE,
387 OPT_USER_CHECK,
388 OPT_USER_STATS,
389 OPT_USER_LIST,
390 OPT_SUBUSER_CREATE,
391 OPT_SUBUSER_MODIFY,
392 OPT_SUBUSER_RM,
393 OPT_KEY_CREATE,
394 OPT_KEY_RM,
395 OPT_BUCKETS_LIST,
396 OPT_BUCKET_LIMIT_CHECK,
397 OPT_BUCKET_LINK,
398 OPT_BUCKET_UNLINK,
399 OPT_BUCKET_STATS,
400 OPT_BUCKET_CHECK,
401 OPT_BUCKET_SYNC_STATUS,
402 OPT_BUCKET_SYNC_MARKERS,
403 OPT_BUCKET_SYNC_INIT,
404 OPT_BUCKET_SYNC_RUN,
405 OPT_BUCKET_SYNC_DISABLE,
406 OPT_BUCKET_SYNC_ENABLE,
407 OPT_BUCKET_RM,
408 OPT_BUCKET_REWRITE,
409 OPT_BUCKET_RESHARD,
410 OPT_POLICY,
411 OPT_POOL_ADD,
412 OPT_POOL_RM,
413 OPT_POOLS_LIST,
414 OPT_LOG_LIST,
415 OPT_LOG_SHOW,
416 OPT_LOG_RM,
417 OPT_USAGE_SHOW,
418 OPT_USAGE_TRIM,
419 OPT_USAGE_CLEAR,
420 OPT_OBJECT_PUT,
421 OPT_OBJECT_RM,
422 OPT_OBJECT_UNLINK,
423 OPT_OBJECT_STAT,
424 OPT_OBJECT_REWRITE,
425 OPT_OBJECTS_EXPIRE,
426 OPT_BI_GET,
427 OPT_BI_PUT,
428 OPT_BI_LIST,
429 OPT_BI_PURGE,
430 OPT_OLH_GET,
431 OPT_OLH_READLOG,
432 OPT_QUOTA_SET,
433 OPT_QUOTA_ENABLE,
434 OPT_QUOTA_DISABLE,
435 OPT_GC_LIST,
436 OPT_GC_PROCESS,
437 OPT_LC_LIST,
438 OPT_LC_GET,
439 OPT_LC_PROCESS,
440 OPT_LC_RESHARD_FIX,
441 OPT_ORPHANS_FIND,
442 OPT_ORPHANS_FINISH,
443 OPT_ORPHANS_LIST_JOBS,
444 OPT_ZONEGROUP_ADD,
445 OPT_ZONEGROUP_CREATE,
446 OPT_ZONEGROUP_DEFAULT,
447 OPT_ZONEGROUP_DELETE,
448 OPT_ZONEGROUP_GET,
449 OPT_ZONEGROUP_MODIFY,
450 OPT_ZONEGROUP_SET,
451 OPT_ZONEGROUP_LIST,
452 OPT_ZONEGROUP_REMOVE,
453 OPT_ZONEGROUP_RENAME,
454 OPT_ZONEGROUP_PLACEMENT_ADD,
455 OPT_ZONEGROUP_PLACEMENT_MODIFY,
456 OPT_ZONEGROUP_PLACEMENT_RM,
457 OPT_ZONEGROUP_PLACEMENT_LIST,
458 OPT_ZONEGROUP_PLACEMENT_DEFAULT,
459 OPT_ZONE_CREATE,
460 OPT_ZONE_DELETE,
461 OPT_ZONE_GET,
462 OPT_ZONE_MODIFY,
463 OPT_ZONE_SET,
464 OPT_ZONE_LIST,
465 OPT_ZONE_RENAME,
466 OPT_ZONE_DEFAULT,
467 OPT_ZONE_PLACEMENT_ADD,
468 OPT_ZONE_PLACEMENT_MODIFY,
469 OPT_ZONE_PLACEMENT_RM,
470 OPT_ZONE_PLACEMENT_LIST,
471 OPT_CAPS_ADD,
472 OPT_CAPS_RM,
473 OPT_METADATA_GET,
474 OPT_METADATA_PUT,
475 OPT_METADATA_RM,
476 OPT_METADATA_LIST,
477 OPT_METADATA_SYNC_STATUS,
478 OPT_METADATA_SYNC_INIT,
479 OPT_METADATA_SYNC_RUN,
480 OPT_MDLOG_LIST,
481 OPT_MDLOG_AUTOTRIM,
482 OPT_MDLOG_TRIM,
483 OPT_MDLOG_FETCH,
484 OPT_MDLOG_STATUS,
485 OPT_SYNC_ERROR_LIST,
486 OPT_SYNC_ERROR_TRIM,
487 OPT_BILOG_LIST,
488 OPT_BILOG_TRIM,
489 OPT_BILOG_STATUS,
490 OPT_BILOG_AUTOTRIM,
491 OPT_DATA_SYNC_STATUS,
492 OPT_DATA_SYNC_INIT,
493 OPT_DATA_SYNC_RUN,
494 OPT_DATALOG_LIST,
495 OPT_DATALOG_STATUS,
496 OPT_DATALOG_AUTOTRIM,
497 OPT_DATALOG_TRIM,
498 OPT_REALM_CREATE,
499 OPT_REALM_DELETE,
500 OPT_REALM_GET,
501 OPT_REALM_GET_DEFAULT,
502 OPT_REALM_LIST,
503 OPT_REALM_LIST_PERIODS,
504 OPT_REALM_RENAME,
505 OPT_REALM_SET,
506 OPT_REALM_DEFAULT,
507 OPT_REALM_PULL,
508 OPT_PERIOD_DELETE,
509 OPT_PERIOD_GET,
510 OPT_PERIOD_GET_CURRENT,
511 OPT_PERIOD_PULL,
512 OPT_PERIOD_PUSH,
513 OPT_PERIOD_LIST,
514 OPT_PERIOD_UPDATE,
515 OPT_PERIOD_COMMIT,
516 OPT_GLOBAL_QUOTA_GET,
517 OPT_GLOBAL_QUOTA_SET,
518 OPT_GLOBAL_QUOTA_ENABLE,
519 OPT_GLOBAL_QUOTA_DISABLE,
520 OPT_SYNC_STATUS,
521 OPT_ROLE_CREATE,
522 OPT_ROLE_DELETE,
523 OPT_ROLE_GET,
524 OPT_ROLE_MODIFY,
525 OPT_ROLE_LIST,
526 OPT_ROLE_POLICY_PUT,
527 OPT_ROLE_POLICY_LIST,
528 OPT_ROLE_POLICY_GET,
529 OPT_ROLE_POLICY_DELETE,
530 OPT_RESHARD_ADD,
531 OPT_RESHARD_LIST,
532 OPT_RESHARD_STATUS,
533 OPT_RESHARD_PROCESS,
534 OPT_RESHARD_CANCEL,
535 OPT_MFA_CREATE,
536 OPT_MFA_REMOVE,
537 OPT_MFA_GET,
538 OPT_MFA_LIST,
539 OPT_MFA_CHECK,
540 OPT_MFA_RESYNC,
541 OPT_RESHARD_STALE_INSTANCES_LIST,
542 OPT_RESHARD_STALE_INSTANCES_DELETE,
543 OPT_PUBSUB_TOPICS_LIST,
544 OPT_PUBSUB_TOPIC_CREATE,
545 OPT_PUBSUB_TOPIC_GET,
546 OPT_PUBSUB_TOPIC_RM,
547 OPT_PUBSUB_NOTIFICATION_CREATE,
548 OPT_PUBSUB_NOTIFICATION_RM,
549 OPT_PUBSUB_SUB_GET,
550 OPT_PUBSUB_SUB_CREATE,
551 OPT_PUBSUB_SUB_RM,
552 OPT_PUBSUB_SUB_PULL,
553 OPT_PUBSUB_EVENT_RM,
554 };
555
556 static int get_cmd(const char *cmd, const char *prev_cmd, const char *prev_prev_cmd, bool *need_more)
557 {
558 using ceph::util::match_str;
559
560 *need_more = false;
561 // NOTE: please keep the checks in alphabetical order !!!
562 if (strcmp(cmd, "bi") == 0 ||
563 strcmp(cmd, "bilog") == 0 ||
564 strcmp(cmd, "buckets") == 0 ||
565 strcmp(cmd, "caps") == 0 ||
566 strcmp(cmd, "data") == 0 ||
567 strcmp(cmd, "datalog") == 0 ||
568 strcmp(cmd, "error") == 0 ||
569 strcmp(cmd, "event") == 0 ||
570 strcmp(cmd, "gc") == 0 ||
571 strcmp(cmd, "global") == 0 ||
572 strcmp(cmd, "key") == 0 ||
573 strcmp(cmd, "log") == 0 ||
574 strcmp(cmd, "lc") == 0 ||
575 strcmp(cmd, "mdlog") == 0 ||
576 strcmp(cmd, "metadata") == 0 ||
577 strcmp(cmd, "mfa") == 0 ||
578 strcmp(cmd, "notification") == 0 ||
579 strcmp(cmd, "object") == 0 ||
580 strcmp(cmd, "objects") == 0 ||
581 strcmp(cmd, "olh") == 0 ||
582 strcmp(cmd, "orphans") == 0 ||
583 strcmp(cmd, "period") == 0 ||
584 strcmp(cmd, "placement") == 0 ||
585 strcmp(cmd, "pool") == 0 ||
586 strcmp(cmd, "pools") == 0 ||
587 strcmp(cmd, "pubsub") == 0 ||
588 strcmp(cmd, "quota") == 0 ||
589 strcmp(cmd, "realm") == 0 ||
590 strcmp(cmd, "role") == 0 ||
591 strcmp(cmd, "role-policy") == 0 ||
592 strcmp(cmd, "stale-instances") == 0 ||
593 strcmp(cmd, "sub") == 0 ||
594 strcmp(cmd, "subuser") == 0 ||
595 strcmp(cmd, "sync") == 0 ||
596 strcmp(cmd, "topic") == 0 ||
597 strcmp(cmd, "topics") == 0 ||
598 strcmp(cmd, "usage") == 0 ||
599 strcmp(cmd, "user") == 0 ||
600 strcmp(cmd, "zone") == 0 ||
601 strcmp(cmd, "zonegroup") == 0 ||
602 strcmp(cmd, "zonegroups") == 0) {
603 *need_more = true;
604 return 0;
605 }
606
607 /*
608 * can do both radosgw-admin bucket reshard, and radosgw-admin reshard bucket
609 */
610 if (strcmp(cmd, "reshard") == 0 &&
611 !(prev_cmd && strcmp(prev_cmd, "bucket") == 0)) {
612 *need_more = true;
613 return 0;
614 }
615 if (strcmp(cmd, "bucket") == 0 &&
616 !(prev_cmd && strcmp(prev_cmd, "reshard") == 0)) {
617 *need_more = true;
618 return 0;
619 }
620
621 if (strcmp(cmd, "policy") == 0)
622 return OPT_POLICY;
623
624 if (!prev_cmd)
625 return -EINVAL;
626
627 if (strcmp(prev_cmd, "user") == 0) {
628 if (strcmp(cmd, "create") == 0)
629 return OPT_USER_CREATE;
630 if (strcmp(cmd, "info") == 0)
631 return OPT_USER_INFO;
632 if (strcmp(cmd, "modify") == 0)
633 return OPT_USER_MODIFY;
634 if (strcmp(cmd, "rm") == 0)
635 return OPT_USER_RM;
636 if (strcmp(cmd, "suspend") == 0)
637 return OPT_USER_SUSPEND;
638 if (strcmp(cmd, "enable") == 0)
639 return OPT_USER_ENABLE;
640 if (strcmp(cmd, "check") == 0)
641 return OPT_USER_CHECK;
642 if (strcmp(cmd, "stats") == 0)
643 return OPT_USER_STATS;
644 if (strcmp(cmd, "list") == 0)
645 return OPT_USER_LIST;
646 } else if (strcmp(prev_cmd, "subuser") == 0) {
647 if (strcmp(cmd, "create") == 0)
648 return OPT_SUBUSER_CREATE;
649 if (strcmp(cmd, "modify") == 0)
650 return OPT_SUBUSER_MODIFY;
651 if (strcmp(cmd, "rm") == 0)
652 return OPT_SUBUSER_RM;
653 } else if (strcmp(prev_cmd, "key") == 0) {
654 if (strcmp(cmd, "create") == 0)
655 return OPT_KEY_CREATE;
656 if (strcmp(cmd, "rm") == 0)
657 return OPT_KEY_RM;
658 } else if (strcmp(prev_cmd, "buckets") == 0) {
659 if (strcmp(cmd, "list") == 0)
660 return OPT_BUCKETS_LIST;
661 } else if (strcmp(prev_cmd, "bucket") == 0) {
662 if (strcmp(cmd, "list") == 0)
663 return OPT_BUCKETS_LIST;
664 if (strcmp(cmd, "link") == 0)
665 return OPT_BUCKET_LINK;
666 if (strcmp(cmd, "unlink") == 0)
667 return OPT_BUCKET_UNLINK;
668 if (strcmp(cmd, "stats") == 0)
669 return OPT_BUCKET_STATS;
670 if (strcmp(cmd, "rm") == 0)
671 return OPT_BUCKET_RM;
672 if (strcmp(cmd, "rewrite") == 0)
673 return OPT_BUCKET_REWRITE;
674 if (strcmp(cmd, "reshard") == 0)
675 return OPT_BUCKET_RESHARD;
676 if (strcmp(cmd, "check") == 0)
677 return OPT_BUCKET_CHECK;
678 if (strcmp(cmd, "sync") == 0) {
679 *need_more = true;
680 return 0;
681 }
682 if (strcmp(cmd, "limit") == 0) {
683 *need_more = true;
684 return 0;
685 }
686 } else if (prev_prev_cmd && strcmp(prev_prev_cmd, "bucket") == 0) {
687 if (strcmp(prev_cmd, "sync") == 0) {
688 if (strcmp(cmd, "status") == 0)
689 return OPT_BUCKET_SYNC_STATUS;
690 if (strcmp(cmd, "markers") == 0)
691 return OPT_BUCKET_SYNC_MARKERS;
692 if (strcmp(cmd, "init") == 0)
693 return OPT_BUCKET_SYNC_INIT;
694 if (strcmp(cmd, "run") == 0)
695 return OPT_BUCKET_SYNC_RUN;
696 if (strcmp(cmd, "disable") == 0)
697 return OPT_BUCKET_SYNC_DISABLE;
698 if (strcmp(cmd, "enable") == 0)
699 return OPT_BUCKET_SYNC_ENABLE;
700 } else if ((strcmp(prev_cmd, "limit") == 0) &&
701 (strcmp(cmd, "check") == 0)) {
702 return OPT_BUCKET_LIMIT_CHECK;
703 }
704 } else if (strcmp(prev_cmd, "log") == 0) {
705 if (strcmp(cmd, "list") == 0)
706 return OPT_LOG_LIST;
707 if (strcmp(cmd, "show") == 0)
708 return OPT_LOG_SHOW;
709 if (strcmp(cmd, "rm") == 0)
710 return OPT_LOG_RM;
711 } else if (strcmp(prev_cmd, "usage") == 0) {
712 if (strcmp(cmd, "show") == 0)
713 return OPT_USAGE_SHOW;
714 if (strcmp(cmd, "trim") == 0)
715 return OPT_USAGE_TRIM;
716 if (strcmp(cmd, "clear") == 0)
717 return OPT_USAGE_CLEAR;
718 } else if (strcmp(prev_cmd, "caps") == 0) {
719 if (strcmp(cmd, "add") == 0)
720 return OPT_CAPS_ADD;
721 if (strcmp(cmd, "rm") == 0)
722 return OPT_CAPS_RM;
723 } else if (strcmp(prev_cmd, "pool") == 0) {
724 if (strcmp(cmd, "add") == 0)
725 return OPT_POOL_ADD;
726 if (strcmp(cmd, "rm") == 0)
727 return OPT_POOL_RM;
728 if (strcmp(cmd, "list") == 0)
729 return OPT_POOLS_LIST;
730 } else if (strcmp(prev_cmd, "pools") == 0) {
731 if (strcmp(cmd, "list") == 0)
732 return OPT_POOLS_LIST;
733 } else if (strcmp(prev_cmd, "object") == 0) {
734 if (strcmp(cmd, "put") == 0)
735 return OPT_OBJECT_PUT;
736 if (strcmp(cmd, "rm") == 0)
737 return OPT_OBJECT_RM;
738 if (strcmp(cmd, "unlink") == 0)
739 return OPT_OBJECT_UNLINK;
740 if (strcmp(cmd, "stat") == 0)
741 return OPT_OBJECT_STAT;
742 if (strcmp(cmd, "rewrite") == 0)
743 return OPT_OBJECT_REWRITE;
744 } else if (strcmp(prev_cmd, "objects") == 0) {
745 if (strcmp(cmd, "expire") == 0)
746 return OPT_OBJECTS_EXPIRE;
747 } else if (strcmp(prev_cmd, "olh") == 0) {
748 if (strcmp(cmd, "get") == 0)
749 return OPT_OLH_GET;
750 if (strcmp(cmd, "readlog") == 0)
751 return OPT_OLH_READLOG;
752 } else if (strcmp(prev_cmd, "bi") == 0) {
753 if (strcmp(cmd, "get") == 0)
754 return OPT_BI_GET;
755 if (strcmp(cmd, "put") == 0)
756 return OPT_BI_PUT;
757 if (strcmp(cmd, "list") == 0)
758 return OPT_BI_LIST;
759 if (strcmp(cmd, "purge") == 0)
760 return OPT_BI_PURGE;
761 } else if ((prev_prev_cmd && strcmp(prev_prev_cmd, "global") == 0) &&
762 (strcmp(prev_cmd, "quota") == 0)) {
763 if (strcmp(cmd, "get") == 0)
764 return OPT_GLOBAL_QUOTA_GET;
765 if (strcmp(cmd, "set") == 0)
766 return OPT_GLOBAL_QUOTA_SET;
767 if (strcmp(cmd, "enable") == 0)
768 return OPT_GLOBAL_QUOTA_ENABLE;
769 if (strcmp(cmd, "disable") == 0)
770 return OPT_GLOBAL_QUOTA_DISABLE;
771 } else if (strcmp(prev_cmd, "period") == 0) {
772 if (match_str(cmd, "rm", "delete"))
773 return OPT_PERIOD_DELETE;
774 if (strcmp(cmd, "get") == 0)
775 return OPT_PERIOD_GET;
776 if (strcmp(cmd, "get-current") == 0)
777 return OPT_PERIOD_GET_CURRENT;
778 if (strcmp(cmd, "pull") == 0)
779 return OPT_PERIOD_PULL;
780 if (strcmp(cmd, "push") == 0)
781 return OPT_PERIOD_PUSH;
782 if (strcmp(cmd, "list") == 0)
783 return OPT_PERIOD_LIST;
784 if (strcmp(cmd, "update") == 0)
785 return OPT_PERIOD_UPDATE;
786 if (strcmp(cmd, "commit") == 0)
787 return OPT_PERIOD_COMMIT;
788 } else if (strcmp(prev_cmd, "realm") == 0) {
789 if (strcmp(cmd, "create") == 0)
790 return OPT_REALM_CREATE;
791 if (match_str(cmd, "rm", "delete"))
792 return OPT_REALM_DELETE;
793 if (strcmp(cmd, "get") == 0)
794 return OPT_REALM_GET;
795 if (strcmp(cmd, "get-default") == 0)
796 return OPT_REALM_GET_DEFAULT;
797 if (strcmp(cmd, "list") == 0)
798 return OPT_REALM_LIST;
799 if (strcmp(cmd, "list-periods") == 0)
800 return OPT_REALM_LIST_PERIODS;
801 if (strcmp(cmd, "rename") == 0)
802 return OPT_REALM_RENAME;
803 if (strcmp(cmd, "set") == 0)
804 return OPT_REALM_SET;
805 if (strcmp(cmd, "default") == 0)
806 return OPT_REALM_DEFAULT;
807 if (strcmp(cmd, "pull") == 0)
808 return OPT_REALM_PULL;
809 } else if ((prev_prev_cmd && strcmp(prev_prev_cmd, "zonegroup") == 0) &&
810 (strcmp(prev_cmd, "placement") == 0)) {
811 if (strcmp(cmd, "add") == 0)
812 return OPT_ZONEGROUP_PLACEMENT_ADD;
813 if (strcmp(cmd, "modify") == 0)
814 return OPT_ZONEGROUP_PLACEMENT_MODIFY;
815 if (strcmp(cmd, "rm") == 0)
816 return OPT_ZONEGROUP_PLACEMENT_RM;
817 if (strcmp(cmd, "list") == 0)
818 return OPT_ZONEGROUP_PLACEMENT_LIST;
819 if (strcmp(cmd, "default") == 0)
820 return OPT_ZONEGROUP_PLACEMENT_DEFAULT;
821 } else if (strcmp(prev_cmd, "zonegroup") == 0) {
822 if (strcmp(cmd, "add") == 0)
823 return OPT_ZONEGROUP_ADD;
824 if (strcmp(cmd, "create")== 0)
825 return OPT_ZONEGROUP_CREATE;
826 if (strcmp(cmd, "default") == 0)
827 return OPT_ZONEGROUP_DEFAULT;
828 if (strcmp(cmd, "delete") == 0)
829 return OPT_ZONEGROUP_DELETE;
830 if (strcmp(cmd, "get") == 0)
831 return OPT_ZONEGROUP_GET;
832 if (strcmp(cmd, "modify") == 0)
833 return OPT_ZONEGROUP_MODIFY;
834 if (strcmp(cmd, "list") == 0)
835 return OPT_ZONEGROUP_LIST;
836 if (strcmp(cmd, "set") == 0)
837 return OPT_ZONEGROUP_SET;
838 if (match_str(cmd, "rm", "remove"))
839 return OPT_ZONEGROUP_REMOVE;
840 if (strcmp(cmd, "rename") == 0)
841 return OPT_ZONEGROUP_RENAME;
842 } else if (strcmp(prev_cmd, "quota") == 0) {
843 if (strcmp(cmd, "set") == 0)
844 return OPT_QUOTA_SET;
845 if (strcmp(cmd, "enable") == 0)
846 return OPT_QUOTA_ENABLE;
847 if (strcmp(cmd, "disable") == 0)
848 return OPT_QUOTA_DISABLE;
849 } else if (strcmp(prev_cmd, "zonegroups") == 0) {
850 if (strcmp(cmd, "list") == 0)
851 return OPT_ZONEGROUP_LIST;
852 } else if ((prev_prev_cmd && strcmp(prev_prev_cmd, "zone") == 0) &&
853 (strcmp(prev_cmd, "placement") == 0)) {
854 if (strcmp(cmd, "add") == 0)
855 return OPT_ZONE_PLACEMENT_ADD;
856 if (strcmp(cmd, "modify") == 0)
857 return OPT_ZONE_PLACEMENT_MODIFY;
858 if (strcmp(cmd, "rm") == 0)
859 return OPT_ZONE_PLACEMENT_RM;
860 if (strcmp(cmd, "list") == 0)
861 return OPT_ZONE_PLACEMENT_LIST;
862 } else if (strcmp(prev_cmd, "zone") == 0) {
863 if (strcmp(cmd, "delete") == 0)
864 return OPT_ZONE_DELETE;
865 if (strcmp(cmd, "create") == 0)
866 return OPT_ZONE_CREATE;
867 if (strcmp(cmd, "get") == 0)
868 return OPT_ZONE_GET;
869 if (strcmp(cmd, "set") == 0)
870 return OPT_ZONE_SET;
871 if (strcmp(cmd, "list") == 0)
872 return OPT_ZONE_LIST;
873 if (strcmp(cmd, "modify") == 0)
874 return OPT_ZONE_MODIFY;
875 if (strcmp(cmd, "rename") == 0)
876 return OPT_ZONE_RENAME;
877 if (strcmp(cmd, "default") == 0)
878 return OPT_ZONE_DEFAULT;
879 } else if (strcmp(prev_cmd, "zones") == 0) {
880 if (strcmp(cmd, "list") == 0)
881 return OPT_ZONE_LIST;
882 } else if (strcmp(prev_cmd, "gc") == 0) {
883 if (strcmp(cmd, "list") == 0)
884 return OPT_GC_LIST;
885 if (strcmp(cmd, "process") == 0)
886 return OPT_GC_PROCESS;
887 } else if (strcmp(prev_cmd, "lc") == 0) {
888 if (strcmp(cmd, "list") == 0)
889 return OPT_LC_LIST;
890 if (strcmp(cmd, "get") == 0)
891 return OPT_LC_GET;
892 if (strcmp(cmd, "process") == 0)
893 return OPT_LC_PROCESS;
894 } else if ((prev_prev_cmd && strcmp(prev_prev_cmd, "lc") == 0) &&
895 strcmp(prev_cmd, "reshard") == 0) {
896 if (strcmp(cmd, "fix") == 0)
897 return OPT_LC_RESHARD_FIX;
898 } else if (strcmp(prev_cmd, "orphans") == 0) {
899 if (strcmp(cmd, "find") == 0)
900 return OPT_ORPHANS_FIND;
901 if (strcmp(cmd, "finish") == 0)
902 return OPT_ORPHANS_FINISH;
903 if (strcmp(cmd, "list-jobs") == 0)
904 return OPT_ORPHANS_LIST_JOBS;
905 } else if (strcmp(prev_cmd, "metadata") == 0) {
906 if (strcmp(cmd, "get") == 0)
907 return OPT_METADATA_GET;
908 if (strcmp(cmd, "put") == 0)
909 return OPT_METADATA_PUT;
910 if (strcmp(cmd, "rm") == 0)
911 return OPT_METADATA_RM;
912 if (strcmp(cmd, "list") == 0)
913 return OPT_METADATA_LIST;
914 if (strcmp(cmd, "sync") == 0) {
915 *need_more = true;
916 return 0;
917 }
918 } else if ((prev_prev_cmd && strcmp(prev_prev_cmd, "metadata") == 0) &&
919 (strcmp(prev_cmd, "sync") == 0)) {
920 if (strcmp(cmd, "status") == 0)
921 return OPT_METADATA_SYNC_STATUS;
922 if (strcmp(cmd, "init") == 0)
923 return OPT_METADATA_SYNC_INIT;
924 if (strcmp(cmd, "run") == 0)
925 return OPT_METADATA_SYNC_RUN;
926 } else if ((prev_prev_cmd && strcmp(prev_prev_cmd, "sync") == 0) &&
927 (strcmp(prev_cmd, "error") == 0)) {
928 if (strcmp(cmd, "list") == 0)
929 return OPT_SYNC_ERROR_LIST;
930 if (strcmp(cmd, "trim") == 0)
931 return OPT_SYNC_ERROR_TRIM;
932 } else if (strcmp(prev_cmd, "mdlog") == 0) {
933 if (strcmp(cmd, "list") == 0)
934 return OPT_MDLOG_LIST;
935 if (strcmp(cmd, "autotrim") == 0)
936 return OPT_MDLOG_AUTOTRIM;
937 if (strcmp(cmd, "trim") == 0)
938 return OPT_MDLOG_TRIM;
939 if (strcmp(cmd, "fetch") == 0)
940 return OPT_MDLOG_FETCH;
941 if (strcmp(cmd, "status") == 0)
942 return OPT_MDLOG_STATUS;
943 } else if (strcmp(prev_cmd, "bilog") == 0) {
944 if (strcmp(cmd, "list") == 0)
945 return OPT_BILOG_LIST;
946 if (strcmp(cmd, "trim") == 0)
947 return OPT_BILOG_TRIM;
948 if (strcmp(cmd, "status") == 0)
949 return OPT_BILOG_STATUS;
950 if (strcmp(cmd, "autotrim") == 0)
951 return OPT_BILOG_AUTOTRIM;
952 } else if (strcmp(prev_cmd, "data") == 0) {
953 if (strcmp(cmd, "sync") == 0) {
954 *need_more = true;
955 return 0;
956 }
957 } else if (strcmp(prev_cmd, "datalog") == 0) {
958 if (strcmp(cmd, "list") == 0)
959 return OPT_DATALOG_LIST;
960 if (strcmp(cmd, "autotrim") == 0)
961 return OPT_DATALOG_AUTOTRIM;
962 if (strcmp(cmd, "trim") == 0)
963 return OPT_DATALOG_TRIM;
964 if (strcmp(cmd, "status") == 0)
965 return OPT_DATALOG_STATUS;
966 } else if ((prev_prev_cmd && strcmp(prev_prev_cmd, "data") == 0) &&
967 (strcmp(prev_cmd, "sync") == 0)) {
968 if (strcmp(cmd, "status") == 0)
969 return OPT_DATA_SYNC_STATUS;
970 if (strcmp(cmd, "init") == 0)
971 return OPT_DATA_SYNC_INIT;
972 if (strcmp(cmd, "run") == 0)
973 return OPT_DATA_SYNC_RUN;
974 } else if (strcmp(prev_cmd, "sync") == 0) {
975 if (strcmp(cmd, "status") == 0)
976 return OPT_SYNC_STATUS;
977 } else if (strcmp(prev_cmd, "role") == 0) {
978 if (strcmp(cmd, "create") == 0)
979 return OPT_ROLE_CREATE;
980 if (strcmp(cmd, "rm") == 0)
981 return OPT_ROLE_DELETE;
982 if (strcmp(cmd, "get") == 0)
983 return OPT_ROLE_GET;
984 if (strcmp(cmd, "modify") == 0)
985 return OPT_ROLE_MODIFY;
986 if (strcmp(cmd, "list") == 0)
987 return OPT_ROLE_LIST;
988 } else if (strcmp(prev_cmd, "role-policy") == 0) {
989 if (strcmp(cmd, "put") == 0)
990 return OPT_ROLE_POLICY_PUT;
991 if (strcmp(cmd, "list") == 0)
992 return OPT_ROLE_POLICY_LIST;
993 if (strcmp(cmd, "get") == 0)
994 return OPT_ROLE_POLICY_GET;
995 if (match_str(cmd, "rm", "delete"))
996 return OPT_ROLE_POLICY_DELETE;
997 } else if (strcmp(prev_cmd, "reshard") == 0) {
998 if (strcmp(cmd, "bucket") == 0)
999 return OPT_BUCKET_RESHARD;
1000 if (strcmp(cmd, "add") == 0)
1001 return OPT_RESHARD_ADD;
1002 if (strcmp(cmd, "list") == 0)
1003 return OPT_RESHARD_LIST;
1004 if (strcmp(cmd, "status") == 0)
1005 return OPT_RESHARD_STATUS;
1006 if (strcmp(cmd, "process") == 0)
1007 return OPT_RESHARD_PROCESS;
1008 if (strcmp(cmd, "cancel") == 0)
1009 return OPT_RESHARD_CANCEL;
1010 } else if (strcmp(prev_cmd, "mfa") == 0) {
1011 if (strcmp(cmd, "create") == 0)
1012 return OPT_MFA_CREATE;
1013 if (strcmp(cmd, "remove") == 0)
1014 return OPT_MFA_REMOVE;
1015 if (strcmp(cmd, "get") == 0)
1016 return OPT_MFA_GET;
1017 if (strcmp(cmd, "list") == 0)
1018 return OPT_MFA_LIST;
1019 if (strcmp(cmd, "check") == 0)
1020 return OPT_MFA_CHECK;
1021 if (strcmp(cmd, "resync") == 0)
1022 return OPT_MFA_RESYNC;
1023 } else if ((prev_prev_cmd && strcmp(prev_prev_cmd, "reshard") == 0) &&
1024 (strcmp(prev_cmd, "stale-instances") == 0)) {
1025 if (strcmp(cmd, "list") == 0)
1026 return OPT_RESHARD_STALE_INSTANCES_LIST;
1027 if (match_str(cmd, "rm", "delete"))
1028 return OPT_RESHARD_STALE_INSTANCES_DELETE;
1029 } else if (prev_prev_cmd && strcmp(prev_prev_cmd, "pubsub") == 0) {
1030 if (strcmp(prev_cmd, "topics") == 0) {
1031 if (strcmp(cmd, "list") == 0)
1032 return OPT_PUBSUB_TOPICS_LIST;
1033 } else if (strcmp(prev_cmd, "topic") == 0) {
1034 if (strcmp(cmd, "create") == 0)
1035 return OPT_PUBSUB_TOPIC_CREATE;
1036 if (strcmp(cmd, "get") == 0)
1037 return OPT_PUBSUB_TOPIC_GET;
1038 if (strcmp(cmd, "rm") == 0)
1039 return OPT_PUBSUB_TOPIC_RM;
1040 } else if (strcmp(prev_cmd, "notification") == 0) {
1041 if (strcmp(cmd, "create") == 0)
1042 return OPT_PUBSUB_NOTIFICATION_CREATE;
1043 if (strcmp(cmd, "rm") == 0)
1044 return OPT_PUBSUB_NOTIFICATION_RM;
1045 } else if (strcmp(prev_cmd, "sub") == 0) {
1046 if (strcmp(cmd, "get") == 0)
1047 return OPT_PUBSUB_SUB_GET;
1048 if (strcmp(cmd, "create") == 0)
1049 return OPT_PUBSUB_SUB_CREATE;
1050 if (strcmp(cmd, "rm") == 0)
1051 return OPT_PUBSUB_SUB_RM;
1052 if (strcmp(cmd, "pull") == 0)
1053 return OPT_PUBSUB_SUB_PULL;
1054 } else if (strcmp(prev_cmd, "event") == 0) {
1055 if (strcmp(cmd, "rm") == 0)
1056 return OPT_PUBSUB_EVENT_RM;
1057 }
1058 }
1059 return -EINVAL;
1060 }
1061
1062 BIIndexType get_bi_index_type(const string& type_str) {
1063 if (type_str == "plain")
1064 return BIIndexType::Plain;
1065 if (type_str == "instance")
1066 return BIIndexType::Instance;
1067 if (type_str == "olh")
1068 return BIIndexType::OLH;
1069
1070 return BIIndexType::Invalid;
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(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<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 RGWRados *store;
1161 public:
1162 explicit StoreDestructor(RGWRados *_s) : store(_s) {}
1163 ~StoreDestructor() {
1164 RGWStoreManager::close_storage(store);
1165 rgw_http_client_cleanup();
1166 }
1167 };
1168
1169 static int init_bucket(const string& tenant_name, const string& bucket_name, const string& bucket_id,
1170 RGWBucketInfo& bucket_info, rgw_bucket& bucket, map<string, bufferlist> *pattrs = nullptr)
1171 {
1172 if (!bucket_name.empty()) {
1173 auto obj_ctx = store->svc.sysobj->init_obj_ctx();
1174 int r;
1175 if (bucket_id.empty()) {
1176 r = store->get_bucket_info(obj_ctx, tenant_name, bucket_name, bucket_info, nullptr, pattrs);
1177 } else {
1178 string bucket_instance_id = bucket_name + ":" + bucket_id;
1179 r = store->get_bucket_instance_info(obj_ctx, bucket_instance_id, bucket_info, NULL, pattrs);
1180 }
1181 if (r < 0) {
1182 cerr << "could not get bucket info for bucket=" << bucket_name << std::endl;
1183 return r;
1184 }
1185 bucket = bucket_info.bucket;
1186 }
1187 return 0;
1188 }
1189
1190 static int read_input(const string& infile, bufferlist& bl)
1191 {
1192 int fd = 0;
1193 if (infile.size()) {
1194 fd = open(infile.c_str(), O_RDONLY);
1195 if (fd < 0) {
1196 int err = -errno;
1197 cerr << "error reading input file " << infile << std::endl;
1198 return err;
1199 }
1200 }
1201
1202 #define READ_CHUNK 8196
1203 int r;
1204 int err;
1205
1206 do {
1207 char buf[READ_CHUNK];
1208
1209 r = safe_read(fd, buf, READ_CHUNK);
1210 if (r < 0) {
1211 err = -errno;
1212 cerr << "error while reading input" << std::endl;
1213 goto out;
1214 }
1215 bl.append(buf, r);
1216 } while (r > 0);
1217 err = 0;
1218
1219 out:
1220 if (infile.size()) {
1221 close(fd);
1222 }
1223 return err;
1224 }
1225
1226 template <class T>
1227 static int read_decode_json(const string& infile, T& t)
1228 {
1229 bufferlist bl;
1230 int ret = read_input(infile, bl);
1231 if (ret < 0) {
1232 cerr << "ERROR: failed to read input: " << cpp_strerror(-ret) << std::endl;
1233 return ret;
1234 }
1235 JSONParser p;
1236 if (!p.parse(bl.c_str(), bl.length())) {
1237 cout << "failed to parse JSON" << std::endl;
1238 return -EINVAL;
1239 }
1240
1241 try {
1242 decode_json_obj(t, &p);
1243 } catch (JSONDecoder::err& e) {
1244 cout << "failed to decode JSON input: " << e.message << std::endl;
1245 return -EINVAL;
1246 }
1247 return 0;
1248 }
1249
1250 template <class T, class K>
1251 static int read_decode_json(const string& infile, T& t, K *k)
1252 {
1253 bufferlist bl;
1254 int ret = read_input(infile, bl);
1255 if (ret < 0) {
1256 cerr << "ERROR: failed to read input: " << cpp_strerror(-ret) << std::endl;
1257 return ret;
1258 }
1259 JSONParser p;
1260 if (!p.parse(bl.c_str(), bl.length())) {
1261 cout << "failed to parse JSON" << std::endl;
1262 return -EINVAL;
1263 }
1264
1265 try {
1266 t.decode_json(&p, k);
1267 } catch (JSONDecoder::err& e) {
1268 cout << "failed to decode JSON input: " << e.message << std::endl;
1269 return -EINVAL;
1270 }
1271 return 0;
1272 }
1273
1274 static int parse_date_str(const string& date_str, utime_t& ut)
1275 {
1276 uint64_t epoch = 0;
1277 uint64_t nsec = 0;
1278
1279 if (!date_str.empty()) {
1280 int ret = utime_t::parse_date(date_str, &epoch, &nsec);
1281 if (ret < 0) {
1282 cerr << "ERROR: failed to parse date: " << date_str << std::endl;
1283 return -EINVAL;
1284 }
1285 }
1286
1287 ut = utime_t(epoch, nsec);
1288
1289 return 0;
1290 }
1291
1292 template <class T>
1293 static bool decode_dump(const char *field_name, bufferlist& bl, Formatter *f)
1294 {
1295 T t;
1296
1297 auto iter = bl.cbegin();
1298
1299 try {
1300 decode(t, iter);
1301 } catch (buffer::error& err) {
1302 return false;
1303 }
1304
1305 encode_json(field_name, t, f);
1306
1307 return true;
1308 }
1309
1310 static bool dump_string(const char *field_name, bufferlist& bl, Formatter *f)
1311 {
1312 string val = bl.to_str();
1313 f->dump_string(field_name, val.c_str() /* hide encoded null termination chars */);
1314
1315 return true;
1316 }
1317
1318 void set_quota_info(RGWQuotaInfo& quota, int opt_cmd, int64_t max_size, int64_t max_objects,
1319 bool have_max_size, bool have_max_objects)
1320 {
1321 switch (opt_cmd) {
1322 case OPT_QUOTA_ENABLE:
1323 case OPT_GLOBAL_QUOTA_ENABLE:
1324 quota.enabled = true;
1325
1326 // falling through on purpose
1327
1328 case OPT_QUOTA_SET:
1329 case OPT_GLOBAL_QUOTA_SET:
1330 if (have_max_objects) {
1331 if (max_objects < 0) {
1332 quota.max_objects = -1;
1333 } else {
1334 quota.max_objects = max_objects;
1335 }
1336 }
1337 if (have_max_size) {
1338 if (max_size < 0) {
1339 quota.max_size = -1;
1340 } else {
1341 quota.max_size = rgw_rounded_kb(max_size) * 1024;
1342 }
1343 }
1344 break;
1345 case OPT_QUOTA_DISABLE:
1346 case OPT_GLOBAL_QUOTA_DISABLE:
1347 quota.enabled = false;
1348 break;
1349 }
1350 }
1351
1352 int set_bucket_quota(RGWRados *store, int opt_cmd,
1353 const string& tenant_name, const string& bucket_name,
1354 int64_t max_size, int64_t max_objects,
1355 bool have_max_size, bool have_max_objects)
1356 {
1357 RGWBucketInfo bucket_info;
1358 map<string, bufferlist> attrs;
1359 auto obj_ctx = store->svc.sysobj->init_obj_ctx();
1360 int r = store->get_bucket_info(obj_ctx, tenant_name, bucket_name, bucket_info, NULL, &attrs);
1361 if (r < 0) {
1362 cerr << "could not get bucket info for bucket=" << bucket_name << ": " << cpp_strerror(-r) << std::endl;
1363 return -r;
1364 }
1365
1366 set_quota_info(bucket_info.quota, opt_cmd, max_size, max_objects, have_max_size, have_max_objects);
1367
1368 r = store->put_bucket_instance_info(bucket_info, false, real_time(), &attrs);
1369 if (r < 0) {
1370 cerr << "ERROR: failed writing bucket instance info: " << cpp_strerror(-r) << std::endl;
1371 return -r;
1372 }
1373 return 0;
1374 }
1375
1376 int set_user_bucket_quota(int opt_cmd, RGWUser& user, RGWUserAdminOpState& op_state, int64_t max_size, int64_t max_objects,
1377 bool have_max_size, bool have_max_objects)
1378 {
1379 RGWUserInfo& user_info = op_state.get_user_info();
1380
1381 set_quota_info(user_info.bucket_quota, opt_cmd, max_size, max_objects, have_max_size, have_max_objects);
1382
1383 op_state.set_bucket_quota(user_info.bucket_quota);
1384
1385 string err;
1386 int r = user.modify(op_state, &err);
1387 if (r < 0) {
1388 cerr << "ERROR: failed updating user info: " << cpp_strerror(-r) << ": " << err << std::endl;
1389 return -r;
1390 }
1391 return 0;
1392 }
1393
1394 int set_user_quota(int opt_cmd, RGWUser& user, RGWUserAdminOpState& op_state, int64_t max_size, int64_t max_objects,
1395 bool have_max_size, bool have_max_objects)
1396 {
1397 RGWUserInfo& user_info = op_state.get_user_info();
1398
1399 set_quota_info(user_info.user_quota, opt_cmd, max_size, max_objects, have_max_size, have_max_objects);
1400
1401 op_state.set_user_quota(user_info.user_quota);
1402
1403 string err;
1404 int r = user.modify(op_state, &err);
1405 if (r < 0) {
1406 cerr << "ERROR: failed updating user info: " << cpp_strerror(-r) << ": " << err << std::endl;
1407 return -r;
1408 }
1409 return 0;
1410 }
1411
1412 static bool bucket_object_check_filter(const string& name)
1413 {
1414 rgw_obj_key k;
1415 string ns; /* empty namespace */
1416 return rgw_obj_key::oid_to_key_in_ns(name, &k, ns);
1417 }
1418
1419 int check_min_obj_stripe_size(RGWRados *store, RGWBucketInfo& bucket_info, rgw_obj& obj, uint64_t min_stripe_size, bool *need_rewrite)
1420 {
1421 map<string, bufferlist> attrs;
1422 uint64_t obj_size;
1423
1424 RGWObjectCtx obj_ctx(store);
1425 RGWRados::Object op_target(store, bucket_info, obj_ctx, obj);
1426 RGWRados::Object::Read read_op(&op_target);
1427
1428 read_op.params.attrs = &attrs;
1429 read_op.params.obj_size = &obj_size;
1430
1431 int ret = read_op.prepare();
1432 if (ret < 0) {
1433 lderr(store->ctx()) << "ERROR: failed to stat object, returned error: " << cpp_strerror(-ret) << dendl;
1434 return ret;
1435 }
1436
1437 map<string, bufferlist>::iterator iter;
1438 iter = attrs.find(RGW_ATTR_MANIFEST);
1439 if (iter == attrs.end()) {
1440 *need_rewrite = (obj_size >= min_stripe_size);
1441 return 0;
1442 }
1443
1444 RGWObjManifest manifest;
1445
1446 try {
1447 bufferlist& bl = iter->second;
1448 auto biter = bl.cbegin();
1449 decode(manifest, biter);
1450 } catch (buffer::error& err) {
1451 ldout(store->ctx(), 0) << "ERROR: failed to decode manifest" << dendl;
1452 return -EIO;
1453 }
1454
1455 map<uint64_t, RGWObjManifestPart>& objs = manifest.get_explicit_objs();
1456 map<uint64_t, RGWObjManifestPart>::iterator oiter;
1457 for (oiter = objs.begin(); oiter != objs.end(); ++oiter) {
1458 RGWObjManifestPart& part = oiter->second;
1459
1460 if (part.size >= min_stripe_size) {
1461 *need_rewrite = true;
1462 return 0;
1463 }
1464 }
1465 *need_rewrite = false;
1466
1467 return 0;
1468 }
1469
1470
1471 int check_obj_locator_underscore(RGWBucketInfo& bucket_info, rgw_obj& obj, rgw_obj_key& key, bool fix, bool remove_bad, Formatter *f) {
1472 f->open_object_section("object");
1473 f->open_object_section("key");
1474 f->dump_string("type", "head");
1475 f->dump_string("name", key.name);
1476 f->dump_string("instance", key.instance);
1477 f->close_section();
1478
1479 string oid;
1480 string locator;
1481
1482 get_obj_bucket_and_oid_loc(obj, oid, locator);
1483
1484 f->dump_string("oid", oid);
1485 f->dump_string("locator", locator);
1486
1487
1488 RGWObjectCtx obj_ctx(store);
1489
1490 RGWRados::Object op_target(store, bucket_info, obj_ctx, obj);
1491 RGWRados::Object::Read read_op(&op_target);
1492
1493 int ret = read_op.prepare();
1494 bool needs_fixing = (ret == -ENOENT);
1495
1496 f->dump_bool("needs_fixing", needs_fixing);
1497
1498 string status = (needs_fixing ? "needs_fixing" : "ok");
1499
1500 if ((needs_fixing || remove_bad) && fix) {
1501 ret = store->fix_head_obj_locator(bucket_info, needs_fixing, remove_bad, key);
1502 if (ret < 0) {
1503 cerr << "ERROR: fix_head_object_locator() returned ret=" << ret << std::endl;
1504 goto done;
1505 }
1506 status = "fixed";
1507 }
1508
1509 done:
1510 f->dump_string("status", status);
1511
1512 f->close_section();
1513
1514 return 0;
1515 }
1516
1517 int check_obj_tail_locator_underscore(RGWBucketInfo& bucket_info, rgw_obj& obj, rgw_obj_key& key, bool fix, Formatter *f) {
1518 f->open_object_section("object");
1519 f->open_object_section("key");
1520 f->dump_string("type", "tail");
1521 f->dump_string("name", key.name);
1522 f->dump_string("instance", key.instance);
1523 f->close_section();
1524
1525 bool needs_fixing;
1526 string status;
1527
1528 int ret = store->fix_tail_obj_locator(bucket_info, key, fix, &needs_fixing);
1529 if (ret < 0) {
1530 cerr << "ERROR: fix_tail_object_locator_underscore() returned ret=" << ret << std::endl;
1531 status = "failed";
1532 } else {
1533 status = (needs_fixing && !fix ? "needs_fixing" : "ok");
1534 }
1535
1536 f->dump_bool("needs_fixing", needs_fixing);
1537 f->dump_string("status", status);
1538
1539 f->close_section();
1540
1541 return 0;
1542 }
1543
1544 int do_check_object_locator(const string& tenant_name, const string& bucket_name,
1545 bool fix, bool remove_bad, Formatter *f)
1546 {
1547 if (remove_bad && !fix) {
1548 cerr << "ERROR: can't have remove_bad specified without fix" << std::endl;
1549 return -EINVAL;
1550 }
1551
1552 RGWBucketInfo bucket_info;
1553 rgw_bucket bucket;
1554 string bucket_id;
1555
1556 f->open_object_section("bucket");
1557 f->dump_string("bucket", bucket_name);
1558 int ret = init_bucket(tenant_name, bucket_name, bucket_id, bucket_info, bucket);
1559 if (ret < 0) {
1560 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
1561 return ret;
1562 }
1563 bool truncated;
1564 int count = 0;
1565
1566 int max_entries = 1000;
1567
1568 string prefix;
1569 string delim;
1570 vector<rgw_bucket_dir_entry> result;
1571 map<string, bool> common_prefixes;
1572 string ns;
1573
1574 RGWRados::Bucket target(store, bucket_info);
1575 RGWRados::Bucket::List list_op(&target);
1576
1577 string marker;
1578
1579 list_op.params.prefix = prefix;
1580 list_op.params.delim = delim;
1581 list_op.params.marker = rgw_obj_key(marker);
1582 list_op.params.ns = ns;
1583 list_op.params.enforce_ns = true;
1584 list_op.params.list_versions = true;
1585
1586 f->open_array_section("check_objects");
1587 do {
1588 ret = list_op.list_objects(max_entries - count, &result, &common_prefixes, &truncated);
1589 if (ret < 0) {
1590 cerr << "ERROR: store->list_objects(): " << cpp_strerror(-ret) << std::endl;
1591 return -ret;
1592 }
1593
1594 count += result.size();
1595
1596 for (vector<rgw_bucket_dir_entry>::iterator iter = result.begin(); iter != result.end(); ++iter) {
1597 rgw_obj_key key = iter->key;
1598 rgw_obj obj(bucket, key);
1599
1600 if (key.name[0] == '_') {
1601 ret = check_obj_locator_underscore(bucket_info, obj, key, fix, remove_bad, f);
1602
1603 if (ret >= 0) {
1604 ret = check_obj_tail_locator_underscore(bucket_info, obj, key, fix, f);
1605 if (ret < 0) {
1606 cerr << "ERROR: check_obj_tail_locator_underscore(): " << cpp_strerror(-ret) << std::endl;
1607 return -ret;
1608 }
1609 }
1610 }
1611 }
1612 f->flush(cout);
1613 } while (truncated && count < max_entries);
1614 f->close_section();
1615 f->close_section();
1616
1617 f->flush(cout);
1618
1619 return 0;
1620 }
1621
1622 int set_bucket_sync_enabled(RGWRados *store, int opt_cmd, const string& tenant_name, const string& bucket_name)
1623 {
1624 RGWBucketInfo bucket_info;
1625 map<string, bufferlist> attrs;
1626 auto obj_ctx = store->svc.sysobj->init_obj_ctx();
1627
1628 int r = store->get_bucket_info(obj_ctx, tenant_name, bucket_name, bucket_info, NULL, &attrs);
1629 if (r < 0) {
1630 cerr << "could not get bucket info for bucket=" << bucket_name << ": " << cpp_strerror(-r) << std::endl;
1631 return -r;
1632 }
1633
1634 if (opt_cmd == OPT_BUCKET_SYNC_ENABLE) {
1635 bucket_info.flags &= ~BUCKET_DATASYNC_DISABLED;
1636 } else if (opt_cmd == OPT_BUCKET_SYNC_DISABLE) {
1637 bucket_info.flags |= BUCKET_DATASYNC_DISABLED;
1638 }
1639
1640 r = store->put_bucket_instance_info(bucket_info, false, real_time(), &attrs);
1641 if (r < 0) {
1642 cerr << "ERROR: failed writing bucket instance info: " << cpp_strerror(-r) << std::endl;
1643 return -r;
1644 }
1645
1646 int shards_num = bucket_info.num_shards? bucket_info.num_shards : 1;
1647 int shard_id = bucket_info.num_shards? 0 : -1;
1648
1649 if (opt_cmd == OPT_BUCKET_SYNC_DISABLE) {
1650 r = store->stop_bi_log_entries(bucket_info, -1);
1651 if (r < 0) {
1652 lderr(store->ctx()) << "ERROR: failed writing stop bilog" << dendl;
1653 return r;
1654 }
1655 } else {
1656 r = store->resync_bi_log_entries(bucket_info, -1);
1657 if (r < 0) {
1658 lderr(store->ctx()) << "ERROR: failed writing resync bilog" << dendl;
1659 return r;
1660 }
1661 }
1662
1663 for (int i = 0; i < shards_num; ++i, ++shard_id) {
1664 r = store->data_log->add_entry(bucket_info.bucket, shard_id);
1665 if (r < 0) {
1666 lderr(store->ctx()) << "ERROR: failed writing data log" << dendl;
1667 return r;
1668 }
1669 }
1670
1671 return 0;
1672 }
1673
1674
1675 /// search for a matching zone/zonegroup id and return a connection if found
1676 static boost::optional<RGWRESTConn> get_remote_conn(RGWRados *store,
1677 const RGWZoneGroup& zonegroup,
1678 const std::string& remote)
1679 {
1680 boost::optional<RGWRESTConn> conn;
1681 if (remote == zonegroup.get_id()) {
1682 conn.emplace(store->ctx(), store->svc.zone, remote, zonegroup.endpoints);
1683 } else {
1684 for (const auto& z : zonegroup.zones) {
1685 const auto& zone = z.second;
1686 if (remote == zone.id) {
1687 conn.emplace(store->ctx(), store->svc.zone, remote, zone.endpoints);
1688 break;
1689 }
1690 }
1691 }
1692 return conn;
1693 }
1694
1695 /// search each zonegroup for a connection
1696 static boost::optional<RGWRESTConn> get_remote_conn(RGWRados *store,
1697 const RGWPeriodMap& period_map,
1698 const std::string& remote)
1699 {
1700 boost::optional<RGWRESTConn> conn;
1701 for (const auto& zg : period_map.zonegroups) {
1702 conn = get_remote_conn(store, zg.second, remote);
1703 if (conn) {
1704 break;
1705 }
1706 }
1707 return conn;
1708 }
1709
1710 // we expect a very small response
1711 static constexpr size_t MAX_REST_RESPONSE = 128 * 1024;
1712
1713 static int send_to_remote_gateway(RGWRESTConn* conn, req_info& info,
1714 bufferlist& in_data, JSONParser& parser)
1715 {
1716 if (!conn) {
1717 return -EINVAL;
1718 }
1719
1720 ceph::bufferlist response;
1721 rgw_user user;
1722 int ret = conn->forward(user, info, nullptr, MAX_REST_RESPONSE, &in_data, &response);
1723
1724 int parse_ret = parser.parse(response.c_str(), response.length());
1725 if (parse_ret < 0) {
1726 cerr << "failed to parse response" << std::endl;
1727 return parse_ret;
1728 }
1729 return ret;
1730 }
1731
1732 static int send_to_url(const string& url, const string& access,
1733 const string& secret, req_info& info,
1734 bufferlist& in_data, JSONParser& parser)
1735 {
1736 if (access.empty() || secret.empty()) {
1737 cerr << "An --access-key and --secret must be provided with --url." << std::endl;
1738 return -EINVAL;
1739 }
1740 RGWAccessKey key;
1741 key.id = access;
1742 key.key = secret;
1743
1744 param_vec_t params;
1745 RGWRESTSimpleRequest req(g_ceph_context, info.method, url, NULL, &params);
1746
1747 bufferlist response;
1748 int ret = req.forward_request(key, info, MAX_REST_RESPONSE, &in_data, &response);
1749
1750 int parse_ret = parser.parse(response.c_str(), response.length());
1751 if (parse_ret < 0) {
1752 cout << "failed to parse response" << std::endl;
1753 return parse_ret;
1754 }
1755 return ret;
1756 }
1757
1758 static int send_to_remote_or_url(RGWRESTConn *conn, const string& url,
1759 const string& access, const string& secret,
1760 req_info& info, bufferlist& in_data,
1761 JSONParser& parser)
1762 {
1763 if (url.empty()) {
1764 return send_to_remote_gateway(conn, info, in_data, parser);
1765 }
1766 return send_to_url(url, access, secret, info, in_data, parser);
1767 }
1768
1769 static int commit_period(RGWRealm& realm, RGWPeriod& period,
1770 string remote, const string& url,
1771 const string& access, const string& secret,
1772 bool force)
1773 {
1774 const string& master_zone = period.get_master_zone();
1775 if (master_zone.empty()) {
1776 cerr << "cannot commit period: period does not have a master zone of a master zonegroup" << std::endl;
1777 return -EINVAL;
1778 }
1779 // are we the period's master zone?
1780 if (store->svc.zone->get_zone_params().get_id() == master_zone) {
1781 // read the current period
1782 RGWPeriod current_period;
1783 int ret = current_period.init(g_ceph_context, store->svc.sysobj, realm.get_id());
1784 if (ret < 0) {
1785 cerr << "Error initializing current period: "
1786 << cpp_strerror(-ret) << std::endl;
1787 return ret;
1788 }
1789 // the master zone can commit locally
1790 ret = period.commit(store, realm, current_period, cerr, force);
1791 if (ret < 0) {
1792 cerr << "failed to commit period: " << cpp_strerror(-ret) << std::endl;
1793 }
1794 return ret;
1795 }
1796
1797 if (remote.empty() && url.empty()) {
1798 // use the new master zone's connection
1799 remote = master_zone;
1800 cout << "Sending period to new master zone " << remote << std::endl;
1801 }
1802 boost::optional<RGWRESTConn> conn;
1803 RGWRESTConn *remote_conn = nullptr;
1804 if (!remote.empty()) {
1805 conn = get_remote_conn(store, period.get_map(), remote);
1806 if (!conn) {
1807 cerr << "failed to find a zone or zonegroup for remote "
1808 << remote << std::endl;
1809 return -ENOENT;
1810 }
1811 remote_conn = &*conn;
1812 }
1813
1814 // push period to the master with an empty period id
1815 period.set_id("");
1816
1817 RGWEnv env;
1818 req_info info(g_ceph_context, &env);
1819 info.method = "POST";
1820 info.request_uri = "/admin/realm/period";
1821
1822 // json format into a bufferlist
1823 JSONFormatter jf(false);
1824 encode_json("period", period, &jf);
1825 bufferlist bl;
1826 jf.flush(bl);
1827
1828 JSONParser p;
1829 int ret = send_to_remote_or_url(remote_conn, url, access, secret, info, bl, p);
1830 if (ret < 0) {
1831 cerr << "request failed: " << cpp_strerror(-ret) << std::endl;
1832
1833 // did we parse an error message?
1834 auto message = p.find_obj("Message");
1835 if (message) {
1836 cerr << "Reason: " << message->get_data() << std::endl;
1837 }
1838 return ret;
1839 }
1840
1841 // decode the response and store it back
1842 try {
1843 decode_json_obj(period, &p);
1844 } catch (JSONDecoder::err& e) {
1845 cout << "failed to decode JSON input: " << e.message << std::endl;
1846 return -EINVAL;
1847 }
1848 if (period.get_id().empty()) {
1849 cerr << "Period commit got back an empty period id" << std::endl;
1850 return -EINVAL;
1851 }
1852 // the master zone gave us back the period that it committed, so it's
1853 // safe to save it as our latest epoch
1854 ret = period.store_info(false);
1855 if (ret < 0) {
1856 cerr << "Error storing committed period " << period.get_id() << ": "
1857 << cpp_strerror(ret) << std::endl;
1858 return ret;
1859 }
1860 ret = period.set_latest_epoch(period.get_epoch());
1861 if (ret < 0) {
1862 cerr << "Error updating period epoch: " << cpp_strerror(ret) << std::endl;
1863 return ret;
1864 }
1865 ret = period.reflect();
1866 if (ret < 0) {
1867 cerr << "Error updating local objects: " << cpp_strerror(ret) << std::endl;
1868 return ret;
1869 }
1870 realm.notify_new_period(period);
1871 return ret;
1872 }
1873
1874 static int update_period(const string& realm_id, const string& realm_name,
1875 const string& period_id, const string& period_epoch,
1876 bool commit, const string& remote, const string& url,
1877 const string& access, const string& secret,
1878 Formatter *formatter, bool force)
1879 {
1880 RGWRealm realm(realm_id, realm_name);
1881 int ret = realm.init(g_ceph_context, store->svc.sysobj);
1882 if (ret < 0 ) {
1883 cerr << "Error initializing realm " << cpp_strerror(-ret) << std::endl;
1884 return ret;
1885 }
1886 epoch_t epoch = 0;
1887 if (!period_epoch.empty()) {
1888 epoch = atoi(period_epoch.c_str());
1889 }
1890 RGWPeriod period(period_id, epoch);
1891 ret = period.init(g_ceph_context, store->svc.sysobj, realm.get_id());
1892 if (ret < 0) {
1893 cerr << "period init failed: " << cpp_strerror(-ret) << std::endl;
1894 return ret;
1895 }
1896 period.fork();
1897 ret = period.update();
1898 if(ret < 0) {
1899 // Dropping the error message here, as both the ret codes were handled in
1900 // period.update()
1901 return ret;
1902 }
1903 ret = period.store_info(false);
1904 if (ret < 0) {
1905 cerr << "failed to store period: " << cpp_strerror(-ret) << std::endl;
1906 return ret;
1907 }
1908 if (commit) {
1909 ret = commit_period(realm, period, remote, url, access, secret, force);
1910 if (ret < 0) {
1911 cerr << "failed to commit period: " << cpp_strerror(-ret) << std::endl;
1912 return ret;
1913 }
1914 }
1915 encode_json("period", period, formatter);
1916 formatter->flush(cout);
1917 return 0;
1918 }
1919
1920 static int init_bucket_for_sync(const string& tenant, const string& bucket_name,
1921 const string& bucket_id, rgw_bucket& bucket)
1922 {
1923 RGWBucketInfo bucket_info;
1924
1925 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
1926 if (ret < 0) {
1927 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
1928 return ret;
1929 }
1930
1931 return 0;
1932 }
1933
1934 static int do_period_pull(RGWRESTConn *remote_conn, const string& url,
1935 const string& access_key, const string& secret_key,
1936 const string& realm_id, const string& realm_name,
1937 const string& period_id, const string& period_epoch,
1938 RGWPeriod *period)
1939 {
1940 RGWEnv env;
1941 req_info info(g_ceph_context, &env);
1942 info.method = "GET";
1943 info.request_uri = "/admin/realm/period";
1944
1945 map<string, string> &params = info.args.get_params();
1946 if (!realm_id.empty())
1947 params["realm_id"] = realm_id;
1948 if (!realm_name.empty())
1949 params["realm_name"] = realm_name;
1950 if (!period_id.empty())
1951 params["period_id"] = period_id;
1952 if (!period_epoch.empty())
1953 params["epoch"] = period_epoch;
1954
1955 bufferlist bl;
1956 JSONParser p;
1957 int ret = send_to_remote_or_url(remote_conn, url, access_key, secret_key,
1958 info, bl, p);
1959 if (ret < 0) {
1960 cerr << "request failed: " << cpp_strerror(-ret) << std::endl;
1961 return ret;
1962 }
1963 ret = period->init(g_ceph_context, store->svc.sysobj, false);
1964 if (ret < 0) {
1965 cerr << "faile to init period " << cpp_strerror(-ret) << std::endl;
1966 return ret;
1967 }
1968 try {
1969 decode_json_obj(*period, &p);
1970 } catch (JSONDecoder::err& e) {
1971 cout << "failed to decode JSON input: " << e.message << std::endl;
1972 return -EINVAL;
1973 }
1974 ret = period->store_info(false);
1975 if (ret < 0) {
1976 cerr << "Error storing period " << period->get_id() << ": " << cpp_strerror(ret) << std::endl;
1977 }
1978 // store latest epoch (ignore errors)
1979 period->update_latest_epoch(period->get_epoch());
1980 return 0;
1981 }
1982
1983 static int read_current_period_id(RGWRados* store, const std::string& realm_id,
1984 const std::string& realm_name,
1985 std::string* period_id)
1986 {
1987 RGWRealm realm(realm_id, realm_name);
1988 int ret = realm.init(g_ceph_context, store->svc.sysobj);
1989 if (ret < 0) {
1990 std::cerr << "failed to read realm: " << cpp_strerror(-ret) << std::endl;
1991 return ret;
1992 }
1993 *period_id = realm.get_current_period();
1994 return 0;
1995 }
1996
1997 void flush_ss(stringstream& ss, list<string>& l)
1998 {
1999 if (!ss.str().empty()) {
2000 l.push_back(ss.str());
2001 }
2002 ss.str("");
2003 }
2004
2005 stringstream& push_ss(stringstream& ss, list<string>& l, int tab = 0)
2006 {
2007 flush_ss(ss, l);
2008 if (tab > 0) {
2009 ss << setw(tab) << "" << setw(1);
2010 }
2011 return ss;
2012 }
2013
2014 static void get_md_sync_status(list<string>& status)
2015 {
2016 RGWMetaSyncStatusManager sync(store, store->get_async_rados());
2017
2018 int ret = sync.init();
2019 if (ret < 0) {
2020 status.push_back(string("failed to retrieve sync info: sync.init() failed: ") + cpp_strerror(-ret));
2021 return;
2022 }
2023
2024 rgw_meta_sync_status sync_status;
2025 ret = sync.read_sync_status(&sync_status);
2026 if (ret < 0) {
2027 status.push_back(string("failed to read sync status: ") + cpp_strerror(-ret));
2028 return;
2029 }
2030
2031 string status_str;
2032 switch (sync_status.sync_info.state) {
2033 case rgw_meta_sync_info::StateInit:
2034 status_str = "init";
2035 break;
2036 case rgw_meta_sync_info::StateBuildingFullSyncMaps:
2037 status_str = "preparing for full sync";
2038 break;
2039 case rgw_meta_sync_info::StateSync:
2040 status_str = "syncing";
2041 break;
2042 default:
2043 status_str = "unknown";
2044 }
2045
2046 status.push_back(status_str);
2047
2048 uint64_t full_total = 0;
2049 uint64_t full_complete = 0;
2050
2051 int num_full = 0;
2052 int num_inc = 0;
2053 int total_shards = 0;
2054 set<int> shards_behind_set;
2055
2056 for (auto marker_iter : sync_status.sync_markers) {
2057 full_total += marker_iter.second.total_entries;
2058 total_shards++;
2059 if (marker_iter.second.state == rgw_meta_sync_marker::SyncState::FullSync) {
2060 num_full++;
2061 full_complete += marker_iter.second.pos;
2062 int shard_id = marker_iter.first;
2063 shards_behind_set.insert(shard_id);
2064 } else {
2065 full_complete += marker_iter.second.total_entries;
2066 }
2067 if (marker_iter.second.state == rgw_meta_sync_marker::SyncState::IncrementalSync) {
2068 num_inc++;
2069 }
2070 }
2071
2072 stringstream ss;
2073 push_ss(ss, status) << "full sync: " << num_full << "/" << total_shards << " shards";
2074
2075 if (num_full > 0) {
2076 push_ss(ss, status) << "full sync: " << full_total - full_complete << " entries to sync";
2077 }
2078
2079 push_ss(ss, status) << "incremental sync: " << num_inc << "/" << total_shards << " shards";
2080
2081 map<int, RGWMetadataLogInfo> master_shards_info;
2082 string master_period = store->svc.zone->get_current_period_id();
2083
2084 ret = sync.read_master_log_shards_info(master_period, &master_shards_info);
2085 if (ret < 0) {
2086 status.push_back(string("failed to fetch master sync status: ") + cpp_strerror(-ret));
2087 return;
2088 }
2089
2090 map<int, string> shards_behind;
2091 if (sync_status.sync_info.period != master_period) {
2092 status.push_back(string("master is on a different period: master_period=" +
2093 master_period + " local_period=" + sync_status.sync_info.period));
2094 } else {
2095 for (auto local_iter : sync_status.sync_markers) {
2096 int shard_id = local_iter.first;
2097 auto iter = master_shards_info.find(shard_id);
2098
2099 if (iter == master_shards_info.end()) {
2100 /* huh? */
2101 derr << "ERROR: could not find remote sync shard status for shard_id=" << shard_id << dendl;
2102 continue;
2103 }
2104 auto master_marker = iter->second.marker;
2105 if (local_iter.second.state == rgw_meta_sync_marker::SyncState::IncrementalSync &&
2106 master_marker > local_iter.second.marker) {
2107 shards_behind[shard_id] = local_iter.second.marker;
2108 shards_behind_set.insert(shard_id);
2109 }
2110 }
2111 }
2112
2113 int total_behind = shards_behind.size() + (sync_status.sync_info.num_shards - num_inc);
2114 if (total_behind == 0) {
2115 push_ss(ss, status) << "metadata is caught up with master";
2116 } else {
2117 push_ss(ss, status) << "metadata is behind on " << total_behind << " shards";
2118
2119 push_ss(ss, status) << "behind shards: " << "[" << shards_behind_set << "]";
2120
2121 map<int, rgw_mdlog_shard_data> master_pos;
2122 ret = sync.read_master_log_shards_next(sync_status.sync_info.period, shards_behind, &master_pos);
2123 if (ret < 0) {
2124 derr << "ERROR: failed to fetch master next positions (" << cpp_strerror(-ret) << ")" << dendl;
2125 } else {
2126 ceph::real_time oldest;
2127 for (auto iter : master_pos) {
2128 rgw_mdlog_shard_data& shard_data = iter.second;
2129
2130 if (!shard_data.entries.empty()) {
2131 rgw_mdlog_entry& entry = shard_data.entries.front();
2132 if (ceph::real_clock::is_zero(oldest)) {
2133 oldest = entry.timestamp;
2134 } else if (!ceph::real_clock::is_zero(entry.timestamp) && entry.timestamp < oldest) {
2135 oldest = entry.timestamp;
2136 }
2137 }
2138 }
2139
2140 if (!ceph::real_clock::is_zero(oldest)) {
2141 push_ss(ss, status) << "oldest incremental change not applied: " << oldest;
2142 }
2143 }
2144 }
2145
2146 flush_ss(ss, status);
2147 }
2148
2149 static void get_data_sync_status(const string& source_zone, list<string>& status, int tab)
2150 {
2151 stringstream ss;
2152
2153 RGWZone *sz;
2154
2155 if (!store->svc.zone->find_zone_by_id(source_zone, &sz)) {
2156 push_ss(ss, status, tab) << string("zone not found");
2157 flush_ss(ss, status);
2158 return;
2159 }
2160
2161 if (!store->svc.zone->zone_syncs_from(store->svc.zone->get_zone(), *sz)) {
2162 push_ss(ss, status, tab) << string("not syncing from zone");
2163 flush_ss(ss, status);
2164 return;
2165 }
2166 RGWDataSyncStatusManager sync(store, store->get_async_rados(), source_zone);
2167
2168 int ret = sync.init();
2169 if (ret < 0) {
2170 push_ss(ss, status, tab) << string("failed to retrieve sync info: ") + cpp_strerror(-ret);
2171 flush_ss(ss, status);
2172 return;
2173 }
2174
2175 rgw_data_sync_status sync_status;
2176 ret = sync.read_sync_status(&sync_status);
2177 if (ret < 0 && ret != -ENOENT) {
2178 push_ss(ss, status, tab) << string("failed read sync status: ") + cpp_strerror(-ret);
2179 return;
2180 }
2181
2182 set<int> recovering_shards;
2183 ret = sync.read_recovering_shards(sync_status.sync_info.num_shards, recovering_shards);
2184 if (ret < 0 && ret != ENOENT) {
2185 push_ss(ss, status, tab) << string("failed read recovering shards: ") + cpp_strerror(-ret);
2186 return;
2187 }
2188
2189 string status_str;
2190 switch (sync_status.sync_info.state) {
2191 case rgw_data_sync_info::StateInit:
2192 status_str = "init";
2193 break;
2194 case rgw_data_sync_info::StateBuildingFullSyncMaps:
2195 status_str = "preparing for full sync";
2196 break;
2197 case rgw_data_sync_info::StateSync:
2198 status_str = "syncing";
2199 break;
2200 default:
2201 status_str = "unknown";
2202 }
2203
2204 push_ss(ss, status, tab) << status_str;
2205
2206 uint64_t full_total = 0;
2207 uint64_t full_complete = 0;
2208
2209 int num_full = 0;
2210 int num_inc = 0;
2211 int total_shards = 0;
2212 set<int> shards_behind_set;
2213
2214 for (auto marker_iter : sync_status.sync_markers) {
2215 full_total += marker_iter.second.total_entries;
2216 total_shards++;
2217 if (marker_iter.second.state == rgw_data_sync_marker::SyncState::FullSync) {
2218 num_full++;
2219 full_complete += marker_iter.second.pos;
2220 int shard_id = marker_iter.first;
2221 shards_behind_set.insert(shard_id);
2222 } else {
2223 full_complete += marker_iter.second.total_entries;
2224 }
2225 if (marker_iter.second.state == rgw_data_sync_marker::SyncState::IncrementalSync) {
2226 num_inc++;
2227 }
2228 }
2229
2230 push_ss(ss, status, tab) << "full sync: " << num_full << "/" << total_shards << " shards";
2231
2232 if (num_full > 0) {
2233 push_ss(ss, status, tab) << "full sync: " << full_total - full_complete << " buckets to sync";
2234 }
2235
2236 push_ss(ss, status, tab) << "incremental sync: " << num_inc << "/" << total_shards << " shards";
2237
2238 map<int, RGWDataChangesLogInfo> source_shards_info;
2239
2240 ret = sync.read_source_log_shards_info(&source_shards_info);
2241 if (ret < 0) {
2242 push_ss(ss, status, tab) << string("failed to fetch source sync status: ") + cpp_strerror(-ret);
2243 return;
2244 }
2245
2246 map<int, string> shards_behind;
2247
2248 for (auto local_iter : sync_status.sync_markers) {
2249 int shard_id = local_iter.first;
2250 auto iter = source_shards_info.find(shard_id);
2251
2252 if (iter == source_shards_info.end()) {
2253 /* huh? */
2254 derr << "ERROR: could not find remote sync shard status for shard_id=" << shard_id << dendl;
2255 continue;
2256 }
2257 auto master_marker = iter->second.marker;
2258 if (local_iter.second.state == rgw_data_sync_marker::SyncState::IncrementalSync &&
2259 master_marker > local_iter.second.marker) {
2260 shards_behind[shard_id] = local_iter.second.marker;
2261 shards_behind_set.insert(shard_id);
2262 }
2263 }
2264
2265 int total_behind = shards_behind.size() + (sync_status.sync_info.num_shards - num_inc);
2266 int total_recovering = recovering_shards.size();
2267 if (total_behind == 0 && total_recovering == 0) {
2268 push_ss(ss, status, tab) << "data is caught up with source";
2269 } else if (total_behind > 0) {
2270 push_ss(ss, status, tab) << "data is behind on " << total_behind << " shards";
2271
2272 push_ss(ss, status, tab) << "behind shards: " << "[" << shards_behind_set << "]" ;
2273
2274 map<int, rgw_datalog_shard_data> master_pos;
2275 ret = sync.read_source_log_shards_next(shards_behind, &master_pos);
2276 if (ret < 0) {
2277 derr << "ERROR: failed to fetch next positions (" << cpp_strerror(-ret) << ")" << dendl;
2278 } else {
2279 ceph::real_time oldest;
2280 for (auto iter : master_pos) {
2281 rgw_datalog_shard_data& shard_data = iter.second;
2282
2283 if (!shard_data.entries.empty()) {
2284 rgw_datalog_entry& entry = shard_data.entries.front();
2285 if (ceph::real_clock::is_zero(oldest)) {
2286 oldest = entry.timestamp;
2287 } else if (!ceph::real_clock::is_zero(entry.timestamp) && entry.timestamp < oldest) {
2288 oldest = entry.timestamp;
2289 }
2290 }
2291 }
2292
2293 if (!ceph::real_clock::is_zero(oldest)) {
2294 push_ss(ss, status, tab) << "oldest incremental change not applied: " << oldest;
2295 }
2296 }
2297 }
2298
2299 if (total_recovering > 0) {
2300 push_ss(ss, status, tab) << total_recovering << " shards are recovering";
2301 push_ss(ss, status, tab) << "recovering shards: " << "[" << recovering_shards << "]";
2302 }
2303
2304 flush_ss(ss, status);
2305 }
2306
2307 static void tab_dump(const string& header, int width, const list<string>& entries)
2308 {
2309 string s = header;
2310
2311 for (auto e : entries) {
2312 cout << std::setw(width) << s << std::setw(1) << " " << e << std::endl;
2313 s.clear();
2314 }
2315 }
2316
2317
2318 static void sync_status(Formatter *formatter)
2319 {
2320 const RGWRealm& realm = store->svc.zone->get_realm();
2321 const RGWZoneGroup& zonegroup = store->svc.zone->get_zonegroup();
2322 const RGWZone& zone = store->svc.zone->get_zone();
2323
2324 int width = 15;
2325
2326 cout << std::setw(width) << "realm" << std::setw(1) << " " << realm.get_id() << " (" << realm.get_name() << ")" << std::endl;
2327 cout << std::setw(width) << "zonegroup" << std::setw(1) << " " << zonegroup.get_id() << " (" << zonegroup.get_name() << ")" << std::endl;
2328 cout << std::setw(width) << "zone" << std::setw(1) << " " << zone.id << " (" << zone.name << ")" << std::endl;
2329
2330 list<string> md_status;
2331
2332 if (store->svc.zone->is_meta_master()) {
2333 md_status.push_back("no sync (zone is master)");
2334 } else {
2335 get_md_sync_status(md_status);
2336 }
2337
2338 tab_dump("metadata sync", width, md_status);
2339
2340 list<string> data_status;
2341
2342 auto& zone_conn_map = store->svc.zone->get_zone_conn_map();
2343
2344 for (auto iter : zone_conn_map) {
2345 const string& source_id = iter.first;
2346 string source_str = "source: ";
2347 string s = source_str + source_id;
2348 RGWZone *sz;
2349 if (store->svc.zone->find_zone_by_id(source_id, &sz)) {
2350 s += string(" (") + sz->name + ")";
2351 }
2352 data_status.push_back(s);
2353 get_data_sync_status(source_id, data_status, source_str.size());
2354 }
2355
2356 tab_dump("data sync", width, data_status);
2357 }
2358
2359 struct indented {
2360 int w; // indent width
2361 std::string_view header;
2362 indented(int w, std::string_view header = "") : w(w), header(header) {}
2363 };
2364 std::ostream& operator<<(std::ostream& out, const indented& h) {
2365 return out << std::setw(h.w) << h.header << std::setw(1) << ' ';
2366 }
2367
2368 static int remote_bilog_markers(RGWRados *store, const RGWZone& source,
2369 RGWRESTConn *conn, const RGWBucketInfo& info,
2370 BucketIndexShardsManager *markers)
2371 {
2372 const auto instance_key = info.bucket.get_key();
2373 const rgw_http_param_pair params[] = {
2374 { "type" , "bucket-index" },
2375 { "bucket-instance", instance_key.c_str() },
2376 { "info" , nullptr },
2377 { nullptr, nullptr }
2378 };
2379 rgw_bucket_index_marker_info result;
2380 int r = conn->get_json_resource("/admin/log/", params, result);
2381 if (r < 0) {
2382 lderr(store->ctx()) << "failed to fetch remote log markers: " << cpp_strerror(r) << dendl;
2383 return r;
2384 }
2385 r = markers->from_string(result.max_marker, -1);
2386 if (r < 0) {
2387 lderr(store->ctx()) << "failed to decode remote log markers" << dendl;
2388 return r;
2389 }
2390 return 0;
2391 }
2392
2393 static int bucket_source_sync_status(RGWRados *store, const RGWZone& zone,
2394 const RGWZone& source, RGWRESTConn *conn,
2395 const RGWBucketInfo& bucket_info,
2396 int width, std::ostream& out)
2397 {
2398 out << indented{width, "source zone"} << source.id << " (" << source.name << ")\n";
2399
2400 // syncing from this zone?
2401 if (!zone.syncs_from(source.id)) {
2402 out << indented{width} << "not in sync_from\n";
2403 return 0;
2404 }
2405 std::vector<rgw_bucket_shard_sync_info> status;
2406 int r = rgw_bucket_sync_status(dpp(), store, source.id, bucket_info, &status);
2407 if (r < 0) {
2408 lderr(store->ctx()) << "failed to read bucket sync status: " << cpp_strerror(r) << dendl;
2409 return r;
2410 }
2411
2412 int num_full = 0;
2413 int num_inc = 0;
2414 uint64_t full_complete = 0;
2415 const size_t total_shards = status.size();
2416
2417 using BucketSyncState = rgw_bucket_shard_sync_info::SyncState;
2418 for (size_t shard_id = 0; shard_id < total_shards; shard_id++) {
2419 auto& m = status[shard_id];
2420 if (m.state == BucketSyncState::StateFullSync) {
2421 num_full++;
2422 full_complete += m.full_marker.count;
2423 } else if (m.state == BucketSyncState::StateIncrementalSync) {
2424 num_inc++;
2425 }
2426 }
2427
2428 out << indented{width} << "full sync: " << num_full << "/" << total_shards << " shards\n";
2429 if (num_full > 0) {
2430 out << indented{width} << "full sync: " << full_complete << " objects completed\n";
2431 }
2432 out << indented{width} << "incremental sync: " << num_inc << "/" << total_shards << " shards\n";
2433
2434 BucketIndexShardsManager remote_markers;
2435 r = remote_bilog_markers(store, source, conn, bucket_info, &remote_markers);
2436 if (r < 0) {
2437 lderr(store->ctx()) << "failed to read remote log: " << cpp_strerror(r) << dendl;
2438 return r;
2439 }
2440
2441 std::set<int> shards_behind;
2442 for (auto& r : remote_markers.get()) {
2443 auto shard_id = r.first;
2444 auto& m = status[shard_id];
2445 if (r.second.empty()) {
2446 continue; // empty bucket index shard
2447 }
2448 auto pos = BucketIndexShardsManager::get_shard_marker(m.inc_marker.position);
2449 if (m.state != BucketSyncState::StateIncrementalSync || pos != r.second) {
2450 shards_behind.insert(shard_id);
2451 }
2452 }
2453 if (shards_behind.empty()) {
2454 out << indented{width} << "bucket is caught up with source\n";
2455 } else {
2456 out << indented{width} << "bucket is behind on " << shards_behind.size() << " shards\n";
2457 out << indented{width} << "behind shards: [" << shards_behind << "]\n" ;
2458 }
2459 return 0;
2460 }
2461
2462 static int bucket_sync_status(RGWRados *store, const RGWBucketInfo& info,
2463 const std::string& source_zone_id,
2464 std::ostream& out)
2465 {
2466 const RGWRealm& realm = store->svc.zone->get_realm();
2467 const RGWZoneGroup& zonegroup = store->svc.zone->get_zonegroup();
2468 const RGWZone& zone = store->svc.zone->get_zone();
2469 constexpr int width = 15;
2470
2471 out << indented{width, "realm"} << realm.get_id() << " (" << realm.get_name() << ")\n";
2472 out << indented{width, "zonegroup"} << zonegroup.get_id() << " (" << zonegroup.get_name() << ")\n";
2473 out << indented{width, "zone"} << zone.id << " (" << zone.name << ")\n";
2474 out << indented{width, "bucket"} << info.bucket << "\n\n";
2475
2476 if (!info.datasync_flag_enabled()) {
2477 out << "Sync is disabled for bucket " << info.bucket.name << '\n';
2478 return 0;
2479 }
2480
2481 auto& zone_conn_map = store->svc.zone->get_zone_conn_map();
2482 if (!source_zone_id.empty()) {
2483 auto z = zonegroup.zones.find(source_zone_id);
2484 if (z == zonegroup.zones.end()) {
2485 lderr(store->ctx()) << "Source zone not found in zonegroup "
2486 << zonegroup.get_name() << dendl;
2487 return -EINVAL;
2488 }
2489 auto c = zone_conn_map.find(source_zone_id);
2490 if (c == zone_conn_map.end()) {
2491 lderr(store->ctx()) << "No connection to zone " << z->second.name << dendl;
2492 return -EINVAL;
2493 }
2494 return bucket_source_sync_status(store, zone, z->second, c->second,
2495 info, width, out);
2496 }
2497
2498 for (const auto& z : zonegroup.zones) {
2499 auto c = zone_conn_map.find(z.second.id);
2500 if (c != zone_conn_map.end()) {
2501 bucket_source_sync_status(store, zone, z.second, c->second,
2502 info, width, out);
2503 }
2504 }
2505 return 0;
2506 }
2507
2508 static void parse_tier_config_param(const string& s, map<string, string, ltstr_nocase>& out)
2509 {
2510 int level = 0;
2511 string cur_conf;
2512 list<string> confs;
2513 for (auto c : s) {
2514 if (c == ',') {
2515 if (level == 0) {
2516 confs.push_back(cur_conf);
2517 cur_conf.clear();
2518 continue;
2519 }
2520 }
2521 if (c == '{') {
2522 ++level;
2523 } else if (c == '}') {
2524 --level;
2525 }
2526 cur_conf += c;
2527 }
2528 if (!cur_conf.empty()) {
2529 confs.push_back(cur_conf);
2530 }
2531
2532 for (auto c : confs) {
2533 ssize_t pos = c.find("=");
2534 if (pos < 0) {
2535 out[c] = "";
2536 } else {
2537 out[c.substr(0, pos)] = c.substr(pos + 1);
2538 }
2539 }
2540 }
2541
2542 static int check_pool_support_omap(const rgw_pool& pool)
2543 {
2544 librados::IoCtx io_ctx;
2545 int ret = store->get_rados_handle()->ioctx_create(pool.to_str().c_str(), io_ctx);
2546 if (ret < 0) {
2547 // the pool may not exist at this moment, we have no way to check if it supports omap.
2548 return 0;
2549 }
2550
2551 ret = io_ctx.omap_clear("__omap_test_not_exist_oid__");
2552 if (ret == -EOPNOTSUPP) {
2553 io_ctx.close();
2554 return ret;
2555 }
2556 io_ctx.close();
2557 return 0;
2558 }
2559
2560 int check_reshard_bucket_params(RGWRados *store,
2561 const string& bucket_name,
2562 const string& tenant,
2563 const string& bucket_id,
2564 bool num_shards_specified,
2565 int num_shards,
2566 int yes_i_really_mean_it,
2567 rgw_bucket& bucket,
2568 RGWBucketInfo& bucket_info,
2569 map<string, bufferlist>& attrs)
2570 {
2571 if (bucket_name.empty()) {
2572 cerr << "ERROR: bucket not specified" << std::endl;
2573 return -EINVAL;
2574 }
2575
2576 if (!num_shards_specified) {
2577 cerr << "ERROR: --num-shards not specified" << std::endl;
2578 return -EINVAL;
2579 }
2580
2581 if (num_shards > (int)store->get_max_bucket_shards()) {
2582 cerr << "ERROR: num_shards too high, max value: " << store->get_max_bucket_shards() << std::endl;
2583 return -EINVAL;
2584 }
2585
2586 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket, &attrs);
2587 if (ret < 0) {
2588 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
2589 return ret;
2590 }
2591
2592 int num_source_shards = (bucket_info.num_shards > 0 ? bucket_info.num_shards : 1);
2593
2594 if (num_shards <= num_source_shards && !yes_i_really_mean_it) {
2595 cerr << "num shards is less or equal to current shards count" << std::endl
2596 << "do you really mean it? (requires --yes-i-really-mean-it)" << std::endl;
2597 return -EINVAL;
2598 }
2599 return 0;
2600 }
2601
2602 int create_new_bucket_instance(RGWRados *store,
2603 int new_num_shards,
2604 const RGWBucketInfo& bucket_info,
2605 map<string, bufferlist>& attrs,
2606 RGWBucketInfo& new_bucket_info)
2607 {
2608
2609 store->create_bucket_id(&new_bucket_info.bucket.bucket_id);
2610 new_bucket_info.bucket.oid.clear();
2611
2612 new_bucket_info.num_shards = new_num_shards;
2613 new_bucket_info.objv_tracker.clear();
2614
2615 int ret = store->init_bucket_index(new_bucket_info, new_bucket_info.num_shards);
2616 if (ret < 0) {
2617 cerr << "ERROR: failed to init new bucket indexes: " << cpp_strerror(-ret) << std::endl;
2618 return -ret;
2619 }
2620
2621 ret = store->put_bucket_instance_info(new_bucket_info, true, real_time(), &attrs);
2622 if (ret < 0) {
2623 cerr << "ERROR: failed to store new bucket instance info: " << cpp_strerror(-ret) << std::endl;
2624 return -ret;
2625 }
2626
2627 return 0;
2628 }
2629
2630 static int scan_totp(CephContext *cct, ceph::real_time& now, rados::cls::otp::otp_info_t& totp, vector<string>& pins,
2631 time_t *pofs)
2632 {
2633 #define MAX_TOTP_SKEW_HOURS (24 * 7)
2634 ceph_assert(pins.size() == 2);
2635
2636 time_t start_time = ceph::real_clock::to_time_t(now);
2637 time_t time_ofs = 0, time_ofs_abs = 0;
2638 time_t step_size = totp.step_size;
2639 if (step_size == 0) {
2640 step_size = OATH_TOTP_DEFAULT_TIME_STEP_SIZE;
2641 }
2642 uint32_t count = 0;
2643 int sign = 1;
2644
2645 uint32_t max_skew = MAX_TOTP_SKEW_HOURS * 3600;
2646
2647 while (time_ofs_abs < max_skew) {
2648 int rc = oath_totp_validate2(totp.seed_bin.c_str(), totp.seed_bin.length(),
2649 start_time,
2650 step_size,
2651 time_ofs,
2652 1,
2653 nullptr,
2654 pins[0].c_str());
2655 if (rc != OATH_INVALID_OTP) {
2656 rc = oath_totp_validate2(totp.seed_bin.c_str(), totp.seed_bin.length(),
2657 start_time,
2658 step_size,
2659 time_ofs - step_size, /* smaller time_ofs moves time forward */
2660 1,
2661 nullptr,
2662 pins[1].c_str());
2663 if (rc != OATH_INVALID_OTP) {
2664 *pofs = time_ofs - step_size + step_size * totp.window / 2;
2665 ldout(cct, 20) << "found at time=" << start_time - time_ofs << " time_ofs=" << time_ofs << dendl;
2666 return 0;
2667 }
2668 }
2669 sign = -sign;
2670 time_ofs_abs = (++count) * step_size;
2671 time_ofs = sign * time_ofs_abs;
2672 }
2673
2674 return -ENOENT;
2675 }
2676
2677 static int trim_sync_error_log(int shard_id, const ceph::real_time& start_time,
2678 const ceph::real_time& end_time,
2679 const string& start_marker, const string& end_marker,
2680 int delay_ms)
2681 {
2682 auto oid = RGWSyncErrorLogger::get_shard_oid(RGW_SYNC_ERROR_LOG_SHARD_PREFIX,
2683 shard_id);
2684 // call cls_log_trim() until it returns -ENODATA
2685 for (;;) {
2686 int ret = store->time_log_trim(oid, start_time, end_time,
2687 start_marker, end_marker);
2688 if (ret == -ENODATA) {
2689 return 0;
2690 }
2691 if (ret < 0) {
2692 return ret;
2693 }
2694 if (delay_ms) {
2695 std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms));
2696 }
2697 }
2698 // unreachable
2699 }
2700
2701 const string& get_tier_type(RGWRados *store) {
2702 return store->svc.zone->get_zone().tier_type;
2703 }
2704
2705 int main(int argc, const char **argv)
2706 {
2707 vector<const char*> args;
2708 argv_to_vec(argc, (const char **)argv, args);
2709 if (args.empty()) {
2710 cerr << argv[0] << ": -h or --help for usage" << std::endl;
2711 exit(1);
2712 }
2713 if (ceph_argparse_need_usage(args)) {
2714 usage();
2715 exit(0);
2716 }
2717
2718 auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT,
2719 CODE_ENVIRONMENT_UTILITY, 0);
2720
2721 // for region -> zonegroup conversion (must happen before common_init_finish())
2722 if (!g_conf()->rgw_region.empty() && g_conf()->rgw_zonegroup.empty()) {
2723 g_conf().set_val_or_die("rgw_zonegroup", g_conf()->rgw_region.c_str());
2724 }
2725
2726 common_init_finish(g_ceph_context);
2727
2728 rgw_user user_id;
2729 string tenant;
2730 std::string access_key, secret_key, user_email, display_name;
2731 std::string bucket_name, pool_name, object;
2732 rgw_pool pool;
2733 std::string date, subuser, access, format;
2734 std::string start_date, end_date;
2735 std::string key_type_str;
2736 std::string period_id, period_epoch, remote, url;
2737 std::string master_zone;
2738 std::string realm_name, realm_id, realm_new_name;
2739 std::string zone_name, zone_id, zone_new_name;
2740 std::string zonegroup_name, zonegroup_id, zonegroup_new_name;
2741 std::string api_name;
2742 std::string role_name, path, assume_role_doc, policy_name, perm_policy_doc, path_prefix;
2743 std::string redirect_zone;
2744 bool redirect_zone_set = false;
2745 list<string> endpoints;
2746 int tmp_int;
2747 int sync_from_all_specified = false;
2748 bool sync_from_all = false;
2749 list<string> sync_from;
2750 list<string> sync_from_rm;
2751 int is_master_int;
2752 int set_default = 0;
2753 bool is_master = false;
2754 bool is_master_set = false;
2755 int read_only_int;
2756 bool read_only = false;
2757 int is_read_only_set = false;
2758 int commit = false;
2759 int staging = false;
2760 int key_type = KEY_TYPE_UNDEFINED;
2761 rgw_bucket bucket;
2762 uint32_t perm_mask = 0;
2763 RGWUserInfo info;
2764 int opt_cmd = OPT_NO_CMD;
2765 bool need_more;
2766 int gen_access_key = 0;
2767 int gen_secret_key = 0;
2768 bool set_perm = false;
2769 bool set_temp_url_key = false;
2770 map<int, string> temp_url_keys;
2771 string bucket_id;
2772 Formatter *formatter = NULL;
2773 int purge_data = false;
2774 int pretty_format = false;
2775 int show_log_entries = true;
2776 int show_log_sum = true;
2777 int skip_zero_entries = false; // log show
2778 int purge_keys = false;
2779 int yes_i_really_mean_it = false;
2780 int delete_child_objects = false;
2781 int fix = false;
2782 int remove_bad = false;
2783 int check_head_obj_locator = false;
2784 int max_buckets = -1;
2785 bool max_buckets_specified = false;
2786 map<string, bool> categories;
2787 string caps;
2788 int check_objects = false;
2789 RGWUserAdminOpState user_op;
2790 RGWBucketAdminOpState bucket_op;
2791 string infile;
2792 string metadata_key;
2793 RGWObjVersionTracker objv_tracker;
2794 string marker;
2795 string start_marker;
2796 string end_marker;
2797 int max_entries = -1;
2798 bool max_entries_specified = false;
2799 int admin = false;
2800 bool admin_specified = false;
2801 int system = false;
2802 bool system_specified = false;
2803 int shard_id = -1;
2804 bool specified_shard_id = false;
2805 string client_id;
2806 string op_id;
2807 string op_mask_str;
2808 string quota_scope;
2809 string object_version;
2810 string placement_id;
2811 string storage_class;
2812 list<string> tags;
2813 list<string> tags_add;
2814 list<string> tags_rm;
2815
2816 int64_t max_objects = -1;
2817 int64_t max_size = -1;
2818 bool have_max_objects = false;
2819 bool have_max_size = false;
2820 int include_all = false;
2821
2822 int sync_stats = false;
2823 int reset_stats = false;
2824 int bypass_gc = false;
2825 int warnings_only = false;
2826 int inconsistent_index = false;
2827
2828 int verbose = false;
2829
2830 int extra_info = false;
2831
2832 uint64_t min_rewrite_size = 4 * 1024 * 1024;
2833 uint64_t max_rewrite_size = ULLONG_MAX;
2834 uint64_t min_rewrite_stripe_size = 0;
2835
2836 BIIndexType bi_index_type = BIIndexType::Plain;
2837
2838 string job_id;
2839 int num_shards = 0;
2840 bool num_shards_specified = false;
2841 int max_concurrent_ios = 32;
2842 uint64_t orphan_stale_secs = (24 * 3600);
2843 int detail = false;
2844
2845 std::string val;
2846 std::ostringstream errs;
2847 string err;
2848
2849 string source_zone_name;
2850 string source_zone; /* zone id */
2851
2852 string tier_type;
2853 bool tier_type_specified = false;
2854
2855 map<string, string, ltstr_nocase> tier_config_add;
2856 map<string, string, ltstr_nocase> tier_config_rm;
2857
2858 boost::optional<string> index_pool;
2859 boost::optional<string> data_pool;
2860 boost::optional<string> data_extra_pool;
2861 RGWBucketIndexType placement_index_type = RGWBIType_Normal;
2862 bool index_type_specified = false;
2863
2864 boost::optional<std::string> compression_type;
2865
2866 string totp_serial;
2867 string totp_seed;
2868 string totp_seed_type = "hex";
2869 vector<string> totp_pin;
2870 int totp_seconds = 0;
2871 int totp_window = 0;
2872 int trim_delay_ms = 0;
2873
2874 string topic_name;
2875 string sub_name;
2876 string sub_oid_prefix;
2877 string sub_dest_bucket;
2878 string sub_push_endpoint;
2879 string event_id;
2880 set<string, ltstr_nocase> event_types;
2881
2882 for (std::vector<const char*>::iterator i = args.begin(); i != args.end(); ) {
2883 if (ceph_argparse_double_dash(args, i)) {
2884 break;
2885 } else if (ceph_argparse_witharg(args, i, &val, "-i", "--uid", (char*)NULL)) {
2886 user_id.from_str(val);
2887 } else if (ceph_argparse_witharg(args, i, &val, "--tenant", (char*)NULL)) {
2888 tenant = val;
2889 } else if (ceph_argparse_witharg(args, i, &val, "--access-key", (char*)NULL)) {
2890 access_key = val;
2891 } else if (ceph_argparse_witharg(args, i, &val, "--subuser", (char*)NULL)) {
2892 subuser = val;
2893 } else if (ceph_argparse_witharg(args, i, &val, "--secret", "--secret-key", (char*)NULL)) {
2894 secret_key = val;
2895 } else if (ceph_argparse_witharg(args, i, &val, "-e", "--email", (char*)NULL)) {
2896 user_email = val;
2897 user_op.user_email_specified=true;
2898 } else if (ceph_argparse_witharg(args, i, &val, "-n", "--display-name", (char*)NULL)) {
2899 display_name = val;
2900 } else if (ceph_argparse_witharg(args, i, &val, "-b", "--bucket", (char*)NULL)) {
2901 bucket_name = val;
2902 } else if (ceph_argparse_witharg(args, i, &val, "-p", "--pool", (char*)NULL)) {
2903 pool_name = val;
2904 pool = rgw_pool(pool_name);
2905 } else if (ceph_argparse_witharg(args, i, &val, "-o", "--object", (char*)NULL)) {
2906 object = val;
2907 } else if (ceph_argparse_witharg(args, i, &val, "--object-version", (char*)NULL)) {
2908 object_version = val;
2909 } else if (ceph_argparse_witharg(args, i, &val, "--client-id", (char*)NULL)) {
2910 client_id = val;
2911 } else if (ceph_argparse_witharg(args, i, &val, "--op-id", (char*)NULL)) {
2912 op_id = val;
2913 } else if (ceph_argparse_witharg(args, i, &val, "--op-mask", (char*)NULL)) {
2914 op_mask_str = val;
2915 } else if (ceph_argparse_witharg(args, i, &val, "--key-type", (char*)NULL)) {
2916 key_type_str = val;
2917 if (key_type_str.compare("swift") == 0) {
2918 key_type = KEY_TYPE_SWIFT;
2919 } else if (key_type_str.compare("s3") == 0) {
2920 key_type = KEY_TYPE_S3;
2921 } else {
2922 cerr << "bad key type: " << key_type_str << std::endl;
2923 exit(1);
2924 }
2925 } else if (ceph_argparse_witharg(args, i, &val, "--job-id", (char*)NULL)) {
2926 job_id = val;
2927 } else if (ceph_argparse_binary_flag(args, i, &gen_access_key, NULL, "--gen-access-key", (char*)NULL)) {
2928 // do nothing
2929 } else if (ceph_argparse_binary_flag(args, i, &gen_secret_key, NULL, "--gen-secret", (char*)NULL)) {
2930 // do nothing
2931 } else if (ceph_argparse_binary_flag(args, i, &show_log_entries, NULL, "--show-log-entries", (char*)NULL)) {
2932 // do nothing
2933 } else if (ceph_argparse_binary_flag(args, i, &show_log_sum, NULL, "--show-log-sum", (char*)NULL)) {
2934 // do nothing
2935 } else if (ceph_argparse_binary_flag(args, i, &skip_zero_entries, NULL, "--skip-zero-entries", (char*)NULL)) {
2936 // do nothing
2937 } else if (ceph_argparse_binary_flag(args, i, &admin, NULL, "--admin", (char*)NULL)) {
2938 admin_specified = true;
2939 } else if (ceph_argparse_binary_flag(args, i, &system, NULL, "--system", (char*)NULL)) {
2940 system_specified = true;
2941 } else if (ceph_argparse_binary_flag(args, i, &verbose, NULL, "--verbose", (char*)NULL)) {
2942 // do nothing
2943 } else if (ceph_argparse_binary_flag(args, i, &staging, NULL, "--staging", (char*)NULL)) {
2944 // do nothing
2945 } else if (ceph_argparse_binary_flag(args, i, &commit, NULL, "--commit", (char*)NULL)) {
2946 // do nothing
2947 } else if (ceph_argparse_witharg(args, i, &val, "--min-rewrite-size", (char*)NULL)) {
2948 min_rewrite_size = (uint64_t)atoll(val.c_str());
2949 } else if (ceph_argparse_witharg(args, i, &val, "--max-rewrite-size", (char*)NULL)) {
2950 max_rewrite_size = (uint64_t)atoll(val.c_str());
2951 } else if (ceph_argparse_witharg(args, i, &val, "--min-rewrite-stripe-size", (char*)NULL)) {
2952 min_rewrite_stripe_size = (uint64_t)atoll(val.c_str());
2953 } else if (ceph_argparse_witharg(args, i, &val, "--max-buckets", (char*)NULL)) {
2954 max_buckets = (int)strict_strtol(val.c_str(), 10, &err);
2955 if (!err.empty()) {
2956 cerr << "ERROR: failed to parse max buckets: " << err << std::endl;
2957 return EINVAL;
2958 }
2959 max_buckets_specified = true;
2960 } else if (ceph_argparse_witharg(args, i, &val, "--max-entries", (char*)NULL)) {
2961 max_entries = (int)strict_strtol(val.c_str(), 10, &err);
2962 max_entries_specified = true;
2963 if (!err.empty()) {
2964 cerr << "ERROR: failed to parse max entries: " << err << std::endl;
2965 return EINVAL;
2966 }
2967 } else if (ceph_argparse_witharg(args, i, &val, "--max-size", (char*)NULL)) {
2968 max_size = strict_iec_cast<long long>(val.c_str(), &err);
2969 if (!err.empty()) {
2970 cerr << "ERROR: failed to parse max size: " << err << std::endl;
2971 return EINVAL;
2972 }
2973 have_max_size = true;
2974 } else if (ceph_argparse_witharg(args, i, &val, "--max-objects", (char*)NULL)) {
2975 max_objects = (int64_t)strict_strtoll(val.c_str(), 10, &err);
2976 if (!err.empty()) {
2977 cerr << "ERROR: failed to parse max objects: " << err << std::endl;
2978 return EINVAL;
2979 }
2980 have_max_objects = true;
2981 } else if (ceph_argparse_witharg(args, i, &val, "--date", "--time", (char*)NULL)) {
2982 date = val;
2983 if (end_date.empty())
2984 end_date = date;
2985 } else if (ceph_argparse_witharg(args, i, &val, "--start-date", "--start-time", (char*)NULL)) {
2986 start_date = val;
2987 } else if (ceph_argparse_witharg(args, i, &val, "--end-date", "--end-time", (char*)NULL)) {
2988 end_date = val;
2989 } else if (ceph_argparse_witharg(args, i, &val, "--num-shards", (char*)NULL)) {
2990 num_shards = (int)strict_strtol(val.c_str(), 10, &err);
2991 if (!err.empty()) {
2992 cerr << "ERROR: failed to parse num shards: " << err << std::endl;
2993 return EINVAL;
2994 }
2995 num_shards_specified = true;
2996 } else if (ceph_argparse_witharg(args, i, &val, "--max-concurrent-ios", (char*)NULL)) {
2997 max_concurrent_ios = (int)strict_strtol(val.c_str(), 10, &err);
2998 if (!err.empty()) {
2999 cerr << "ERROR: failed to parse max concurrent ios: " << err << std::endl;
3000 return EINVAL;
3001 }
3002 } else if (ceph_argparse_witharg(args, i, &val, "--orphan-stale-secs", (char*)NULL)) {
3003 orphan_stale_secs = (uint64_t)strict_strtoll(val.c_str(), 10, &err);
3004 if (!err.empty()) {
3005 cerr << "ERROR: failed to parse orphan stale secs: " << err << std::endl;
3006 return EINVAL;
3007 }
3008 } else if (ceph_argparse_witharg(args, i, &val, "--shard-id", (char*)NULL)) {
3009 shard_id = (int)strict_strtol(val.c_str(), 10, &err);
3010 if (!err.empty()) {
3011 cerr << "ERROR: failed to parse shard id: " << err << std::endl;
3012 return EINVAL;
3013 }
3014 specified_shard_id = true;
3015 } else if (ceph_argparse_witharg(args, i, &val, "--access", (char*)NULL)) {
3016 access = val;
3017 perm_mask = rgw_str_to_perm(access.c_str());
3018 set_perm = true;
3019 } else if (ceph_argparse_witharg(args, i, &val, "--temp-url-key", (char*)NULL)) {
3020 temp_url_keys[0] = val;
3021 set_temp_url_key = true;
3022 } else if (ceph_argparse_witharg(args, i, &val, "--temp-url-key2", "--temp-url-key-2", (char*)NULL)) {
3023 temp_url_keys[1] = val;
3024 set_temp_url_key = true;
3025 } else if (ceph_argparse_witharg(args, i, &val, "--bucket-id", (char*)NULL)) {
3026 bucket_id = val;
3027 if (bucket_id.empty()) {
3028 cerr << "bad bucket-id" << std::endl;
3029 exit(1);
3030 }
3031 } else if (ceph_argparse_witharg(args, i, &val, "--format", (char*)NULL)) {
3032 format = val;
3033 } else if (ceph_argparse_witharg(args, i, &val, "--categories", (char*)NULL)) {
3034 string cat_str = val;
3035 list<string> cat_list;
3036 list<string>::iterator iter;
3037 get_str_list(cat_str, cat_list);
3038 for (iter = cat_list.begin(); iter != cat_list.end(); ++iter) {
3039 categories[*iter] = true;
3040 }
3041 } else if (ceph_argparse_binary_flag(args, i, &delete_child_objects, NULL, "--purge-objects", (char*)NULL)) {
3042 // do nothing
3043 } else if (ceph_argparse_binary_flag(args, i, &pretty_format, NULL, "--pretty-format", (char*)NULL)) {
3044 // do nothing
3045 } else if (ceph_argparse_binary_flag(args, i, &purge_data, NULL, "--purge-data", (char*)NULL)) {
3046 delete_child_objects = purge_data;
3047 } else if (ceph_argparse_binary_flag(args, i, &purge_keys, NULL, "--purge-keys", (char*)NULL)) {
3048 // do nothing
3049 } else if (ceph_argparse_binary_flag(args, i, &yes_i_really_mean_it, NULL, "--yes-i-really-mean-it", (char*)NULL)) {
3050 // do nothing
3051 } else if (ceph_argparse_binary_flag(args, i, &fix, NULL, "--fix", (char*)NULL)) {
3052 // do nothing
3053 } else if (ceph_argparse_binary_flag(args, i, &remove_bad, NULL, "--remove-bad", (char*)NULL)) {
3054 // do nothing
3055 } else if (ceph_argparse_binary_flag(args, i, &check_head_obj_locator, NULL, "--check-head-obj-locator", (char*)NULL)) {
3056 // do nothing
3057 } else if (ceph_argparse_binary_flag(args, i, &check_objects, NULL, "--check-objects", (char*)NULL)) {
3058 // do nothing
3059 } else if (ceph_argparse_binary_flag(args, i, &sync_stats, NULL, "--sync-stats", (char*)NULL)) {
3060 // do nothing
3061 } else if (ceph_argparse_binary_flag(args, i, &reset_stats, NULL, "--reset-stats", (char*)NULL)) {
3062 // do nothing
3063 } else if (ceph_argparse_binary_flag(args, i, &include_all, NULL, "--include-all", (char*)NULL)) {
3064 // do nothing
3065 } else if (ceph_argparse_binary_flag(args, i, &extra_info, NULL, "--extra-info", (char*)NULL)) {
3066 // do nothing
3067 } else if (ceph_argparse_binary_flag(args, i, &bypass_gc, NULL, "--bypass-gc", (char*)NULL)) {
3068 // do nothing
3069 } else if (ceph_argparse_binary_flag(args, i, &warnings_only, NULL, "--warnings-only", (char*)NULL)) {
3070 // do nothing
3071 } else if (ceph_argparse_binary_flag(args, i, &inconsistent_index, NULL, "--inconsistent-index", (char*)NULL)) {
3072 // do nothing
3073 } else if (ceph_argparse_witharg(args, i, &val, "--caps", (char*)NULL)) {
3074 caps = val;
3075 } else if (ceph_argparse_witharg(args, i, &val, "-i", "--infile", (char*)NULL)) {
3076 infile = val;
3077 } else if (ceph_argparse_witharg(args, i, &val, "--metadata-key", (char*)NULL)) {
3078 metadata_key = val;
3079 } else if (ceph_argparse_witharg(args, i, &val, "--marker", (char*)NULL)) {
3080 marker = val;
3081 } else if (ceph_argparse_witharg(args, i, &val, "--start-marker", (char*)NULL)) {
3082 start_marker = val;
3083 } else if (ceph_argparse_witharg(args, i, &val, "--end-marker", (char*)NULL)) {
3084 end_marker = val;
3085 } else if (ceph_argparse_witharg(args, i, &val, "--quota-scope", (char*)NULL)) {
3086 quota_scope = val;
3087 } else if (ceph_argparse_witharg(args, i, &val, "--index-type", (char*)NULL)) {
3088 string index_type_str = val;
3089 bi_index_type = get_bi_index_type(index_type_str);
3090 if (bi_index_type == BIIndexType::Invalid) {
3091 cerr << "ERROR: invalid bucket index entry type" << std::endl;
3092 return EINVAL;
3093 }
3094 } else if (ceph_argparse_binary_flag(args, i, &is_master_int, NULL, "--master", (char*)NULL)) {
3095 is_master = (bool)is_master_int;
3096 is_master_set = true;
3097 } else if (ceph_argparse_binary_flag(args, i, &set_default, NULL, "--default", (char*)NULL)) {
3098 /* do nothing */
3099 } else if (ceph_argparse_witharg(args, i, &val, "--redirect-zone", (char*)NULL)) {
3100 redirect_zone = val;
3101 redirect_zone_set = true;
3102 } else if (ceph_argparse_binary_flag(args, i, &read_only_int, NULL, "--read-only", (char*)NULL)) {
3103 read_only = (bool)read_only_int;
3104 is_read_only_set = true;
3105 } else if (ceph_argparse_witharg(args, i, &val, "--master-zone", (char*)NULL)) {
3106 master_zone = val;
3107 } else if (ceph_argparse_witharg(args, i, &val, "--period", (char*)NULL)) {
3108 period_id = val;
3109 } else if (ceph_argparse_witharg(args, i, &val, "--epoch", (char*)NULL)) {
3110 period_epoch = val;
3111 } else if (ceph_argparse_witharg(args, i, &val, "--remote", (char*)NULL)) {
3112 remote = val;
3113 } else if (ceph_argparse_witharg(args, i, &val, "--url", (char*)NULL)) {
3114 url = val;
3115 } else if (ceph_argparse_witharg(args, i, &val, "--realm-id", (char*)NULL)) {
3116 realm_id = val;
3117 } else if (ceph_argparse_witharg(args, i, &val, "--realm-new-name", (char*)NULL)) {
3118 realm_new_name = val;
3119 } else if (ceph_argparse_witharg(args, i, &val, "--zonegroup-id", (char*)NULL)) {
3120 zonegroup_id = val;
3121 } else if (ceph_argparse_witharg(args, i, &val, "--zonegroup-new-name", (char*)NULL)) {
3122 zonegroup_new_name = val;
3123 } else if (ceph_argparse_witharg(args, i, &val, "--placement-id", (char*)NULL)) {
3124 placement_id = val;
3125 } else if (ceph_argparse_witharg(args, i, &val, "--storage-class", (char*)NULL)) {
3126 storage_class = val;
3127 } else if (ceph_argparse_witharg(args, i, &val, "--tags", (char*)NULL)) {
3128 get_str_list(val, tags);
3129 } else if (ceph_argparse_witharg(args, i, &val, "--tags-add", (char*)NULL)) {
3130 get_str_list(val, tags_add);
3131 } else if (ceph_argparse_witharg(args, i, &val, "--tags-rm", (char*)NULL)) {
3132 get_str_list(val, tags_rm);
3133 } else if (ceph_argparse_witharg(args, i, &val, "--api-name", (char*)NULL)) {
3134 api_name = val;
3135 } else if (ceph_argparse_witharg(args, i, &val, "--zone-id", (char*)NULL)) {
3136 zone_id = val;
3137 } else if (ceph_argparse_witharg(args, i, &val, "--zone-new-name", (char*)NULL)) {
3138 zone_new_name = val;
3139 } else if (ceph_argparse_witharg(args, i, &val, "--endpoints", (char*)NULL)) {
3140 get_str_list(val, endpoints);
3141 } else if (ceph_argparse_witharg(args, i, &val, "--sync-from", (char*)NULL)) {
3142 get_str_list(val, sync_from);
3143 } else if (ceph_argparse_witharg(args, i, &val, "--sync-from-rm", (char*)NULL)) {
3144 get_str_list(val, sync_from_rm);
3145 } else if (ceph_argparse_binary_flag(args, i, &tmp_int, NULL, "--sync-from-all", (char*)NULL)) {
3146 sync_from_all = (bool)tmp_int;
3147 sync_from_all_specified = true;
3148 } else if (ceph_argparse_witharg(args, i, &val, "--source-zone", (char*)NULL)) {
3149 source_zone_name = val;
3150 } else if (ceph_argparse_witharg(args, i, &val, "--tier-type", (char*)NULL)) {
3151 tier_type = val;
3152 tier_type_specified = true;
3153 } else if (ceph_argparse_witharg(args, i, &val, "--tier-config", (char*)NULL)) {
3154 parse_tier_config_param(val, tier_config_add);
3155 } else if (ceph_argparse_witharg(args, i, &val, "--tier-config-rm", (char*)NULL)) {
3156 parse_tier_config_param(val, tier_config_rm);
3157 } else if (ceph_argparse_witharg(args, i, &val, "--index-pool", (char*)NULL)) {
3158 index_pool = val;
3159 } else if (ceph_argparse_witharg(args, i, &val, "--data-pool", (char*)NULL)) {
3160 data_pool = val;
3161 } else if (ceph_argparse_witharg(args, i, &val, "--data-extra-pool", (char*)NULL)) {
3162 data_extra_pool = val;
3163 } else if (ceph_argparse_witharg(args, i, &val, "--placement-index-type", (char*)NULL)) {
3164 if (val == "normal") {
3165 placement_index_type = RGWBIType_Normal;
3166 } else if (val == "indexless") {
3167 placement_index_type = RGWBIType_Indexless;
3168 } else {
3169 placement_index_type = (RGWBucketIndexType)strict_strtol(val.c_str(), 10, &err);
3170 if (!err.empty()) {
3171 cerr << "ERROR: failed to parse index type index: " << err << std::endl;
3172 return EINVAL;
3173 }
3174 }
3175 index_type_specified = true;
3176 } else if (ceph_argparse_witharg(args, i, &val, "--compression", (char*)NULL)) {
3177 compression_type = val;
3178 } else if (ceph_argparse_witharg(args, i, &val, "--role-name", (char*)NULL)) {
3179 role_name = val;
3180 } else if (ceph_argparse_witharg(args, i, &val, "--path", (char*)NULL)) {
3181 path = val;
3182 } else if (ceph_argparse_witharg(args, i, &val, "--assume-role-policy-doc", (char*)NULL)) {
3183 assume_role_doc = val;
3184 } else if (ceph_argparse_witharg(args, i, &val, "--policy-name", (char*)NULL)) {
3185 policy_name = val;
3186 } else if (ceph_argparse_witharg(args, i, &val, "--policy-doc", (char*)NULL)) {
3187 perm_policy_doc = val;
3188 } else if (ceph_argparse_witharg(args, i, &val, "--path-prefix", (char*)NULL)) {
3189 path_prefix = val;
3190 } else if (ceph_argparse_witharg(args, i, &val, "--totp-serial", (char*)NULL)) {
3191 totp_serial = val;
3192 } else if (ceph_argparse_witharg(args, i, &val, "--totp-pin", (char*)NULL)) {
3193 totp_pin.push_back(val);
3194 } else if (ceph_argparse_witharg(args, i, &val, "--totp-seed", (char*)NULL)) {
3195 totp_seed = val;
3196 } else if (ceph_argparse_witharg(args, i, &val, "--totp-seed-type", (char*)NULL)) {
3197 totp_seed_type = val;
3198 } else if (ceph_argparse_witharg(args, i, &val, "--totp-seconds", (char*)NULL)) {
3199 totp_seconds = atoi(val.c_str());
3200 } else if (ceph_argparse_witharg(args, i, &val, "--totp-window", (char*)NULL)) {
3201 totp_window = atoi(val.c_str());
3202 } else if (ceph_argparse_witharg(args, i, &val, "--trim-delay-ms", (char*)NULL)) {
3203 trim_delay_ms = atoi(val.c_str());
3204 } else if (ceph_argparse_witharg(args, i, &val, "--topic", (char*)NULL)) {
3205 topic_name = val;
3206 } else if (ceph_argparse_witharg(args, i, &val, "--sub-name", (char*)NULL)) {
3207 sub_name = val;
3208 } else if (ceph_argparse_witharg(args, i, &val, "--sub-oid-prefix", (char*)NULL)) {
3209 sub_oid_prefix = val;
3210 } else if (ceph_argparse_witharg(args, i, &val, "--sub-dest-bucket", (char*)NULL)) {
3211 sub_dest_bucket = val;
3212 } else if (ceph_argparse_witharg(args, i, &val, "--sub-push-endpoint", (char*)NULL)) {
3213 sub_push_endpoint = val;
3214 } else if (ceph_argparse_witharg(args, i, &val, "--event-id", (char*)NULL)) {
3215 event_id = val;
3216 } else if (ceph_argparse_witharg(args, i, &val, "--event-type", "--event-types", (char*)NULL)) {
3217 get_str_set(val, ",", event_types);
3218 } else if (ceph_argparse_binary_flag(args, i, &detail, NULL, "--detail", (char*)NULL)) {
3219 // do nothing
3220 } else if (strncmp(*i, "-", 1) == 0) {
3221 cerr << "ERROR: invalid flag " << *i << std::endl;
3222 return EINVAL;
3223 } else {
3224 ++i;
3225 }
3226 }
3227
3228 if (args.empty()) {
3229 usage();
3230 exit(1);
3231 }
3232 else {
3233 const char *prev_cmd = NULL;
3234 const char *prev_prev_cmd = NULL;
3235 std::vector<const char*>::iterator i ;
3236 for (i = args.begin(); i != args.end(); ++i) {
3237 opt_cmd = get_cmd(*i, prev_cmd, prev_prev_cmd, &need_more);
3238 if (opt_cmd < 0) {
3239 cerr << "unrecognized arg " << *i << std::endl;
3240 exit(1);
3241 }
3242 if (!need_more) {
3243 ++i;
3244 break;
3245 }
3246 prev_prev_cmd = prev_cmd;
3247 prev_cmd = *i;
3248 }
3249
3250 if (opt_cmd == OPT_NO_CMD) {
3251 cerr << "no command" << std::endl;
3252 exit(1);
3253 }
3254
3255 /* some commands may have an optional extra param */
3256 if (i != args.end()) {
3257 switch (opt_cmd) {
3258 case OPT_METADATA_GET:
3259 case OPT_METADATA_PUT:
3260 case OPT_METADATA_RM:
3261 case OPT_METADATA_LIST:
3262 metadata_key = *i;
3263 break;
3264 default:
3265 break;
3266 }
3267 }
3268
3269 if (tenant.empty()) {
3270 tenant = user_id.tenant;
3271 } else {
3272 if (user_id.empty() && opt_cmd != OPT_ROLE_CREATE
3273 && opt_cmd != OPT_ROLE_DELETE
3274 && opt_cmd != OPT_ROLE_GET
3275 && opt_cmd != OPT_ROLE_MODIFY
3276 && opt_cmd != OPT_ROLE_LIST
3277 && opt_cmd != OPT_ROLE_POLICY_PUT
3278 && opt_cmd != OPT_ROLE_POLICY_LIST
3279 && opt_cmd != OPT_ROLE_POLICY_GET
3280 && opt_cmd != OPT_ROLE_POLICY_DELETE
3281 && opt_cmd != OPT_RESHARD_ADD
3282 && opt_cmd != OPT_RESHARD_CANCEL
3283 && opt_cmd != OPT_RESHARD_STATUS) {
3284 cerr << "ERROR: --tenant is set, but there's no user ID" << std::endl;
3285 return EINVAL;
3286 }
3287 user_id.tenant = tenant;
3288 }
3289 /* check key parameter conflict */
3290 if ((!access_key.empty()) && gen_access_key) {
3291 cerr << "ERROR: key parameter conflict, --access-key & --gen-access-key" << std::endl;
3292 return EINVAL;
3293 }
3294 if ((!secret_key.empty()) && gen_secret_key) {
3295 cerr << "ERROR: key parameter conflict, --secret & --gen-secret" << std::endl;
3296 return EINVAL;
3297 }
3298 }
3299
3300 // default to pretty json
3301 if (format.empty()) {
3302 format = "json";
3303 pretty_format = true;
3304 }
3305
3306 if (format == "xml")
3307 formatter = new XMLFormatter(pretty_format);
3308 else if (format == "json")
3309 formatter = new JSONFormatter(pretty_format);
3310 else {
3311 cerr << "unrecognized format: " << format << std::endl;
3312 exit(1);
3313 }
3314
3315 realm_name = g_conf()->rgw_realm;
3316 zone_name = g_conf()->rgw_zone;
3317 zonegroup_name = g_conf()->rgw_zonegroup;
3318
3319 RGWStreamFlusher f(formatter, cout);
3320
3321 // not a raw op if 'period update' needs to commit to master
3322 bool raw_period_update = opt_cmd == OPT_PERIOD_UPDATE && !commit;
3323 std::set<int> raw_storage_ops_list = {OPT_ZONEGROUP_ADD, OPT_ZONEGROUP_CREATE, OPT_ZONEGROUP_DELETE,
3324 OPT_ZONEGROUP_GET, OPT_ZONEGROUP_LIST,
3325 OPT_ZONEGROUP_SET, OPT_ZONEGROUP_DEFAULT,
3326 OPT_ZONEGROUP_RENAME, OPT_ZONEGROUP_MODIFY,
3327 OPT_ZONEGROUP_REMOVE,
3328 OPT_ZONEGROUP_PLACEMENT_ADD, OPT_ZONEGROUP_PLACEMENT_RM,
3329 OPT_ZONEGROUP_PLACEMENT_MODIFY, OPT_ZONEGROUP_PLACEMENT_LIST,
3330 OPT_ZONEGROUP_PLACEMENT_DEFAULT,
3331 OPT_ZONE_CREATE, OPT_ZONE_DELETE,
3332 OPT_ZONE_GET, OPT_ZONE_SET, OPT_ZONE_RENAME,
3333 OPT_ZONE_LIST, OPT_ZONE_MODIFY, OPT_ZONE_DEFAULT,
3334 OPT_ZONE_PLACEMENT_ADD, OPT_ZONE_PLACEMENT_RM,
3335 OPT_ZONE_PLACEMENT_MODIFY, OPT_ZONE_PLACEMENT_LIST,
3336 OPT_REALM_CREATE,
3337 OPT_PERIOD_DELETE, OPT_PERIOD_GET,
3338 OPT_PERIOD_PULL,
3339 OPT_PERIOD_GET_CURRENT, OPT_PERIOD_LIST,
3340 OPT_GLOBAL_QUOTA_GET, OPT_GLOBAL_QUOTA_SET,
3341 OPT_GLOBAL_QUOTA_ENABLE, OPT_GLOBAL_QUOTA_DISABLE,
3342 OPT_REALM_DELETE, OPT_REALM_GET, OPT_REALM_LIST,
3343 OPT_REALM_LIST_PERIODS,
3344 OPT_REALM_GET_DEFAULT,
3345 OPT_REALM_RENAME, OPT_REALM_SET,
3346 OPT_REALM_DEFAULT, OPT_REALM_PULL};
3347
3348 std::set<int> readonly_ops_list = {
3349 OPT_USER_INFO,
3350 OPT_USER_STATS,
3351 OPT_BUCKETS_LIST,
3352 OPT_BUCKET_LIMIT_CHECK,
3353 OPT_BUCKET_STATS,
3354 OPT_BUCKET_SYNC_STATUS,
3355 OPT_BUCKET_SYNC_MARKERS,
3356 OPT_LOG_LIST,
3357 OPT_LOG_SHOW,
3358 OPT_USAGE_SHOW,
3359 OPT_OBJECT_STAT,
3360 OPT_BI_GET,
3361 OPT_BI_LIST,
3362 OPT_OLH_GET,
3363 OPT_OLH_READLOG,
3364 OPT_GC_LIST,
3365 OPT_LC_LIST,
3366 OPT_ORPHANS_LIST_JOBS,
3367 OPT_ZONEGROUP_GET,
3368 OPT_ZONEGROUP_LIST,
3369 OPT_ZONEGROUP_PLACEMENT_LIST,
3370 OPT_ZONE_GET,
3371 OPT_ZONE_LIST,
3372 OPT_ZONE_PLACEMENT_LIST,
3373 OPT_METADATA_GET,
3374 OPT_METADATA_LIST,
3375 OPT_METADATA_SYNC_STATUS,
3376 OPT_MDLOG_LIST,
3377 OPT_MDLOG_STATUS,
3378 OPT_SYNC_ERROR_LIST,
3379 OPT_BILOG_LIST,
3380 OPT_BILOG_STATUS,
3381 OPT_DATA_SYNC_STATUS,
3382 OPT_DATALOG_LIST,
3383 OPT_DATALOG_STATUS,
3384 OPT_REALM_GET,
3385 OPT_REALM_GET_DEFAULT,
3386 OPT_REALM_LIST,
3387 OPT_REALM_LIST_PERIODS,
3388 OPT_PERIOD_GET,
3389 OPT_PERIOD_GET_CURRENT,
3390 OPT_PERIOD_LIST,
3391 OPT_GLOBAL_QUOTA_GET,
3392 OPT_SYNC_STATUS,
3393 OPT_ROLE_GET,
3394 OPT_ROLE_LIST,
3395 OPT_ROLE_POLICY_LIST,
3396 OPT_ROLE_POLICY_GET,
3397 OPT_RESHARD_LIST,
3398 OPT_RESHARD_STATUS,
3399 };
3400
3401 bool raw_storage_op = (raw_storage_ops_list.find(opt_cmd) != raw_storage_ops_list.end() ||
3402 raw_period_update);
3403 bool need_cache = readonly_ops_list.find(opt_cmd) == readonly_ops_list.end();
3404
3405 if (raw_storage_op) {
3406 store = RGWStoreManager::get_raw_storage(g_ceph_context);
3407 } else {
3408 store = RGWStoreManager::get_storage(g_ceph_context, false, false, false, false, false,
3409 need_cache && g_conf()->rgw_cache_enabled);
3410 }
3411 if (!store) {
3412 cerr << "couldn't init storage provider" << std::endl;
3413 return 5; //EIO
3414 }
3415
3416 if (!source_zone_name.empty()) {
3417 if (!store->svc.zone->find_zone_id_by_name(source_zone_name, &source_zone)) {
3418 cerr << "WARNING: cannot find source zone id for name=" << source_zone_name << std::endl;
3419 source_zone = source_zone_name;
3420 }
3421 }
3422
3423 rgw_user_init(store);
3424 rgw_bucket_init(store->meta_mgr);
3425 rgw_otp_init(store);
3426
3427 rgw_http_client_init(g_ceph_context);
3428
3429 struct rgw_curl_setup {
3430 rgw_curl_setup() {
3431 rgw::curl::setup_curl(boost::none);
3432 }
3433 ~rgw_curl_setup() {
3434 rgw::curl::cleanup_curl();
3435 }
3436 } curl_cleanup;
3437
3438 oath_init();
3439
3440 StoreDestructor store_destructor(store);
3441
3442 if (raw_storage_op) {
3443 switch (opt_cmd) {
3444 case OPT_PERIOD_DELETE:
3445 {
3446 if (period_id.empty()) {
3447 cerr << "missing period id" << std::endl;
3448 return EINVAL;
3449 }
3450 RGWPeriod period(period_id);
3451 int ret = period.init(g_ceph_context, store->svc.sysobj);
3452 if (ret < 0) {
3453 cerr << "period.init failed: " << cpp_strerror(-ret) << std::endl;
3454 return -ret;
3455 }
3456 ret = period.delete_obj();
3457 if (ret < 0) {
3458 cerr << "ERROR: couldn't delete period: " << cpp_strerror(-ret) << std::endl;
3459 return -ret;
3460 }
3461
3462 }
3463 break;
3464 case OPT_PERIOD_GET:
3465 {
3466 epoch_t epoch = 0;
3467 if (!period_epoch.empty()) {
3468 epoch = atoi(period_epoch.c_str());
3469 }
3470 if (staging) {
3471 RGWRealm realm(realm_id, realm_name);
3472 int ret = realm.init(g_ceph_context, store->svc.sysobj);
3473 if (ret < 0 ) {
3474 cerr << "Error initializing realm " << cpp_strerror(-ret) << std::endl;
3475 return -ret;
3476 }
3477 realm_id = realm.get_id();
3478 realm_name = realm.get_name();
3479 period_id = RGWPeriod::get_staging_id(realm_id);
3480 epoch = 1;
3481 }
3482 RGWPeriod period(period_id, epoch);
3483 int ret = period.init(g_ceph_context, store->svc.sysobj, realm_id, realm_name);
3484 if (ret < 0) {
3485 cerr << "period init failed: " << cpp_strerror(-ret) << std::endl;
3486 return -ret;
3487 }
3488 encode_json("period", period, formatter);
3489 formatter->flush(cout);
3490 }
3491 break;
3492 case OPT_PERIOD_GET_CURRENT:
3493 {
3494 int ret = read_current_period_id(store, realm_id, realm_name, &period_id);
3495 if (ret < 0) {
3496 return -ret;
3497 }
3498 formatter->open_object_section("period_get_current");
3499 encode_json("current_period", period_id, formatter);
3500 formatter->close_section();
3501 formatter->flush(cout);
3502 }
3503 break;
3504 case OPT_PERIOD_LIST:
3505 {
3506 list<string> periods;
3507 int ret = store->svc.zone->list_periods(periods);
3508 if (ret < 0) {
3509 cerr << "failed to list periods: " << cpp_strerror(-ret) << std::endl;
3510 return -ret;
3511 }
3512 formatter->open_object_section("periods_list");
3513 encode_json("periods", periods, formatter);
3514 formatter->close_section();
3515 formatter->flush(cout);
3516 }
3517 break;
3518 case OPT_PERIOD_UPDATE:
3519 {
3520 int ret = update_period(realm_id, realm_name, period_id, period_epoch,
3521 commit, remote, url, access_key, secret_key,
3522 formatter, yes_i_really_mean_it);
3523 if (ret < 0) {
3524 return -ret;
3525 }
3526 }
3527 break;
3528 case OPT_PERIOD_PULL:
3529 {
3530 boost::optional<RGWRESTConn> conn;
3531 RGWRESTConn *remote_conn = nullptr;
3532 if (url.empty()) {
3533 // load current period for endpoints
3534 RGWRealm realm(realm_id, realm_name);
3535 int ret = realm.init(g_ceph_context, store->svc.sysobj);
3536 if (ret < 0) {
3537 cerr << "failed to init realm: " << cpp_strerror(-ret) << std::endl;
3538 return -ret;
3539 }
3540 RGWPeriod current_period(realm.get_current_period());
3541 ret = current_period.init(g_ceph_context, store->svc.sysobj);
3542 if (ret < 0) {
3543 cerr << "failed to init current period: " << cpp_strerror(-ret) << std::endl;
3544 return -ret;
3545 }
3546 if (remote.empty()) {
3547 // use realm master zone as remote
3548 remote = current_period.get_master_zone();
3549 }
3550 conn = get_remote_conn(store, current_period.get_map(), remote);
3551 if (!conn) {
3552 cerr << "failed to find a zone or zonegroup for remote "
3553 << remote << std::endl;
3554 return -ENOENT;
3555 }
3556 remote_conn = &*conn;
3557 }
3558
3559 RGWPeriod period;
3560 int ret = do_period_pull(remote_conn, url, access_key, secret_key,
3561 realm_id, realm_name, period_id, period_epoch,
3562 &period);
3563 if (ret < 0) {
3564 cerr << "period pull failed: " << cpp_strerror(-ret) << std::endl;
3565 return -ret;
3566 }
3567
3568 encode_json("period", period, formatter);
3569 formatter->flush(cout);
3570 }
3571 break;
3572 case OPT_GLOBAL_QUOTA_GET:
3573 case OPT_GLOBAL_QUOTA_SET:
3574 case OPT_GLOBAL_QUOTA_ENABLE:
3575 case OPT_GLOBAL_QUOTA_DISABLE:
3576 {
3577 if (realm_id.empty()) {
3578 RGWRealm realm(g_ceph_context, store->svc.sysobj);
3579 if (!realm_name.empty()) {
3580 // look up realm_id for the given realm_name
3581 int ret = realm.read_id(realm_name, realm_id);
3582 if (ret < 0) {
3583 cerr << "ERROR: failed to read realm for " << realm_name
3584 << ": " << cpp_strerror(-ret) << std::endl;
3585 return -ret;
3586 }
3587 } else {
3588 // use default realm_id when none is given
3589 int ret = realm.read_default_id(realm_id);
3590 if (ret < 0 && ret != -ENOENT) { // on ENOENT, use empty realm_id
3591 cerr << "ERROR: failed to read default realm: "
3592 << cpp_strerror(-ret) << std::endl;
3593 return -ret;
3594 }
3595 }
3596 }
3597
3598 RGWPeriodConfig period_config;
3599 int ret = period_config.read(store->svc.sysobj, realm_id);
3600 if (ret < 0 && ret != -ENOENT) {
3601 cerr << "ERROR: failed to read period config: "
3602 << cpp_strerror(-ret) << std::endl;
3603 return -ret;
3604 }
3605
3606 formatter->open_object_section("period_config");
3607 if (quota_scope == "bucket") {
3608 set_quota_info(period_config.bucket_quota, opt_cmd,
3609 max_size, max_objects,
3610 have_max_size, have_max_objects);
3611 encode_json("bucket quota", period_config.bucket_quota, formatter);
3612 } else if (quota_scope == "user") {
3613 set_quota_info(period_config.user_quota, opt_cmd,
3614 max_size, max_objects,
3615 have_max_size, have_max_objects);
3616 encode_json("user quota", period_config.user_quota, formatter);
3617 } else if (quota_scope.empty() && opt_cmd == OPT_GLOBAL_QUOTA_GET) {
3618 // if no scope is given for GET, print both
3619 encode_json("bucket quota", period_config.bucket_quota, formatter);
3620 encode_json("user quota", period_config.user_quota, formatter);
3621 } else {
3622 cerr << "ERROR: invalid quota scope specification. Please specify "
3623 "either --quota-scope=bucket, or --quota-scope=user" << std::endl;
3624 return EINVAL;
3625 }
3626 formatter->close_section();
3627
3628 if (opt_cmd != OPT_GLOBAL_QUOTA_GET) {
3629 // write the modified period config
3630 ret = period_config.write(store->svc.sysobj, realm_id);
3631 if (ret < 0) {
3632 cerr << "ERROR: failed to write period config: "
3633 << cpp_strerror(-ret) << std::endl;
3634 return -ret;
3635 }
3636 if (!realm_id.empty()) {
3637 cout << "Global quota changes saved. Use 'period update' to apply "
3638 "them to the staging period, and 'period commit' to commit the "
3639 "new period." << std::endl;
3640 } else {
3641 cout << "Global quota changes saved. They will take effect as "
3642 "the gateways are restarted." << std::endl;
3643 }
3644 }
3645
3646 formatter->flush(cout);
3647 }
3648 break;
3649 case OPT_REALM_CREATE:
3650 {
3651 if (realm_name.empty()) {
3652 cerr << "missing realm name" << std::endl;
3653 return EINVAL;
3654 }
3655
3656 RGWRealm realm(realm_name, g_ceph_context, store->svc.sysobj);
3657 int ret = realm.create();
3658 if (ret < 0) {
3659 cerr << "ERROR: couldn't create realm " << realm_name << ": " << cpp_strerror(-ret) << std::endl;
3660 return -ret;
3661 }
3662
3663 if (set_default) {
3664 ret = realm.set_as_default();
3665 if (ret < 0) {
3666 cerr << "failed to set realm " << realm_name << " as default: " << cpp_strerror(-ret) << std::endl;
3667 }
3668 }
3669
3670 encode_json("realm", realm, formatter);
3671 formatter->flush(cout);
3672 }
3673 break;
3674 case OPT_REALM_DELETE:
3675 {
3676 RGWRealm realm(realm_id, realm_name);
3677 if (realm_name.empty() && realm_id.empty()) {
3678 cerr << "missing realm name or id" << std::endl;
3679 return EINVAL;
3680 }
3681 int ret = realm.init(g_ceph_context, store->svc.sysobj);
3682 if (ret < 0) {
3683 cerr << "realm.init failed: " << cpp_strerror(-ret) << std::endl;
3684 return -ret;
3685 }
3686 ret = realm.delete_obj();
3687 if (ret < 0) {
3688 cerr << "ERROR: couldn't : " << cpp_strerror(-ret) << std::endl;
3689 return -ret;
3690 }
3691
3692 }
3693 break;
3694 case OPT_REALM_GET:
3695 {
3696 RGWRealm realm(realm_id, realm_name);
3697 int ret = realm.init(g_ceph_context, store->svc.sysobj);
3698 if (ret < 0) {
3699 if (ret == -ENOENT && realm_name.empty() && realm_id.empty()) {
3700 cerr << "missing realm name or id, or default realm not found" << std::endl;
3701 } else {
3702 cerr << "realm.init failed: " << cpp_strerror(-ret) << std::endl;
3703 }
3704 return -ret;
3705 }
3706 encode_json("realm", realm, formatter);
3707 formatter->flush(cout);
3708 }
3709 break;
3710 case OPT_REALM_GET_DEFAULT:
3711 {
3712 RGWRealm realm(g_ceph_context, store->svc.sysobj);
3713 string default_id;
3714 int ret = realm.read_default_id(default_id);
3715 if (ret == -ENOENT) {
3716 cout << "No default realm is set" << std::endl;
3717 return -ret;
3718 } else if (ret < 0) {
3719 cerr << "Error reading default realm:" << cpp_strerror(-ret) << std::endl;
3720 return -ret;
3721 }
3722 cout << "default realm: " << default_id << std::endl;
3723 }
3724 break;
3725 case OPT_REALM_LIST:
3726 {
3727 RGWRealm realm(g_ceph_context, store->svc.sysobj);
3728 string default_id;
3729 int ret = realm.read_default_id(default_id);
3730 if (ret < 0 && ret != -ENOENT) {
3731 cerr << "could not determine default realm: " << cpp_strerror(-ret) << std::endl;
3732 }
3733 list<string> realms;
3734 ret = store->svc.zone->list_realms(realms);
3735 if (ret < 0) {
3736 cerr << "failed to list realms: " << cpp_strerror(-ret) << std::endl;
3737 return -ret;
3738 }
3739 formatter->open_object_section("realms_list");
3740 encode_json("default_info", default_id, formatter);
3741 encode_json("realms", realms, formatter);
3742 formatter->close_section();
3743 formatter->flush(cout);
3744 }
3745 break;
3746 case OPT_REALM_LIST_PERIODS:
3747 {
3748 int ret = read_current_period_id(store, realm_id, realm_name, &period_id);
3749 if (ret < 0) {
3750 return -ret;
3751 }
3752 list<string> periods;
3753 ret = store->svc.zone->list_periods(period_id, periods);
3754 if (ret < 0) {
3755 cerr << "list periods failed: " << cpp_strerror(-ret) << std::endl;
3756 return -ret;
3757 }
3758 formatter->open_object_section("realm_periods_list");
3759 encode_json("current_period", period_id, formatter);
3760 encode_json("periods", periods, formatter);
3761 formatter->close_section();
3762 formatter->flush(cout);
3763 }
3764 break;
3765
3766 case OPT_REALM_RENAME:
3767 {
3768 RGWRealm realm(realm_id, realm_name);
3769 if (realm_new_name.empty()) {
3770 cerr << "missing realm new name" << std::endl;
3771 return EINVAL;
3772 }
3773 if (realm_name.empty() && realm_id.empty()) {
3774 cerr << "missing realm name or id" << std::endl;
3775 return EINVAL;
3776 }
3777 int ret = realm.init(g_ceph_context, store->svc.sysobj);
3778 if (ret < 0) {
3779 cerr << "realm.init failed: " << cpp_strerror(-ret) << std::endl;
3780 return -ret;
3781 }
3782 ret = realm.rename(realm_new_name);
3783 if (ret < 0) {
3784 cerr << "realm.rename failed: " << cpp_strerror(-ret) << std::endl;
3785 return -ret;
3786 }
3787 cout << "Realm name updated. Note that this change only applies to "
3788 "the current cluster, so this command must be run separately "
3789 "on each of the realm's other clusters." << std::endl;
3790 }
3791 break;
3792 case OPT_REALM_SET:
3793 {
3794 if (realm_id.empty() && realm_name.empty()) {
3795 cerr << "no realm name or id provided" << std::endl;
3796 return EINVAL;
3797 }
3798 RGWRealm realm(realm_id, realm_name);
3799 bool new_realm = false;
3800 int ret = realm.init(g_ceph_context, store->svc.sysobj);
3801 if (ret < 0 && ret != -ENOENT) {
3802 cerr << "failed to init realm: " << cpp_strerror(-ret) << std::endl;
3803 return -ret;
3804 } else if (ret == -ENOENT) {
3805 new_realm = true;
3806 }
3807 ret = read_decode_json(infile, realm);
3808 if (ret < 0) {
3809 return 1;
3810 }
3811 if (!realm_name.empty() && realm.get_name() != realm_name) {
3812 cerr << "mismatch between --rgw-realm " << realm_name << " and json input file name " <<
3813 realm.get_name() << std::endl;
3814 return EINVAL;
3815 }
3816 /* new realm */
3817 if (new_realm) {
3818 cout << "clearing period and epoch for new realm" << std::endl;
3819 realm.clear_current_period_and_epoch();
3820 ret = realm.create();
3821 if (ret < 0) {
3822 cerr << "ERROR: couldn't create new realm: " << cpp_strerror(-ret) << std::endl;
3823 return 1;
3824 }
3825 } else {
3826 ret = realm.update();
3827 if (ret < 0) {
3828 cerr << "ERROR: couldn't store realm info: " << cpp_strerror(-ret) << std::endl;
3829 return 1;
3830 }
3831 }
3832
3833 if (set_default) {
3834 ret = realm.set_as_default();
3835 if (ret < 0) {
3836 cerr << "failed to set realm " << realm_name << " as default: " << cpp_strerror(-ret) << std::endl;
3837 }
3838 }
3839 encode_json("realm", realm, formatter);
3840 formatter->flush(cout);
3841 }
3842 break;
3843
3844 case OPT_REALM_DEFAULT:
3845 {
3846 RGWRealm realm(realm_id, realm_name);
3847 int ret = realm.init(g_ceph_context, store->svc.sysobj);
3848 if (ret < 0) {
3849 cerr << "failed to init realm: " << cpp_strerror(-ret) << std::endl;
3850 return -ret;
3851 }
3852 ret = realm.set_as_default();
3853 if (ret < 0) {
3854 cerr << "failed to set realm as default: " << cpp_strerror(-ret) << std::endl;
3855 return -ret;
3856 }
3857 }
3858 break;
3859 case OPT_REALM_PULL:
3860 {
3861 if (url.empty()) {
3862 cerr << "A --url must be provided." << std::endl;
3863 return EINVAL;
3864 }
3865 RGWEnv env;
3866 req_info info(g_ceph_context, &env);
3867 info.method = "GET";
3868 info.request_uri = "/admin/realm";
3869
3870 map<string, string> &params = info.args.get_params();
3871 if (!realm_id.empty())
3872 params["id"] = realm_id;
3873 if (!realm_name.empty())
3874 params["name"] = realm_name;
3875
3876 bufferlist bl;
3877 JSONParser p;
3878 int ret = send_to_url(url, access_key, secret_key, info, bl, p);
3879 if (ret < 0) {
3880 cerr << "request failed: " << cpp_strerror(-ret) << std::endl;
3881 if (ret == -EACCES) {
3882 cerr << "If the realm has been changed on the master zone, the "
3883 "master zone's gateway may need to be restarted to recognize "
3884 "this user." << std::endl;
3885 }
3886 return -ret;
3887 }
3888 RGWRealm realm;
3889 realm.init(g_ceph_context, store->svc.sysobj, false);
3890 try {
3891 decode_json_obj(realm, &p);
3892 } catch (JSONDecoder::err& e) {
3893 cerr << "failed to decode JSON response: " << e.message << std::endl;
3894 return EINVAL;
3895 }
3896 RGWPeriod period;
3897 auto& current_period = realm.get_current_period();
3898 if (!current_period.empty()) {
3899 // pull the latest epoch of the realm's current period
3900 ret = do_period_pull(nullptr, url, access_key, secret_key,
3901 realm_id, realm_name, current_period, "",
3902 &period);
3903 if (ret < 0) {
3904 cerr << "could not fetch period " << current_period << std::endl;
3905 return -ret;
3906 }
3907 }
3908 ret = realm.create(false);
3909 if (ret < 0 && ret != -EEXIST) {
3910 cerr << "Error storing realm " << realm.get_id() << ": "
3911 << cpp_strerror(ret) << std::endl;
3912 return -ret;
3913 } else if (ret ==-EEXIST) {
3914 ret = realm.update();
3915 if (ret < 0) {
3916 cerr << "Error storing realm " << realm.get_id() << ": "
3917 << cpp_strerror(ret) << std::endl;
3918 }
3919 }
3920
3921 if (set_default) {
3922 ret = realm.set_as_default();
3923 if (ret < 0) {
3924 cerr << "failed to set realm " << realm_name << " as default: " << cpp_strerror(-ret) << std::endl;
3925 }
3926 }
3927
3928 encode_json("realm", realm, formatter);
3929 formatter->flush(cout);
3930 }
3931 break;
3932
3933 case OPT_ZONEGROUP_ADD:
3934 {
3935 if (zonegroup_id.empty() && zonegroup_name.empty()) {
3936 cerr << "no zonegroup name or id provided" << std::endl;
3937 return EINVAL;
3938 }
3939
3940 RGWZoneGroup zonegroup(zonegroup_id,zonegroup_name);
3941 int ret = zonegroup.init(g_ceph_context, store->svc.sysobj);
3942 if (ret < 0) {
3943 cerr << "failed to initialize zonegroup " << zonegroup_name << " id " << zonegroup_id << " :"
3944 << cpp_strerror(-ret) << std::endl;
3945 return -ret;
3946 }
3947 RGWZoneParams zone(zone_id, zone_name);
3948 ret = zone.init(g_ceph_context, store->svc.sysobj);
3949 if (ret < 0) {
3950 cerr << "unable to initialize zone: " << cpp_strerror(-ret) << std::endl;
3951 return -ret;
3952 }
3953 if (zone.realm_id != zonegroup.realm_id) {
3954 zone.realm_id = zonegroup.realm_id;
3955 ret = zone.update();
3956 if (ret < 0) {
3957 cerr << "failed to save zone info: " << cpp_strerror(-ret) << std::endl;
3958 return -ret;
3959 }
3960 }
3961
3962 string *ptier_type = (tier_type_specified ? &tier_type : nullptr);
3963
3964 for (auto a : tier_config_add) {
3965 int r = zone.tier_config.set(a.first, a.second);
3966 if (r < 0) {
3967 cerr << "ERROR: failed to set configurable: " << a << std::endl;
3968 return EINVAL;
3969 }
3970 }
3971
3972 bool *psync_from_all = (sync_from_all_specified ? &sync_from_all : nullptr);
3973 string *predirect_zone = (redirect_zone_set ? &redirect_zone : nullptr);
3974
3975 ret = zonegroup.add_zone(zone,
3976 (is_master_set ? &is_master : NULL),
3977 (is_read_only_set ? &read_only : NULL),
3978 endpoints, ptier_type,
3979 psync_from_all, sync_from, sync_from_rm,
3980 predirect_zone,
3981 store->svc.sync_modules->get_manager());
3982 if (ret < 0) {
3983 cerr << "failed to add zone " << zone_name << " to zonegroup " << zonegroup.get_name() << ": "
3984 << cpp_strerror(-ret) << std::endl;
3985 return -ret;
3986 }
3987
3988 encode_json("zonegroup", zonegroup, formatter);
3989 formatter->flush(cout);
3990 }
3991 break;
3992 case OPT_ZONEGROUP_CREATE:
3993 {
3994 if (zonegroup_name.empty()) {
3995 cerr << "Missing zonegroup name" << std::endl;
3996 return EINVAL;
3997 }
3998 RGWRealm realm(realm_id, realm_name);
3999 int ret = realm.init(g_ceph_context, store->svc.sysobj);
4000 if (ret < 0) {
4001 cerr << "failed to init realm: " << cpp_strerror(-ret) << std::endl;
4002 return -ret;
4003 }
4004
4005 RGWZoneGroup zonegroup(zonegroup_name, is_master, g_ceph_context, store->svc.sysobj, realm.get_id(), endpoints);
4006 zonegroup.api_name = (api_name.empty() ? zonegroup_name : api_name);
4007 ret = zonegroup.create();
4008 if (ret < 0) {
4009 cerr << "failed to create zonegroup " << zonegroup_name << ": " << cpp_strerror(-ret) << std::endl;
4010 return -ret;
4011 }
4012
4013 if (set_default) {
4014 ret = zonegroup.set_as_default();
4015 if (ret < 0) {
4016 cerr << "failed to set zonegroup " << zonegroup_name << " as default: " << cpp_strerror(-ret) << std::endl;
4017 }
4018 }
4019
4020 encode_json("zonegroup", zonegroup, formatter);
4021 formatter->flush(cout);
4022 }
4023 break;
4024 case OPT_ZONEGROUP_DEFAULT:
4025 {
4026 if (zonegroup_id.empty() && zonegroup_name.empty()) {
4027 cerr << "no zonegroup name or id provided" << std::endl;
4028 return EINVAL;
4029 }
4030
4031 RGWZoneGroup zonegroup(zonegroup_id, zonegroup_name);
4032 int ret = zonegroup.init(g_ceph_context, store->svc.sysobj);
4033 if (ret < 0) {
4034 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
4035 return -ret;
4036 }
4037
4038 ret = zonegroup.set_as_default();
4039 if (ret < 0) {
4040 cerr << "failed to set zonegroup as default: " << cpp_strerror(-ret) << std::endl;
4041 return -ret;
4042 }
4043 }
4044 break;
4045 case OPT_ZONEGROUP_DELETE:
4046 {
4047 if (zonegroup_id.empty() && zonegroup_name.empty()) {
4048 cerr << "no zonegroup name or id provided" << std::endl;
4049 return EINVAL;
4050 }
4051 RGWZoneGroup zonegroup(zonegroup_id, zonegroup_name);
4052 int ret = zonegroup.init(g_ceph_context, store->svc.sysobj);
4053 if (ret < 0) {
4054 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
4055 return -ret;
4056 }
4057 ret = zonegroup.delete_obj();
4058 if (ret < 0) {
4059 cerr << "ERROR: couldn't delete zonegroup: " << cpp_strerror(-ret) << std::endl;
4060 return -ret;
4061 }
4062 }
4063 break;
4064 case OPT_ZONEGROUP_GET:
4065 {
4066 RGWZoneGroup zonegroup(zonegroup_id, zonegroup_name);
4067 int ret = zonegroup.init(g_ceph_context, store->svc.sysobj);
4068 if (ret < 0) {
4069 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
4070 return -ret;
4071 }
4072
4073 encode_json("zonegroup", zonegroup, formatter);
4074 formatter->flush(cout);
4075 }
4076 break;
4077 case OPT_ZONEGROUP_LIST:
4078 {
4079 RGWZoneGroup zonegroup;
4080 int ret = zonegroup.init(g_ceph_context, store->svc.sysobj, false);
4081 if (ret < 0) {
4082 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
4083 return -ret;
4084 }
4085
4086 list<string> zonegroups;
4087 ret = store->svc.zone->list_zonegroups(zonegroups);
4088 if (ret < 0) {
4089 cerr << "failed to list zonegroups: " << cpp_strerror(-ret) << std::endl;
4090 return -ret;
4091 }
4092 string default_zonegroup;
4093 ret = zonegroup.read_default_id(default_zonegroup);
4094 if (ret < 0 && ret != -ENOENT) {
4095 cerr << "could not determine default zonegroup: " << cpp_strerror(-ret) << std::endl;
4096 }
4097 formatter->open_object_section("zonegroups_list");
4098 encode_json("default_info", default_zonegroup, formatter);
4099 encode_json("zonegroups", zonegroups, formatter);
4100 formatter->close_section();
4101 formatter->flush(cout);
4102 }
4103 break;
4104 case OPT_ZONEGROUP_MODIFY:
4105 {
4106 RGWRealm realm(realm_id, realm_name);
4107 int ret = realm.init(g_ceph_context, store->svc.sysobj);
4108 if (ret < 0) {
4109 cerr << "failed to init realm: " << cpp_strerror(-ret) << std::endl;
4110 return -ret;
4111 }
4112
4113 RGWZoneGroup zonegroup(zonegroup_id, zonegroup_name);
4114 ret = zonegroup.init(g_ceph_context, store->svc.sysobj);
4115 if (ret < 0) {
4116 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
4117 return -ret;
4118 }
4119
4120 bool need_update = false;
4121
4122 if (!master_zone.empty()) {
4123 zonegroup.master_zone = master_zone;
4124 need_update = true;
4125 }
4126
4127 if (is_master_set) {
4128 zonegroup.update_master(is_master);
4129 need_update = true;
4130 }
4131
4132 if (!endpoints.empty()) {
4133 zonegroup.endpoints = endpoints;
4134 need_update = true;
4135 }
4136
4137 if (!api_name.empty()) {
4138 zonegroup.api_name = api_name;
4139 need_update = true;
4140 }
4141
4142 if (!realm_id.empty()) {
4143 zonegroup.realm_id = realm_id;
4144 need_update = true;
4145 } else if (!realm_name.empty()) {
4146 // get realm id from name
4147 RGWRealm realm{g_ceph_context, store->svc.sysobj};
4148 ret = realm.read_id(realm_name, zonegroup.realm_id);
4149 if (ret < 0) {
4150 cerr << "failed to find realm by name " << realm_name << std::endl;
4151 return -ret;
4152 }
4153 need_update = true;
4154 }
4155
4156 if (need_update) {
4157 ret = zonegroup.update();
4158 if (ret < 0) {
4159 cerr << "failed to update zonegroup: " << cpp_strerror(-ret) << std::endl;
4160 return -ret;
4161 }
4162 }
4163
4164 if (set_default) {
4165 ret = zonegroup.set_as_default();
4166 if (ret < 0) {
4167 cerr << "failed to set zonegroup " << zonegroup_name << " as default: " << cpp_strerror(-ret) << std::endl;
4168 }
4169 }
4170
4171 encode_json("zonegroup", zonegroup, formatter);
4172 formatter->flush(cout);
4173 }
4174 break;
4175 case OPT_ZONEGROUP_SET:
4176 {
4177 RGWRealm realm(realm_id, realm_name);
4178 int ret = realm.init(g_ceph_context, store->svc.sysobj);
4179 bool default_realm_not_exist = (ret == -ENOENT && realm_id.empty() && realm_name.empty());
4180
4181 if (ret < 0 && !default_realm_not_exist ) {
4182 cerr << "failed to init realm: " << cpp_strerror(-ret) << std::endl;
4183 return -ret;
4184 }
4185
4186 RGWZoneGroup zonegroup;
4187 ret = zonegroup.init(g_ceph_context, store->svc.sysobj, false);
4188 if (ret < 0) {
4189 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
4190 return -ret;
4191 }
4192 ret = read_decode_json(infile, zonegroup);
4193 if (ret < 0) {
4194 return 1;
4195 }
4196 if (zonegroup.realm_id.empty() && !default_realm_not_exist) {
4197 zonegroup.realm_id = realm.get_id();
4198 }
4199 ret = zonegroup.create();
4200 if (ret < 0 && ret != -EEXIST) {
4201 cerr << "ERROR: couldn't create zonegroup info: " << cpp_strerror(-ret) << std::endl;
4202 return 1;
4203 } else if (ret == -EEXIST) {
4204 ret = zonegroup.update();
4205 if (ret < 0) {
4206 cerr << "ERROR: couldn't store zonegroup info: " << cpp_strerror(-ret) << std::endl;
4207 return 1;
4208 }
4209 }
4210
4211 if (set_default) {
4212 ret = zonegroup.set_as_default();
4213 if (ret < 0) {
4214 cerr << "failed to set zonegroup " << zonegroup_name << " as default: " << cpp_strerror(-ret) << std::endl;
4215 }
4216 }
4217
4218 encode_json("zonegroup", zonegroup, formatter);
4219 formatter->flush(cout);
4220 }
4221 break;
4222 case OPT_ZONEGROUP_REMOVE:
4223 {
4224 RGWZoneGroup zonegroup(zonegroup_id, zonegroup_name);
4225 int ret = zonegroup.init(g_ceph_context, store->svc.sysobj);
4226 if (ret < 0) {
4227 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
4228 return -ret;
4229 }
4230
4231 if (zone_id.empty()) {
4232 if (zone_name.empty()) {
4233 cerr << "no --zone-id or --rgw-zone name provided" << std::endl;
4234 return EINVAL;
4235 }
4236 // look up zone id by name
4237 for (auto& z : zonegroup.zones) {
4238 if (zone_name == z.second.name) {
4239 zone_id = z.second.id;
4240 break;
4241 }
4242 }
4243 if (zone_id.empty()) {
4244 cerr << "zone name " << zone_name << " not found in zonegroup "
4245 << zonegroup.get_name() << std::endl;
4246 return ENOENT;
4247 }
4248 }
4249
4250 ret = zonegroup.remove_zone(zone_id);
4251 if (ret < 0) {
4252 cerr << "failed to remove zone: " << cpp_strerror(-ret) << std::endl;
4253 return -ret;
4254 }
4255
4256 encode_json("zonegroup", zonegroup, formatter);
4257 formatter->flush(cout);
4258 }
4259 break;
4260 case OPT_ZONEGROUP_RENAME:
4261 {
4262 if (zonegroup_new_name.empty()) {
4263 cerr << " missing zonegroup new name" << std::endl;
4264 return EINVAL;
4265 }
4266 if (zonegroup_id.empty() && zonegroup_name.empty()) {
4267 cerr << "no zonegroup name or id provided" << std::endl;
4268 return EINVAL;
4269 }
4270 RGWZoneGroup zonegroup(zonegroup_id, zonegroup_name);
4271 int ret = zonegroup.init(g_ceph_context, store->svc.sysobj);
4272 if (ret < 0) {
4273 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
4274 return -ret;
4275 }
4276 ret = zonegroup.rename(zonegroup_new_name);
4277 if (ret < 0) {
4278 cerr << "failed to rename zonegroup: " << cpp_strerror(-ret) << std::endl;
4279 return -ret;
4280 }
4281 }
4282 break;
4283 case OPT_ZONEGROUP_PLACEMENT_LIST:
4284 {
4285 RGWZoneGroup zonegroup(zonegroup_id, zonegroup_name);
4286 int ret = zonegroup.init(g_ceph_context, store->svc.sysobj);
4287 if (ret < 0) {
4288 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
4289 return -ret;
4290 }
4291
4292 encode_json("placement_targets", zonegroup.placement_targets, formatter);
4293 formatter->flush(cout);
4294 }
4295 break;
4296 case OPT_ZONEGROUP_PLACEMENT_ADD:
4297 case OPT_ZONEGROUP_PLACEMENT_MODIFY:
4298 case OPT_ZONEGROUP_PLACEMENT_RM:
4299 case OPT_ZONEGROUP_PLACEMENT_DEFAULT:
4300 {
4301 if (placement_id.empty()) {
4302 cerr << "ERROR: --placement-id not specified" << std::endl;
4303 return EINVAL;
4304 }
4305
4306 rgw_placement_rule rule;
4307 rule.from_str(placement_id);
4308
4309 if (!rule.storage_class.empty() && !storage_class.empty() &&
4310 rule.storage_class != storage_class) {
4311 cerr << "ERROR: provided contradicting storage class configuration" << std::endl;
4312 return EINVAL;
4313 } else if (rule.storage_class.empty()) {
4314 rule.storage_class = storage_class;
4315 }
4316
4317 RGWZoneGroup zonegroup(zonegroup_id, zonegroup_name);
4318 int ret = zonegroup.init(g_ceph_context, store->svc.sysobj);
4319 if (ret < 0) {
4320 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
4321 return -ret;
4322 }
4323
4324 if (opt_cmd == OPT_ZONEGROUP_PLACEMENT_ADD ||
4325 opt_cmd == OPT_ZONEGROUP_PLACEMENT_MODIFY) {
4326 RGWZoneGroupPlacementTarget& target = zonegroup.placement_targets[placement_id];
4327 if (!tags.empty()) {
4328 target.tags.clear();
4329 for (auto& t : tags) {
4330 target.tags.insert(t);
4331 }
4332 }
4333 target.name = placement_id;
4334 for (auto& t : tags_rm) {
4335 target.tags.erase(t);
4336 }
4337 for (auto& t : tags_add) {
4338 target.tags.insert(t);
4339 }
4340 target.storage_classes.insert(rule.get_storage_class());
4341 } else if (opt_cmd == OPT_ZONEGROUP_PLACEMENT_RM) {
4342 zonegroup.placement_targets.erase(placement_id);
4343 } else if (opt_cmd == OPT_ZONEGROUP_PLACEMENT_DEFAULT) {
4344 if (!zonegroup.placement_targets.count(placement_id)) {
4345 cerr << "failed to find a zonegroup placement target named '"
4346 << placement_id << "'" << std::endl;
4347 return -ENOENT;
4348 }
4349 zonegroup.default_placement = rule;
4350 }
4351
4352 zonegroup.post_process_params();
4353 ret = zonegroup.update();
4354 if (ret < 0) {
4355 cerr << "failed to update zonegroup: " << cpp_strerror(-ret) << std::endl;
4356 return -ret;
4357 }
4358
4359 encode_json("placement_targets", zonegroup.placement_targets, formatter);
4360 formatter->flush(cout);
4361 }
4362 break;
4363 case OPT_ZONE_CREATE:
4364 {
4365 if (zone_name.empty()) {
4366 cerr << "zone name not provided" << std::endl;
4367 return EINVAL;
4368 }
4369 int ret;
4370 RGWZoneGroup zonegroup(zonegroup_id, zonegroup_name);
4371 /* if the user didn't provide zonegroup info , create stand alone zone */
4372 if (!zonegroup_id.empty() || !zonegroup_name.empty()) {
4373 ret = zonegroup.init(g_ceph_context, store->svc.sysobj);
4374 if (ret < 0) {
4375 cerr << "unable to initialize zonegroup " << zonegroup_name << ": " << cpp_strerror(-ret) << std::endl;
4376 return -ret;
4377 }
4378 if (realm_id.empty() && realm_name.empty()) {
4379 realm_id = zonegroup.realm_id;
4380 }
4381 }
4382
4383 RGWZoneParams zone(zone_id, zone_name);
4384 ret = zone.init(g_ceph_context, store->svc.sysobj, false);
4385 if (ret < 0) {
4386 cerr << "unable to initialize zone: " << cpp_strerror(-ret) << std::endl;
4387 return -ret;
4388 }
4389
4390 zone.system_key.id = access_key;
4391 zone.system_key.key = secret_key;
4392 zone.realm_id = realm_id;
4393 for (auto a : tier_config_add) {
4394 int r = zone.tier_config.set(a.first, a.second);
4395 if (r < 0) {
4396 cerr << "ERROR: failed to set configurable: " << a << std::endl;
4397 return EINVAL;
4398 }
4399 }
4400
4401 ret = zone.create();
4402 if (ret < 0) {
4403 cerr << "failed to create zone " << zone_name << ": " << cpp_strerror(-ret) << std::endl;
4404 return -ret;
4405 }
4406
4407 if (!zonegroup_id.empty() || !zonegroup_name.empty()) {
4408 string *ptier_type = (tier_type_specified ? &tier_type : nullptr);
4409 bool *psync_from_all = (sync_from_all_specified ? &sync_from_all : nullptr);
4410 string *predirect_zone = (redirect_zone_set ? &redirect_zone : nullptr);
4411 ret = zonegroup.add_zone(zone,
4412 (is_master_set ? &is_master : NULL),
4413 (is_read_only_set ? &read_only : NULL),
4414 endpoints,
4415 ptier_type,
4416 psync_from_all,
4417 sync_from, sync_from_rm,
4418 predirect_zone,
4419 store->svc.sync_modules->get_manager());
4420 if (ret < 0) {
4421 cerr << "failed to add zone " << zone_name << " to zonegroup " << zonegroup.get_name()
4422 << ": " << cpp_strerror(-ret) << std::endl;
4423 return -ret;
4424 }
4425 }
4426
4427 if (set_default) {
4428 ret = zone.set_as_default();
4429 if (ret < 0) {
4430 cerr << "failed to set zone " << zone_name << " as default: " << cpp_strerror(-ret) << std::endl;
4431 }
4432 }
4433
4434 encode_json("zone", zone, formatter);
4435 formatter->flush(cout);
4436 }
4437 break;
4438 case OPT_ZONE_DEFAULT:
4439 {
4440 RGWZoneGroup zonegroup(zonegroup_id,zonegroup_name);
4441 int ret = zonegroup.init(g_ceph_context, store->svc.sysobj);
4442 if (ret < 0) {
4443 cerr << "WARNING: failed to initialize zonegroup " << zonegroup_name << std::endl;
4444 }
4445 if (zone_id.empty() && zone_name.empty()) {
4446 cerr << "no zone name or id provided" << std::endl;
4447 return EINVAL;
4448 }
4449 RGWZoneParams zone(zone_id, zone_name);
4450 ret = zone.init(g_ceph_context, store->svc.sysobj);
4451 if (ret < 0) {
4452 cerr << "unable to initialize zone: " << cpp_strerror(-ret) << std::endl;
4453 return -ret;
4454 }
4455 ret = zone.set_as_default();
4456 if (ret < 0) {
4457 cerr << "failed to set zone as default: " << cpp_strerror(-ret) << std::endl;
4458 return -ret;
4459 }
4460 }
4461 break;
4462 case OPT_ZONE_DELETE:
4463 {
4464 if (zone_id.empty() && zone_name.empty()) {
4465 cerr << "no zone name or id provided" << std::endl;
4466 return EINVAL;
4467 }
4468 RGWZoneParams zone(zone_id, zone_name);
4469 int ret = zone.init(g_ceph_context, store->svc.sysobj);
4470 if (ret < 0) {
4471 cerr << "unable to initialize zone: " << cpp_strerror(-ret) << std::endl;
4472 return -ret;
4473 }
4474
4475 list<string> zonegroups;
4476 ret = store->svc.zone->list_zonegroups(zonegroups);
4477 if (ret < 0) {
4478 cerr << "failed to list zonegroups: " << cpp_strerror(-ret) << std::endl;
4479 return -ret;
4480 }
4481
4482 for (list<string>::iterator iter = zonegroups.begin(); iter != zonegroups.end(); ++iter) {
4483 RGWZoneGroup zonegroup(string(), *iter);
4484 int ret = zonegroup.init(g_ceph_context, store->svc.sysobj);
4485 if (ret < 0) {
4486 cerr << "WARNING: failed to initialize zonegroup " << zonegroup_name << std::endl;
4487 continue;
4488 }
4489 ret = zonegroup.remove_zone(zone.get_id());
4490 if (ret < 0 && ret != -ENOENT) {
4491 cerr << "failed to remove zone " << zone_name << " from zonegroup " << zonegroup.get_name() << ": "
4492 << cpp_strerror(-ret) << std::endl;
4493 }
4494 }
4495
4496 ret = zone.delete_obj();
4497 if (ret < 0) {
4498 cerr << "failed to delete zone " << zone_name << ": " << cpp_strerror(-ret) << std::endl;
4499 return -ret;
4500 }
4501 }
4502 break;
4503 case OPT_ZONE_GET:
4504 {
4505 RGWZoneParams zone(zone_id, zone_name);
4506 int ret = zone.init(g_ceph_context, store->svc.sysobj);
4507 if (ret < 0) {
4508 cerr << "unable to initialize zone: " << cpp_strerror(-ret) << std::endl;
4509 return -ret;
4510 }
4511 encode_json("zone", zone, formatter);
4512 formatter->flush(cout);
4513 }
4514 break;
4515 case OPT_ZONE_SET:
4516 {
4517 RGWZoneParams zone(zone_name);
4518 int ret = zone.init(g_ceph_context, store->svc.sysobj, false);
4519 if (ret < 0) {
4520 return -ret;
4521 }
4522
4523 ret = zone.read();
4524 if (ret < 0 && ret != -ENOENT) {
4525 cerr << "zone.read() returned ret=" << ret << std::endl;
4526 return -ret;
4527 }
4528
4529 string orig_id = zone.get_id();
4530
4531 ret = read_decode_json(infile, zone);
4532 if (ret < 0) {
4533 return 1;
4534 }
4535
4536 if(zone.realm_id.empty()) {
4537 RGWRealm realm(realm_id, realm_name);
4538 int ret = realm.init(g_ceph_context, store->svc.sysobj);
4539 if (ret < 0 && ret != -ENOENT) {
4540 cerr << "failed to init realm: " << cpp_strerror(-ret) << std::endl;
4541 return -ret;
4542 }
4543 zone.realm_id = realm.get_id();
4544 }
4545
4546 if( !zone_name.empty() && !zone.get_name().empty() && zone.get_name() != zone_name) {
4547 cerr << "Error: zone name" << zone_name << " is different than the zone name " << zone.get_name() << " in the provided json " << std::endl;
4548 return EINVAL;
4549 }
4550
4551 if (zone.get_name().empty()) {
4552 zone.set_name(zone_name);
4553 if (zone.get_name().empty()) {
4554 cerr << "no zone name specified" << std::endl;
4555 return EINVAL;
4556 }
4557 }
4558
4559 zone_name = zone.get_name();
4560
4561 if (zone.get_id().empty()) {
4562 zone.set_id(orig_id);
4563 }
4564
4565 if (zone.get_id().empty()) {
4566 cerr << "no zone name id the json provided, assuming old format" << std::endl;
4567 if (zone_name.empty()) {
4568 cerr << "missing zone name" << std::endl;
4569 return EINVAL;
4570 }
4571 zone.set_name(zone_name);
4572 zone.set_id(zone_name);
4573 }
4574
4575 cerr << "zone id " << zone.get_id();
4576 ret = zone.fix_pool_names();
4577 if (ret < 0) {
4578 cerr << "ERROR: couldn't fix zone: " << cpp_strerror(-ret) << std::endl;
4579 return -ret;
4580 }
4581 ret = zone.write(false);
4582 if (ret < 0) {
4583 cerr << "ERROR: couldn't create zone: " << cpp_strerror(-ret) << std::endl;
4584 return 1;
4585 }
4586
4587 if (set_default) {
4588 ret = zone.set_as_default();
4589 if (ret < 0) {
4590 cerr << "failed to set zone " << zone_name << " as default: " << cpp_strerror(-ret) << std::endl;
4591 }
4592 }
4593
4594 encode_json("zone", zone, formatter);
4595 formatter->flush(cout);
4596 }
4597 break;
4598 case OPT_ZONE_LIST:
4599 {
4600 list<string> zones;
4601 int ret = store->svc.zone->list_zones(zones);
4602 if (ret < 0) {
4603 cerr << "failed to list zones: " << cpp_strerror(-ret) << std::endl;
4604 return -ret;
4605 }
4606
4607 RGWZoneParams zone;
4608 ret = zone.init(g_ceph_context, store->svc.sysobj, false);
4609 if (ret < 0) {
4610 cerr << "failed to init zone: " << cpp_strerror(-ret) << std::endl;
4611 return -ret;
4612 }
4613 string default_zone;
4614 ret = zone.read_default_id(default_zone);
4615 if (ret < 0 && ret != -ENOENT) {
4616 cerr << "could not determine default zone: " << cpp_strerror(-ret) << std::endl;
4617 }
4618 formatter->open_object_section("zones_list");
4619 encode_json("default_info", default_zone, formatter);
4620 encode_json("zones", zones, formatter);
4621 formatter->close_section();
4622 formatter->flush(cout);
4623 }
4624 break;
4625 case OPT_ZONE_MODIFY:
4626 {
4627 RGWZoneParams zone(zone_id, zone_name);
4628 int ret = zone.init(g_ceph_context, store->svc.sysobj);
4629 if (ret < 0) {
4630 cerr << "failed to init zone: " << cpp_strerror(-ret) << std::endl;
4631 return -ret;
4632 }
4633
4634 bool need_zone_update = false;
4635 if (!access_key.empty()) {
4636 zone.system_key.id = access_key;
4637 need_zone_update = true;
4638 }
4639
4640 if (!secret_key.empty()) {
4641 zone.system_key.key = secret_key;
4642 need_zone_update = true;
4643 }
4644
4645 if (!realm_id.empty()) {
4646 zone.realm_id = realm_id;
4647 need_zone_update = true;
4648 } else if (!realm_name.empty()) {
4649 // get realm id from name
4650 RGWRealm realm{g_ceph_context, store->svc.sysobj};
4651 ret = realm.read_id(realm_name, zone.realm_id);
4652 if (ret < 0) {
4653 cerr << "failed to find realm by name " << realm_name << std::endl;
4654 return -ret;
4655 }
4656 need_zone_update = true;
4657 }
4658
4659 if (tier_config_add.size() > 0) {
4660 for (auto add : tier_config_add) {
4661 int r = zone.tier_config.set(add.first, add.second);
4662 if (r < 0) {
4663 cerr << "ERROR: failed to set configurable: " << add << std::endl;
4664 return EINVAL;
4665 }
4666 }
4667 need_zone_update = true;
4668 }
4669
4670 for (auto rm : tier_config_rm) {
4671 if (!rm.first.empty()) { /* otherwise will remove the entire config */
4672 zone.tier_config.erase(rm.first);
4673 need_zone_update = true;
4674 }
4675 }
4676
4677 if (need_zone_update) {
4678 ret = zone.update();
4679 if (ret < 0) {
4680 cerr << "failed to save zone info: " << cpp_strerror(-ret) << std::endl;
4681 return -ret;
4682 }
4683 }
4684
4685 RGWZoneGroup zonegroup(zonegroup_id, zonegroup_name);
4686 ret = zonegroup.init(g_ceph_context, store->svc.sysobj);
4687 if (ret < 0) {
4688 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
4689 return -ret;
4690 }
4691 string *ptier_type = (tier_type_specified ? &tier_type : nullptr);
4692
4693 bool *psync_from_all = (sync_from_all_specified ? &sync_from_all : nullptr);
4694 string *predirect_zone = (redirect_zone_set ? &redirect_zone : nullptr);
4695
4696 ret = zonegroup.add_zone(zone,
4697 (is_master_set ? &is_master : NULL),
4698 (is_read_only_set ? &read_only : NULL),
4699 endpoints, ptier_type,
4700 psync_from_all, sync_from, sync_from_rm,
4701 predirect_zone,
4702 store->svc.sync_modules->get_manager());
4703 if (ret < 0) {
4704 cerr << "failed to update zonegroup: " << cpp_strerror(-ret) << std::endl;
4705 return -ret;
4706 }
4707
4708 ret = zonegroup.update();
4709 if (ret < 0) {
4710 cerr << "failed to update zonegroup: " << cpp_strerror(-ret) << std::endl;
4711 return -ret;
4712 }
4713
4714 if (set_default) {
4715 ret = zone.set_as_default();
4716 if (ret < 0) {
4717 cerr << "failed to set zone " << zone_name << " as default: " << cpp_strerror(-ret) << std::endl;
4718 }
4719 }
4720
4721 encode_json("zone", zone, formatter);
4722 formatter->flush(cout);
4723 }
4724 break;
4725 case OPT_ZONE_RENAME:
4726 {
4727 if (zone_new_name.empty()) {
4728 cerr << " missing zone new name" << std::endl;
4729 return EINVAL;
4730 }
4731 if (zone_id.empty() && zone_name.empty()) {
4732 cerr << "no zonegroup name or id provided" << std::endl;
4733 return EINVAL;
4734 }
4735 RGWZoneParams zone(zone_id,zone_name);
4736 int ret = zone.init(g_ceph_context, store->svc.sysobj);
4737 if (ret < 0) {
4738 cerr << "unable to initialize zone: " << cpp_strerror(-ret) << std::endl;
4739 return -ret;
4740 }
4741 ret = zone.rename(zone_new_name);
4742 if (ret < 0) {
4743 cerr << "failed to rename zone " << zone_name << " to " << zone_new_name << ": " << cpp_strerror(-ret)
4744 << std::endl;
4745 return -ret;
4746 }
4747 RGWZoneGroup zonegroup(zonegroup_id, zonegroup_name);
4748 ret = zonegroup.init(g_ceph_context, store->svc.sysobj);
4749 if (ret < 0) {
4750 cerr << "WARNING: failed to initialize zonegroup " << zonegroup_name << std::endl;
4751 } else {
4752 ret = zonegroup.rename_zone(zone);
4753 if (ret < 0) {
4754 cerr << "Error in zonegroup rename for " << zone_name << ": " << cpp_strerror(-ret) << std::endl;
4755 return -ret;
4756 }
4757 }
4758 }
4759 break;
4760 case OPT_ZONE_PLACEMENT_ADD:
4761 case OPT_ZONE_PLACEMENT_MODIFY:
4762 case OPT_ZONE_PLACEMENT_RM:
4763 {
4764 if (placement_id.empty()) {
4765 cerr << "ERROR: --placement-id not specified" << std::endl;
4766 return EINVAL;
4767 }
4768 // validate compression type
4769 if (compression_type && *compression_type != "random"
4770 && !Compressor::get_comp_alg_type(*compression_type)) {
4771 std::cerr << "Unrecognized compression type" << std::endl;
4772 return EINVAL;
4773 }
4774
4775 RGWZoneParams zone(zone_id, zone_name);
4776 int ret = zone.init(g_ceph_context, store->svc.sysobj);
4777 if (ret < 0) {
4778 cerr << "failed to init zone: " << cpp_strerror(-ret) << std::endl;
4779 return -ret;
4780 }
4781
4782 if (opt_cmd == OPT_ZONE_PLACEMENT_ADD ||
4783 opt_cmd == OPT_ZONE_PLACEMENT_MODIFY) {
4784 RGWZoneGroup zonegroup(zonegroup_id, zonegroup_name);
4785 ret = zonegroup.init(g_ceph_context, store->svc.sysobj);
4786 if (ret < 0) {
4787 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
4788 return -ret;
4789 }
4790
4791 auto ptiter = zonegroup.placement_targets.find(placement_id);
4792 if (ptiter == zonegroup.placement_targets.end()) {
4793 cerr << "ERROR: placement id '" << placement_id << "' is not configured in zonegroup placement targets" << std::endl;
4794 return EINVAL;
4795 }
4796
4797 storage_class = rgw_placement_rule::get_canonical_storage_class(storage_class);
4798 if (ptiter->second.storage_classes.find(storage_class) == ptiter->second.storage_classes.end()) {
4799 cerr << "ERROR: storage class '" << storage_class << "' is not defined in zonegroup '" << placement_id << "' placement target" << std::endl;
4800 return EINVAL;
4801 }
4802
4803 RGWZonePlacementInfo& info = zone.placement_pools[placement_id];
4804
4805 string opt_index_pool = index_pool.value_or(string());
4806 string opt_data_pool = data_pool.value_or(string());
4807
4808 if (!opt_index_pool.empty()) {
4809 info.index_pool = opt_index_pool;
4810 }
4811
4812 if (info.index_pool.empty()) {
4813 cerr << "ERROR: index pool not configured, need to specify --index-pool" << std::endl;
4814 return EINVAL;
4815 }
4816
4817 if (opt_data_pool.empty()) {
4818 const RGWZoneStorageClass *porig_sc{nullptr};
4819 if (info.storage_classes.find(storage_class, &porig_sc)) {
4820 if (porig_sc->data_pool) {
4821 opt_data_pool = porig_sc->data_pool->to_str();
4822 }
4823 }
4824 if (opt_data_pool.empty()) {
4825 cerr << "ERROR: data pool not configured, need to specify --data-pool" << std::endl;
4826 return EINVAL;
4827 }
4828 }
4829
4830 rgw_pool dp = opt_data_pool;
4831 info.storage_classes.set_storage_class(storage_class, &dp, compression_type.get_ptr());
4832
4833 if (data_extra_pool) {
4834 info.data_extra_pool = *data_extra_pool;
4835 }
4836 if (index_type_specified) {
4837 info.index_type = placement_index_type;
4838 }
4839
4840 ret = check_pool_support_omap(info.get_data_extra_pool());
4841 if (ret < 0) {
4842 cerr << "ERROR: the data extra (non-ec) pool '" << info.get_data_extra_pool()
4843 << "' does not support omap" << std::endl;
4844 return ret;
4845 }
4846 } else if (opt_cmd == OPT_ZONE_PLACEMENT_RM) {
4847 zone.placement_pools.erase(placement_id);
4848 }
4849
4850 ret = zone.update();
4851 if (ret < 0) {
4852 cerr << "failed to save zone info: " << cpp_strerror(-ret) << std::endl;
4853 return -ret;
4854 }
4855
4856 encode_json("zone", zone, formatter);
4857 formatter->flush(cout);
4858 }
4859 break;
4860 case OPT_ZONE_PLACEMENT_LIST:
4861 {
4862 RGWZoneParams zone(zone_id, zone_name);
4863 int ret = zone.init(g_ceph_context, store->svc.sysobj);
4864 if (ret < 0) {
4865 cerr << "unable to initialize zone: " << cpp_strerror(-ret) << std::endl;
4866 return -ret;
4867 }
4868 encode_json("placement_pools", zone.placement_pools, formatter);
4869 formatter->flush(cout);
4870 }
4871 break;
4872 }
4873 return 0;
4874 }
4875
4876 if (!user_id.empty()) {
4877 user_op.set_user_id(user_id);
4878 bucket_op.set_user_id(user_id);
4879 }
4880
4881 if (!display_name.empty())
4882 user_op.set_display_name(display_name);
4883
4884 if (!user_email.empty())
4885 user_op.set_user_email(user_email);
4886
4887 if (!access_key.empty())
4888 user_op.set_access_key(access_key);
4889
4890 if (!secret_key.empty())
4891 user_op.set_secret_key(secret_key);
4892
4893 if (!subuser.empty())
4894 user_op.set_subuser(subuser);
4895
4896 if (!caps.empty())
4897 user_op.set_caps(caps);
4898
4899 user_op.set_purge_data(purge_data);
4900
4901 if (purge_keys)
4902 user_op.set_purge_keys();
4903
4904 if (gen_access_key)
4905 user_op.set_generate_key();
4906
4907 if (gen_secret_key)
4908 user_op.set_gen_secret(); // assume that a key pair should be created
4909
4910 if (max_buckets_specified)
4911 user_op.set_max_buckets(max_buckets);
4912
4913 if (admin_specified)
4914 user_op.set_admin(admin);
4915
4916 if (system_specified)
4917 user_op.set_system(system);
4918
4919 if (set_perm)
4920 user_op.set_perm(perm_mask);
4921
4922 if (set_temp_url_key) {
4923 map<int, string>::iterator iter = temp_url_keys.begin();
4924 for (; iter != temp_url_keys.end(); ++iter) {
4925 user_op.set_temp_url_key(iter->second, iter->first);
4926 }
4927 }
4928
4929 if (!op_mask_str.empty()) {
4930 uint32_t op_mask;
4931 int ret = rgw_parse_op_type_list(op_mask_str, &op_mask);
4932 if (ret < 0) {
4933 cerr << "failed to parse op_mask: " << cpp_strerror(-ret) << std::endl;
4934 return -ret;
4935 }
4936
4937 user_op.set_op_mask(op_mask);
4938 }
4939
4940 if (key_type != KEY_TYPE_UNDEFINED)
4941 user_op.set_key_type(key_type);
4942
4943 // set suspension operation parameters
4944 if (opt_cmd == OPT_USER_ENABLE)
4945 user_op.set_suspension(false);
4946 else if (opt_cmd == OPT_USER_SUSPEND)
4947 user_op.set_suspension(true);
4948
4949 // RGWUser to use for user operations
4950 RGWUser user;
4951 int ret = 0;
4952 if (!user_id.empty() || !subuser.empty()) {
4953 ret = user.init(store, user_op);
4954 if (ret < 0) {
4955 cerr << "user.init failed: " << cpp_strerror(-ret) << std::endl;
4956 return -ret;
4957 }
4958 }
4959
4960 /* populate bucket operation */
4961 bucket_op.set_bucket_name(bucket_name);
4962 bucket_op.set_object(object);
4963 bucket_op.set_check_objects(check_objects);
4964 bucket_op.set_delete_children(delete_child_objects);
4965 bucket_op.set_fix_index(fix);
4966 bucket_op.set_max_aio(max_concurrent_ios);
4967
4968 // required to gather errors from operations
4969 std::string err_msg;
4970
4971 bool output_user_info = true;
4972
4973 switch (opt_cmd) {
4974 case OPT_USER_INFO:
4975 if (user_id.empty()) {
4976 cerr << "ERROR: uid not specified" << std::endl;
4977 return EINVAL;
4978 }
4979 break;
4980 case OPT_USER_CREATE:
4981 if (!user_op.has_existing_user()) {
4982 user_op.set_generate_key(); // generate a new key by default
4983 }
4984 ret = user.add(user_op, &err_msg);
4985 if (ret < 0) {
4986 cerr << "could not create user: " << err_msg << std::endl;
4987 if (ret == -ERR_INVALID_TENANT_NAME)
4988 ret = -EINVAL;
4989
4990 return -ret;
4991 }
4992 if (!subuser.empty()) {
4993 ret = user.subusers.add(user_op, &err_msg);
4994 if (ret < 0) {
4995 cerr << "could not create subuser: " << err_msg << std::endl;
4996 return -ret;
4997 }
4998 }
4999 break;
5000 case OPT_USER_RM:
5001 ret = user.remove(user_op, &err_msg);
5002 if (ret < 0) {
5003 cerr << "could not remove user: " << err_msg << std::endl;
5004 return -ret;
5005 }
5006
5007 output_user_info = false;
5008 break;
5009 case OPT_USER_ENABLE:
5010 case OPT_USER_SUSPEND:
5011 case OPT_USER_MODIFY:
5012 ret = user.modify(user_op, &err_msg);
5013 if (ret < 0) {
5014 cerr << "could not modify user: " << err_msg << std::endl;
5015 return -ret;
5016 }
5017
5018 break;
5019 case OPT_SUBUSER_CREATE:
5020 ret = user.subusers.add(user_op, &err_msg);
5021 if (ret < 0) {
5022 cerr << "could not create subuser: " << err_msg << std::endl;
5023 return -ret;
5024 }
5025
5026 break;
5027 case OPT_SUBUSER_MODIFY:
5028 ret = user.subusers.modify(user_op, &err_msg);
5029 if (ret < 0) {
5030 cerr << "could not modify subuser: " << err_msg << std::endl;
5031 return -ret;
5032 }
5033
5034 break;
5035 case OPT_SUBUSER_RM:
5036 ret = user.subusers.remove(user_op, &err_msg);
5037 if (ret < 0) {
5038 cerr << "could not remove subuser: " << err_msg << std::endl;
5039 return -ret;
5040 }
5041
5042 break;
5043 case OPT_CAPS_ADD:
5044 ret = user.caps.add(user_op, &err_msg);
5045 if (ret < 0) {
5046 cerr << "could not add caps: " << err_msg << std::endl;
5047 return -ret;
5048 }
5049
5050 break;
5051 case OPT_CAPS_RM:
5052 ret = user.caps.remove(user_op, &err_msg);
5053 if (ret < 0) {
5054 cerr << "could not remove caps: " << err_msg << std::endl;
5055 return -ret;
5056 }
5057
5058 break;
5059 case OPT_KEY_CREATE:
5060 ret = user.keys.add(user_op, &err_msg);
5061 if (ret < 0) {
5062 cerr << "could not create key: " << err_msg << std::endl;
5063 return -ret;
5064 }
5065
5066 break;
5067 case OPT_KEY_RM:
5068 ret = user.keys.remove(user_op, &err_msg);
5069 if (ret < 0) {
5070 cerr << "could not remove key: " << err_msg << std::endl;
5071 return -ret;
5072 }
5073 break;
5074 case OPT_PERIOD_PUSH:
5075 {
5076 RGWEnv env;
5077 req_info info(g_ceph_context, &env);
5078 info.method = "POST";
5079 info.request_uri = "/admin/realm/period";
5080
5081 map<string, string> &params = info.args.get_params();
5082 if (!realm_id.empty())
5083 params["realm_id"] = realm_id;
5084 if (!realm_name.empty())
5085 params["realm_name"] = realm_name;
5086 if (!period_id.empty())
5087 params["period_id"] = period_id;
5088 if (!period_epoch.empty())
5089 params["epoch"] = period_epoch;
5090
5091 // load the period
5092 RGWPeriod period(period_id);
5093 int ret = period.init(g_ceph_context, store->svc.sysobj);
5094 if (ret < 0) {
5095 cerr << "period init failed: " << cpp_strerror(-ret) << std::endl;
5096 return -ret;
5097 }
5098 // json format into a bufferlist
5099 JSONFormatter jf(false);
5100 encode_json("period", period, &jf);
5101 bufferlist bl;
5102 jf.flush(bl);
5103
5104 JSONParser p;
5105 ret = send_to_remote_or_url(nullptr, url, access_key, secret_key,
5106 info, bl, p);
5107 if (ret < 0) {
5108 cerr << "request failed: " << cpp_strerror(-ret) << std::endl;
5109 return -ret;
5110 }
5111 }
5112 return 0;
5113 case OPT_PERIOD_UPDATE:
5114 {
5115 int ret = update_period(realm_id, realm_name, period_id, period_epoch,
5116 commit, remote, url, access_key, secret_key,
5117 formatter, yes_i_really_mean_it);
5118 if (ret < 0) {
5119 return -ret;
5120 }
5121 }
5122 return 0;
5123 case OPT_PERIOD_COMMIT:
5124 {
5125 // read realm and staging period
5126 RGWRealm realm(realm_id, realm_name);
5127 int ret = realm.init(g_ceph_context, store->svc.sysobj);
5128 if (ret < 0) {
5129 cerr << "Error initializing realm: " << cpp_strerror(-ret) << std::endl;
5130 return -ret;
5131 }
5132 RGWPeriod period(RGWPeriod::get_staging_id(realm.get_id()), 1);
5133 ret = period.init(g_ceph_context, store->svc.sysobj, realm.get_id());
5134 if (ret < 0) {
5135 cerr << "period init failed: " << cpp_strerror(-ret) << std::endl;
5136 return -ret;
5137 }
5138 ret = commit_period(realm, period, remote, url, access_key, secret_key,
5139 yes_i_really_mean_it);
5140 if (ret < 0) {
5141 cerr << "failed to commit period: " << cpp_strerror(-ret) << std::endl;
5142 return -ret;
5143 }
5144
5145 encode_json("period", period, formatter);
5146 formatter->flush(cout);
5147 }
5148 return 0;
5149 case OPT_ROLE_CREATE:
5150 {
5151 if (role_name.empty()) {
5152 cerr << "ERROR: role name is empty" << std::endl;
5153 return -EINVAL;
5154 }
5155
5156 if (assume_role_doc.empty()) {
5157 cerr << "ERROR: assume role policy document is empty" << std::endl;
5158 return -EINVAL;
5159 }
5160 bufferlist bl = bufferlist::static_from_string(assume_role_doc);
5161 try {
5162 const rgw::IAM::Policy p(g_ceph_context, tenant, bl);
5163 } catch (rgw::IAM::PolicyParseException& e) {
5164 cerr << "failed to parse policy: " << e.what() << std::endl;
5165 return -EINVAL;
5166 }
5167 RGWRole role(g_ceph_context, store, role_name, path, assume_role_doc, tenant);
5168 ret = role.create(true);
5169 if (ret < 0) {
5170 return -ret;
5171 }
5172 show_role_info(role, formatter);
5173 return 0;
5174 }
5175 case OPT_ROLE_DELETE:
5176 {
5177 if (role_name.empty()) {
5178 cerr << "ERROR: empty role name" << std::endl;
5179 return -EINVAL;
5180 }
5181 RGWRole role(g_ceph_context, store, role_name, tenant);
5182 ret = role.delete_obj();
5183 if (ret < 0) {
5184 return -ret;
5185 }
5186 cout << "role: " << role_name << " successfully deleted" << std::endl;
5187 return 0;
5188 }
5189 case OPT_ROLE_GET:
5190 {
5191 if (role_name.empty()) {
5192 cerr << "ERROR: empty role name" << std::endl;
5193 return -EINVAL;
5194 }
5195 RGWRole role(g_ceph_context, store, role_name, tenant);
5196 ret = role.get();
5197 if (ret < 0) {
5198 return -ret;
5199 }
5200 show_role_info(role, formatter);
5201 return 0;
5202 }
5203 case OPT_ROLE_MODIFY:
5204 {
5205 if (role_name.empty()) {
5206 cerr << "ERROR: role name is empty" << std::endl;
5207 return -EINVAL;
5208 }
5209
5210 if (assume_role_doc.empty()) {
5211 cerr << "ERROR: assume role policy document is empty" << std::endl;
5212 return -EINVAL;
5213 }
5214
5215 bufferlist bl = bufferlist::static_from_string(assume_role_doc);
5216 try {
5217 const rgw::IAM::Policy p(g_ceph_context, tenant, bl);
5218 } catch (rgw::IAM::PolicyParseException& e) {
5219 cerr << "failed to parse policy: " << e.what() << std::endl;
5220 return -EINVAL;
5221 }
5222
5223 RGWRole role(g_ceph_context, store, role_name, tenant);
5224 ret = role.get();
5225 if (ret < 0) {
5226 return -ret;
5227 }
5228 role.update_trust_policy(assume_role_doc);
5229 ret = role.update();
5230 if (ret < 0) {
5231 return -ret;
5232 }
5233 cout << "Assume role policy document updated successfully for role: " << role_name << std::endl;
5234 return 0;
5235 }
5236 case OPT_ROLE_LIST:
5237 {
5238 vector<RGWRole> result;
5239 ret = RGWRole::get_roles_by_path_prefix(store, g_ceph_context, path_prefix, tenant, result);
5240 if (ret < 0) {
5241 return -ret;
5242 }
5243 show_roles_info(result, formatter);
5244 return 0;
5245 }
5246 case OPT_ROLE_POLICY_PUT:
5247 {
5248 if (role_name.empty()) {
5249 cerr << "role name is empty" << std::endl;
5250 return -EINVAL;
5251 }
5252
5253 if (policy_name.empty()) {
5254 cerr << "policy name is empty" << std::endl;
5255 return -EINVAL;
5256 }
5257
5258 if (perm_policy_doc.empty()) {
5259 cerr << "permission policy document is empty" << std::endl;
5260 return -EINVAL;
5261 }
5262
5263 bufferlist bl = bufferlist::static_from_string(perm_policy_doc);
5264 try {
5265 const rgw::IAM::Policy p(g_ceph_context, tenant, bl);
5266 } catch (rgw::IAM::PolicyParseException& e) {
5267 cerr << "failed to parse perm policy: " << e.what() << std::endl;
5268 return -EINVAL;
5269 }
5270
5271 RGWRole role(g_ceph_context, store, role_name, tenant);
5272 ret = role.get();
5273 if (ret < 0) {
5274 return -ret;
5275 }
5276 role.set_perm_policy(policy_name, perm_policy_doc);
5277 ret = role.update();
5278 if (ret < 0) {
5279 return -ret;
5280 }
5281 cout << "Permission policy attached successfully" << std::endl;
5282 return 0;
5283 }
5284 case OPT_ROLE_POLICY_LIST:
5285 {
5286 if (role_name.empty()) {
5287 cerr << "ERROR: Role name is empty" << std::endl;
5288 return -EINVAL;
5289 }
5290 RGWRole role(g_ceph_context, store, role_name, tenant);
5291 ret = role.get();
5292 if (ret < 0) {
5293 return -ret;
5294 }
5295 std::vector<string> policy_names = role.get_role_policy_names();
5296 show_policy_names(policy_names, formatter);
5297 return 0;
5298 }
5299 case OPT_ROLE_POLICY_GET:
5300 {
5301 if (role_name.empty()) {
5302 cerr << "ERROR: role name is empty" << std::endl;
5303 return -EINVAL;
5304 }
5305
5306 if (policy_name.empty()) {
5307 cerr << "ERROR: policy name is empty" << std::endl;
5308 return -EINVAL;
5309 }
5310 RGWRole role(g_ceph_context, store, role_name, tenant);
5311 int ret = role.get();
5312 if (ret < 0) {
5313 return -ret;
5314 }
5315 string perm_policy;
5316 ret = role.get_role_policy(policy_name, perm_policy);
5317 if (ret < 0) {
5318 return -ret;
5319 }
5320 show_perm_policy(perm_policy, formatter);
5321 return 0;
5322 }
5323 case OPT_ROLE_POLICY_DELETE:
5324 {
5325 if (role_name.empty()) {
5326 cerr << "ERROR: role name is empty" << std::endl;
5327 return -EINVAL;
5328 }
5329
5330 if (policy_name.empty()) {
5331 cerr << "ERROR: policy name is empty" << std::endl;
5332 return -EINVAL;
5333 }
5334 RGWRole role(g_ceph_context, store, role_name, tenant);
5335 ret = role.get();
5336 if (ret < 0) {
5337 return -ret;
5338 }
5339 ret = role.delete_policy(policy_name);
5340 if (ret < 0) {
5341 return -ret;
5342 }
5343 ret = role.update();
5344 if (ret < 0) {
5345 return -ret;
5346 }
5347 cout << "Policy: " << policy_name << " successfully deleted for role: "
5348 << role_name << std::endl;
5349 return 0;
5350 }
5351 default:
5352 output_user_info = false;
5353 }
5354
5355 // output the result of a user operation
5356 if (output_user_info) {
5357 ret = user.info(info, &err_msg);
5358 if (ret < 0) {
5359 cerr << "could not fetch user info: " << err_msg << std::endl;
5360 return -ret;
5361 }
5362 show_user_info(info, formatter);
5363 }
5364
5365 if (opt_cmd == OPT_POLICY) {
5366 if (format == "xml") {
5367 int ret = RGWBucketAdminOp::dump_s3_policy(store, bucket_op, cout);
5368 if (ret < 0) {
5369 cerr << "ERROR: failed to get policy: " << cpp_strerror(-ret) << std::endl;
5370 return -ret;
5371 }
5372 } else {
5373 int ret = RGWBucketAdminOp::get_policy(store, bucket_op, f);
5374 if (ret < 0) {
5375 cerr << "ERROR: failed to get policy: " << cpp_strerror(-ret) << std::endl;
5376 return -ret;
5377 }
5378 }
5379 }
5380
5381 if (opt_cmd == OPT_BUCKET_LIMIT_CHECK) {
5382 void *handle;
5383 std::list<std::string> user_ids;
5384 metadata_key = "user";
5385 int max = 1000;
5386
5387 bool truncated;
5388
5389 if (! user_id.empty()) {
5390 user_ids.push_back(user_id.id);
5391 ret =
5392 RGWBucketAdminOp::limit_check(store, bucket_op, user_ids, f,
5393 warnings_only);
5394 } else {
5395 /* list users in groups of max-keys, then perform user-bucket
5396 * limit-check on each group */
5397 ret = store->meta_mgr->list_keys_init(metadata_key, &handle);
5398 if (ret < 0) {
5399 cerr << "ERROR: buckets limit check can't get user metadata_key: "
5400 << cpp_strerror(-ret) << std::endl;
5401 return -ret;
5402 }
5403
5404 do {
5405 ret = store->meta_mgr->list_keys_next(handle, max, user_ids,
5406 &truncated);
5407 if (ret < 0 && ret != -ENOENT) {
5408 cerr << "ERROR: buckets limit check lists_keys_next(): "
5409 << cpp_strerror(-ret) << std::endl;
5410 break;
5411 } else {
5412 /* ok, do the limit checks for this group */
5413 ret =
5414 RGWBucketAdminOp::limit_check(store, bucket_op, user_ids, f,
5415 warnings_only);
5416 if (ret < 0)
5417 break;
5418 }
5419 user_ids.clear();
5420 } while (truncated);
5421 store->meta_mgr->list_keys_complete(handle);
5422 }
5423 return -ret;
5424 } /* OPT_BUCKET_LIMIT_CHECK */
5425
5426 if (opt_cmd == OPT_BUCKETS_LIST) {
5427 if (bucket_name.empty()) {
5428 RGWBucketAdminOp::info(store, bucket_op, f);
5429 } else {
5430 RGWBucketInfo bucket_info;
5431 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
5432 if (ret < 0) {
5433 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
5434 return -ret;
5435 }
5436 formatter->open_array_section("entries");
5437 bool truncated;
5438 int count = 0;
5439 if (max_entries < 0)
5440 max_entries = 1000;
5441
5442 string prefix;
5443 string delim;
5444 vector<rgw_bucket_dir_entry> result;
5445 map<string, bool> common_prefixes;
5446 string ns;
5447
5448 RGWRados::Bucket target(store, bucket_info);
5449 RGWRados::Bucket::List list_op(&target);
5450
5451 list_op.params.prefix = prefix;
5452 list_op.params.delim = delim;
5453 list_op.params.marker = rgw_obj_key(marker);
5454 list_op.params.ns = ns;
5455 list_op.params.enforce_ns = false;
5456 list_op.params.list_versions = true;
5457
5458 do {
5459 ret = list_op.list_objects(max_entries - count, &result, &common_prefixes, &truncated);
5460 if (ret < 0) {
5461 cerr << "ERROR: store->list_objects(): " << cpp_strerror(-ret) << std::endl;
5462 return -ret;
5463 }
5464
5465 count += result.size();
5466
5467 for (vector<rgw_bucket_dir_entry>::iterator iter = result.begin(); iter != result.end(); ++iter) {
5468 rgw_bucket_dir_entry& entry = *iter;
5469 encode_json("entry", entry, formatter);
5470 }
5471 formatter->flush(cout);
5472 } while (truncated && count < max_entries);
5473
5474 formatter->close_section();
5475 formatter->flush(cout);
5476 } /* have bucket_name */
5477 } /* OPT_BUCKETS_LIST */
5478
5479 if (opt_cmd == OPT_BUCKET_STATS) {
5480 bucket_op.set_fetch_stats(true);
5481
5482 int r = RGWBucketAdminOp::info(store, bucket_op, f);
5483 if (r < 0) {
5484 cerr << "failure: " << cpp_strerror(-r) << ": " << err << std::endl;
5485 return -r;
5486 }
5487 }
5488
5489 if (opt_cmd == OPT_BUCKET_LINK) {
5490 bucket_op.set_bucket_id(bucket_id);
5491 string err;
5492 int r = RGWBucketAdminOp::link(store, bucket_op, &err);
5493 if (r < 0) {
5494 cerr << "failure: " << cpp_strerror(-r) << ": " << err << std::endl;
5495 return -r;
5496 }
5497 }
5498
5499 if (opt_cmd == OPT_BUCKET_UNLINK) {
5500 int r = RGWBucketAdminOp::unlink(store, bucket_op);
5501 if (r < 0) {
5502 cerr << "failure: " << cpp_strerror(-r) << std::endl;
5503 return -r;
5504 }
5505 }
5506
5507 if (opt_cmd == OPT_LOG_LIST) {
5508 // filter by date?
5509 if (date.size() && date.size() != 10) {
5510 cerr << "bad date format for '" << date << "', expect YYYY-MM-DD" << std::endl;
5511 return EINVAL;
5512 }
5513
5514 formatter->reset();
5515 formatter->open_array_section("logs");
5516 RGWAccessHandle h;
5517 int r = store->log_list_init(date, &h);
5518 if (r == -ENOENT) {
5519 // no logs.
5520 } else {
5521 if (r < 0) {
5522 cerr << "log list: error " << r << std::endl;
5523 return -r;
5524 }
5525 while (true) {
5526 string name;
5527 int r = store->log_list_next(h, &name);
5528 if (r == -ENOENT)
5529 break;
5530 if (r < 0) {
5531 cerr << "log list: error " << r << std::endl;
5532 return -r;
5533 }
5534 formatter->dump_string("object", name);
5535 }
5536 }
5537 formatter->close_section();
5538 formatter->flush(cout);
5539 cout << std::endl;
5540 }
5541
5542 if (opt_cmd == OPT_LOG_SHOW || opt_cmd == OPT_LOG_RM) {
5543 if (object.empty() && (date.empty() || bucket_name.empty() || bucket_id.empty())) {
5544 cerr << "specify an object or a date, bucket and bucket-id" << std::endl;
5545 exit(1);
5546 }
5547
5548 string oid;
5549 if (!object.empty()) {
5550 oid = object;
5551 } else {
5552 oid = date;
5553 oid += "-";
5554 oid += bucket_id;
5555 oid += "-";
5556 oid += bucket_name;
5557 }
5558
5559 if (opt_cmd == OPT_LOG_SHOW) {
5560 RGWAccessHandle h;
5561
5562 int r = store->log_show_init(oid, &h);
5563 if (r < 0) {
5564 cerr << "error opening log " << oid << ": " << cpp_strerror(-r) << std::endl;
5565 return -r;
5566 }
5567
5568 formatter->reset();
5569 formatter->open_object_section("log");
5570
5571 struct rgw_log_entry entry;
5572
5573 // peek at first entry to get bucket metadata
5574 r = store->log_show_next(h, &entry);
5575 if (r < 0) {
5576 cerr << "error reading log " << oid << ": " << cpp_strerror(-r) << std::endl;
5577 return -r;
5578 }
5579 formatter->dump_string("bucket_id", entry.bucket_id);
5580 formatter->dump_string("bucket_owner", entry.bucket_owner.to_str());
5581 formatter->dump_string("bucket", entry.bucket);
5582
5583 uint64_t agg_time = 0;
5584 uint64_t agg_bytes_sent = 0;
5585 uint64_t agg_bytes_received = 0;
5586 uint64_t total_entries = 0;
5587
5588 if (show_log_entries)
5589 formatter->open_array_section("log_entries");
5590
5591 do {
5592 using namespace std::chrono;
5593 uint64_t total_time = duration_cast<milliseconds>(entry.total_time).count();
5594
5595 agg_time += total_time;
5596 agg_bytes_sent += entry.bytes_sent;
5597 agg_bytes_received += entry.bytes_received;
5598 total_entries++;
5599
5600 if (skip_zero_entries && entry.bytes_sent == 0 &&
5601 entry.bytes_received == 0)
5602 goto next;
5603
5604 if (show_log_entries) {
5605
5606 rgw_format_ops_log_entry(entry, formatter);
5607 formatter->flush(cout);
5608 }
5609 next:
5610 r = store->log_show_next(h, &entry);
5611 } while (r > 0);
5612
5613 if (r < 0) {
5614 cerr << "error reading log " << oid << ": " << cpp_strerror(-r) << std::endl;
5615 return -r;
5616 }
5617 if (show_log_entries)
5618 formatter->close_section();
5619
5620 if (show_log_sum) {
5621 formatter->open_object_section("log_sum");
5622 formatter->dump_int("bytes_sent", agg_bytes_sent);
5623 formatter->dump_int("bytes_received", agg_bytes_received);
5624 formatter->dump_int("total_time", agg_time);
5625 formatter->dump_int("total_entries", total_entries);
5626 formatter->close_section();
5627 }
5628 formatter->close_section();
5629 formatter->flush(cout);
5630 cout << std::endl;
5631 }
5632 if (opt_cmd == OPT_LOG_RM) {
5633 int r = store->log_remove(oid);
5634 if (r < 0) {
5635 cerr << "error removing log " << oid << ": " << cpp_strerror(-r) << std::endl;
5636 return -r;
5637 }
5638 }
5639 }
5640
5641 if (opt_cmd == OPT_POOL_ADD) {
5642 if (pool_name.empty()) {
5643 cerr << "need to specify pool to add!" << std::endl;
5644 exit(1);
5645 }
5646
5647 int ret = store->svc.zone->add_bucket_placement(pool);
5648 if (ret < 0)
5649 cerr << "failed to add bucket placement: " << cpp_strerror(-ret) << std::endl;
5650 }
5651
5652 if (opt_cmd == OPT_POOL_RM) {
5653 if (pool_name.empty()) {
5654 cerr << "need to specify pool to remove!" << std::endl;
5655 exit(1);
5656 }
5657
5658 int ret = store->svc.zone->remove_bucket_placement(pool);
5659 if (ret < 0)
5660 cerr << "failed to remove bucket placement: " << cpp_strerror(-ret) << std::endl;
5661 }
5662
5663 if (opt_cmd == OPT_POOLS_LIST) {
5664 set<rgw_pool> pools;
5665 int ret = store->svc.zone->list_placement_set(pools);
5666 if (ret < 0) {
5667 cerr << "could not list placement set: " << cpp_strerror(-ret) << std::endl;
5668 return -ret;
5669 }
5670 formatter->reset();
5671 formatter->open_array_section("pools");
5672 for (auto siter = pools.begin(); siter != pools.end(); ++siter) {
5673 formatter->open_object_section("pool");
5674 formatter->dump_string("name", siter->to_str());
5675 formatter->close_section();
5676 }
5677 formatter->close_section();
5678 formatter->flush(cout);
5679 cout << std::endl;
5680 }
5681
5682 if (opt_cmd == OPT_USAGE_SHOW) {
5683 uint64_t start_epoch = 0;
5684 uint64_t end_epoch = (uint64_t)-1;
5685
5686 int ret;
5687
5688 if (!start_date.empty()) {
5689 ret = utime_t::parse_date(start_date, &start_epoch, NULL);
5690 if (ret < 0) {
5691 cerr << "ERROR: failed to parse start date" << std::endl;
5692 return 1;
5693 }
5694 }
5695 if (!end_date.empty()) {
5696 ret = utime_t::parse_date(end_date, &end_epoch, NULL);
5697 if (ret < 0) {
5698 cerr << "ERROR: failed to parse end date" << std::endl;
5699 return 1;
5700 }
5701 }
5702
5703
5704 ret = RGWUsage::show(store, user_id, bucket_name, start_epoch, end_epoch,
5705 show_log_entries, show_log_sum, &categories,
5706 f);
5707 if (ret < 0) {
5708 cerr << "ERROR: failed to show usage" << std::endl;
5709 return 1;
5710 }
5711 }
5712
5713 if (opt_cmd == OPT_USAGE_TRIM) {
5714 if (user_id.empty() && bucket_name.empty() &&
5715 start_date.empty() && end_date.empty() && !yes_i_really_mean_it) {
5716 cerr << "usage trim without user/date/bucket specified will remove *all* users data" << std::endl;
5717 cerr << "do you really mean it? (requires --yes-i-really-mean-it)" << std::endl;
5718 return 1;
5719 }
5720 int ret;
5721 uint64_t start_epoch = 0;
5722 uint64_t end_epoch = (uint64_t)-1;
5723
5724
5725 if (!start_date.empty()) {
5726 ret = utime_t::parse_date(start_date, &start_epoch, NULL);
5727 if (ret < 0) {
5728 cerr << "ERROR: failed to parse start date" << std::endl;
5729 return 1;
5730 }
5731 }
5732
5733 if (!end_date.empty()) {
5734 ret = utime_t::parse_date(end_date, &end_epoch, NULL);
5735 if (ret < 0) {
5736 cerr << "ERROR: failed to parse end date" << std::endl;
5737 return 1;
5738 }
5739 }
5740
5741 ret = RGWUsage::trim(store, user_id, bucket_name, start_epoch, end_epoch);
5742 if (ret < 0) {
5743 cerr << "ERROR: read_usage() returned ret=" << ret << std::endl;
5744 return 1;
5745 }
5746 }
5747
5748 if (opt_cmd == OPT_USAGE_CLEAR) {
5749 if (!yes_i_really_mean_it) {
5750 cerr << "usage clear would remove *all* users usage data for all time" << std::endl;
5751 cerr << "do you really mean it? (requires --yes-i-really-mean-it)" << std::endl;
5752 return 1;
5753 }
5754
5755 ret = RGWUsage::clear(store);
5756 if (ret < 0) {
5757 return ret;
5758 }
5759 }
5760
5761
5762 if (opt_cmd == OPT_OLH_GET || opt_cmd == OPT_OLH_READLOG) {
5763 if (bucket_name.empty()) {
5764 cerr << "ERROR: bucket not specified" << std::endl;
5765 return EINVAL;
5766 }
5767 if (object.empty()) {
5768 cerr << "ERROR: object not specified" << std::endl;
5769 return EINVAL;
5770 }
5771 }
5772
5773 if (opt_cmd == OPT_OLH_GET) {
5774 RGWBucketInfo bucket_info;
5775 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
5776 if (ret < 0) {
5777 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
5778 return -ret;
5779 }
5780 RGWOLHInfo olh;
5781 rgw_obj obj(bucket, object);
5782 ret = store->get_olh(bucket_info, obj, &olh);
5783 if (ret < 0) {
5784 cerr << "ERROR: failed reading olh: " << cpp_strerror(-ret) << std::endl;
5785 return -ret;
5786 }
5787 encode_json("olh", olh, formatter);
5788 formatter->flush(cout);
5789 }
5790
5791 if (opt_cmd == OPT_OLH_READLOG) {
5792 RGWBucketInfo bucket_info;
5793 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
5794 if (ret < 0) {
5795 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
5796 return -ret;
5797 }
5798 map<uint64_t, vector<rgw_bucket_olh_log_entry> > log;
5799 bool is_truncated;
5800
5801 RGWObjectCtx rctx(store);
5802 rgw_obj obj(bucket, object);
5803
5804 RGWObjState *state;
5805
5806 ret = store->get_obj_state(&rctx, bucket_info, obj, &state, false); /* don't follow olh */
5807 if (ret < 0) {
5808 return -ret;
5809 }
5810
5811 ret = store->bucket_index_read_olh_log(bucket_info, *state, obj, 0, &log, &is_truncated);
5812 if (ret < 0) {
5813 cerr << "ERROR: failed reading olh: " << cpp_strerror(-ret) << std::endl;
5814 return -ret;
5815 }
5816 formatter->open_object_section("result");
5817 encode_json("is_truncated", is_truncated, formatter);
5818 encode_json("log", log, formatter);
5819 formatter->close_section();
5820 formatter->flush(cout);
5821 }
5822
5823 if (opt_cmd == OPT_BI_GET) {
5824 if (bucket_name.empty()) {
5825 cerr << "ERROR: bucket name not specified" << std::endl;
5826 return EINVAL;
5827 }
5828 if (object.empty()) {
5829 cerr << "ERROR: object not specified" << std::endl;
5830 return EINVAL;
5831 }
5832 RGWBucketInfo bucket_info;
5833 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
5834 if (ret < 0) {
5835 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
5836 return -ret;
5837 }
5838 rgw_obj obj(bucket, object);
5839 if (!object_version.empty()) {
5840 obj.key.set_instance(object_version);
5841 }
5842
5843 rgw_cls_bi_entry entry;
5844
5845 ret = store->bi_get(bucket_info, obj, bi_index_type, &entry);
5846 if (ret < 0) {
5847 cerr << "ERROR: bi_get(): " << cpp_strerror(-ret) << std::endl;
5848 return -ret;
5849 }
5850
5851 encode_json("entry", entry, formatter);
5852 formatter->flush(cout);
5853 }
5854
5855 if (opt_cmd == OPT_BI_PUT) {
5856 if (bucket_name.empty()) {
5857 cerr << "ERROR: bucket name not specified" << std::endl;
5858 return EINVAL;
5859 }
5860 RGWBucketInfo bucket_info;
5861 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
5862 if (ret < 0) {
5863 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
5864 return -ret;
5865 }
5866
5867 rgw_cls_bi_entry entry;
5868 cls_rgw_obj_key key;
5869 ret = read_decode_json(infile, entry, &key);
5870 if (ret < 0) {
5871 return 1;
5872 }
5873
5874 rgw_obj obj(bucket, key);
5875
5876 ret = store->bi_put(bucket, obj, entry);
5877 if (ret < 0) {
5878 cerr << "ERROR: bi_put(): " << cpp_strerror(-ret) << std::endl;
5879 return -ret;
5880 }
5881 }
5882
5883 if (opt_cmd == OPT_BI_LIST) {
5884 if (bucket_name.empty()) {
5885 cerr << "ERROR: bucket name not specified" << std::endl;
5886 return EINVAL;
5887 }
5888 RGWBucketInfo bucket_info;
5889 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
5890 if (ret < 0) {
5891 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
5892 return -ret;
5893 }
5894
5895 list<rgw_cls_bi_entry> entries;
5896 bool is_truncated;
5897 if (max_entries < 0) {
5898 max_entries = 1000;
5899 }
5900
5901 int max_shards = (bucket_info.num_shards > 0 ? bucket_info.num_shards : 1);
5902
5903 formatter->open_array_section("entries");
5904
5905 for (int i = 0; i < max_shards; i++) {
5906 RGWRados::BucketShard bs(store);
5907 int shard_id = (bucket_info.num_shards > 0 ? i : -1);
5908 int ret = bs.init(bucket, shard_id, nullptr /* no RGWBucketInfo */);
5909 marker.clear();
5910
5911 if (ret < 0) {
5912 cerr << "ERROR: bs.init(bucket=" << bucket << ", shard=" << shard_id << "): " << cpp_strerror(-ret) << std::endl;
5913 return -ret;
5914 }
5915
5916 do {
5917 entries.clear();
5918 ret = store->bi_list(bs, object, marker, max_entries, &entries, &is_truncated);
5919 if (ret < 0) {
5920 cerr << "ERROR: bi_list(): " << cpp_strerror(-ret) << std::endl;
5921 return -ret;
5922 }
5923
5924 list<rgw_cls_bi_entry>::iterator iter;
5925 for (iter = entries.begin(); iter != entries.end(); ++iter) {
5926 rgw_cls_bi_entry& entry = *iter;
5927 encode_json("entry", entry, formatter);
5928 marker = entry.idx;
5929 }
5930 formatter->flush(cout);
5931 } while (is_truncated);
5932 formatter->flush(cout);
5933 }
5934 formatter->close_section();
5935 formatter->flush(cout);
5936 }
5937
5938 if (opt_cmd == OPT_BI_PURGE) {
5939 if (bucket_name.empty()) {
5940 cerr << "ERROR: bucket name not specified" << std::endl;
5941 return EINVAL;
5942 }
5943 RGWBucketInfo bucket_info;
5944 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
5945 if (ret < 0) {
5946 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
5947 return -ret;
5948 }
5949
5950 RGWBucketInfo cur_bucket_info;
5951 rgw_bucket cur_bucket;
5952 ret = init_bucket(tenant, bucket_name, string(), cur_bucket_info, cur_bucket);
5953 if (ret < 0) {
5954 cerr << "ERROR: could not init current bucket info for bucket_name=" << bucket_name << ": " << cpp_strerror(-ret) << std::endl;
5955 return -ret;
5956 }
5957
5958 if (cur_bucket_info.bucket.bucket_id == bucket_info.bucket.bucket_id && !yes_i_really_mean_it) {
5959 cerr << "specified bucket instance points to a current bucket instance" << std::endl;
5960 cerr << "do you really mean it? (requires --yes-i-really-mean-it)" << std::endl;
5961 return EINVAL;
5962 }
5963
5964 int max_shards = (bucket_info.num_shards > 0 ? bucket_info.num_shards : 1);
5965
5966 for (int i = 0; i < max_shards; i++) {
5967 RGWRados::BucketShard bs(store);
5968 int shard_id = (bucket_info.num_shards > 0 ? i : -1);
5969 int ret = bs.init(bucket, shard_id, nullptr /* no RGWBucketInfo */);
5970 if (ret < 0) {
5971 cerr << "ERROR: bs.init(bucket=" << bucket << ", shard=" << shard_id << "): " << cpp_strerror(-ret) << std::endl;
5972 return -ret;
5973 }
5974
5975 ret = store->bi_remove(bs);
5976 if (ret < 0) {
5977 cerr << "ERROR: failed to remove bucket index object: " << cpp_strerror(-ret) << std::endl;
5978 return -ret;
5979 }
5980 }
5981 }
5982
5983 if (opt_cmd == OPT_OBJECT_PUT) {
5984 if (bucket_name.empty()) {
5985 cerr << "ERROR: bucket not specified" << std::endl;
5986 return EINVAL;
5987 }
5988 if (object.empty()) {
5989 cerr << "ERROR: object not specified" << std::endl;
5990 return EINVAL;
5991 }
5992
5993 RGWDataAccess data_access(store);
5994 rgw_obj_key key(object, object_version);
5995
5996 RGWDataAccess::BucketRef b;
5997 RGWDataAccess::ObjectRef obj;
5998
5999 int ret = data_access.get_bucket(tenant, bucket_name, bucket_id, &b);
6000 if (ret < 0) {
6001 cerr << "ERROR: failed to init bucket: " << cpp_strerror(-ret) << std::endl;
6002 return -ret;
6003 }
6004
6005 ret = b->get_object(key, &obj);
6006 if (ret < 0) {
6007 cerr << "ERROR: failed to get object: " << cpp_strerror(-ret) << std::endl;
6008 return -ret;
6009 }
6010
6011 bufferlist bl;
6012 ret = read_input(infile, bl);
6013 if (ret < 0) {
6014 cerr << "ERROR: failed to read input: " << cpp_strerror(-ret) << std::endl;
6015 }
6016
6017 map<string, bufferlist> attrs;
6018 ret = obj->put(bl, attrs);
6019 if (ret < 0) {
6020 cerr << "ERROR: put object returned error: " << cpp_strerror(-ret) << std::endl;
6021 }
6022 }
6023
6024 if (opt_cmd == OPT_OBJECT_RM) {
6025 RGWBucketInfo bucket_info;
6026 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
6027 if (ret < 0) {
6028 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
6029 return -ret;
6030 }
6031 rgw_obj_key key(object, object_version);
6032 ret = rgw_remove_object(store, bucket_info, bucket, key);
6033
6034 if (ret < 0) {
6035 cerr << "ERROR: object remove returned: " << cpp_strerror(-ret) << std::endl;
6036 return -ret;
6037 }
6038 }
6039
6040 if (opt_cmd == OPT_OBJECT_REWRITE) {
6041 if (bucket_name.empty()) {
6042 cerr << "ERROR: bucket not specified" << std::endl;
6043 return EINVAL;
6044 }
6045 if (object.empty()) {
6046 cerr << "ERROR: object not specified" << std::endl;
6047 return EINVAL;
6048 }
6049
6050 RGWBucketInfo bucket_info;
6051 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
6052 if (ret < 0) {
6053 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
6054 return -ret;
6055 }
6056
6057 rgw_obj obj(bucket, object);
6058 obj.key.set_instance(object_version);
6059 bool need_rewrite = true;
6060 if (min_rewrite_stripe_size > 0) {
6061 ret = check_min_obj_stripe_size(store, bucket_info, obj, min_rewrite_stripe_size, &need_rewrite);
6062 if (ret < 0) {
6063 ldout(store->ctx(), 0) << "WARNING: check_min_obj_stripe_size failed, r=" << ret << dendl;
6064 }
6065 }
6066 if (need_rewrite) {
6067 ret = store->rewrite_obj(bucket_info, obj);
6068 if (ret < 0) {
6069 cerr << "ERROR: object rewrite returned: " << cpp_strerror(-ret) << std::endl;
6070 return -ret;
6071 }
6072 } else {
6073 ldout(store->ctx(), 20) << "skipped object" << dendl;
6074 }
6075 }
6076
6077 if (opt_cmd == OPT_OBJECTS_EXPIRE) {
6078 if (!store->process_expire_objects()) {
6079 cerr << "ERROR: process_expire_objects() processing returned error." << std::endl;
6080 return 1;
6081 }
6082 }
6083
6084 if (opt_cmd == OPT_BUCKET_REWRITE) {
6085 if (bucket_name.empty()) {
6086 cerr << "ERROR: bucket not specified" << std::endl;
6087 return EINVAL;
6088 }
6089
6090 RGWBucketInfo bucket_info;
6091 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
6092 if (ret < 0) {
6093 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
6094 return -ret;
6095 }
6096
6097 uint64_t start_epoch = 0;
6098 uint64_t end_epoch = 0;
6099
6100 if (!end_date.empty()) {
6101 int ret = utime_t::parse_date(end_date, &end_epoch, NULL);
6102 if (ret < 0) {
6103 cerr << "ERROR: failed to parse end date" << std::endl;
6104 return EINVAL;
6105 }
6106 }
6107 if (!start_date.empty()) {
6108 int ret = utime_t::parse_date(start_date, &start_epoch, NULL);
6109 if (ret < 0) {
6110 cerr << "ERROR: failed to parse start date" << std::endl;
6111 return EINVAL;
6112 }
6113 }
6114
6115 bool is_truncated = true;
6116
6117 rgw_obj_index_key marker;
6118 string prefix;
6119
6120 formatter->open_object_section("result");
6121 formatter->dump_string("bucket", bucket_name);
6122 formatter->open_array_section("objects");
6123 while (is_truncated) {
6124 map<string, rgw_bucket_dir_entry> result;
6125 int r =
6126 store->cls_bucket_list_ordered(bucket_info, RGW_NO_SHARD, marker,
6127 prefix, 1000, true,
6128 result, &is_truncated, &marker,
6129 bucket_object_check_filter);
6130
6131 if (r < 0 && r != -ENOENT) {
6132 cerr << "ERROR: failed operation r=" << r << std::endl;
6133 }
6134
6135 if (r == -ENOENT)
6136 break;
6137
6138 map<string, rgw_bucket_dir_entry>::iterator iter;
6139 for (iter = result.begin(); iter != result.end(); ++iter) {
6140 rgw_obj_key key = iter->second.key;
6141 rgw_bucket_dir_entry& entry = iter->second;
6142
6143 formatter->open_object_section("object");
6144 formatter->dump_string("name", key.name);
6145 formatter->dump_string("instance", key.instance);
6146 formatter->dump_int("size", entry.meta.size);
6147 utime_t ut(entry.meta.mtime);
6148 ut.gmtime(formatter->dump_stream("mtime"));
6149
6150 if ((entry.meta.size < min_rewrite_size) ||
6151 (entry.meta.size > max_rewrite_size) ||
6152 (start_epoch > 0 && start_epoch > (uint64_t)ut.sec()) ||
6153 (end_epoch > 0 && end_epoch < (uint64_t)ut.sec())) {
6154 formatter->dump_string("status", "Skipped");
6155 } else {
6156 rgw_obj obj(bucket, key);
6157
6158 bool need_rewrite = true;
6159 if (min_rewrite_stripe_size > 0) {
6160 r = check_min_obj_stripe_size(store, bucket_info, obj, min_rewrite_stripe_size, &need_rewrite);
6161 if (r < 0) {
6162 ldout(store->ctx(), 0) << "WARNING: check_min_obj_stripe_size failed, r=" << r << dendl;
6163 }
6164 }
6165 if (!need_rewrite) {
6166 formatter->dump_string("status", "Skipped");
6167 } else {
6168 r = store->rewrite_obj(bucket_info, obj);
6169 if (r == 0) {
6170 formatter->dump_string("status", "Success");
6171 } else {
6172 formatter->dump_string("status", cpp_strerror(-r));
6173 }
6174 }
6175 }
6176 formatter->dump_int("flags", entry.flags);
6177
6178 formatter->close_section();
6179 formatter->flush(cout);
6180 }
6181 }
6182 formatter->close_section();
6183 formatter->close_section();
6184 formatter->flush(cout);
6185 }
6186
6187 if (opt_cmd == OPT_BUCKET_RESHARD) {
6188 rgw_bucket bucket;
6189 RGWBucketInfo bucket_info;
6190 map<string, bufferlist> attrs;
6191
6192 int ret = check_reshard_bucket_params(store,
6193 bucket_name,
6194 tenant,
6195 bucket_id,
6196 num_shards_specified,
6197 num_shards,
6198 yes_i_really_mean_it,
6199 bucket,
6200 bucket_info,
6201 attrs);
6202 if (ret < 0) {
6203 return ret;
6204 }
6205
6206 RGWBucketReshard br(store, bucket_info, attrs, nullptr /* no callback */);
6207
6208 #define DEFAULT_RESHARD_MAX_ENTRIES 1000
6209 if (max_entries < 1) {
6210 max_entries = DEFAULT_RESHARD_MAX_ENTRIES;
6211 }
6212
6213 return br.execute(num_shards, max_entries,
6214 verbose, &cout, formatter);
6215 }
6216
6217 if (opt_cmd == OPT_RESHARD_ADD) {
6218 rgw_bucket bucket;
6219 RGWBucketInfo bucket_info;
6220 map<string, bufferlist> attrs;
6221
6222 int ret = check_reshard_bucket_params(store,
6223 bucket_name,
6224 tenant,
6225 bucket_id,
6226 num_shards_specified,
6227 num_shards,
6228 yes_i_really_mean_it,
6229 bucket,
6230 bucket_info,
6231 attrs);
6232 if (ret < 0) {
6233 return ret;
6234 }
6235
6236 int num_source_shards = (bucket_info.num_shards > 0 ? bucket_info.num_shards : 1);
6237
6238 RGWReshard reshard(store);
6239 cls_rgw_reshard_entry entry;
6240 entry.time = real_clock::now();
6241 entry.tenant = tenant;
6242 entry.bucket_name = bucket_name;
6243 entry.bucket_id = bucket_info.bucket.bucket_id;
6244 entry.old_num_shards = num_source_shards;
6245 entry.new_num_shards = num_shards;
6246
6247 return reshard.add(entry);
6248 }
6249
6250 if (opt_cmd == OPT_RESHARD_LIST) {
6251 list<cls_rgw_reshard_entry> entries;
6252 int ret;
6253 int count = 0;
6254 if (max_entries < 0) {
6255 max_entries = 1000;
6256 }
6257
6258 int num_logshards =
6259 store->ctx()->_conf.get_val<uint64_t>("rgw_reshard_num_logs");
6260
6261 RGWReshard reshard(store);
6262
6263 formatter->open_array_section("reshard");
6264 for (int i = 0; i < num_logshards; i++) {
6265 bool is_truncated = true;
6266 string marker;
6267 do {
6268 entries.clear();
6269 ret = reshard.list(i, marker, max_entries, entries, &is_truncated);
6270 if (ret < 0) {
6271 cerr << "Error listing resharding buckets: " << cpp_strerror(-ret) << std::endl;
6272 return ret;
6273 }
6274 for (auto iter=entries.begin(); iter != entries.end(); ++iter) {
6275 cls_rgw_reshard_entry& entry = *iter;
6276 encode_json("entry", entry, formatter);
6277 entry.get_key(&marker);
6278 }
6279 count += entries.size();
6280 formatter->flush(cout);
6281 } while (is_truncated && count < max_entries);
6282
6283 if (count >= max_entries) {
6284 break;
6285 }
6286 }
6287
6288 formatter->close_section();
6289 formatter->flush(cout);
6290 return 0;
6291 }
6292
6293 if (opt_cmd == OPT_RESHARD_STATUS) {
6294 if (bucket_name.empty()) {
6295 cerr << "ERROR: bucket not specified" << std::endl;
6296 return EINVAL;
6297 }
6298
6299 rgw_bucket bucket;
6300 RGWBucketInfo bucket_info;
6301 map<string, bufferlist> attrs;
6302 ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket, &attrs);
6303 if (ret < 0) {
6304 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
6305 return -ret;
6306 }
6307
6308 RGWBucketReshard br(store, bucket_info, attrs, nullptr /* no callback */);
6309 list<cls_rgw_bucket_instance_entry> status;
6310 int r = br.get_status(&status);
6311 if (r < 0) {
6312 cerr << "ERROR: could not get resharding status for bucket " <<
6313 bucket_name << std::endl;
6314 return -r;
6315 }
6316
6317 show_reshard_status(status, formatter);
6318 }
6319
6320 if (opt_cmd == OPT_RESHARD_PROCESS) {
6321 RGWReshard reshard(store, true, &cout);
6322
6323 int ret = reshard.process_all_logshards();
6324 if (ret < 0) {
6325 cerr << "ERROR: failed to process reshard logs, error=" << cpp_strerror(-ret) << std::endl;
6326 return -ret;
6327 }
6328 }
6329
6330 if (opt_cmd == OPT_RESHARD_CANCEL) {
6331 if (bucket_name.empty()) {
6332 cerr << "ERROR: bucket not specified" << std::endl;
6333 return EINVAL;
6334 }
6335
6336 rgw_bucket bucket;
6337 RGWBucketInfo bucket_info;
6338 map<string, bufferlist> attrs;
6339 ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket, &attrs);
6340 if (ret < 0) {
6341 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
6342 return -ret;
6343 }
6344
6345 RGWBucketReshard br(store, bucket_info, attrs, nullptr /* no callback */);
6346 int ret = br.cancel();
6347 if (ret < 0) {
6348 if (ret == -EBUSY) {
6349 cerr << "There is ongoing resharding, please retry after " <<
6350 store->ctx()->_conf.get_val<uint64_t>(
6351 "rgw_reshard_bucket_lock_duration") <<
6352 " seconds " << std::endl;
6353 } else {
6354 cerr << "Error canceling bucket " << bucket_name <<
6355 " resharding: " << cpp_strerror(-ret) << std::endl;
6356 }
6357 return ret;
6358 }
6359 RGWReshard reshard(store);
6360
6361 cls_rgw_reshard_entry entry;
6362 //entry.tenant = tenant;
6363 entry.bucket_name = bucket_name;
6364 //entry.bucket_id = bucket_id;
6365
6366 ret = reshard.remove(entry);
6367 if (ret < 0 && ret != -ENOENT) {
6368 cerr << "Error in getting bucket " << bucket_name << ": " << cpp_strerror(-ret) << std::endl;
6369 return ret;
6370 }
6371 }
6372
6373 if (opt_cmd == OPT_OBJECT_UNLINK) {
6374 RGWBucketInfo bucket_info;
6375 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
6376 if (ret < 0) {
6377 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
6378 return -ret;
6379 }
6380 list<rgw_obj_index_key> oid_list;
6381 rgw_obj_key key(object, object_version);
6382 rgw_obj_index_key index_key;
6383 key.get_index_key(&index_key);
6384 oid_list.push_back(index_key);
6385 ret = store->remove_objs_from_index(bucket_info, oid_list);
6386 if (ret < 0) {
6387 cerr << "ERROR: remove_obj_from_index() returned error: " << cpp_strerror(-ret) << std::endl;
6388 return 1;
6389 }
6390 }
6391
6392 if (opt_cmd == OPT_OBJECT_STAT) {
6393 RGWBucketInfo bucket_info;
6394 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
6395 if (ret < 0) {
6396 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
6397 return -ret;
6398 }
6399 rgw_obj obj(bucket, object);
6400 obj.key.set_instance(object_version);
6401
6402 uint64_t obj_size;
6403 map<string, bufferlist> attrs;
6404 RGWObjectCtx obj_ctx(store);
6405 RGWRados::Object op_target(store, bucket_info, obj_ctx, obj);
6406 RGWRados::Object::Read read_op(&op_target);
6407
6408 read_op.params.attrs = &attrs;
6409 read_op.params.obj_size = &obj_size;
6410
6411 ret = read_op.prepare();
6412 if (ret < 0) {
6413 cerr << "ERROR: failed to stat object, returned error: " << cpp_strerror(-ret) << std::endl;
6414 return 1;
6415 }
6416 formatter->open_object_section("object_metadata");
6417 formatter->dump_string("name", object);
6418 formatter->dump_unsigned("size", obj_size);
6419
6420 map<string, bufferlist>::iterator iter;
6421 map<string, bufferlist> other_attrs;
6422 for (iter = attrs.begin(); iter != attrs.end(); ++iter) {
6423 bufferlist& bl = iter->second;
6424 bool handled = false;
6425 if (iter->first == RGW_ATTR_MANIFEST) {
6426 handled = decode_dump<RGWObjManifest>("manifest", bl, formatter);
6427 } else if (iter->first == RGW_ATTR_ACL) {
6428 handled = decode_dump<RGWAccessControlPolicy>("policy", bl, formatter);
6429 } else if (iter->first == RGW_ATTR_ID_TAG) {
6430 handled = dump_string("tag", bl, formatter);
6431 } else if (iter->first == RGW_ATTR_ETAG) {
6432 handled = dump_string("etag", bl, formatter);
6433 } else if (iter->first == RGW_ATTR_COMPRESSION) {
6434 handled = decode_dump<RGWCompressionInfo>("compression", bl, formatter);
6435 }
6436
6437 if (!handled)
6438 other_attrs[iter->first] = bl;
6439 }
6440
6441 formatter->open_object_section("attrs");
6442 for (iter = other_attrs.begin(); iter != other_attrs.end(); ++iter) {
6443 dump_string(iter->first.c_str(), iter->second, formatter);
6444 }
6445 formatter->close_section();
6446 formatter->close_section();
6447 formatter->flush(cout);
6448 }
6449
6450 if (opt_cmd == OPT_BUCKET_CHECK) {
6451 if (check_head_obj_locator) {
6452 if (bucket_name.empty()) {
6453 cerr << "ERROR: need to specify bucket name" << std::endl;
6454 return EINVAL;
6455 }
6456 do_check_object_locator(tenant, bucket_name, fix, remove_bad, formatter);
6457 } else {
6458 RGWBucketAdminOp::check_index(store, bucket_op, f);
6459 }
6460 }
6461
6462 if (opt_cmd == OPT_BUCKET_RM) {
6463 if (!inconsistent_index) {
6464 RGWBucketAdminOp::remove_bucket(store, bucket_op, bypass_gc, true);
6465 } else {
6466 if (!yes_i_really_mean_it) {
6467 cerr << "using --inconsistent_index can corrupt the bucket index " << std::endl
6468 << "do you really mean it? (requires --yes-i-really-mean-it)" << std::endl;
6469 return 1;
6470 }
6471 RGWBucketAdminOp::remove_bucket(store, bucket_op, bypass_gc, false);
6472 }
6473 }
6474
6475 if (opt_cmd == OPT_GC_LIST) {
6476 int index = 0;
6477 bool truncated;
6478 formatter->open_array_section("entries");
6479
6480 do {
6481 list<cls_rgw_gc_obj_info> result;
6482 int ret = store->list_gc_objs(&index, marker, 1000, !include_all, result, &truncated);
6483 if (ret < 0) {
6484 cerr << "ERROR: failed to list objs: " << cpp_strerror(-ret) << std::endl;
6485 return 1;
6486 }
6487
6488
6489 list<cls_rgw_gc_obj_info>::iterator iter;
6490 for (iter = result.begin(); iter != result.end(); ++iter) {
6491 cls_rgw_gc_obj_info& info = *iter;
6492 formatter->open_object_section("chain_info");
6493 formatter->dump_string("tag", info.tag);
6494 formatter->dump_stream("time") << info.time;
6495 formatter->open_array_section("objs");
6496 list<cls_rgw_obj>::iterator liter;
6497 cls_rgw_obj_chain& chain = info.chain;
6498 for (liter = chain.objs.begin(); liter != chain.objs.end(); ++liter) {
6499 cls_rgw_obj& obj = *liter;
6500 encode_json("obj", obj, formatter);
6501 }
6502 formatter->close_section(); // objs
6503 formatter->close_section(); // obj_chain
6504 formatter->flush(cout);
6505 }
6506 } while (truncated);
6507 formatter->close_section();
6508 formatter->flush(cout);
6509 }
6510
6511 if (opt_cmd == OPT_GC_PROCESS) {
6512 int ret = store->process_gc(!include_all);
6513 if (ret < 0) {
6514 cerr << "ERROR: gc processing returned error: " << cpp_strerror(-ret) << std::endl;
6515 return 1;
6516 }
6517 }
6518
6519 if (opt_cmd == OPT_LC_LIST) {
6520 formatter->open_array_section("lifecycle_list");
6521 map<string, int> bucket_lc_map;
6522 string marker;
6523 #define MAX_LC_LIST_ENTRIES 100
6524 if (max_entries < 0) {
6525 max_entries = MAX_LC_LIST_ENTRIES;
6526 }
6527 do {
6528 int ret = store->list_lc_progress(marker, max_entries, &bucket_lc_map);
6529 if (ret < 0) {
6530 cerr << "ERROR: failed to list objs: " << cpp_strerror(-ret) << std::endl;
6531 return 1;
6532 }
6533 map<string, int>::iterator iter;
6534 for (iter = bucket_lc_map.begin(); iter != bucket_lc_map.end(); ++iter) {
6535 formatter->open_object_section("bucket_lc_info");
6536 formatter->dump_string("bucket", iter->first);
6537 string lc_status = LC_STATUS[iter->second];
6538 formatter->dump_string("status", lc_status);
6539 formatter->close_section(); // objs
6540 formatter->flush(cout);
6541 marker = iter->first;
6542 }
6543 } while (!bucket_lc_map.empty());
6544
6545 formatter->close_section(); //lifecycle list
6546 formatter->flush(cout);
6547 }
6548
6549
6550 if (opt_cmd == OPT_LC_GET) {
6551 if (bucket_name.empty()) {
6552 cerr << "ERROR: bucket not specified" << std::endl;
6553 return EINVAL;
6554 }
6555
6556 rgw_bucket bucket;
6557 RGWBucketInfo bucket_info;
6558 map<string, bufferlist> attrs;
6559 RGWLifecycleConfiguration config;
6560 ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket, &attrs);
6561 if (ret < 0) {
6562 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
6563 return -ret;
6564 }
6565
6566 auto aiter = attrs.find(RGW_ATTR_LC);
6567 if (aiter == attrs.end()) {
6568 return -ENOENT;
6569 }
6570
6571 bufferlist::const_iterator iter{&aiter->second};
6572 try {
6573 config.decode(iter);
6574 } catch (const buffer::error& e) {
6575 cerr << "ERROR: decode life cycle config failed" << std::endl;
6576 return -EIO;
6577 }
6578
6579 encode_json("result", config, formatter);
6580 formatter->flush(cout);
6581 }
6582
6583 if (opt_cmd == OPT_LC_PROCESS) {
6584 int ret = store->process_lc();
6585 if (ret < 0) {
6586 cerr << "ERROR: lc processing returned error: " << cpp_strerror(-ret) << std::endl;
6587 return 1;
6588 }
6589 }
6590
6591
6592 if (opt_cmd == OPT_LC_RESHARD_FIX) {
6593 ret = RGWBucketAdminOp::fix_lc_shards(store, bucket_op,f);
6594 if (ret < 0) {
6595 cerr << "ERROR: listing stale instances" << cpp_strerror(-ret) << std::endl;
6596 }
6597
6598 }
6599
6600 if (opt_cmd == OPT_ORPHANS_FIND) {
6601 if (!yes_i_really_mean_it) {
6602 cerr << "accidental removal of active objects can not be reversed; "
6603 << "do you really mean it? (requires --yes-i-really-mean-it)"
6604 << std::endl;
6605 return EINVAL;
6606 }
6607
6608 RGWOrphanSearch search(store, max_concurrent_ios, orphan_stale_secs);
6609
6610 if (job_id.empty()) {
6611 cerr << "ERROR: --job-id not specified" << std::endl;
6612 return EINVAL;
6613 }
6614 if (pool_name.empty()) {
6615 cerr << "ERROR: --pool not specified" << std::endl;
6616 return EINVAL;
6617 }
6618
6619 RGWOrphanSearchInfo info;
6620
6621 info.pool = pool;
6622 info.job_name = job_id;
6623 info.num_shards = num_shards;
6624
6625 int ret = search.init(job_id, &info, detail);
6626 if (ret < 0) {
6627 cerr << "could not init search, ret=" << ret << std::endl;
6628 return -ret;
6629 }
6630 ret = search.run();
6631 if (ret < 0) {
6632 return -ret;
6633 }
6634 }
6635
6636 if (opt_cmd == OPT_ORPHANS_FINISH) {
6637 RGWOrphanSearch search(store, max_concurrent_ios, orphan_stale_secs);
6638
6639 if (job_id.empty()) {
6640 cerr << "ERROR: --job-id not specified" << std::endl;
6641 return EINVAL;
6642 }
6643 int ret = search.init(job_id, NULL);
6644 if (ret < 0) {
6645 if (ret == -ENOENT) {
6646 cerr << "job not found" << std::endl;
6647 }
6648 return -ret;
6649 }
6650 ret = search.finish();
6651 if (ret < 0) {
6652 return -ret;
6653 }
6654 }
6655
6656 if (opt_cmd == OPT_ORPHANS_LIST_JOBS){
6657 RGWOrphanStore orphan_store(store);
6658 int ret = orphan_store.init();
6659 if (ret < 0){
6660 cerr << "connection to cluster failed!" << std::endl;
6661 return -ret;
6662 }
6663
6664 map <string,RGWOrphanSearchState> m;
6665 ret = orphan_store.list_jobs(m);
6666 if (ret < 0) {
6667 cerr << "job list failed" << std::endl;
6668 return -ret;
6669 }
6670 formatter->open_array_section("entries");
6671 for (const auto &it: m){
6672 if (!extra_info){
6673 formatter->dump_string("job-id",it.first);
6674 } else {
6675 encode_json("orphan_search_state", it.second, formatter);
6676 }
6677 }
6678 formatter->close_section();
6679 formatter->flush(cout);
6680 }
6681
6682 if (opt_cmd == OPT_USER_CHECK) {
6683 check_bad_user_bucket_mapping(store, user_id, fix);
6684 }
6685
6686 if (opt_cmd == OPT_USER_STATS) {
6687 if (user_id.empty()) {
6688 cerr << "ERROR: uid not specified" << std::endl;
6689 return EINVAL;
6690 }
6691
6692 string user_str = user_id.to_str();
6693 if (reset_stats) {
6694 if (!bucket_name.empty()){
6695 cerr << "ERROR: recalculate doesn't work on buckets" << std::endl;
6696 return EINVAL;
6697 }
6698 ret = store->cls_user_reset_stats(user_str);
6699 if (ret < 0) {
6700 cerr << "ERROR: could not clear user stats: " << cpp_strerror(-ret) << std::endl;
6701 return -ret;
6702 }
6703 }
6704
6705 if (sync_stats) {
6706 if (!bucket_name.empty()) {
6707 int ret = rgw_bucket_sync_user_stats(store, tenant, bucket_name);
6708 if (ret < 0) {
6709 cerr << "ERROR: could not sync bucket stats: " << cpp_strerror(-ret) << std::endl;
6710 return -ret;
6711 }
6712 } else {
6713 int ret = rgw_user_sync_all_stats(store, user_id);
6714 if (ret < 0) {
6715 cerr << "ERROR: failed to sync user stats: " << cpp_strerror(-ret) << std::endl;
6716 return -ret;
6717 }
6718 }
6719 }
6720
6721 cls_user_header header;
6722 int ret = store->cls_user_get_header(user_str, &header);
6723 if (ret < 0) {
6724 if (ret == -ENOENT) { /* in case of ENOENT */
6725 cerr << "User has not been initialized or user does not exist" << std::endl;
6726 } else {
6727 cerr << "ERROR: can't read user: " << cpp_strerror(ret) << std::endl;
6728 }
6729 return -ret;
6730 }
6731
6732 encode_json("header", header, formatter);
6733 formatter->flush(cout);
6734 }
6735
6736 if (opt_cmd == OPT_METADATA_GET) {
6737 int ret = store->meta_mgr->get(metadata_key, formatter);
6738 if (ret < 0) {
6739 cerr << "ERROR: can't get key: " << cpp_strerror(-ret) << std::endl;
6740 return -ret;
6741 }
6742
6743 formatter->flush(cout);
6744 }
6745
6746 if (opt_cmd == OPT_METADATA_PUT) {
6747 bufferlist bl;
6748 int ret = read_input(infile, bl);
6749 if (ret < 0) {
6750 cerr << "ERROR: failed to read input: " << cpp_strerror(-ret) << std::endl;
6751 return -ret;
6752 }
6753 ret = store->meta_mgr->put(metadata_key, bl, RGWMetadataHandler::RGWMetadataHandler::APPLY_ALWAYS);
6754 if (ret < 0) {
6755 cerr << "ERROR: can't put key: " << cpp_strerror(-ret) << std::endl;
6756 return -ret;
6757 }
6758 }
6759
6760 if (opt_cmd == OPT_METADATA_RM) {
6761 int ret = store->meta_mgr->remove(metadata_key);
6762 if (ret < 0) {
6763 cerr << "ERROR: can't remove key: " << cpp_strerror(-ret) << std::endl;
6764 return -ret;
6765 }
6766 }
6767
6768 if (opt_cmd == OPT_METADATA_LIST || opt_cmd == OPT_USER_LIST) {
6769 if (opt_cmd == OPT_USER_LIST) {
6770 metadata_key = "user";
6771 }
6772 void *handle;
6773 int max = 1000;
6774 int ret = store->meta_mgr->list_keys_init(metadata_key, marker, &handle);
6775 if (ret < 0) {
6776 cerr << "ERROR: can't get key: " << cpp_strerror(-ret) << std::endl;
6777 return -ret;
6778 }
6779
6780 bool truncated;
6781 uint64_t count = 0;
6782
6783 if (max_entries_specified) {
6784 formatter->open_object_section("result");
6785 }
6786 formatter->open_array_section("keys");
6787
6788 uint64_t left;
6789 do {
6790 list<string> keys;
6791 left = (max_entries_specified ? max_entries - count : max);
6792 ret = store->meta_mgr->list_keys_next(handle, left, keys, &truncated);
6793 if (ret < 0 && ret != -ENOENT) {
6794 cerr << "ERROR: lists_keys_next(): " << cpp_strerror(-ret) << std::endl;
6795 return -ret;
6796 } if (ret != -ENOENT) {
6797 for (list<string>::iterator iter = keys.begin(); iter != keys.end(); ++iter) {
6798 formatter->dump_string("key", *iter);
6799 ++count;
6800 }
6801 formatter->flush(cout);
6802 }
6803 } while (truncated && left > 0);
6804
6805 formatter->close_section();
6806
6807 if (max_entries_specified) {
6808 encode_json("truncated", truncated, formatter);
6809 encode_json("count", count, formatter);
6810 if (truncated) {
6811 encode_json("marker", store->meta_mgr->get_marker(handle), formatter);
6812 }
6813 formatter->close_section();
6814 }
6815 formatter->flush(cout);
6816
6817 store->meta_mgr->list_keys_complete(handle);
6818 }
6819
6820 if (opt_cmd == OPT_MDLOG_LIST) {
6821 utime_t start_time, end_time;
6822
6823 int ret = parse_date_str(start_date, start_time);
6824 if (ret < 0)
6825 return -ret;
6826
6827 ret = parse_date_str(end_date, end_time);
6828 if (ret < 0)
6829 return -ret;
6830
6831 int i = (specified_shard_id ? shard_id : 0);
6832
6833 if (period_id.empty()) {
6834 int ret = read_current_period_id(store, realm_id, realm_name, &period_id);
6835 if (ret < 0) {
6836 return -ret;
6837 }
6838 std::cerr << "No --period given, using current period="
6839 << period_id << std::endl;
6840 }
6841 RGWMetadataLog *meta_log = store->meta_mgr->get_log(period_id);
6842
6843 formatter->open_array_section("entries");
6844 for (; i < g_ceph_context->_conf->rgw_md_log_max_shards; i++) {
6845 void *handle;
6846 list<cls_log_entry> entries;
6847
6848
6849 meta_log->init_list_entries(i, start_time.to_real_time(), end_time.to_real_time(), marker, &handle);
6850 bool truncated;
6851 do {
6852 int ret = meta_log->list_entries(handle, 1000, entries, NULL, &truncated);
6853 if (ret < 0) {
6854 cerr << "ERROR: meta_log->list_entries(): " << cpp_strerror(-ret) << std::endl;
6855 return -ret;
6856 }
6857
6858 for (list<cls_log_entry>::iterator iter = entries.begin(); iter != entries.end(); ++iter) {
6859 cls_log_entry& entry = *iter;
6860 store->meta_mgr->dump_log_entry(entry, formatter);
6861 }
6862 formatter->flush(cout);
6863 } while (truncated);
6864
6865 meta_log->complete_list_entries(handle);
6866
6867 if (specified_shard_id)
6868 break;
6869 }
6870
6871
6872 formatter->close_section();
6873 formatter->flush(cout);
6874 }
6875
6876 if (opt_cmd == OPT_MDLOG_STATUS) {
6877 int i = (specified_shard_id ? shard_id : 0);
6878
6879 if (period_id.empty()) {
6880 int ret = read_current_period_id(store, realm_id, realm_name, &period_id);
6881 if (ret < 0) {
6882 return -ret;
6883 }
6884 std::cerr << "No --period given, using current period="
6885 << period_id << std::endl;
6886 }
6887 RGWMetadataLog *meta_log = store->meta_mgr->get_log(period_id);
6888
6889 formatter->open_array_section("entries");
6890
6891 for (; i < g_ceph_context->_conf->rgw_md_log_max_shards; i++) {
6892 RGWMetadataLogInfo info;
6893 meta_log->get_info(i, &info);
6894
6895 ::encode_json("info", info, formatter);
6896
6897 if (specified_shard_id)
6898 break;
6899 }
6900
6901
6902 formatter->close_section();
6903 formatter->flush(cout);
6904 }
6905
6906 if (opt_cmd == OPT_MDLOG_AUTOTRIM) {
6907 // need a full history for purging old mdlog periods
6908 store->meta_mgr->init_oldest_log_period();
6909
6910 RGWCoroutinesManager crs(store->ctx(), store->get_cr_registry());
6911 RGWHTTPManager http(store->ctx(), crs.get_completion_mgr());
6912 int ret = http.start();
6913 if (ret < 0) {
6914 cerr << "failed to initialize http client with " << cpp_strerror(ret) << std::endl;
6915 return -ret;
6916 }
6917
6918 auto num_shards = g_conf()->rgw_md_log_max_shards;
6919 ret = crs.run(create_admin_meta_log_trim_cr(dpp(), store, &http, num_shards));
6920 if (ret < 0) {
6921 cerr << "automated mdlog trim failed with " << cpp_strerror(ret) << std::endl;
6922 return -ret;
6923 }
6924 }
6925
6926 if (opt_cmd == OPT_MDLOG_TRIM) {
6927 utime_t start_time, end_time;
6928
6929 if (!specified_shard_id) {
6930 cerr << "ERROR: shard-id must be specified for trim operation" << std::endl;
6931 return EINVAL;
6932 }
6933
6934 int ret = parse_date_str(start_date, start_time);
6935 if (ret < 0)
6936 return -ret;
6937
6938 ret = parse_date_str(end_date, end_time);
6939 if (ret < 0)
6940 return -ret;
6941
6942 if (period_id.empty()) {
6943 std::cerr << "missing --period argument" << std::endl;
6944 return EINVAL;
6945 }
6946 RGWMetadataLog *meta_log = store->meta_mgr->get_log(period_id);
6947
6948 ret = meta_log->trim(shard_id, start_time.to_real_time(), end_time.to_real_time(), start_marker, end_marker);
6949 if (ret < 0) {
6950 cerr << "ERROR: meta_log->trim(): " << cpp_strerror(-ret) << std::endl;
6951 return -ret;
6952 }
6953 }
6954
6955 if (opt_cmd == OPT_SYNC_STATUS) {
6956 sync_status(formatter);
6957 }
6958
6959 if (opt_cmd == OPT_METADATA_SYNC_STATUS) {
6960 RGWMetaSyncStatusManager sync(store, store->get_async_rados());
6961
6962 int ret = sync.init();
6963 if (ret < 0) {
6964 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
6965 return -ret;
6966 }
6967
6968 rgw_meta_sync_status sync_status;
6969 ret = sync.read_sync_status(&sync_status);
6970 if (ret < 0) {
6971 cerr << "ERROR: sync.read_sync_status() returned ret=" << ret << std::endl;
6972 return -ret;
6973 }
6974
6975 formatter->open_object_section("summary");
6976 encode_json("sync_status", sync_status, formatter);
6977
6978 uint64_t full_total = 0;
6979 uint64_t full_complete = 0;
6980
6981 for (auto marker_iter : sync_status.sync_markers) {
6982 full_total += marker_iter.second.total_entries;
6983 if (marker_iter.second.state == rgw_meta_sync_marker::SyncState::FullSync) {
6984 full_complete += marker_iter.second.pos;
6985 } else {
6986 full_complete += marker_iter.second.total_entries;
6987 }
6988 }
6989
6990 formatter->open_object_section("full_sync");
6991 encode_json("total", full_total, formatter);
6992 encode_json("complete", full_complete, formatter);
6993 formatter->close_section();
6994 formatter->close_section();
6995
6996 formatter->flush(cout);
6997
6998 }
6999
7000 if (opt_cmd == OPT_METADATA_SYNC_INIT) {
7001 RGWMetaSyncStatusManager sync(store, store->get_async_rados());
7002
7003 int ret = sync.init();
7004 if (ret < 0) {
7005 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
7006 return -ret;
7007 }
7008 ret = sync.init_sync_status();
7009 if (ret < 0) {
7010 cerr << "ERROR: sync.init_sync_status() returned ret=" << ret << std::endl;
7011 return -ret;
7012 }
7013 }
7014
7015
7016 if (opt_cmd == OPT_METADATA_SYNC_RUN) {
7017 RGWMetaSyncStatusManager sync(store, store->get_async_rados());
7018
7019 int ret = sync.init();
7020 if (ret < 0) {
7021 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
7022 return -ret;
7023 }
7024
7025 ret = sync.run();
7026 if (ret < 0) {
7027 cerr << "ERROR: sync.run() returned ret=" << ret << std::endl;
7028 return -ret;
7029 }
7030 }
7031
7032 if (opt_cmd == OPT_DATA_SYNC_STATUS) {
7033 if (source_zone.empty()) {
7034 cerr << "ERROR: source zone not specified" << std::endl;
7035 return EINVAL;
7036 }
7037 RGWDataSyncStatusManager sync(store, store->get_async_rados(), source_zone);
7038
7039 int ret = sync.init();
7040 if (ret < 0) {
7041 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
7042 return -ret;
7043 }
7044
7045 rgw_data_sync_status sync_status;
7046 if (specified_shard_id) {
7047 set<string> pending_buckets;
7048 set<string> recovering_buckets;
7049 rgw_data_sync_marker sync_marker;
7050 ret = sync.read_shard_status(shard_id, pending_buckets, recovering_buckets, &sync_marker,
7051 max_entries_specified ? max_entries : 20);
7052 if (ret < 0 && ret != -ENOENT) {
7053 cerr << "ERROR: sync.read_shard_status() returned ret=" << ret << std::endl;
7054 return -ret;
7055 }
7056 formatter->open_object_section("summary");
7057 encode_json("shard_id", shard_id, formatter);
7058 encode_json("marker", sync_marker, formatter);
7059 encode_json("pending_buckets", pending_buckets, formatter);
7060 encode_json("recovering_buckets", recovering_buckets, formatter);
7061 formatter->close_section();
7062 formatter->flush(cout);
7063 } else {
7064 ret = sync.read_sync_status(&sync_status);
7065 if (ret < 0 && ret != -ENOENT) {
7066 cerr << "ERROR: sync.read_sync_status() returned ret=" << ret << std::endl;
7067 return -ret;
7068 }
7069
7070 formatter->open_object_section("summary");
7071 encode_json("sync_status", sync_status, formatter);
7072
7073 uint64_t full_total = 0;
7074 uint64_t full_complete = 0;
7075
7076 for (auto marker_iter : sync_status.sync_markers) {
7077 full_total += marker_iter.second.total_entries;
7078 if (marker_iter.second.state == rgw_meta_sync_marker::SyncState::FullSync) {
7079 full_complete += marker_iter.second.pos;
7080 } else {
7081 full_complete += marker_iter.second.total_entries;
7082 }
7083 }
7084
7085 formatter->open_object_section("full_sync");
7086 encode_json("total", full_total, formatter);
7087 encode_json("complete", full_complete, formatter);
7088 formatter->close_section();
7089 formatter->close_section();
7090
7091 formatter->flush(cout);
7092 }
7093 }
7094
7095 if (opt_cmd == OPT_DATA_SYNC_INIT) {
7096 if (source_zone.empty()) {
7097 cerr << "ERROR: source zone not specified" << std::endl;
7098 return EINVAL;
7099 }
7100
7101 RGWDataSyncStatusManager sync(store, store->get_async_rados(), source_zone);
7102
7103 int ret = sync.init();
7104 if (ret < 0) {
7105 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
7106 return -ret;
7107 }
7108
7109 ret = sync.init_sync_status();
7110 if (ret < 0) {
7111 cerr << "ERROR: sync.init_sync_status() returned ret=" << ret << std::endl;
7112 return -ret;
7113 }
7114 }
7115
7116 if (opt_cmd == OPT_DATA_SYNC_RUN) {
7117 if (source_zone.empty()) {
7118 cerr << "ERROR: source zone not specified" << std::endl;
7119 return EINVAL;
7120 }
7121
7122 RGWSyncModuleInstanceRef sync_module;
7123 int ret = store->svc.sync_modules->get_manager()->create_instance(g_ceph_context, store->svc.zone->get_zone().tier_type,
7124 store->svc.zone->get_zone_params().tier_config, &sync_module);
7125 if (ret < 0) {
7126 lderr(cct) << "ERROR: failed to init sync module instance, ret=" << ret << dendl;
7127 return ret;
7128 }
7129
7130 RGWDataSyncStatusManager sync(store, store->get_async_rados(), source_zone, sync_module);
7131
7132 ret = sync.init();
7133 if (ret < 0) {
7134 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
7135 return -ret;
7136 }
7137
7138 ret = sync.run();
7139 if (ret < 0) {
7140 cerr << "ERROR: sync.run() returned ret=" << ret << std::endl;
7141 return -ret;
7142 }
7143 }
7144
7145 if (opt_cmd == OPT_BUCKET_SYNC_INIT) {
7146 if (source_zone.empty()) {
7147 cerr << "ERROR: source zone not specified" << std::endl;
7148 return EINVAL;
7149 }
7150 if (bucket_name.empty()) {
7151 cerr << "ERROR: bucket not specified" << std::endl;
7152 return EINVAL;
7153 }
7154 rgw_bucket bucket;
7155 int ret = init_bucket_for_sync(tenant, bucket_name, bucket_id, bucket);
7156 if (ret < 0) {
7157 return -ret;
7158 }
7159 RGWBucketSyncStatusManager sync(store, source_zone, bucket);
7160
7161 ret = sync.init();
7162 if (ret < 0) {
7163 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
7164 return -ret;
7165 }
7166 ret = sync.init_sync_status();
7167 if (ret < 0) {
7168 cerr << "ERROR: sync.init_sync_status() returned ret=" << ret << std::endl;
7169 return -ret;
7170 }
7171 }
7172
7173 if ((opt_cmd == OPT_BUCKET_SYNC_DISABLE) || (opt_cmd == OPT_BUCKET_SYNC_ENABLE)) {
7174 if (bucket_name.empty()) {
7175 cerr << "ERROR: bucket not specified" << std::endl;
7176 return EINVAL;
7177 }
7178
7179 if (ret < 0) {
7180 cerr << "could not init realm " << ": " << cpp_strerror(-ret) << std::endl;
7181 return ret;
7182 }
7183 RGWPeriod period;
7184 ret = period.init(g_ceph_context, store->svc.sysobj, realm_id, realm_name, true);
7185 if (ret < 0) {
7186 cerr << "failed to init period " << ": " << cpp_strerror(-ret) << std::endl;
7187 return ret;
7188 }
7189
7190 if (!store->svc.zone->is_meta_master()) {
7191 cerr << "failed to update bucket sync: only allowed on meta master zone " << std::endl;
7192 cerr << period.get_master_zone() << " | " << period.get_realm() << std::endl;
7193 return EINVAL;
7194 }
7195
7196 rgw_obj obj(bucket, object);
7197 ret = set_bucket_sync_enabled(store, opt_cmd, tenant, bucket_name);
7198 if (ret < 0)
7199 return -ret;
7200 }
7201
7202 if (opt_cmd == OPT_BUCKET_SYNC_STATUS) {
7203 if (bucket_name.empty()) {
7204 cerr << "ERROR: bucket not specified" << std::endl;
7205 return EINVAL;
7206 }
7207 RGWBucketInfo bucket_info;
7208 rgw_bucket bucket;
7209 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
7210 if (ret < 0) {
7211 return -ret;
7212 }
7213 bucket_sync_status(store, bucket_info, source_zone, std::cout);
7214 }
7215
7216 if (opt_cmd == OPT_BUCKET_SYNC_MARKERS) {
7217 if (source_zone.empty()) {
7218 cerr << "ERROR: source zone not specified" << std::endl;
7219 return EINVAL;
7220 }
7221 if (bucket_name.empty()) {
7222 cerr << "ERROR: bucket not specified" << std::endl;
7223 return EINVAL;
7224 }
7225 rgw_bucket bucket;
7226 int ret = init_bucket_for_sync(tenant, bucket_name, bucket_id, bucket);
7227 if (ret < 0) {
7228 return -ret;
7229 }
7230 RGWBucketSyncStatusManager sync(store, source_zone, bucket);
7231
7232 ret = sync.init();
7233 if (ret < 0) {
7234 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
7235 return -ret;
7236 }
7237 ret = sync.read_sync_status();
7238 if (ret < 0) {
7239 cerr << "ERROR: sync.read_sync_status() returned ret=" << ret << std::endl;
7240 return -ret;
7241 }
7242
7243 map<int, rgw_bucket_shard_sync_info>& sync_status = sync.get_sync_status();
7244
7245 encode_json("sync_status", sync_status, formatter);
7246 formatter->flush(cout);
7247 }
7248
7249 if (opt_cmd == OPT_BUCKET_SYNC_RUN) {
7250 if (source_zone.empty()) {
7251 cerr << "ERROR: source zone not specified" << std::endl;
7252 return EINVAL;
7253 }
7254 if (bucket_name.empty()) {
7255 cerr << "ERROR: bucket not specified" << std::endl;
7256 return EINVAL;
7257 }
7258 rgw_bucket bucket;
7259 int ret = init_bucket_for_sync(tenant, bucket_name, bucket_id, bucket);
7260 if (ret < 0) {
7261 return -ret;
7262 }
7263 RGWBucketSyncStatusManager sync(store, source_zone, bucket);
7264
7265 ret = sync.init();
7266 if (ret < 0) {
7267 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
7268 return -ret;
7269 }
7270
7271 ret = sync.run();
7272 if (ret < 0) {
7273 cerr << "ERROR: sync.run() returned ret=" << ret << std::endl;
7274 return -ret;
7275 }
7276 }
7277
7278 if (opt_cmd == OPT_BILOG_LIST) {
7279 if (bucket_name.empty()) {
7280 cerr << "ERROR: bucket not specified" << std::endl;
7281 return EINVAL;
7282 }
7283 RGWBucketInfo bucket_info;
7284 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
7285 if (ret < 0) {
7286 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7287 return -ret;
7288 }
7289 formatter->open_array_section("entries");
7290 bool truncated;
7291 int count = 0;
7292 if (max_entries < 0)
7293 max_entries = 1000;
7294
7295 do {
7296 list<rgw_bi_log_entry> entries;
7297 ret = store->list_bi_log_entries(bucket_info, shard_id, marker, max_entries - count, entries, &truncated);
7298 if (ret < 0) {
7299 cerr << "ERROR: list_bi_log_entries(): " << cpp_strerror(-ret) << std::endl;
7300 return -ret;
7301 }
7302
7303 count += entries.size();
7304
7305 for (list<rgw_bi_log_entry>::iterator iter = entries.begin(); iter != entries.end(); ++iter) {
7306 rgw_bi_log_entry& entry = *iter;
7307 encode_json("entry", entry, formatter);
7308
7309 marker = entry.id;
7310 }
7311 formatter->flush(cout);
7312 } while (truncated && count < max_entries);
7313
7314 formatter->close_section();
7315 formatter->flush(cout);
7316 }
7317
7318 if (opt_cmd == OPT_SYNC_ERROR_LIST) {
7319 if (max_entries < 0) {
7320 max_entries = 1000;
7321 }
7322
7323 bool truncated;
7324 utime_t start_time, end_time;
7325
7326 int ret = parse_date_str(start_date, start_time);
7327 if (ret < 0)
7328 return -ret;
7329
7330 ret = parse_date_str(end_date, end_time);
7331 if (ret < 0)
7332 return -ret;
7333
7334 if (shard_id < 0) {
7335 shard_id = 0;
7336 }
7337
7338 formatter->open_array_section("entries");
7339
7340 for (; shard_id < ERROR_LOGGER_SHARDS; ++shard_id) {
7341 formatter->open_object_section("shard");
7342 encode_json("shard_id", shard_id, formatter);
7343 formatter->open_array_section("entries");
7344
7345 int count = 0;
7346 string oid = RGWSyncErrorLogger::get_shard_oid(RGW_SYNC_ERROR_LOG_SHARD_PREFIX, shard_id);
7347
7348 do {
7349 list<cls_log_entry> entries;
7350 ret = store->time_log_list(oid, start_time.to_real_time(), end_time.to_real_time(),
7351 max_entries - count, entries, marker, &marker, &truncated);
7352 if (ret == -ENOENT) {
7353 break;
7354 }
7355 if (ret < 0) {
7356 cerr << "ERROR: store->time_log_list(): " << cpp_strerror(-ret) << std::endl;
7357 return -ret;
7358 }
7359
7360 count += entries.size();
7361
7362 for (auto& cls_entry : entries) {
7363 rgw_sync_error_info log_entry;
7364
7365 auto iter = cls_entry.data.cbegin();
7366 try {
7367 decode(log_entry, iter);
7368 } catch (buffer::error& err) {
7369 cerr << "ERROR: failed to decode log entry" << std::endl;
7370 continue;
7371 }
7372 formatter->open_object_section("entry");
7373 encode_json("id", cls_entry.id, formatter);
7374 encode_json("section", cls_entry.section, formatter);
7375 encode_json("name", cls_entry.name, formatter);
7376 encode_json("timestamp", cls_entry.timestamp, formatter);
7377 encode_json("info", log_entry, formatter);
7378 formatter->close_section();
7379 formatter->flush(cout);
7380 }
7381 } while (truncated && count < max_entries);
7382
7383 formatter->close_section();
7384 formatter->close_section();
7385
7386 if (specified_shard_id) {
7387 break;
7388 }
7389 }
7390
7391 formatter->close_section();
7392 formatter->flush(cout);
7393 }
7394
7395 if (opt_cmd == OPT_SYNC_ERROR_TRIM) {
7396 utime_t start_time, end_time;
7397 int ret = parse_date_str(start_date, start_time);
7398 if (ret < 0)
7399 return -ret;
7400
7401 ret = parse_date_str(end_date, end_time);
7402 if (ret < 0)
7403 return -ret;
7404
7405 if (shard_id < 0) {
7406 shard_id = 0;
7407 }
7408
7409 for (; shard_id < ERROR_LOGGER_SHARDS; ++shard_id) {
7410 ret = trim_sync_error_log(shard_id, start_time.to_real_time(),
7411 end_time.to_real_time(), start_marker,
7412 end_marker, trim_delay_ms);
7413 if (ret < 0) {
7414 cerr << "ERROR: sync error trim: " << cpp_strerror(-ret) << std::endl;
7415 return -ret;
7416 }
7417 if (specified_shard_id) {
7418 break;
7419 }
7420 }
7421 }
7422
7423 if (opt_cmd == OPT_BILOG_TRIM) {
7424 if (bucket_name.empty()) {
7425 cerr << "ERROR: bucket not specified" << std::endl;
7426 return EINVAL;
7427 }
7428 RGWBucketInfo bucket_info;
7429 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
7430 if (ret < 0) {
7431 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7432 return -ret;
7433 }
7434 ret = store->trim_bi_log_entries(bucket_info, shard_id, start_marker, end_marker);
7435 if (ret < 0) {
7436 cerr << "ERROR: trim_bi_log_entries(): " << cpp_strerror(-ret) << std::endl;
7437 return -ret;
7438 }
7439 }
7440
7441 if (opt_cmd == OPT_BILOG_STATUS) {
7442 if (bucket_name.empty()) {
7443 cerr << "ERROR: bucket not specified" << std::endl;
7444 return EINVAL;
7445 }
7446 RGWBucketInfo bucket_info;
7447 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
7448 if (ret < 0) {
7449 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7450 return -ret;
7451 }
7452 map<int, string> markers;
7453 ret = store->get_bi_log_status(bucket_info, shard_id, markers);
7454 if (ret < 0) {
7455 cerr << "ERROR: get_bi_log_status(): " << cpp_strerror(-ret) << std::endl;
7456 return -ret;
7457 }
7458 formatter->open_object_section("entries");
7459 encode_json("markers", markers, formatter);
7460 formatter->close_section();
7461 formatter->flush(cout);
7462 }
7463
7464 if (opt_cmd == OPT_BILOG_AUTOTRIM) {
7465 RGWCoroutinesManager crs(store->ctx(), store->get_cr_registry());
7466 RGWHTTPManager http(store->ctx(), crs.get_completion_mgr());
7467 int ret = http.start();
7468 if (ret < 0) {
7469 cerr << "failed to initialize http client with " << cpp_strerror(ret) << std::endl;
7470 return -ret;
7471 }
7472
7473 rgw::BucketTrimConfig config;
7474 configure_bucket_trim(store->ctx(), config);
7475
7476 rgw::BucketTrimManager trim(store, config);
7477 ret = trim.init();
7478 if (ret < 0) {
7479 cerr << "trim manager init failed with " << cpp_strerror(ret) << std::endl;
7480 return -ret;
7481 }
7482 ret = crs.run(trim.create_admin_bucket_trim_cr(&http));
7483 if (ret < 0) {
7484 cerr << "automated bilog trim failed with " << cpp_strerror(ret) << std::endl;
7485 return -ret;
7486 }
7487 }
7488
7489 if (opt_cmd == OPT_DATALOG_LIST) {
7490 formatter->open_array_section("entries");
7491 bool truncated;
7492 int count = 0;
7493 if (max_entries < 0)
7494 max_entries = 1000;
7495
7496 utime_t start_time, end_time;
7497
7498 int ret = parse_date_str(start_date, start_time);
7499 if (ret < 0)
7500 return -ret;
7501
7502 ret = parse_date_str(end_date, end_time);
7503 if (ret < 0)
7504 return -ret;
7505
7506 RGWDataChangesLog *log = store->data_log;
7507 RGWDataChangesLog::LogMarker log_marker;
7508
7509 do {
7510 list<rgw_data_change_log_entry> entries;
7511 if (specified_shard_id) {
7512 ret = log->list_entries(shard_id, start_time.to_real_time(), end_time.to_real_time(), max_entries - count, entries, marker, NULL, &truncated);
7513 } else {
7514 ret = log->list_entries(start_time.to_real_time(), end_time.to_real_time(), max_entries - count, entries, log_marker, &truncated);
7515 }
7516 if (ret < 0) {
7517 cerr << "ERROR: list_bi_log_entries(): " << cpp_strerror(-ret) << std::endl;
7518 return -ret;
7519 }
7520
7521 count += entries.size();
7522
7523 for (list<rgw_data_change_log_entry>::iterator iter = entries.begin(); iter != entries.end(); ++iter) {
7524 rgw_data_change_log_entry& entry = *iter;
7525 if (!extra_info) {
7526 encode_json("entry", entry.entry, formatter);
7527 } else {
7528 encode_json("entry", entry, formatter);
7529 }
7530 }
7531 formatter->flush(cout);
7532 } while (truncated && count < max_entries);
7533
7534 formatter->close_section();
7535 formatter->flush(cout);
7536 }
7537
7538 if (opt_cmd == OPT_DATALOG_STATUS) {
7539 RGWDataChangesLog *log = store->data_log;
7540 int i = (specified_shard_id ? shard_id : 0);
7541
7542 formatter->open_array_section("entries");
7543 for (; i < g_ceph_context->_conf->rgw_data_log_num_shards; i++) {
7544 list<cls_log_entry> entries;
7545
7546 RGWDataChangesLogInfo info;
7547 log->get_info(i, &info);
7548
7549 ::encode_json("info", info, formatter);
7550
7551 if (specified_shard_id)
7552 break;
7553 }
7554
7555 formatter->close_section();
7556 formatter->flush(cout);
7557 }
7558
7559 if (opt_cmd == OPT_DATALOG_AUTOTRIM) {
7560 RGWCoroutinesManager crs(store->ctx(), store->get_cr_registry());
7561 RGWHTTPManager http(store->ctx(), crs.get_completion_mgr());
7562 int ret = http.start();
7563 if (ret < 0) {
7564 cerr << "failed to initialize http client with " << cpp_strerror(ret) << std::endl;
7565 return -ret;
7566 }
7567
7568 auto num_shards = g_conf()->rgw_data_log_num_shards;
7569 std::vector<std::string> markers(num_shards);
7570 ret = crs.run(create_admin_data_log_trim_cr(store, &http, num_shards, markers));
7571 if (ret < 0) {
7572 cerr << "automated datalog trim failed with " << cpp_strerror(ret) << std::endl;
7573 return -ret;
7574 }
7575 }
7576
7577 if (opt_cmd == OPT_DATALOG_TRIM) {
7578 utime_t start_time, end_time;
7579
7580 int ret = parse_date_str(start_date, start_time);
7581 if (ret < 0)
7582 return -ret;
7583
7584 ret = parse_date_str(end_date, end_time);
7585 if (ret < 0)
7586 return -ret;
7587
7588 RGWDataChangesLog *log = store->data_log;
7589 ret = log->trim_entries(start_time.to_real_time(), end_time.to_real_time(), start_marker, end_marker);
7590 if (ret < 0) {
7591 cerr << "ERROR: trim_entries(): " << cpp_strerror(-ret) << std::endl;
7592 return -ret;
7593 }
7594 }
7595
7596 bool quota_op = (opt_cmd == OPT_QUOTA_SET || opt_cmd == OPT_QUOTA_ENABLE || opt_cmd == OPT_QUOTA_DISABLE);
7597
7598 if (quota_op) {
7599 if (bucket_name.empty() && user_id.empty()) {
7600 cerr << "ERROR: bucket name or uid is required for quota operation" << std::endl;
7601 return EINVAL;
7602 }
7603
7604 if (!bucket_name.empty()) {
7605 if (!quota_scope.empty() && quota_scope != "bucket") {
7606 cerr << "ERROR: invalid quota scope specification." << std::endl;
7607 return EINVAL;
7608 }
7609 set_bucket_quota(store, opt_cmd, tenant, bucket_name,
7610 max_size, max_objects, have_max_size, have_max_objects);
7611 } else if (!user_id.empty()) {
7612 if (quota_scope == "bucket") {
7613 return set_user_bucket_quota(opt_cmd, user, user_op, max_size, max_objects, have_max_size, have_max_objects);
7614 } else if (quota_scope == "user") {
7615 return set_user_quota(opt_cmd, user, user_op, max_size, max_objects, have_max_size, have_max_objects);
7616 } else {
7617 cerr << "ERROR: invalid quota scope specification. Please specify either --quota-scope=bucket, or --quota-scope=user" << std::endl;
7618 return EINVAL;
7619 }
7620 }
7621 }
7622
7623 if (opt_cmd == OPT_MFA_CREATE) {
7624 rados::cls::otp::otp_info_t config;
7625
7626 if (user_id.empty()) {
7627 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
7628 return EINVAL;
7629 }
7630
7631 if (totp_serial.empty()) {
7632 cerr << "ERROR: TOTP device serial number was not provided (via --totp-serial)" << std::endl;
7633 return EINVAL;
7634 }
7635
7636 if (totp_seed.empty()) {
7637 cerr << "ERROR: TOTP device seed was not provided (via --totp-seed)" << std::endl;
7638 return EINVAL;
7639 }
7640
7641
7642 rados::cls::otp::SeedType seed_type;
7643 if (totp_seed_type == "hex") {
7644 seed_type = rados::cls::otp::OTP_SEED_HEX;
7645 } else if (totp_seed_type == "base32") {
7646 seed_type = rados::cls::otp::OTP_SEED_BASE32;
7647 } else {
7648 cerr << "ERROR: invalid seed type: " << totp_seed_type << std::endl;
7649 return EINVAL;
7650 }
7651
7652 config.id = totp_serial;
7653 config.seed = totp_seed;
7654 config.seed_type = seed_type;
7655
7656 if (totp_seconds > 0) {
7657 config.step_size = totp_seconds;
7658 }
7659
7660 if (totp_window > 0) {
7661 config.window = totp_window;
7662 }
7663
7664 real_time mtime = real_clock::now();
7665 string oid = store->get_mfa_oid(user_id);
7666
7667 int ret = store->meta_mgr->mutate(rgw_otp_get_handler(), oid, mtime, &objv_tracker,
7668 MDLOG_STATUS_WRITE, RGWMetadataHandler::APPLY_ALWAYS,
7669 [&] {
7670 return store->create_mfa(user_id, config, &objv_tracker, mtime);
7671 });
7672 if (ret < 0) {
7673 cerr << "MFA creation failed, error: " << cpp_strerror(-ret) << std::endl;
7674 return -ret;
7675 }
7676
7677 RGWUserInfo& user_info = user_op.get_user_info();
7678 user_info.mfa_ids.insert(totp_serial);
7679 user_op.set_mfa_ids(user_info.mfa_ids);
7680 string err;
7681 ret = user.modify(user_op, &err);
7682 if (ret < 0) {
7683 cerr << "ERROR: failed storing user info, error: " << err << std::endl;
7684 return -ret;
7685 }
7686 }
7687
7688 if (opt_cmd == OPT_MFA_REMOVE) {
7689 if (user_id.empty()) {
7690 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
7691 return EINVAL;
7692 }
7693
7694 if (totp_serial.empty()) {
7695 cerr << "ERROR: TOTP device serial number was not provided (via --totp-serial)" << std::endl;
7696 return EINVAL;
7697 }
7698
7699 real_time mtime = real_clock::now();
7700 string oid = store->get_mfa_oid(user_id);
7701
7702 int ret = store->meta_mgr->mutate(rgw_otp_get_handler(), oid, mtime, &objv_tracker,
7703 MDLOG_STATUS_WRITE, RGWMetadataHandler::APPLY_ALWAYS,
7704 [&] {
7705 return store->remove_mfa(user_id, totp_serial, &objv_tracker, mtime);
7706 });
7707 if (ret < 0) {
7708 cerr << "MFA removal failed, error: " << cpp_strerror(-ret) << std::endl;
7709 return -ret;
7710 }
7711
7712 RGWUserInfo& user_info = user_op.get_user_info();
7713 user_info.mfa_ids.erase(totp_serial);
7714 user_op.set_mfa_ids(user_info.mfa_ids);
7715 string err;
7716 ret = user.modify(user_op, &err);
7717 if (ret < 0) {
7718 cerr << "ERROR: failed storing user info, error: " << err << std::endl;
7719 return -ret;
7720 }
7721 }
7722
7723 if (opt_cmd == OPT_MFA_GET) {
7724 if (user_id.empty()) {
7725 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
7726 return EINVAL;
7727 }
7728
7729 if (totp_serial.empty()) {
7730 cerr << "ERROR: TOTP device serial number was not provided (via --totp-serial)" << std::endl;
7731 return EINVAL;
7732 }
7733
7734 rados::cls::otp::otp_info_t result;
7735 int ret = store->get_mfa(user_id, totp_serial, &result);
7736 if (ret < 0) {
7737 if (ret == -ENOENT || ret == -ENODATA) {
7738 cerr << "MFA serial id not found" << std::endl;
7739 } else {
7740 cerr << "MFA retrieval failed, error: " << cpp_strerror(-ret) << std::endl;
7741 }
7742 return -ret;
7743 }
7744 formatter->open_object_section("result");
7745 encode_json("entry", result, formatter);
7746 formatter->close_section();
7747 formatter->flush(cout);
7748 }
7749
7750 if (opt_cmd == OPT_MFA_LIST) {
7751 if (user_id.empty()) {
7752 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
7753 return EINVAL;
7754 }
7755
7756 list<rados::cls::otp::otp_info_t> result;
7757 int ret = store->list_mfa(user_id, &result);
7758 if (ret < 0) {
7759 cerr << "MFA listing failed, error: " << cpp_strerror(-ret) << std::endl;
7760 return -ret;
7761 }
7762 formatter->open_object_section("result");
7763 encode_json("entries", result, formatter);
7764 formatter->close_section();
7765 formatter->flush(cout);
7766 }
7767
7768 if (opt_cmd == OPT_MFA_CHECK) {
7769 if (user_id.empty()) {
7770 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
7771 return EINVAL;
7772 }
7773
7774 if (totp_serial.empty()) {
7775 cerr << "ERROR: TOTP device serial number was not provided (via --totp-serial)" << std::endl;
7776 return EINVAL;
7777 }
7778
7779 if (totp_pin.empty()) {
7780 cerr << "ERROR: TOTP device serial number was not provided (via --totp-pin)" << std::endl;
7781 return EINVAL;
7782 }
7783
7784 list<rados::cls::otp::otp_info_t> result;
7785 int ret = store->check_mfa(user_id, totp_serial, totp_pin.front());
7786 if (ret < 0) {
7787 cerr << "MFA check failed, error: " << cpp_strerror(-ret) << std::endl;
7788 return -ret;
7789 }
7790
7791 cout << "ok" << std::endl;
7792 }
7793
7794 if (opt_cmd == OPT_MFA_RESYNC) {
7795 if (user_id.empty()) {
7796 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
7797 return EINVAL;
7798 }
7799
7800 if (totp_serial.empty()) {
7801 cerr << "ERROR: TOTP device serial number was not provided (via --totp-serial)" << std::endl;
7802 return EINVAL;
7803 }
7804
7805 if (totp_pin.size() != 2) {
7806 cerr << "ERROR: missing two --totp-pin params (--totp-pin=<first> --totp-pin=<second>)" << std::endl;
7807 }
7808
7809 rados::cls::otp::otp_info_t config;
7810 int ret = store->get_mfa(user_id, totp_serial, &config);
7811 if (ret < 0) {
7812 if (ret == -ENOENT || ret == -ENODATA) {
7813 cerr << "MFA serial id not found" << std::endl;
7814 } else {
7815 cerr << "MFA retrieval failed, error: " << cpp_strerror(-ret) << std::endl;
7816 }
7817 return -ret;
7818 }
7819
7820 ceph::real_time now;
7821
7822 ret = store->otp_get_current_time(user_id, &now);
7823 if (ret < 0) {
7824 cerr << "ERROR: failed to fetch current time from osd: " << cpp_strerror(-ret) << std::endl;
7825 return -ret;
7826 }
7827 time_t time_ofs;
7828
7829 ret = scan_totp(store->ctx(), now, config, totp_pin, &time_ofs);
7830 if (ret < 0) {
7831 if (ret == -ENOENT) {
7832 cerr << "failed to resync, TOTP values not found in range" << std::endl;
7833 } else {
7834 cerr << "ERROR: failed to scan for TOTP values: " << cpp_strerror(-ret) << std::endl;
7835 }
7836 return -ret;
7837 }
7838
7839 config.time_ofs = time_ofs;
7840
7841 /* now update the backend */
7842 real_time mtime = real_clock::now();
7843 string oid = store->get_mfa_oid(user_id);
7844
7845 ret = store->meta_mgr->mutate(rgw_otp_get_handler(), oid, mtime, &objv_tracker,
7846 MDLOG_STATUS_WRITE, RGWMetadataHandler::APPLY_ALWAYS,
7847 [&] {
7848 return store->create_mfa(user_id, config, &objv_tracker, mtime);
7849 });
7850 if (ret < 0) {
7851 cerr << "MFA update failed, error: " << cpp_strerror(-ret) << std::endl;
7852 return -ret;
7853 }
7854
7855 }
7856
7857 if (opt_cmd == OPT_RESHARD_STALE_INSTANCES_LIST) {
7858 if (!store->svc.zone->can_reshard() && !yes_i_really_mean_it) {
7859 cerr << "Resharding disabled in a multisite env, stale instances unlikely from resharding" << std::endl;
7860 cerr << "These instances may not be safe to delete." << std::endl;
7861 cerr << "Use --yes-i-really-mean-it to force displaying these instances." << std::endl;
7862 return EINVAL;
7863 }
7864
7865 ret = RGWBucketAdminOp::list_stale_instances(store, bucket_op,f);
7866 if (ret < 0) {
7867 cerr << "ERROR: listing stale instances" << cpp_strerror(-ret) << std::endl;
7868 }
7869 }
7870
7871 if (opt_cmd == OPT_RESHARD_STALE_INSTANCES_DELETE) {
7872 if (!store->svc.zone->can_reshard()) {
7873 cerr << "Resharding disabled in a multisite env. Stale instances are not safe to be deleted." << std::endl;
7874 return EINVAL;
7875 }
7876
7877 ret = RGWBucketAdminOp::clear_stale_instances(store, bucket_op,f);
7878 if (ret < 0) {
7879 cerr << "ERROR: deleting stale instances" << cpp_strerror(-ret) << std::endl;
7880 }
7881 }
7882
7883 if (opt_cmd == OPT_PUBSUB_TOPICS_LIST) {
7884 if (get_tier_type(store) != "pubsub") {
7885 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
7886 return EINVAL;
7887 }
7888 if (user_id.empty()) {
7889 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
7890 return EINVAL;
7891 }
7892 RGWUserInfo& user_info = user_op.get_user_info();
7893
7894 RGWUserPubSub ups(store, user_info.user_id);
7895
7896 rgw_bucket bucket;
7897
7898 if (!bucket_name.empty()) {
7899 rgw_pubsub_bucket_topics result;
7900 RGWBucketInfo bucket_info;
7901 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
7902 if (ret < 0) {
7903 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7904 return -ret;
7905 }
7906
7907 auto b = ups.get_bucket(bucket_info.bucket);
7908 ret = b->get_topics(&result);
7909 if (ret < 0) {
7910 cerr << "ERROR: could not get topics: " << cpp_strerror(-ret) << std::endl;
7911 return -ret;
7912 }
7913 encode_json("result", result, formatter);
7914 } else {
7915 rgw_pubsub_user_topics result;
7916 int ret = ups.get_user_topics(&result);
7917 if (ret < 0) {
7918 cerr << "ERROR: could not get topics: " << cpp_strerror(-ret) << std::endl;
7919 return -ret;
7920 }
7921 encode_json("result", result, formatter);
7922 }
7923 formatter->flush(cout);
7924 }
7925
7926 if (opt_cmd == OPT_PUBSUB_TOPIC_CREATE) {
7927 if (get_tier_type(store) != "pubsub") {
7928 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
7929 return EINVAL;
7930 }
7931 if (topic_name.empty()) {
7932 cerr << "ERROR: topic name was not provided (via --topic)" << std::endl;
7933 return EINVAL;
7934 }
7935 if (user_id.empty()) {
7936 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
7937 return EINVAL;
7938 }
7939 RGWUserInfo& user_info = user_op.get_user_info();
7940 RGWUserPubSub ups(store, user_info.user_id);
7941
7942 ret = ups.create_topic(topic_name);
7943 if (ret < 0) {
7944 cerr << "ERROR: could not create topic: " << cpp_strerror(-ret) << std::endl;
7945 return -ret;
7946 }
7947 }
7948
7949 if (opt_cmd == OPT_PUBSUB_TOPIC_GET) {
7950 if (get_tier_type(store) != "pubsub") {
7951 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
7952 return EINVAL;
7953 }
7954 if (topic_name.empty()) {
7955 cerr << "ERROR: topic name was not provided (via --topic)" << std::endl;
7956 return EINVAL;
7957 }
7958 if (user_id.empty()) {
7959 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
7960 return EINVAL;
7961 }
7962 RGWUserInfo& user_info = user_op.get_user_info();
7963 RGWUserPubSub ups(store, user_info.user_id);
7964
7965 rgw_pubsub_topic_subs topic;
7966 ret = ups.get_topic(topic_name, &topic);
7967 if (ret < 0) {
7968 cerr << "ERROR: could not create topic: " << cpp_strerror(-ret) << std::endl;
7969 return -ret;
7970 }
7971 encode_json("topic", topic, formatter);
7972 formatter->flush(cout);
7973 }
7974
7975 if (opt_cmd == OPT_PUBSUB_NOTIFICATION_CREATE) {
7976 if (get_tier_type(store) != "pubsub") {
7977 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
7978 return EINVAL;
7979 }
7980 if (topic_name.empty()) {
7981 cerr << "ERROR: topic name was not provided (via --topic)" << std::endl;
7982 return EINVAL;
7983 }
7984 if (user_id.empty()) {
7985 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
7986 return EINVAL;
7987 }
7988 if (bucket_name.empty()) {
7989 cerr << "ERROR: bucket name was not provided (via --bucket)" << std::endl;
7990 return EINVAL;
7991 }
7992 RGWUserInfo& user_info = user_op.get_user_info();
7993 RGWUserPubSub ups(store, user_info.user_id);
7994
7995 rgw_bucket bucket;
7996
7997 RGWBucketInfo bucket_info;
7998 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
7999 if (ret < 0) {
8000 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
8001 return -ret;
8002 }
8003
8004 auto b = ups.get_bucket(bucket_info.bucket);
8005 ret = b->create_notification(topic_name, event_types);
8006 if (ret < 0) {
8007 cerr << "ERROR: could not publish bucket: " << cpp_strerror(-ret) << std::endl;
8008 return -ret;
8009 }
8010 }
8011
8012 if (opt_cmd == OPT_PUBSUB_NOTIFICATION_RM) {
8013 if (get_tier_type(store) != "pubsub") {
8014 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
8015 return EINVAL;
8016 }
8017 if (topic_name.empty()) {
8018 cerr << "ERROR: topic name was not provided (via --topic)" << std::endl;
8019 return EINVAL;
8020 }
8021 if (user_id.empty()) {
8022 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
8023 return EINVAL;
8024 }
8025 if (bucket_name.empty()) {
8026 cerr << "ERROR: bucket name was not provided (via --bucket)" << std::endl;
8027 return EINVAL;
8028 }
8029 RGWUserInfo& user_info = user_op.get_user_info();
8030 RGWUserPubSub ups(store, user_info.user_id);
8031
8032 rgw_bucket bucket;
8033
8034 RGWBucketInfo bucket_info;
8035 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
8036 if (ret < 0) {
8037 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
8038 return -ret;
8039 }
8040
8041 auto b = ups.get_bucket(bucket_info.bucket);
8042 ret = b->remove_notification(topic_name);
8043 if (ret < 0) {
8044 cerr << "ERROR: could not publish bucket: " << cpp_strerror(-ret) << std::endl;
8045 return -ret;
8046 }
8047 }
8048
8049 if (opt_cmd == OPT_PUBSUB_TOPIC_RM) {
8050 if (get_tier_type(store) != "pubsub") {
8051 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
8052 return EINVAL;
8053 }
8054 if (topic_name.empty()) {
8055 cerr << "ERROR: topic name was not provided (via --topic)" << std::endl;
8056 return EINVAL;
8057 }
8058 if (user_id.empty()) {
8059 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
8060 return EINVAL;
8061 }
8062 RGWUserInfo& user_info = user_op.get_user_info();
8063 RGWUserPubSub ups(store, user_info.user_id);
8064
8065 ret = ups.remove_topic(topic_name);
8066 if (ret < 0) {
8067 cerr << "ERROR: could not remove topic: " << cpp_strerror(-ret) << std::endl;
8068 return -ret;
8069 }
8070 }
8071
8072 if (opt_cmd == OPT_PUBSUB_SUB_GET) {
8073 if (get_tier_type(store) != "pubsub") {
8074 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
8075 return EINVAL;
8076 }
8077 if (user_id.empty()) {
8078 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
8079 return EINVAL;
8080 }
8081 if (sub_name.empty()) {
8082 cerr << "ERROR: subscription name was not provided (via --sub-name)" << std::endl;
8083 return EINVAL;
8084 }
8085 RGWUserInfo& user_info = user_op.get_user_info();
8086 RGWUserPubSub ups(store, user_info.user_id);
8087
8088 rgw_pubsub_sub_config sub_conf;
8089
8090 auto sub = ups.get_sub(sub_name);
8091 ret = sub->get_conf(&sub_conf);
8092 if (ret < 0) {
8093 cerr << "ERROR: could not get subscription info: " << cpp_strerror(-ret) << std::endl;
8094 return -ret;
8095 }
8096 encode_json("sub", sub_conf, formatter);
8097 formatter->flush(cout);
8098 }
8099
8100 if (opt_cmd == OPT_PUBSUB_SUB_CREATE) {
8101 if (get_tier_type(store) != "pubsub") {
8102 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
8103 return EINVAL;
8104 }
8105 if (user_id.empty()) {
8106 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
8107 return EINVAL;
8108 }
8109 if (sub_name.empty()) {
8110 cerr << "ERROR: subscription name was not provided (via --sub-name)" << std::endl;
8111 return EINVAL;
8112 }
8113 if (topic_name.empty()) {
8114 cerr << "ERROR: topic name was not provided (via --topic)" << std::endl;
8115 return EINVAL;
8116 }
8117 RGWUserInfo& user_info = user_op.get_user_info();
8118 RGWUserPubSub ups(store, user_info.user_id);
8119
8120 rgw_pubsub_topic_subs topic;
8121 int ret = ups.get_topic(topic_name, &topic);
8122 if (ret < 0) {
8123 cerr << "ERROR: topic not found" << std::endl;
8124 return EINVAL;
8125 }
8126
8127 rgw_pubsub_sub_dest dest_config;
8128 dest_config.bucket_name = sub_dest_bucket;
8129 dest_config.oid_prefix = sub_oid_prefix;
8130 dest_config.push_endpoint = sub_push_endpoint;
8131
8132 auto psmodule = static_cast<RGWPSSyncModuleInstance *>(store->get_sync_module().get());
8133 auto conf = psmodule->get_effective_conf();
8134
8135 if (dest_config.bucket_name.empty()) {
8136 dest_config.bucket_name = string(conf["data_bucket_prefix"]) + user_info.user_id.to_str() + "-" + topic.topic.name;
8137 }
8138 if (dest_config.oid_prefix.empty()) {
8139 dest_config.oid_prefix = conf["data_oid_prefix"];
8140 }
8141 auto sub = ups.get_sub(sub_name);
8142 ret = sub->subscribe(topic_name, dest_config);
8143 if (ret < 0) {
8144 cerr << "ERROR: could not store subscription info: " << cpp_strerror(-ret) << std::endl;
8145 return -ret;
8146 }
8147 }
8148
8149 if (opt_cmd == OPT_PUBSUB_SUB_RM) {
8150 if (get_tier_type(store) != "pubsub") {
8151 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
8152 return EINVAL;
8153 }
8154 if (user_id.empty()) {
8155 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
8156 return EINVAL;
8157 }
8158 if (sub_name.empty()) {
8159 cerr << "ERROR: subscription name was not provided (via --sub-name)" << std::endl;
8160 return EINVAL;
8161 }
8162 RGWUserInfo& user_info = user_op.get_user_info();
8163 RGWUserPubSub ups(store, user_info.user_id);
8164
8165 auto sub = ups.get_sub(sub_name);
8166 ret = sub->unsubscribe(topic_name);
8167 if (ret < 0) {
8168 cerr << "ERROR: could not get subscription info: " << cpp_strerror(-ret) << std::endl;
8169 return -ret;
8170 }
8171 }
8172
8173 if (opt_cmd == OPT_PUBSUB_SUB_PULL) {
8174 if (get_tier_type(store) != "pubsub") {
8175 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
8176 return EINVAL;
8177 }
8178 if (user_id.empty()) {
8179 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
8180 return EINVAL;
8181 }
8182 if (sub_name.empty()) {
8183 cerr << "ERROR: subscription name was not provided (via --sub-name)" << std::endl;
8184 return EINVAL;
8185 }
8186 RGWUserInfo& user_info = user_op.get_user_info();
8187 RGWUserPubSub ups(store, user_info.user_id);
8188
8189 RGWUserPubSub::Sub::list_events_result result;
8190
8191 if (!max_entries_specified) {
8192 max_entries = 100;
8193 }
8194 auto sub = ups.get_sub(sub_name);
8195 ret = sub->list_events(marker, max_entries, &result);
8196 if (ret < 0) {
8197 cerr << "ERROR: could not list events: " << cpp_strerror(-ret) << std::endl;
8198 return -ret;
8199 }
8200 encode_json("result", result, formatter);
8201 formatter->flush(cout);
8202 }
8203
8204 if (opt_cmd == OPT_PUBSUB_EVENT_RM) {
8205 if (get_tier_type(store) != "pubsub") {
8206 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
8207 return EINVAL;
8208 }
8209 if (user_id.empty()) {
8210 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
8211 return EINVAL;
8212 }
8213 if (sub_name.empty()) {
8214 cerr << "ERROR: subscription name was not provided (via --sub-name)" << std::endl;
8215 return EINVAL;
8216 }
8217 if (event_id.empty()) {
8218 cerr << "ERROR: event id was not provided (via --event-id)" << std::endl;
8219 return EINVAL;
8220 }
8221 RGWUserInfo& user_info = user_op.get_user_info();
8222 RGWUserPubSub ups(store, user_info.user_id);
8223
8224 auto sub = ups.get_sub(sub_name);
8225 ret = sub->remove_event(event_id);
8226 if (ret < 0) {
8227 cerr << "ERROR: could not remove event: " << cpp_strerror(-ret) << std::endl;
8228 return -ret;
8229 }
8230 }
8231
8232 return 0;
8233 }