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