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