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