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