]> git.proxmox.com Git - ceph.git/blob - ceph/src/rgw/rgw_admin.cc
fb463ea88c9da5fe7dae22d7421c24be9d0046b4
[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 << "no value for 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 if (bucket_name.empty() && !bucket_id.empty()) {
6081 rgw_bucket bucket;
6082 if (!rgw_find_bucket_by_id(store->ctx(), store->ctl()->meta.mgr, marker, bucket_id, &bucket)) {
6083 cerr << "failure: no such bucket id" << std::endl;
6084 return -ENOENT;
6085 }
6086 bucket_op.set_tenant(bucket.tenant);
6087 bucket_op.set_bucket_name(bucket.name);
6088 }
6089 bucket_op.set_fetch_stats(true);
6090
6091 int r = RGWBucketAdminOp::info(store, bucket_op, f);
6092 if (r < 0) {
6093 cerr << "failure: " << cpp_strerror(-r) << ": " << err << std::endl;
6094 return -r;
6095 }
6096 }
6097
6098 if (opt_cmd == OPT::BUCKET_LINK) {
6099 bucket_op.set_bucket_id(bucket_id);
6100 bucket_op.set_new_bucket_name(new_bucket_name);
6101 string err;
6102 int r = RGWBucketAdminOp::link(store, bucket_op, &err);
6103 if (r < 0) {
6104 cerr << "failure: " << cpp_strerror(-r) << ": " << err << std::endl;
6105 return -r;
6106 }
6107 }
6108
6109 if (opt_cmd == OPT::BUCKET_UNLINK) {
6110 int r = RGWBucketAdminOp::unlink(store, bucket_op);
6111 if (r < 0) {
6112 cerr << "failure: " << cpp_strerror(-r) << std::endl;
6113 return -r;
6114 }
6115 }
6116
6117 if (opt_cmd == OPT::BUCKET_CHOWN) {
6118
6119 bucket_op.set_bucket_name(bucket_name);
6120 bucket_op.set_new_bucket_name(new_bucket_name);
6121 string err;
6122 string marker;
6123
6124 int r = RGWBucketAdminOp::chown(store, bucket_op, marker, &err);
6125 if (r < 0) {
6126 cerr << "failure: " << cpp_strerror(-r) << ": " << err << std::endl;
6127 return -r;
6128 }
6129 }
6130
6131 if (opt_cmd == OPT::LOG_LIST) {
6132 // filter by date?
6133 if (date.size() && date.size() != 10) {
6134 cerr << "bad date format for '" << date << "', expect YYYY-MM-DD" << std::endl;
6135 return EINVAL;
6136 }
6137
6138 formatter->reset();
6139 formatter->open_array_section("logs");
6140 RGWAccessHandle h;
6141 int r = store->getRados()->log_list_init(date, &h);
6142 if (r == -ENOENT) {
6143 // no logs.
6144 } else {
6145 if (r < 0) {
6146 cerr << "log list: error " << r << std::endl;
6147 return -r;
6148 }
6149 while (true) {
6150 string name;
6151 int r = store->getRados()->log_list_next(h, &name);
6152 if (r == -ENOENT)
6153 break;
6154 if (r < 0) {
6155 cerr << "log list: error " << r << std::endl;
6156 return -r;
6157 }
6158 formatter->dump_string("object", name);
6159 }
6160 }
6161 formatter->close_section();
6162 formatter->flush(cout);
6163 cout << std::endl;
6164 }
6165
6166 if (opt_cmd == OPT::LOG_SHOW || opt_cmd == OPT::LOG_RM) {
6167 if (object.empty() && (date.empty() || bucket_name.empty() || bucket_id.empty())) {
6168 cerr << "specify an object or a date, bucket and bucket-id" << std::endl;
6169 exit(1);
6170 }
6171
6172 string oid;
6173 if (!object.empty()) {
6174 oid = object;
6175 } else {
6176 oid = date;
6177 oid += "-";
6178 oid += bucket_id;
6179 oid += "-";
6180 oid += bucket_name;
6181 }
6182
6183 if (opt_cmd == OPT::LOG_SHOW) {
6184 RGWAccessHandle h;
6185
6186 int r = store->getRados()->log_show_init(oid, &h);
6187 if (r < 0) {
6188 cerr << "error opening log " << oid << ": " << cpp_strerror(-r) << std::endl;
6189 return -r;
6190 }
6191
6192 formatter->reset();
6193 formatter->open_object_section("log");
6194
6195 struct rgw_log_entry entry;
6196
6197 // peek at first entry to get bucket metadata
6198 r = store->getRados()->log_show_next(h, &entry);
6199 if (r < 0) {
6200 cerr << "error reading log " << oid << ": " << cpp_strerror(-r) << std::endl;
6201 return -r;
6202 }
6203 formatter->dump_string("bucket_id", entry.bucket_id);
6204 formatter->dump_string("bucket_owner", entry.bucket_owner.to_str());
6205 formatter->dump_string("bucket", entry.bucket);
6206
6207 uint64_t agg_time = 0;
6208 uint64_t agg_bytes_sent = 0;
6209 uint64_t agg_bytes_received = 0;
6210 uint64_t total_entries = 0;
6211
6212 if (show_log_entries)
6213 formatter->open_array_section("log_entries");
6214
6215 do {
6216 using namespace std::chrono;
6217 uint64_t total_time = duration_cast<milliseconds>(entry.total_time).count();
6218
6219 agg_time += total_time;
6220 agg_bytes_sent += entry.bytes_sent;
6221 agg_bytes_received += entry.bytes_received;
6222 total_entries++;
6223
6224 if (skip_zero_entries && entry.bytes_sent == 0 &&
6225 entry.bytes_received == 0)
6226 goto next;
6227
6228 if (show_log_entries) {
6229
6230 rgw_format_ops_log_entry(entry, formatter);
6231 formatter->flush(cout);
6232 }
6233 next:
6234 r = store->getRados()->log_show_next(h, &entry);
6235 } while (r > 0);
6236
6237 if (r < 0) {
6238 cerr << "error reading log " << oid << ": " << cpp_strerror(-r) << std::endl;
6239 return -r;
6240 }
6241 if (show_log_entries)
6242 formatter->close_section();
6243
6244 if (show_log_sum) {
6245 formatter->open_object_section("log_sum");
6246 formatter->dump_int("bytes_sent", agg_bytes_sent);
6247 formatter->dump_int("bytes_received", agg_bytes_received);
6248 formatter->dump_int("total_time", agg_time);
6249 formatter->dump_int("total_entries", total_entries);
6250 formatter->close_section();
6251 }
6252 formatter->close_section();
6253 formatter->flush(cout);
6254 cout << std::endl;
6255 }
6256 if (opt_cmd == OPT::LOG_RM) {
6257 int r = store->getRados()->log_remove(oid);
6258 if (r < 0) {
6259 cerr << "error removing log " << oid << ": " << cpp_strerror(-r) << std::endl;
6260 return -r;
6261 }
6262 }
6263 }
6264
6265 if (opt_cmd == OPT::POOL_ADD) {
6266 if (pool_name.empty()) {
6267 cerr << "need to specify pool to add!" << std::endl;
6268 exit(1);
6269 }
6270
6271 int ret = store->svc()->zone->add_bucket_placement(pool);
6272 if (ret < 0)
6273 cerr << "failed to add bucket placement: " << cpp_strerror(-ret) << std::endl;
6274 }
6275
6276 if (opt_cmd == OPT::POOL_RM) {
6277 if (pool_name.empty()) {
6278 cerr << "need to specify pool to remove!" << std::endl;
6279 exit(1);
6280 }
6281
6282 int ret = store->svc()->zone->remove_bucket_placement(pool);
6283 if (ret < 0)
6284 cerr << "failed to remove bucket placement: " << cpp_strerror(-ret) << std::endl;
6285 }
6286
6287 if (opt_cmd == OPT::POOLS_LIST) {
6288 set<rgw_pool> pools;
6289 int ret = store->svc()->zone->list_placement_set(pools);
6290 if (ret < 0) {
6291 cerr << "could not list placement set: " << cpp_strerror(-ret) << std::endl;
6292 return -ret;
6293 }
6294 formatter->reset();
6295 formatter->open_array_section("pools");
6296 for (auto siter = pools.begin(); siter != pools.end(); ++siter) {
6297 formatter->open_object_section("pool");
6298 formatter->dump_string("name", siter->to_str());
6299 formatter->close_section();
6300 }
6301 formatter->close_section();
6302 formatter->flush(cout);
6303 cout << std::endl;
6304 }
6305
6306 if (opt_cmd == OPT::USAGE_SHOW) {
6307 uint64_t start_epoch = 0;
6308 uint64_t end_epoch = (uint64_t)-1;
6309
6310 int ret;
6311
6312 if (!start_date.empty()) {
6313 ret = utime_t::parse_date(start_date, &start_epoch, NULL);
6314 if (ret < 0) {
6315 cerr << "ERROR: failed to parse start date" << std::endl;
6316 return 1;
6317 }
6318 }
6319 if (!end_date.empty()) {
6320 ret = utime_t::parse_date(end_date, &end_epoch, NULL);
6321 if (ret < 0) {
6322 cerr << "ERROR: failed to parse end date" << std::endl;
6323 return 1;
6324 }
6325 }
6326
6327
6328 ret = RGWUsage::show(store->getRados(), user_id, bucket_name, start_epoch, end_epoch,
6329 show_log_entries, show_log_sum, &categories,
6330 f);
6331 if (ret < 0) {
6332 cerr << "ERROR: failed to show usage" << std::endl;
6333 return 1;
6334 }
6335 }
6336
6337 if (opt_cmd == OPT::USAGE_TRIM) {
6338 if (user_id.empty() && bucket_name.empty() &&
6339 start_date.empty() && end_date.empty() && !yes_i_really_mean_it) {
6340 cerr << "usage trim without user/date/bucket specified will remove *all* users data" << std::endl;
6341 cerr << "do you really mean it? (requires --yes-i-really-mean-it)" << std::endl;
6342 return 1;
6343 }
6344 int ret;
6345 uint64_t start_epoch = 0;
6346 uint64_t end_epoch = (uint64_t)-1;
6347
6348
6349 if (!start_date.empty()) {
6350 ret = utime_t::parse_date(start_date, &start_epoch, NULL);
6351 if (ret < 0) {
6352 cerr << "ERROR: failed to parse start date" << std::endl;
6353 return 1;
6354 }
6355 }
6356
6357 if (!end_date.empty()) {
6358 ret = utime_t::parse_date(end_date, &end_epoch, NULL);
6359 if (ret < 0) {
6360 cerr << "ERROR: failed to parse end date" << std::endl;
6361 return 1;
6362 }
6363 }
6364
6365 ret = RGWUsage::trim(store->getRados(), user_id, bucket_name, start_epoch, end_epoch);
6366 if (ret < 0) {
6367 cerr << "ERROR: read_usage() returned ret=" << ret << std::endl;
6368 return 1;
6369 }
6370 }
6371
6372 if (opt_cmd == OPT::USAGE_CLEAR) {
6373 if (!yes_i_really_mean_it) {
6374 cerr << "usage clear would remove *all* users usage data for all time" << std::endl;
6375 cerr << "do you really mean it? (requires --yes-i-really-mean-it)" << std::endl;
6376 return 1;
6377 }
6378
6379 ret = RGWUsage::clear(store->getRados());
6380 if (ret < 0) {
6381 return ret;
6382 }
6383 }
6384
6385
6386 if (opt_cmd == OPT::OLH_GET || opt_cmd == OPT::OLH_READLOG) {
6387 if (bucket_name.empty()) {
6388 cerr << "ERROR: bucket not specified" << std::endl;
6389 return EINVAL;
6390 }
6391 if (object.empty()) {
6392 cerr << "ERROR: object not specified" << std::endl;
6393 return EINVAL;
6394 }
6395 }
6396
6397 if (opt_cmd == OPT::OLH_GET) {
6398 RGWBucketInfo bucket_info;
6399 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
6400 if (ret < 0) {
6401 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
6402 return -ret;
6403 }
6404 RGWOLHInfo olh;
6405 rgw_obj obj(bucket, object);
6406 ret = store->getRados()->get_olh(bucket_info, obj, &olh);
6407 if (ret < 0) {
6408 cerr << "ERROR: failed reading olh: " << cpp_strerror(-ret) << std::endl;
6409 return -ret;
6410 }
6411 encode_json("olh", olh, formatter);
6412 formatter->flush(cout);
6413 }
6414
6415 if (opt_cmd == OPT::OLH_READLOG) {
6416 RGWBucketInfo bucket_info;
6417 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
6418 if (ret < 0) {
6419 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
6420 return -ret;
6421 }
6422 map<uint64_t, vector<rgw_bucket_olh_log_entry> > log;
6423 bool is_truncated;
6424
6425 RGWObjectCtx rctx(store);
6426 rgw_obj obj(bucket, object);
6427
6428 RGWObjState *state;
6429
6430 ret = store->getRados()->get_obj_state(&rctx, bucket_info, obj, &state, false, null_yield); /* don't follow olh */
6431 if (ret < 0) {
6432 return -ret;
6433 }
6434
6435 ret = store->getRados()->bucket_index_read_olh_log(bucket_info, *state, obj, 0, &log, &is_truncated);
6436 if (ret < 0) {
6437 cerr << "ERROR: failed reading olh: " << cpp_strerror(-ret) << std::endl;
6438 return -ret;
6439 }
6440 formatter->open_object_section("result");
6441 encode_json("is_truncated", is_truncated, formatter);
6442 encode_json("log", log, formatter);
6443 formatter->close_section();
6444 formatter->flush(cout);
6445 }
6446
6447 if (opt_cmd == OPT::BI_GET) {
6448 if (bucket_name.empty()) {
6449 cerr << "ERROR: bucket name not specified" << std::endl;
6450 return EINVAL;
6451 }
6452 if (object.empty()) {
6453 cerr << "ERROR: object not specified" << std::endl;
6454 return EINVAL;
6455 }
6456 RGWBucketInfo bucket_info;
6457 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
6458 if (ret < 0) {
6459 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
6460 return -ret;
6461 }
6462 rgw_obj obj(bucket, object);
6463 if (!object_version.empty()) {
6464 obj.key.set_instance(object_version);
6465 }
6466
6467 rgw_cls_bi_entry entry;
6468
6469 ret = store->getRados()->bi_get(bucket_info, obj, bi_index_type, &entry);
6470 if (ret < 0) {
6471 cerr << "ERROR: bi_get(): " << cpp_strerror(-ret) << std::endl;
6472 return -ret;
6473 }
6474
6475 encode_json("entry", entry, formatter);
6476 formatter->flush(cout);
6477 }
6478
6479 if (opt_cmd == OPT::BI_PUT) {
6480 if (bucket_name.empty()) {
6481 cerr << "ERROR: bucket name not specified" << std::endl;
6482 return EINVAL;
6483 }
6484 RGWBucketInfo bucket_info;
6485 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
6486 if (ret < 0) {
6487 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
6488 return -ret;
6489 }
6490
6491 rgw_cls_bi_entry entry;
6492 cls_rgw_obj_key key;
6493 ret = read_decode_json(infile, entry, &key);
6494 if (ret < 0) {
6495 return 1;
6496 }
6497
6498 rgw_obj obj(bucket, key);
6499
6500 ret = store->getRados()->bi_put(bucket, obj, entry);
6501 if (ret < 0) {
6502 cerr << "ERROR: bi_put(): " << cpp_strerror(-ret) << std::endl;
6503 return -ret;
6504 }
6505 }
6506
6507 if (opt_cmd == OPT::BI_LIST) {
6508 if (bucket_name.empty()) {
6509 cerr << "ERROR: bucket name not specified" << std::endl;
6510 return EINVAL;
6511 }
6512 RGWBucketInfo bucket_info;
6513 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
6514 if (ret < 0) {
6515 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
6516 return -ret;
6517 }
6518
6519 list<rgw_cls_bi_entry> entries;
6520 bool is_truncated;
6521 if (max_entries < 0) {
6522 max_entries = 1000;
6523 }
6524
6525 int max_shards = (bucket_info.num_shards > 0 ? bucket_info.num_shards : 1);
6526
6527 formatter->open_array_section("entries");
6528
6529 int i = (specified_shard_id ? shard_id : 0);
6530 for (; i < max_shards; i++) {
6531 RGWRados::BucketShard bs(store->getRados());
6532 int shard_id = (bucket_info.num_shards > 0 ? i : -1);
6533 int ret = bs.init(bucket, shard_id, nullptr /* no RGWBucketInfo */);
6534 marker.clear();
6535
6536 if (ret < 0) {
6537 cerr << "ERROR: bs.init(bucket=" << bucket << ", shard=" << shard_id << "): " << cpp_strerror(-ret) << std::endl;
6538 return -ret;
6539 }
6540
6541 do {
6542 entries.clear();
6543 ret = store->getRados()->bi_list(bs, object, marker, max_entries, &entries, &is_truncated);
6544 if (ret < 0) {
6545 cerr << "ERROR: bi_list(): " << cpp_strerror(-ret) << std::endl;
6546 return -ret;
6547 }
6548
6549 list<rgw_cls_bi_entry>::iterator iter;
6550 for (iter = entries.begin(); iter != entries.end(); ++iter) {
6551 rgw_cls_bi_entry& entry = *iter;
6552 encode_json("entry", entry, formatter);
6553 marker = entry.idx;
6554 }
6555 formatter->flush(cout);
6556 } while (is_truncated);
6557 formatter->flush(cout);
6558
6559 if (specified_shard_id)
6560 break;
6561 }
6562 formatter->close_section();
6563 formatter->flush(cout);
6564 }
6565
6566 if (opt_cmd == OPT::BI_PURGE) {
6567 if (bucket_name.empty()) {
6568 cerr << "ERROR: bucket name not specified" << std::endl;
6569 return EINVAL;
6570 }
6571 RGWBucketInfo bucket_info;
6572 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
6573 if (ret < 0) {
6574 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
6575 return -ret;
6576 }
6577
6578 RGWBucketInfo cur_bucket_info;
6579 rgw_bucket cur_bucket;
6580 ret = init_bucket(tenant, bucket_name, string(), cur_bucket_info, cur_bucket);
6581 if (ret < 0) {
6582 cerr << "ERROR: could not init current bucket info for bucket_name=" << bucket_name << ": " << cpp_strerror(-ret) << std::endl;
6583 return -ret;
6584 }
6585
6586 if (cur_bucket_info.bucket.bucket_id == bucket_info.bucket.bucket_id && !yes_i_really_mean_it) {
6587 cerr << "specified bucket instance points to a current bucket instance" << std::endl;
6588 cerr << "do you really mean it? (requires --yes-i-really-mean-it)" << std::endl;
6589 return EINVAL;
6590 }
6591
6592 int max_shards = (bucket_info.num_shards > 0 ? bucket_info.num_shards : 1);
6593
6594 for (int i = 0; i < max_shards; i++) {
6595 RGWRados::BucketShard bs(store->getRados());
6596 int shard_id = (bucket_info.num_shards > 0 ? i : -1);
6597 int ret = bs.init(bucket, shard_id, nullptr /* no RGWBucketInfo */);
6598 if (ret < 0) {
6599 cerr << "ERROR: bs.init(bucket=" << bucket << ", shard=" << shard_id << "): " << cpp_strerror(-ret) << std::endl;
6600 return -ret;
6601 }
6602
6603 ret = store->getRados()->bi_remove(bs);
6604 if (ret < 0) {
6605 cerr << "ERROR: failed to remove bucket index object: " << cpp_strerror(-ret) << std::endl;
6606 return -ret;
6607 }
6608 }
6609 }
6610
6611 if (opt_cmd == OPT::OBJECT_PUT) {
6612 if (bucket_name.empty()) {
6613 cerr << "ERROR: bucket not specified" << std::endl;
6614 return EINVAL;
6615 }
6616 if (object.empty()) {
6617 cerr << "ERROR: object not specified" << std::endl;
6618 return EINVAL;
6619 }
6620
6621 RGWDataAccess data_access(store);
6622 rgw_obj_key key(object, object_version);
6623
6624 RGWDataAccess::BucketRef b;
6625 RGWDataAccess::ObjectRef obj;
6626
6627 int ret = data_access.get_bucket(tenant, bucket_name, bucket_id, &b);
6628 if (ret < 0) {
6629 cerr << "ERROR: failed to init bucket: " << cpp_strerror(-ret) << std::endl;
6630 return -ret;
6631 }
6632
6633 ret = b->get_object(key, &obj);
6634 if (ret < 0) {
6635 cerr << "ERROR: failed to get object: " << cpp_strerror(-ret) << std::endl;
6636 return -ret;
6637 }
6638
6639 bufferlist bl;
6640 ret = read_input(infile, bl);
6641 if (ret < 0) {
6642 cerr << "ERROR: failed to read input: " << cpp_strerror(-ret) << std::endl;
6643 }
6644
6645 map<string, bufferlist> attrs;
6646 ret = obj->put(bl, attrs, dpp(), null_yield);
6647 if (ret < 0) {
6648 cerr << "ERROR: put object returned error: " << cpp_strerror(-ret) << std::endl;
6649 }
6650 }
6651
6652 if (opt_cmd == OPT::OBJECT_RM) {
6653 RGWBucketInfo bucket_info;
6654 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
6655 if (ret < 0) {
6656 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
6657 return -ret;
6658 }
6659 rgw_obj_key key(object, object_version);
6660 ret = rgw_remove_object(store, bucket_info, bucket, key);
6661
6662 if (ret < 0) {
6663 cerr << "ERROR: object remove returned: " << cpp_strerror(-ret) << std::endl;
6664 return -ret;
6665 }
6666 }
6667
6668 if (opt_cmd == OPT::OBJECT_REWRITE) {
6669 if (bucket_name.empty()) {
6670 cerr << "ERROR: bucket not specified" << std::endl;
6671 return EINVAL;
6672 }
6673 if (object.empty()) {
6674 cerr << "ERROR: object not specified" << std::endl;
6675 return EINVAL;
6676 }
6677
6678 RGWBucketInfo bucket_info;
6679 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
6680 if (ret < 0) {
6681 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
6682 return -ret;
6683 }
6684
6685 rgw_obj obj(bucket, object);
6686 obj.key.set_instance(object_version);
6687 bool need_rewrite = true;
6688 if (min_rewrite_stripe_size > 0) {
6689 ret = check_min_obj_stripe_size(store, bucket_info, obj, min_rewrite_stripe_size, &need_rewrite);
6690 if (ret < 0) {
6691 ldout(store->ctx(), 0) << "WARNING: check_min_obj_stripe_size failed, r=" << ret << dendl;
6692 }
6693 }
6694 if (need_rewrite) {
6695 ret = store->getRados()->rewrite_obj(bucket_info, obj, dpp(), null_yield);
6696 if (ret < 0) {
6697 cerr << "ERROR: object rewrite returned: " << cpp_strerror(-ret) << std::endl;
6698 return -ret;
6699 }
6700 } else {
6701 ldout(store->ctx(), 20) << "skipped object" << dendl;
6702 }
6703 }
6704
6705 if (opt_cmd == OPT::OBJECTS_EXPIRE) {
6706 if (!store->getRados()->process_expire_objects()) {
6707 cerr << "ERROR: process_expire_objects() processing returned error." << std::endl;
6708 return 1;
6709 }
6710 }
6711
6712 if (opt_cmd == OPT::OBJECTS_EXPIRE_STALE_LIST) {
6713 ret = RGWBucketAdminOp::fix_obj_expiry(store, bucket_op, f, true);
6714 if (ret < 0) {
6715 cerr << "ERROR: listing returned " << cpp_strerror(-ret) << std::endl;
6716 return -ret;
6717 }
6718 }
6719
6720 if (opt_cmd == OPT::OBJECTS_EXPIRE_STALE_RM) {
6721 ret = RGWBucketAdminOp::fix_obj_expiry(store, bucket_op, f, false);
6722 if (ret < 0) {
6723 cerr << "ERROR: removing returned " << cpp_strerror(-ret) << std::endl;
6724 return -ret;
6725 }
6726 }
6727
6728 if (opt_cmd == OPT::BUCKET_REWRITE) {
6729 if (bucket_name.empty()) {
6730 cerr << "ERROR: bucket not specified" << std::endl;
6731 return EINVAL;
6732 }
6733
6734 RGWBucketInfo bucket_info;
6735 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
6736 if (ret < 0) {
6737 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
6738 return -ret;
6739 }
6740
6741 uint64_t start_epoch = 0;
6742 uint64_t end_epoch = 0;
6743
6744 if (!end_date.empty()) {
6745 int ret = utime_t::parse_date(end_date, &end_epoch, NULL);
6746 if (ret < 0) {
6747 cerr << "ERROR: failed to parse end date" << std::endl;
6748 return EINVAL;
6749 }
6750 }
6751 if (!start_date.empty()) {
6752 int ret = utime_t::parse_date(start_date, &start_epoch, NULL);
6753 if (ret < 0) {
6754 cerr << "ERROR: failed to parse start date" << std::endl;
6755 return EINVAL;
6756 }
6757 }
6758
6759 bool is_truncated = true;
6760 bool cls_filtered = true;
6761
6762 rgw_obj_index_key marker;
6763 string empty_prefix;
6764 string empty_delimiter;
6765
6766 formatter->open_object_section("result");
6767 formatter->dump_string("bucket", bucket_name);
6768 formatter->open_array_section("objects");
6769
6770 constexpr uint32_t NUM_ENTRIES = 1000;
6771 uint16_t expansion_factor = 1;
6772 while (is_truncated) {
6773 RGWRados::ent_map_t result;
6774 result.reserve(NUM_ENTRIES);
6775
6776 int r = store->getRados()->cls_bucket_list_ordered(
6777 bucket_info, RGW_NO_SHARD,
6778 marker, empty_prefix, empty_delimiter,
6779 NUM_ENTRIES, true, expansion_factor,
6780 result, &is_truncated, &cls_filtered, &marker,
6781 null_yield,
6782 rgw_bucket_object_check_filter);
6783 if (r < 0 && r != -ENOENT) {
6784 cerr << "ERROR: failed operation r=" << r << std::endl;
6785 } else if (r == -ENOENT) {
6786 break;
6787 }
6788
6789 if (result.size() < NUM_ENTRIES / 8) {
6790 ++expansion_factor;
6791 } else if (result.size() > NUM_ENTRIES * 7 / 8 &&
6792 expansion_factor > 1) {
6793 --expansion_factor;
6794 }
6795
6796 for (auto iter = result.begin(); iter != result.end(); ++iter) {
6797 rgw_obj_key key = iter->second.key;
6798 rgw_bucket_dir_entry& entry = iter->second;
6799
6800 formatter->open_object_section("object");
6801 formatter->dump_string("name", key.name);
6802 formatter->dump_string("instance", key.instance);
6803 formatter->dump_int("size", entry.meta.size);
6804 utime_t ut(entry.meta.mtime);
6805 ut.gmtime(formatter->dump_stream("mtime"));
6806
6807 if ((entry.meta.size < min_rewrite_size) ||
6808 (entry.meta.size > max_rewrite_size) ||
6809 (start_epoch > 0 && start_epoch > (uint64_t)ut.sec()) ||
6810 (end_epoch > 0 && end_epoch < (uint64_t)ut.sec())) {
6811 formatter->dump_string("status", "Skipped");
6812 } else {
6813 rgw_obj obj(bucket, key);
6814
6815 bool need_rewrite = true;
6816 if (min_rewrite_stripe_size > 0) {
6817 r = check_min_obj_stripe_size(store, bucket_info, obj, min_rewrite_stripe_size, &need_rewrite);
6818 if (r < 0) {
6819 ldout(store->ctx(), 0) << "WARNING: check_min_obj_stripe_size failed, r=" << r << dendl;
6820 }
6821 }
6822 if (!need_rewrite) {
6823 formatter->dump_string("status", "Skipped");
6824 } else {
6825 r = store->getRados()->rewrite_obj(bucket_info, obj, dpp(), null_yield);
6826 if (r == 0) {
6827 formatter->dump_string("status", "Success");
6828 } else {
6829 formatter->dump_string("status", cpp_strerror(-r));
6830 }
6831 }
6832 }
6833 formatter->dump_int("flags", entry.flags);
6834
6835 formatter->close_section();
6836 formatter->flush(cout);
6837 }
6838 }
6839 formatter->close_section();
6840 formatter->close_section();
6841 formatter->flush(cout);
6842 }
6843
6844 if (opt_cmd == OPT::BUCKET_RESHARD) {
6845 rgw_bucket bucket;
6846 RGWBucketInfo bucket_info;
6847 map<string, bufferlist> attrs;
6848
6849 int ret = check_reshard_bucket_params(store,
6850 bucket_name,
6851 tenant,
6852 bucket_id,
6853 num_shards_specified,
6854 num_shards,
6855 yes_i_really_mean_it,
6856 bucket,
6857 bucket_info,
6858 attrs);
6859 if (ret < 0) {
6860 return ret;
6861 }
6862
6863 RGWBucketReshard br(store, bucket_info, attrs, nullptr /* no callback */);
6864
6865 #define DEFAULT_RESHARD_MAX_ENTRIES 1000
6866 if (max_entries < 1) {
6867 max_entries = DEFAULT_RESHARD_MAX_ENTRIES;
6868 }
6869
6870 return br.execute(num_shards, max_entries,
6871 verbose, &cout, formatter);
6872 }
6873
6874 if (opt_cmd == OPT::RESHARD_ADD) {
6875 rgw_bucket bucket;
6876 RGWBucketInfo bucket_info;
6877 map<string, bufferlist> attrs;
6878
6879 int ret = check_reshard_bucket_params(store,
6880 bucket_name,
6881 tenant,
6882 bucket_id,
6883 num_shards_specified,
6884 num_shards,
6885 yes_i_really_mean_it,
6886 bucket,
6887 bucket_info,
6888 attrs);
6889 if (ret < 0) {
6890 return ret;
6891 }
6892
6893 int num_source_shards = (bucket_info.num_shards > 0 ? bucket_info.num_shards : 1);
6894
6895 RGWReshard reshard(store);
6896 cls_rgw_reshard_entry entry;
6897 entry.time = real_clock::now();
6898 entry.tenant = tenant;
6899 entry.bucket_name = bucket_name;
6900 entry.bucket_id = bucket_info.bucket.bucket_id;
6901 entry.old_num_shards = num_source_shards;
6902 entry.new_num_shards = num_shards;
6903
6904 return reshard.add(entry);
6905 }
6906
6907 if (opt_cmd == OPT::RESHARD_LIST) {
6908 list<cls_rgw_reshard_entry> entries;
6909 int ret;
6910 int count = 0;
6911 if (max_entries < 0) {
6912 max_entries = 1000;
6913 }
6914
6915 int num_logshards =
6916 store->ctx()->_conf.get_val<uint64_t>("rgw_reshard_num_logs");
6917
6918 RGWReshard reshard(store);
6919
6920 formatter->open_array_section("reshard");
6921 for (int i = 0; i < num_logshards; i++) {
6922 bool is_truncated = true;
6923 string marker;
6924 do {
6925 entries.clear();
6926 ret = reshard.list(i, marker, max_entries - count, entries, &is_truncated);
6927 if (ret < 0) {
6928 cerr << "Error listing resharding buckets: " << cpp_strerror(-ret) << std::endl;
6929 return ret;
6930 }
6931 for (auto iter=entries.begin(); iter != entries.end(); ++iter) {
6932 cls_rgw_reshard_entry& entry = *iter;
6933 encode_json("entry", entry, formatter);
6934 entry.get_key(&marker);
6935 }
6936 count += entries.size();
6937 formatter->flush(cout);
6938 } while (is_truncated && count < max_entries);
6939
6940 if (count >= max_entries) {
6941 break;
6942 }
6943 }
6944
6945 formatter->close_section();
6946 formatter->flush(cout);
6947 return 0;
6948 }
6949
6950 if (opt_cmd == OPT::RESHARD_STATUS) {
6951 if (bucket_name.empty()) {
6952 cerr << "ERROR: bucket not specified" << std::endl;
6953 return EINVAL;
6954 }
6955
6956 rgw_bucket bucket;
6957 RGWBucketInfo bucket_info;
6958 map<string, bufferlist> attrs;
6959 ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket, &attrs);
6960 if (ret < 0) {
6961 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
6962 return -ret;
6963 }
6964
6965 RGWBucketReshard br(store, bucket_info, attrs, nullptr /* no callback */);
6966 list<cls_rgw_bucket_instance_entry> status;
6967 int r = br.get_status(&status);
6968 if (r < 0) {
6969 cerr << "ERROR: could not get resharding status for bucket " <<
6970 bucket_name << std::endl;
6971 return -r;
6972 }
6973
6974 show_reshard_status(status, formatter);
6975 }
6976
6977 if (opt_cmd == OPT::RESHARD_PROCESS) {
6978 RGWReshard reshard(store, true, &cout);
6979
6980 int ret = reshard.process_all_logshards();
6981 if (ret < 0) {
6982 cerr << "ERROR: failed to process reshard logs, error=" << cpp_strerror(-ret) << std::endl;
6983 return -ret;
6984 }
6985 }
6986
6987 if (opt_cmd == OPT::RESHARD_CANCEL) {
6988 if (bucket_name.empty()) {
6989 cerr << "ERROR: bucket not specified" << std::endl;
6990 return EINVAL;
6991 }
6992
6993 rgw_bucket bucket;
6994 RGWBucketInfo bucket_info;
6995 map<string, bufferlist> attrs;
6996 bool bucket_initable = true;
6997 ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket,
6998 &attrs);
6999 if (ret < 0) {
7000 if (yes_i_really_mean_it) {
7001 bucket_initable = false;
7002 } else {
7003 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) <<
7004 "; if you want to cancel the reshard request nonetheless, please "
7005 "use the --yes-i-really-mean-it option" << std::endl;
7006 return -ret;
7007 }
7008 }
7009
7010 if (bucket_initable) {
7011 // we did not encounter an error, so let's work with the bucket
7012 RGWBucketReshard br(store, bucket_info, attrs,
7013 nullptr /* no callback */);
7014 int ret = br.cancel();
7015 if (ret < 0) {
7016 if (ret == -EBUSY) {
7017 cerr << "There is ongoing resharding, please retry after " <<
7018 store->ctx()->_conf.get_val<uint64_t>(
7019 "rgw_reshard_bucket_lock_duration") <<
7020 " seconds " << std::endl;
7021 } else {
7022 cerr << "Error canceling bucket " << bucket_name <<
7023 " resharding: " << cpp_strerror(-ret) << std::endl;
7024 }
7025 return ret;
7026 }
7027 }
7028
7029 RGWReshard reshard(store);
7030
7031 cls_rgw_reshard_entry entry;
7032 entry.tenant = tenant;
7033 entry.bucket_name = bucket_name;
7034 //entry.bucket_id = bucket_id;
7035
7036 ret = reshard.remove(entry);
7037 if (ret < 0 && ret != -ENOENT) {
7038 cerr << "Error in updating reshard log with bucket " <<
7039 bucket_name << ": " << cpp_strerror(-ret) << std::endl;
7040 return ret;
7041 }
7042 } // OPT_RESHARD_CANCEL
7043
7044 if (opt_cmd == OPT::OBJECT_UNLINK) {
7045 RGWBucketInfo bucket_info;
7046 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
7047 if (ret < 0) {
7048 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7049 return -ret;
7050 }
7051 list<rgw_obj_index_key> oid_list;
7052 rgw_obj_key key(object, object_version);
7053 rgw_obj_index_key index_key;
7054 key.get_index_key(&index_key);
7055 oid_list.push_back(index_key);
7056 ret = store->getRados()->remove_objs_from_index(bucket_info, oid_list);
7057 if (ret < 0) {
7058 cerr << "ERROR: remove_obj_from_index() returned error: " << cpp_strerror(-ret) << std::endl;
7059 return 1;
7060 }
7061 }
7062
7063 if (opt_cmd == OPT::OBJECT_STAT) {
7064 RGWBucketInfo bucket_info;
7065 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
7066 if (ret < 0) {
7067 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7068 return -ret;
7069 }
7070 rgw_obj obj(bucket, object);
7071 obj.key.set_instance(object_version);
7072
7073 uint64_t obj_size;
7074 map<string, bufferlist> attrs;
7075 RGWObjectCtx obj_ctx(store);
7076 RGWRados::Object op_target(store->getRados(), bucket_info, obj_ctx, obj);
7077 RGWRados::Object::Read read_op(&op_target);
7078
7079 read_op.params.attrs = &attrs;
7080 read_op.params.obj_size = &obj_size;
7081
7082 ret = read_op.prepare(null_yield);
7083 if (ret < 0) {
7084 cerr << "ERROR: failed to stat object, returned error: " << cpp_strerror(-ret) << std::endl;
7085 return 1;
7086 }
7087 formatter->open_object_section("object_metadata");
7088 formatter->dump_string("name", object);
7089 formatter->dump_unsigned("size", obj_size);
7090
7091 map<string, bufferlist>::iterator iter;
7092 map<string, bufferlist> other_attrs;
7093 for (iter = attrs.begin(); iter != attrs.end(); ++iter) {
7094 bufferlist& bl = iter->second;
7095 bool handled = false;
7096 if (iter->first == RGW_ATTR_MANIFEST) {
7097 handled = decode_dump<RGWObjManifest>("manifest", bl, formatter);
7098 } else if (iter->first == RGW_ATTR_ACL) {
7099 handled = decode_dump<RGWAccessControlPolicy>("policy", bl, formatter);
7100 } else if (iter->first == RGW_ATTR_ID_TAG) {
7101 handled = dump_string("tag", bl, formatter);
7102 } else if (iter->first == RGW_ATTR_ETAG) {
7103 handled = dump_string("etag", bl, formatter);
7104 } else if (iter->first == RGW_ATTR_COMPRESSION) {
7105 handled = decode_dump<RGWCompressionInfo>("compression", bl, formatter);
7106 } else if (iter->first == RGW_ATTR_DELETE_AT) {
7107 handled = decode_dump<utime_t>("delete_at", bl, formatter);
7108 }
7109
7110 if (!handled)
7111 other_attrs[iter->first] = bl;
7112 }
7113
7114 formatter->open_object_section("attrs");
7115 for (iter = other_attrs.begin(); iter != other_attrs.end(); ++iter) {
7116 dump_string(iter->first.c_str(), iter->second, formatter);
7117 }
7118 formatter->close_section();
7119 formatter->close_section();
7120 formatter->flush(cout);
7121 }
7122
7123 if (opt_cmd == OPT::BUCKET_CHECK) {
7124 if (check_head_obj_locator) {
7125 if (bucket_name.empty()) {
7126 cerr << "ERROR: need to specify bucket name" << std::endl;
7127 return EINVAL;
7128 }
7129 do_check_object_locator(tenant, bucket_name, fix, remove_bad, formatter);
7130 } else {
7131 RGWBucketAdminOp::check_index(store, bucket_op, f, null_yield);
7132 }
7133 }
7134
7135 if (opt_cmd == OPT::BUCKET_RM) {
7136 if (!inconsistent_index) {
7137 RGWBucketAdminOp::remove_bucket(store, bucket_op, null_yield, bypass_gc, true);
7138 } else {
7139 if (!yes_i_really_mean_it) {
7140 cerr << "using --inconsistent_index can corrupt the bucket index " << std::endl
7141 << "do you really mean it? (requires --yes-i-really-mean-it)" << std::endl;
7142 return 1;
7143 }
7144 RGWBucketAdminOp::remove_bucket(store, bucket_op, null_yield, bypass_gc, false);
7145 }
7146 }
7147
7148 if (opt_cmd == OPT::GC_LIST) {
7149 int index = 0;
7150 bool truncated;
7151 bool processing_queue = false;
7152 formatter->open_array_section("entries");
7153
7154 do {
7155 list<cls_rgw_gc_obj_info> result;
7156 int ret = store->getRados()->list_gc_objs(&index, marker, 1000, !include_all, result, &truncated, processing_queue);
7157 if (ret < 0) {
7158 cerr << "ERROR: failed to list objs: " << cpp_strerror(-ret) << std::endl;
7159 return 1;
7160 }
7161
7162
7163 list<cls_rgw_gc_obj_info>::iterator iter;
7164 for (iter = result.begin(); iter != result.end(); ++iter) {
7165 cls_rgw_gc_obj_info& info = *iter;
7166 formatter->open_object_section("chain_info");
7167 formatter->dump_string("tag", info.tag);
7168 formatter->dump_stream("time") << info.time;
7169 formatter->open_array_section("objs");
7170 list<cls_rgw_obj>::iterator liter;
7171 cls_rgw_obj_chain& chain = info.chain;
7172 for (liter = chain.objs.begin(); liter != chain.objs.end(); ++liter) {
7173 cls_rgw_obj& obj = *liter;
7174 encode_json("obj", obj, formatter);
7175 }
7176 formatter->close_section(); // objs
7177 formatter->close_section(); // obj_chain
7178 formatter->flush(cout);
7179 }
7180 } while (truncated);
7181 formatter->close_section();
7182 formatter->flush(cout);
7183 }
7184
7185 if (opt_cmd == OPT::GC_PROCESS) {
7186 int ret = store->getRados()->process_gc(!include_all);
7187 if (ret < 0) {
7188 cerr << "ERROR: gc processing returned error: " << cpp_strerror(-ret) << std::endl;
7189 return 1;
7190 }
7191 }
7192
7193 if (opt_cmd == OPT::LC_LIST) {
7194 formatter->open_array_section("lifecycle_list");
7195 map<string, int> bucket_lc_map;
7196 string marker;
7197 #define MAX_LC_LIST_ENTRIES 100
7198 if (max_entries < 0) {
7199 max_entries = MAX_LC_LIST_ENTRIES;
7200 }
7201 do {
7202 int ret = store->getRados()->list_lc_progress(marker, max_entries, &bucket_lc_map);
7203 if (ret < 0) {
7204 cerr << "ERROR: failed to list objs: " << cpp_strerror(-ret) << std::endl;
7205 return 1;
7206 }
7207 map<string, int>::iterator iter;
7208 for (iter = bucket_lc_map.begin(); iter != bucket_lc_map.end(); ++iter) {
7209 formatter->open_object_section("bucket_lc_info");
7210 formatter->dump_string("bucket", iter->first);
7211 string lc_status = LC_STATUS[iter->second];
7212 formatter->dump_string("status", lc_status);
7213 formatter->close_section(); // objs
7214 formatter->flush(cout);
7215 marker = iter->first;
7216 }
7217 } while (!bucket_lc_map.empty());
7218
7219 formatter->close_section(); //lifecycle list
7220 formatter->flush(cout);
7221 }
7222
7223
7224 if (opt_cmd == OPT::LC_GET) {
7225 if (bucket_name.empty()) {
7226 cerr << "ERROR: bucket not specified" << std::endl;
7227 return EINVAL;
7228 }
7229
7230 rgw_bucket bucket;
7231 RGWBucketInfo bucket_info;
7232 map<string, bufferlist> attrs;
7233 RGWLifecycleConfiguration config;
7234 ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket, &attrs);
7235 if (ret < 0) {
7236 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7237 return -ret;
7238 }
7239
7240 auto aiter = attrs.find(RGW_ATTR_LC);
7241 if (aiter == attrs.end()) {
7242 return -ENOENT;
7243 }
7244
7245 bufferlist::const_iterator iter{&aiter->second};
7246 try {
7247 config.decode(iter);
7248 } catch (const buffer::error& e) {
7249 cerr << "ERROR: decode life cycle config failed" << std::endl;
7250 return -EIO;
7251 }
7252
7253 encode_json("result", config, formatter);
7254 formatter->flush(cout);
7255 }
7256
7257 if (opt_cmd == OPT::LC_PROCESS) {
7258 int ret = store->getRados()->process_lc();
7259 if (ret < 0) {
7260 cerr << "ERROR: lc processing returned error: " << cpp_strerror(-ret) << std::endl;
7261 return 1;
7262 }
7263 }
7264
7265
7266 if (opt_cmd == OPT::LC_RESHARD_FIX) {
7267 ret = RGWBucketAdminOp::fix_lc_shards(store, bucket_op,f);
7268 if (ret < 0) {
7269 cerr << "ERROR: listing stale instances" << cpp_strerror(-ret) << std::endl;
7270 }
7271
7272 }
7273
7274 if (opt_cmd == OPT::ORPHANS_FIND) {
7275 if (!yes_i_really_mean_it) {
7276 cerr << "accidental removal of active objects can not be reversed; "
7277 << "do you really mean it? (requires --yes-i-really-mean-it)"
7278 << std::endl;
7279 return EINVAL;
7280 }
7281
7282 RGWOrphanSearch search(store, max_concurrent_ios, orphan_stale_secs);
7283
7284 if (job_id.empty()) {
7285 cerr << "ERROR: --job-id not specified" << std::endl;
7286 return EINVAL;
7287 }
7288 if (pool_name.empty()) {
7289 cerr << "ERROR: --pool not specified" << std::endl;
7290 return EINVAL;
7291 }
7292
7293 RGWOrphanSearchInfo info;
7294
7295 info.pool = pool;
7296 info.job_name = job_id;
7297 info.num_shards = num_shards;
7298
7299 int ret = search.init(job_id, &info, detail);
7300 if (ret < 0) {
7301 cerr << "could not init search, ret=" << ret << std::endl;
7302 return -ret;
7303 }
7304 ret = search.run();
7305 if (ret < 0) {
7306 return -ret;
7307 }
7308 }
7309
7310 if (opt_cmd == OPT::ORPHANS_FINISH) {
7311 RGWOrphanSearch search(store, max_concurrent_ios, orphan_stale_secs);
7312
7313 if (job_id.empty()) {
7314 cerr << "ERROR: --job-id not specified" << std::endl;
7315 return EINVAL;
7316 }
7317 int ret = search.init(job_id, NULL);
7318 if (ret < 0) {
7319 if (ret == -ENOENT) {
7320 cerr << "job not found" << std::endl;
7321 }
7322 return -ret;
7323 }
7324 ret = search.finish();
7325 if (ret < 0) {
7326 return -ret;
7327 }
7328 }
7329
7330 if (opt_cmd == OPT::ORPHANS_LIST_JOBS){
7331 RGWOrphanStore orphan_store(store);
7332 int ret = orphan_store.init();
7333 if (ret < 0){
7334 cerr << "connection to cluster failed!" << std::endl;
7335 return -ret;
7336 }
7337
7338 map <string,RGWOrphanSearchState> m;
7339 ret = orphan_store.list_jobs(m);
7340 if (ret < 0) {
7341 cerr << "job list failed" << std::endl;
7342 return -ret;
7343 }
7344 formatter->open_array_section("entries");
7345 for (const auto &it: m){
7346 if (!extra_info){
7347 formatter->dump_string("job-id",it.first);
7348 } else {
7349 encode_json("orphan_search_state", it.second, formatter);
7350 }
7351 }
7352 formatter->close_section();
7353 formatter->flush(cout);
7354 }
7355
7356 if (opt_cmd == OPT::USER_CHECK) {
7357 check_bad_user_bucket_mapping(store, user_id, fix);
7358 }
7359
7360 if (opt_cmd == OPT::USER_STATS) {
7361 if (user_id.empty()) {
7362 cerr << "ERROR: uid not specified" << std::endl;
7363 return EINVAL;
7364 }
7365
7366 if (reset_stats) {
7367 if (!bucket_name.empty()) {
7368 cerr << "ERROR: --reset-stats does not work on buckets and "
7369 "bucket specified" << std::endl;
7370 return EINVAL;
7371 }
7372 if (sync_stats) {
7373 cerr << "ERROR: sync-stats includes the reset-stats functionality, "
7374 "so at most one of the two should be specified" << std::endl;
7375 return EINVAL;
7376 }
7377 ret = store->ctl()->user->reset_stats(user_id);
7378 if (ret < 0) {
7379 cerr << "ERROR: could not reset user stats: " << cpp_strerror(-ret) <<
7380 std::endl;
7381 return -ret;
7382 }
7383 }
7384
7385 if (sync_stats) {
7386 if (!bucket_name.empty()) {
7387 RGWBucketInfo bucket_info;
7388 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
7389 if (ret < 0) {
7390 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7391 return -ret;
7392 }
7393 ret = store->ctl()->bucket->sync_user_stats(user_id, bucket_info);
7394 if (ret < 0) {
7395 cerr << "ERROR: could not sync bucket stats: " <<
7396 cpp_strerror(-ret) << std::endl;
7397 return -ret;
7398 }
7399 } else {
7400 int ret = rgw_user_sync_all_stats(store, user_id);
7401 if (ret < 0) {
7402 cerr << "ERROR: could not sync user stats: " <<
7403 cpp_strerror(-ret) << std::endl;
7404 return -ret;
7405 }
7406 }
7407 }
7408
7409 RGWStorageStats stats;
7410 ceph::real_time last_stats_sync;
7411 ceph::real_time last_stats_update;
7412 int ret = store->ctl()->user->read_stats(user_id, &stats, &last_stats_sync, &last_stats_update);
7413 if (ret < 0) {
7414 if (ret == -ENOENT) { /* in case of ENOENT */
7415 cerr << "User has not been initialized or user does not exist" << std::endl;
7416 } else {
7417 cerr << "ERROR: can't read user: " << cpp_strerror(ret) << std::endl;
7418 }
7419 return -ret;
7420 }
7421
7422
7423 {
7424 Formatter::ObjectSection os(*formatter, "result");
7425 encode_json("stats", stats, formatter);
7426 utime_t last_sync_ut(last_stats_sync);
7427 encode_json("last_stats_sync", last_sync_ut, formatter);
7428 utime_t last_update_ut(last_stats_update);
7429 encode_json("last_stats_update", last_update_ut, formatter);
7430 }
7431 formatter->flush(cout);
7432 }
7433
7434 if (opt_cmd == OPT::METADATA_GET) {
7435 int ret = store->ctl()->meta.mgr->get(metadata_key, formatter, null_yield);
7436 if (ret < 0) {
7437 cerr << "ERROR: can't get key: " << cpp_strerror(-ret) << std::endl;
7438 return -ret;
7439 }
7440
7441 formatter->flush(cout);
7442 }
7443
7444 if (opt_cmd == OPT::METADATA_PUT) {
7445 bufferlist bl;
7446 int ret = read_input(infile, bl);
7447 if (ret < 0) {
7448 cerr << "ERROR: failed to read input: " << cpp_strerror(-ret) << std::endl;
7449 return -ret;
7450 }
7451 ret = store->ctl()->meta.mgr->put(metadata_key, bl, null_yield, RGWMDLogSyncType::APPLY_ALWAYS);
7452 if (ret < 0) {
7453 cerr << "ERROR: can't put key: " << cpp_strerror(-ret) << std::endl;
7454 return -ret;
7455 }
7456 }
7457
7458 if (opt_cmd == OPT::METADATA_RM) {
7459 int ret = store->ctl()->meta.mgr->remove(metadata_key, null_yield);
7460 if (ret < 0) {
7461 cerr << "ERROR: can't remove key: " << cpp_strerror(-ret) << std::endl;
7462 return -ret;
7463 }
7464 }
7465
7466 if (opt_cmd == OPT::METADATA_LIST || opt_cmd == OPT::USER_LIST) {
7467 if (opt_cmd == OPT::USER_LIST) {
7468 metadata_key = "user";
7469 }
7470 void *handle;
7471 int max = 1000;
7472 int ret = store->ctl()->meta.mgr->list_keys_init(metadata_key, marker, &handle);
7473 if (ret < 0) {
7474 cerr << "ERROR: can't get key: " << cpp_strerror(-ret) << std::endl;
7475 return -ret;
7476 }
7477
7478 bool truncated;
7479 uint64_t count = 0;
7480
7481 if (max_entries_specified) {
7482 formatter->open_object_section("result");
7483 }
7484 formatter->open_array_section("keys");
7485
7486 uint64_t left;
7487 do {
7488 list<string> keys;
7489 left = (max_entries_specified ? max_entries - count : max);
7490 ret = store->ctl()->meta.mgr->list_keys_next(handle, left, keys, &truncated);
7491 if (ret < 0 && ret != -ENOENT) {
7492 cerr << "ERROR: lists_keys_next(): " << cpp_strerror(-ret) << std::endl;
7493 return -ret;
7494 } if (ret != -ENOENT) {
7495 for (list<string>::iterator iter = keys.begin(); iter != keys.end(); ++iter) {
7496 formatter->dump_string("key", *iter);
7497 ++count;
7498 }
7499 formatter->flush(cout);
7500 }
7501 } while (truncated && left > 0);
7502
7503 formatter->close_section();
7504
7505 if (max_entries_specified) {
7506 encode_json("truncated", truncated, formatter);
7507 encode_json("count", count, formatter);
7508 if (truncated) {
7509 encode_json("marker", store->ctl()->meta.mgr->get_marker(handle), formatter);
7510 }
7511 formatter->close_section();
7512 }
7513 formatter->flush(cout);
7514
7515 store->ctl()->meta.mgr->list_keys_complete(handle);
7516 }
7517
7518 if (opt_cmd == OPT::MDLOG_LIST) {
7519 utime_t start_time, end_time;
7520
7521 int ret = parse_date_str(start_date, start_time);
7522 if (ret < 0)
7523 return -ret;
7524
7525 ret = parse_date_str(end_date, end_time);
7526 if (ret < 0)
7527 return -ret;
7528
7529 int i = (specified_shard_id ? shard_id : 0);
7530
7531 if (period_id.empty()) {
7532 int ret = read_current_period_id(store, realm_id, realm_name, &period_id);
7533 if (ret < 0) {
7534 return -ret;
7535 }
7536 std::cerr << "No --period given, using current period="
7537 << period_id << std::endl;
7538 }
7539 RGWMetadataLog *meta_log = store->svc()->mdlog->get_log(period_id);
7540
7541 formatter->open_array_section("entries");
7542 for (; i < g_ceph_context->_conf->rgw_md_log_max_shards; i++) {
7543 void *handle;
7544 list<cls_log_entry> entries;
7545
7546
7547 meta_log->init_list_entries(i, start_time.to_real_time(), end_time.to_real_time(), marker, &handle);
7548 bool truncated;
7549 do {
7550 int ret = meta_log->list_entries(handle, 1000, entries, NULL, &truncated);
7551 if (ret < 0) {
7552 cerr << "ERROR: meta_log->list_entries(): " << cpp_strerror(-ret) << std::endl;
7553 return -ret;
7554 }
7555
7556 for (list<cls_log_entry>::iterator iter = entries.begin(); iter != entries.end(); ++iter) {
7557 cls_log_entry& entry = *iter;
7558 store->ctl()->meta.mgr->dump_log_entry(entry, formatter);
7559 }
7560 formatter->flush(cout);
7561 } while (truncated);
7562
7563 meta_log->complete_list_entries(handle);
7564
7565 if (specified_shard_id)
7566 break;
7567 }
7568
7569
7570 formatter->close_section();
7571 formatter->flush(cout);
7572 }
7573
7574 if (opt_cmd == OPT::MDLOG_STATUS) {
7575 int i = (specified_shard_id ? shard_id : 0);
7576
7577 if (period_id.empty()) {
7578 int ret = read_current_period_id(store, realm_id, realm_name, &period_id);
7579 if (ret < 0) {
7580 return -ret;
7581 }
7582 std::cerr << "No --period given, using current period="
7583 << period_id << std::endl;
7584 }
7585 RGWMetadataLog *meta_log = store->svc()->mdlog->get_log(period_id);
7586
7587 formatter->open_array_section("entries");
7588
7589 for (; i < g_ceph_context->_conf->rgw_md_log_max_shards; i++) {
7590 RGWMetadataLogInfo info;
7591 meta_log->get_info(i, &info);
7592
7593 ::encode_json("info", info, formatter);
7594
7595 if (specified_shard_id)
7596 break;
7597 }
7598
7599
7600 formatter->close_section();
7601 formatter->flush(cout);
7602 }
7603
7604 if (opt_cmd == OPT::MDLOG_AUTOTRIM) {
7605 // need a full history for purging old mdlog periods
7606 store->svc()->mdlog->init_oldest_log_period();
7607
7608 RGWCoroutinesManager crs(store->ctx(), store->getRados()->get_cr_registry());
7609 RGWHTTPManager http(store->ctx(), crs.get_completion_mgr());
7610 int ret = http.start();
7611 if (ret < 0) {
7612 cerr << "failed to initialize http client with " << cpp_strerror(ret) << std::endl;
7613 return -ret;
7614 }
7615
7616 auto num_shards = g_conf()->rgw_md_log_max_shards;
7617 ret = crs.run(create_admin_meta_log_trim_cr(dpp(), store, &http, num_shards));
7618 if (ret < 0) {
7619 cerr << "automated mdlog trim failed with " << cpp_strerror(ret) << std::endl;
7620 return -ret;
7621 }
7622 }
7623
7624 if (opt_cmd == OPT::MDLOG_TRIM) {
7625 utime_t start_time, end_time;
7626
7627 if (!specified_shard_id) {
7628 cerr << "ERROR: shard-id must be specified for trim operation" << std::endl;
7629 return EINVAL;
7630 }
7631
7632 int ret = parse_date_str(start_date, start_time);
7633 if (ret < 0)
7634 return -ret;
7635
7636 ret = parse_date_str(end_date, end_time);
7637 if (ret < 0)
7638 return -ret;
7639
7640 if (period_id.empty()) {
7641 std::cerr << "missing --period argument" << std::endl;
7642 return EINVAL;
7643 }
7644 RGWMetadataLog *meta_log = store->svc()->mdlog->get_log(period_id);
7645
7646 // trim until -ENODATA
7647 do {
7648 ret = meta_log->trim(shard_id, start_time.to_real_time(),
7649 end_time.to_real_time(), start_marker, end_marker);
7650 } while (ret == 0);
7651 if (ret < 0 && ret != -ENODATA) {
7652 cerr << "ERROR: meta_log->trim(): " << cpp_strerror(-ret) << std::endl;
7653 return -ret;
7654 }
7655 }
7656
7657 if (opt_cmd == OPT::SYNC_INFO) {
7658 sync_info(opt_effective_zone_id, opt_bucket, zone_formatter);
7659 }
7660
7661 if (opt_cmd == OPT::SYNC_STATUS) {
7662 sync_status(formatter);
7663 }
7664
7665 if (opt_cmd == OPT::METADATA_SYNC_STATUS) {
7666 RGWMetaSyncStatusManager sync(store, store->svc()->rados->get_async_processor());
7667
7668 int ret = sync.init();
7669 if (ret < 0) {
7670 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
7671 return -ret;
7672 }
7673
7674 rgw_meta_sync_status sync_status;
7675 ret = sync.read_sync_status(&sync_status);
7676 if (ret < 0) {
7677 cerr << "ERROR: sync.read_sync_status() returned ret=" << ret << std::endl;
7678 return -ret;
7679 }
7680
7681 formatter->open_object_section("summary");
7682 encode_json("sync_status", sync_status, formatter);
7683
7684 uint64_t full_total = 0;
7685 uint64_t full_complete = 0;
7686
7687 for (auto marker_iter : sync_status.sync_markers) {
7688 full_total += marker_iter.second.total_entries;
7689 if (marker_iter.second.state == rgw_meta_sync_marker::SyncState::FullSync) {
7690 full_complete += marker_iter.second.pos;
7691 } else {
7692 full_complete += marker_iter.second.total_entries;
7693 }
7694 }
7695
7696 formatter->open_object_section("full_sync");
7697 encode_json("total", full_total, formatter);
7698 encode_json("complete", full_complete, formatter);
7699 formatter->close_section();
7700 formatter->close_section();
7701
7702 formatter->flush(cout);
7703
7704 }
7705
7706 if (opt_cmd == OPT::METADATA_SYNC_INIT) {
7707 RGWMetaSyncStatusManager sync(store, store->svc()->rados->get_async_processor());
7708
7709 int ret = sync.init();
7710 if (ret < 0) {
7711 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
7712 return -ret;
7713 }
7714 ret = sync.init_sync_status();
7715 if (ret < 0) {
7716 cerr << "ERROR: sync.init_sync_status() returned ret=" << ret << std::endl;
7717 return -ret;
7718 }
7719 }
7720
7721
7722 if (opt_cmd == OPT::METADATA_SYNC_RUN) {
7723 RGWMetaSyncStatusManager sync(store, store->svc()->rados->get_async_processor());
7724
7725 int ret = sync.init();
7726 if (ret < 0) {
7727 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
7728 return -ret;
7729 }
7730
7731 ret = sync.run();
7732 if (ret < 0) {
7733 cerr << "ERROR: sync.run() returned ret=" << ret << std::endl;
7734 return -ret;
7735 }
7736 }
7737
7738 if (opt_cmd == OPT::DATA_SYNC_STATUS) {
7739 if (source_zone.empty()) {
7740 cerr << "ERROR: source zone not specified" << std::endl;
7741 return EINVAL;
7742 }
7743 RGWDataSyncStatusManager sync(store, store->svc()->rados->get_async_processor(), source_zone, nullptr);
7744
7745 int ret = sync.init();
7746 if (ret < 0) {
7747 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
7748 return -ret;
7749 }
7750
7751 rgw_data_sync_status sync_status;
7752 if (specified_shard_id) {
7753 set<string> pending_buckets;
7754 set<string> recovering_buckets;
7755 rgw_data_sync_marker sync_marker;
7756 ret = sync.read_shard_status(shard_id, pending_buckets, recovering_buckets, &sync_marker,
7757 max_entries_specified ? max_entries : 20);
7758 if (ret < 0 && ret != -ENOENT) {
7759 cerr << "ERROR: sync.read_shard_status() returned ret=" << ret << std::endl;
7760 return -ret;
7761 }
7762 formatter->open_object_section("summary");
7763 encode_json("shard_id", shard_id, formatter);
7764 encode_json("marker", sync_marker, formatter);
7765 encode_json("pending_buckets", pending_buckets, formatter);
7766 encode_json("recovering_buckets", recovering_buckets, formatter);
7767 formatter->close_section();
7768 formatter->flush(cout);
7769 } else {
7770 ret = sync.read_sync_status(&sync_status);
7771 if (ret < 0 && ret != -ENOENT) {
7772 cerr << "ERROR: sync.read_sync_status() returned ret=" << ret << std::endl;
7773 return -ret;
7774 }
7775
7776 formatter->open_object_section("summary");
7777 encode_json("sync_status", sync_status, formatter);
7778
7779 uint64_t full_total = 0;
7780 uint64_t full_complete = 0;
7781
7782 for (auto marker_iter : sync_status.sync_markers) {
7783 full_total += marker_iter.second.total_entries;
7784 if (marker_iter.second.state == rgw_meta_sync_marker::SyncState::FullSync) {
7785 full_complete += marker_iter.second.pos;
7786 } else {
7787 full_complete += marker_iter.second.total_entries;
7788 }
7789 }
7790
7791 formatter->open_object_section("full_sync");
7792 encode_json("total", full_total, formatter);
7793 encode_json("complete", full_complete, formatter);
7794 formatter->close_section();
7795 formatter->close_section();
7796
7797 formatter->flush(cout);
7798 }
7799 }
7800
7801 if (opt_cmd == OPT::DATA_SYNC_INIT) {
7802 if (source_zone.empty()) {
7803 cerr << "ERROR: source zone not specified" << std::endl;
7804 return EINVAL;
7805 }
7806
7807 RGWDataSyncStatusManager sync(store, store->svc()->rados->get_async_processor(), source_zone, nullptr);
7808
7809 int ret = sync.init();
7810 if (ret < 0) {
7811 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
7812 return -ret;
7813 }
7814
7815 ret = sync.init_sync_status();
7816 if (ret < 0) {
7817 cerr << "ERROR: sync.init_sync_status() returned ret=" << ret << std::endl;
7818 return -ret;
7819 }
7820 }
7821
7822 if (opt_cmd == OPT::DATA_SYNC_RUN) {
7823 if (source_zone.empty()) {
7824 cerr << "ERROR: source zone not specified" << std::endl;
7825 return EINVAL;
7826 }
7827
7828 RGWSyncModuleInstanceRef sync_module;
7829 int ret = store->svc()->sync_modules->get_manager()->create_instance(g_ceph_context, store->svc()->zone->get_zone().tier_type,
7830 store->svc()->zone->get_zone_params().tier_config, &sync_module);
7831 if (ret < 0) {
7832 lderr(cct) << "ERROR: failed to init sync module instance, ret=" << ret << dendl;
7833 return ret;
7834 }
7835
7836 RGWDataSyncStatusManager sync(store, store->svc()->rados->get_async_processor(), source_zone, nullptr, sync_module);
7837
7838 ret = sync.init();
7839 if (ret < 0) {
7840 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
7841 return -ret;
7842 }
7843
7844 ret = sync.run();
7845 if (ret < 0) {
7846 cerr << "ERROR: sync.run() returned ret=" << ret << std::endl;
7847 return -ret;
7848 }
7849 }
7850
7851 if (opt_cmd == OPT::BUCKET_SYNC_INIT) {
7852 if (source_zone.empty()) {
7853 cerr << "ERROR: source zone not specified" << std::endl;
7854 return EINVAL;
7855 }
7856 if (bucket_name.empty()) {
7857 cerr << "ERROR: bucket not specified" << std::endl;
7858 return EINVAL;
7859 }
7860 rgw_bucket bucket;
7861 int ret = init_bucket_for_sync(tenant, bucket_name, bucket_id, bucket);
7862 if (ret < 0) {
7863 return -ret;
7864 }
7865 auto opt_sb = opt_source_bucket;
7866 if (opt_sb && opt_sb->bucket_id.empty()) {
7867 string sbid;
7868 rgw_bucket sbuck;
7869 int ret = init_bucket_for_sync(opt_sb->tenant, opt_sb->name, sbid, sbuck);
7870 if (ret < 0) {
7871 return -ret;
7872 }
7873 opt_sb = sbuck;
7874 }
7875
7876 RGWBucketPipeSyncStatusManager sync(store, source_zone, opt_sb, bucket);
7877
7878 ret = sync.init();
7879 if (ret < 0) {
7880 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
7881 return -ret;
7882 }
7883 ret = sync.init_sync_status();
7884 if (ret < 0) {
7885 cerr << "ERROR: sync.init_sync_status() returned ret=" << ret << std::endl;
7886 return -ret;
7887 }
7888 }
7889
7890 if ((opt_cmd == OPT::BUCKET_SYNC_DISABLE) || (opt_cmd == OPT::BUCKET_SYNC_ENABLE)) {
7891 if (bucket_name.empty()) {
7892 cerr << "ERROR: bucket not specified" << std::endl;
7893 return EINVAL;
7894 }
7895 if (opt_cmd == OPT::BUCKET_SYNC_DISABLE) {
7896 bucket_op.set_sync_bucket(false);
7897 } else {
7898 bucket_op.set_sync_bucket(true);
7899 }
7900 bucket_op.set_tenant(tenant);
7901 string err_msg;
7902 ret = RGWBucketAdminOp::sync_bucket(store, bucket_op, &err_msg);
7903 if (ret < 0) {
7904 cerr << err_msg << std::endl;
7905 return -ret;
7906 }
7907 }
7908
7909 if (opt_cmd == OPT::BUCKET_SYNC_INFO) {
7910 if (bucket_name.empty()) {
7911 cerr << "ERROR: bucket not specified" << std::endl;
7912 return EINVAL;
7913 }
7914 RGWBucketInfo bucket_info;
7915 rgw_bucket bucket;
7916 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
7917 if (ret < 0) {
7918 return -ret;
7919 }
7920 bucket_sync_info(store, bucket_info, std::cout);
7921 }
7922
7923 if (opt_cmd == OPT::BUCKET_SYNC_STATUS) {
7924 if (bucket_name.empty()) {
7925 cerr << "ERROR: bucket not specified" << std::endl;
7926 return EINVAL;
7927 }
7928 RGWBucketInfo bucket_info;
7929 rgw_bucket bucket;
7930 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
7931 if (ret < 0) {
7932 return -ret;
7933 }
7934 bucket_sync_status(store, bucket_info, source_zone, opt_source_bucket, std::cout);
7935 }
7936
7937 if (opt_cmd == OPT::BUCKET_SYNC_MARKERS) {
7938 if (source_zone.empty()) {
7939 cerr << "ERROR: source zone not specified" << std::endl;
7940 return EINVAL;
7941 }
7942 if (bucket_name.empty()) {
7943 cerr << "ERROR: bucket not specified" << std::endl;
7944 return EINVAL;
7945 }
7946 rgw_bucket bucket;
7947 int ret = init_bucket_for_sync(tenant, bucket_name, bucket_id, bucket);
7948 if (ret < 0) {
7949 return -ret;
7950 }
7951 RGWBucketPipeSyncStatusManager sync(store, source_zone, opt_source_bucket, bucket);
7952
7953 ret = sync.init();
7954 if (ret < 0) {
7955 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
7956 return -ret;
7957 }
7958 ret = sync.read_sync_status();
7959 if (ret < 0) {
7960 cerr << "ERROR: sync.read_sync_status() returned ret=" << ret << std::endl;
7961 return -ret;
7962 }
7963
7964 map<int, rgw_bucket_shard_sync_info>& sync_status = sync.get_sync_status();
7965
7966 encode_json("sync_status", sync_status, formatter);
7967 formatter->flush(cout);
7968 }
7969
7970 if (opt_cmd == OPT::BUCKET_SYNC_RUN) {
7971 if (source_zone.empty()) {
7972 cerr << "ERROR: source zone not specified" << std::endl;
7973 return EINVAL;
7974 }
7975 if (bucket_name.empty()) {
7976 cerr << "ERROR: bucket not specified" << std::endl;
7977 return EINVAL;
7978 }
7979 rgw_bucket bucket;
7980 int ret = init_bucket_for_sync(tenant, bucket_name, bucket_id, bucket);
7981 if (ret < 0) {
7982 return -ret;
7983 }
7984 RGWBucketPipeSyncStatusManager sync(store, source_zone, opt_source_bucket, bucket);
7985
7986 ret = sync.init();
7987 if (ret < 0) {
7988 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
7989 return -ret;
7990 }
7991
7992 ret = sync.run();
7993 if (ret < 0) {
7994 cerr << "ERROR: sync.run() returned ret=" << ret << std::endl;
7995 return -ret;
7996 }
7997 }
7998
7999 if (opt_cmd == OPT::BILOG_LIST) {
8000 if (bucket_name.empty()) {
8001 cerr << "ERROR: bucket not specified" << std::endl;
8002 return EINVAL;
8003 }
8004 RGWBucketInfo bucket_info;
8005 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
8006 if (ret < 0) {
8007 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
8008 return -ret;
8009 }
8010 formatter->open_array_section("entries");
8011 bool truncated;
8012 int count = 0;
8013 if (max_entries < 0)
8014 max_entries = 1000;
8015
8016 do {
8017 list<rgw_bi_log_entry> entries;
8018 ret = store->svc()->bilog_rados->log_list(bucket_info, shard_id, marker, max_entries - count, entries, &truncated);
8019 if (ret < 0) {
8020 cerr << "ERROR: list_bi_log_entries(): " << cpp_strerror(-ret) << std::endl;
8021 return -ret;
8022 }
8023
8024 count += entries.size();
8025
8026 for (list<rgw_bi_log_entry>::iterator iter = entries.begin(); iter != entries.end(); ++iter) {
8027 rgw_bi_log_entry& entry = *iter;
8028 encode_json("entry", entry, formatter);
8029
8030 marker = entry.id;
8031 }
8032 formatter->flush(cout);
8033 } while (truncated && count < max_entries);
8034
8035 formatter->close_section();
8036 formatter->flush(cout);
8037 }
8038
8039 if (opt_cmd == OPT::SYNC_ERROR_LIST) {
8040 if (max_entries < 0) {
8041 max_entries = 1000;
8042 }
8043
8044 bool truncated;
8045 utime_t start_time, end_time;
8046
8047 int ret = parse_date_str(start_date, start_time);
8048 if (ret < 0)
8049 return -ret;
8050
8051 ret = parse_date_str(end_date, end_time);
8052 if (ret < 0)
8053 return -ret;
8054
8055 if (shard_id < 0) {
8056 shard_id = 0;
8057 }
8058
8059 formatter->open_array_section("entries");
8060
8061 for (; shard_id < ERROR_LOGGER_SHARDS; ++shard_id) {
8062 formatter->open_object_section("shard");
8063 encode_json("shard_id", shard_id, formatter);
8064 formatter->open_array_section("entries");
8065
8066 int count = 0;
8067 string oid = RGWSyncErrorLogger::get_shard_oid(RGW_SYNC_ERROR_LOG_SHARD_PREFIX, shard_id);
8068
8069 do {
8070 list<cls_log_entry> entries;
8071 ret = store->svc()->cls->timelog.list(oid, start_time.to_real_time(), end_time.to_real_time(),
8072 max_entries - count, entries, marker, &marker, &truncated,
8073 null_yield);
8074 if (ret == -ENOENT) {
8075 break;
8076 }
8077 if (ret < 0) {
8078 cerr << "ERROR: svc.cls->timelog.list(): " << cpp_strerror(-ret) << std::endl;
8079 return -ret;
8080 }
8081
8082 count += entries.size();
8083
8084 for (auto& cls_entry : entries) {
8085 rgw_sync_error_info log_entry;
8086
8087 auto iter = cls_entry.data.cbegin();
8088 try {
8089 decode(log_entry, iter);
8090 } catch (buffer::error& err) {
8091 cerr << "ERROR: failed to decode log entry" << std::endl;
8092 continue;
8093 }
8094 formatter->open_object_section("entry");
8095 encode_json("id", cls_entry.id, formatter);
8096 encode_json("section", cls_entry.section, formatter);
8097 encode_json("name", cls_entry.name, formatter);
8098 encode_json("timestamp", cls_entry.timestamp, formatter);
8099 encode_json("info", log_entry, formatter);
8100 formatter->close_section();
8101 formatter->flush(cout);
8102 }
8103 } while (truncated && count < max_entries);
8104
8105 formatter->close_section();
8106 formatter->close_section();
8107
8108 if (specified_shard_id) {
8109 break;
8110 }
8111 }
8112
8113 formatter->close_section();
8114 formatter->flush(cout);
8115 }
8116
8117 if (opt_cmd == OPT::SYNC_ERROR_TRIM) {
8118 utime_t start_time, end_time;
8119 int ret = parse_date_str(start_date, start_time);
8120 if (ret < 0)
8121 return -ret;
8122
8123 ret = parse_date_str(end_date, end_time);
8124 if (ret < 0)
8125 return -ret;
8126
8127 if (shard_id < 0) {
8128 shard_id = 0;
8129 }
8130
8131 for (; shard_id < ERROR_LOGGER_SHARDS; ++shard_id) {
8132 ret = trim_sync_error_log(shard_id, start_time.to_real_time(),
8133 end_time.to_real_time(), start_marker,
8134 end_marker, trim_delay_ms);
8135 if (ret < 0) {
8136 cerr << "ERROR: sync error trim: " << cpp_strerror(-ret) << std::endl;
8137 return -ret;
8138 }
8139 if (specified_shard_id) {
8140 break;
8141 }
8142 }
8143 }
8144
8145 if (opt_cmd == OPT::SYNC_GROUP_CREATE ||
8146 opt_cmd == OPT::SYNC_GROUP_MODIFY) {
8147 CHECK_TRUE(require_opt(opt_group_id), "ERROR: --group-id not specified", EINVAL);
8148 CHECK_TRUE(require_opt(opt_status), "ERROR: --status is not specified (options: forbidden, allowed, enabled)", EINVAL);
8149
8150 SyncPolicyContext sync_policy_ctx(zonegroup_id, zonegroup_name, opt_bucket);
8151 ret = sync_policy_ctx.init();
8152 if (ret < 0) {
8153 return -ret;
8154 }
8155 auto& sync_policy = sync_policy_ctx.get_policy();
8156
8157 if (opt_cmd == OPT::SYNC_GROUP_MODIFY) {
8158 auto iter = sync_policy.groups.find(*opt_group_id);
8159 if (iter == sync_policy.groups.end()) {
8160 cerr << "ERROR: could not find group '" << *opt_group_id << "'" << std::endl;
8161 return ENOENT;
8162 }
8163 }
8164
8165 auto& group = sync_policy.groups[*opt_group_id];
8166 group.id = *opt_group_id;
8167
8168 if (opt_status) {
8169 if (!group.set_status(*opt_status)) {
8170 cerr << "ERROR: unrecognized status (options: forbidden, allowed, enabled)" << std::endl;
8171 return EINVAL;
8172 }
8173 }
8174
8175 ret = sync_policy_ctx.write_policy();
8176 if (ret < 0) {
8177 return -ret;
8178 }
8179
8180 show_result(sync_policy, zone_formatter, cout);
8181 }
8182
8183 if (opt_cmd == OPT::SYNC_GROUP_GET) {
8184 SyncPolicyContext sync_policy_ctx(zonegroup_id, zonegroup_name, opt_bucket);
8185 ret = sync_policy_ctx.init();
8186 if (ret < 0) {
8187 return -ret;
8188 }
8189 auto& sync_policy = sync_policy_ctx.get_policy();
8190
8191 auto& groups = sync_policy.groups;
8192
8193 if (!opt_group_id) {
8194 show_result(groups, zone_formatter, cout);
8195 } else {
8196 auto iter = sync_policy.groups.find(*opt_group_id);
8197 if (iter == sync_policy.groups.end()) {
8198 cerr << "ERROR: could not find group '" << *opt_group_id << "'" << std::endl;
8199 return ENOENT;
8200 }
8201
8202 show_result(iter->second, zone_formatter, cout);
8203 }
8204 }
8205
8206 if (opt_cmd == OPT::SYNC_GROUP_REMOVE) {
8207 CHECK_TRUE(require_opt(opt_group_id), "ERROR: --group-id not specified", EINVAL);
8208
8209 SyncPolicyContext sync_policy_ctx(zonegroup_id, zonegroup_name, opt_bucket);
8210 ret = sync_policy_ctx.init();
8211 if (ret < 0) {
8212 return -ret;
8213 }
8214 auto& sync_policy = sync_policy_ctx.get_policy();
8215
8216 sync_policy.groups.erase(*opt_group_id);
8217
8218 ret = sync_policy_ctx.write_policy();
8219 if (ret < 0) {
8220 return -ret;
8221 }
8222
8223 {
8224 Formatter::ObjectSection os(*zone_formatter, "result");
8225 encode_json("sync_policy", sync_policy, zone_formatter);
8226 }
8227
8228 zone_formatter->flush(cout);
8229 }
8230
8231 if (opt_cmd == OPT::SYNC_GROUP_FLOW_CREATE) {
8232 CHECK_TRUE(require_opt(opt_group_id), "ERROR: --group-id not specified", EINVAL);
8233 CHECK_TRUE(require_opt(opt_flow_id), "ERROR: --flow-id not specified", EINVAL);
8234 CHECK_TRUE(require_opt(opt_flow_type,
8235 (symmetrical_flow_opt(*opt_flow_type) ||
8236 directional_flow_opt(*opt_flow_type))),
8237 "ERROR: --flow-type not specified or invalid (options: symmetrical, directional)", EINVAL);
8238
8239 SyncPolicyContext sync_policy_ctx(zonegroup_id, zonegroup_name, opt_bucket);
8240 ret = sync_policy_ctx.init();
8241 if (ret < 0) {
8242 return -ret;
8243 }
8244 auto& sync_policy = sync_policy_ctx.get_policy();
8245
8246 auto iter = sync_policy.groups.find(*opt_group_id);
8247 if (iter == sync_policy.groups.end()) {
8248 cerr << "ERROR: could not find group '" << *opt_group_id << "'" << std::endl;
8249 return ENOENT;
8250 }
8251
8252 auto& group = iter->second;
8253
8254 if (symmetrical_flow_opt(*opt_flow_type)) {
8255 CHECK_TRUE(require_non_empty_opt(opt_zone_ids), "ERROR: --zones not provided for symmetrical flow, or is empty", EINVAL);
8256
8257 rgw_sync_symmetric_group *flow_group;
8258
8259 group.data_flow.find_or_create_symmetrical(*opt_flow_id, &flow_group);
8260
8261 for (auto& z : *opt_zone_ids) {
8262 flow_group->zones.insert(z);
8263 }
8264 } else { /* directional */
8265 CHECK_TRUE(require_non_empty_opt(opt_source_zone_id), "ERROR: --source-zone not provided for directional flow rule, or is empty", EINVAL);
8266 CHECK_TRUE(require_non_empty_opt(opt_dest_zone_id), "ERROR: --dest-zone not provided for directional flow rule, or is empty", EINVAL);
8267
8268 rgw_sync_directional_rule *flow_rule;
8269
8270 group.data_flow.find_or_create_directional(*opt_source_zone_id, *opt_dest_zone_id, &flow_rule);
8271 }
8272
8273 ret = sync_policy_ctx.write_policy();
8274 if (ret < 0) {
8275 return -ret;
8276 }
8277
8278 show_result(sync_policy, zone_formatter, cout);
8279 }
8280
8281 if (opt_cmd == OPT::SYNC_GROUP_FLOW_REMOVE) {
8282 CHECK_TRUE(require_opt(opt_group_id), "ERROR: --group-id not specified", EINVAL);
8283 CHECK_TRUE(require_opt(opt_flow_id), "ERROR: --flow-id not specified", EINVAL);
8284 CHECK_TRUE(require_opt(opt_flow_type,
8285 (symmetrical_flow_opt(*opt_flow_type) ||
8286 directional_flow_opt(*opt_flow_type))),
8287 "ERROR: --flow-type not specified or invalid (options: symmetrical, directional)", EINVAL);
8288
8289 SyncPolicyContext sync_policy_ctx(zonegroup_id, zonegroup_name, opt_bucket);
8290 ret = sync_policy_ctx.init();
8291 if (ret < 0) {
8292 return -ret;
8293 }
8294 auto& sync_policy = sync_policy_ctx.get_policy();
8295
8296 auto iter = sync_policy.groups.find(*opt_group_id);
8297 if (iter == sync_policy.groups.end()) {
8298 cerr << "ERROR: could not find group '" << *opt_group_id << "'" << std::endl;
8299 return ENOENT;
8300 }
8301
8302 auto& group = iter->second;
8303
8304 if (symmetrical_flow_opt(*opt_flow_type)) {
8305 group.data_flow.remove_symmetrical(*opt_flow_id, opt_zone_ids);
8306 } else { /* directional */
8307 CHECK_TRUE(require_non_empty_opt(opt_source_zone_id), "ERROR: --source-zone not provided for directional flow rule, or is empty", EINVAL);
8308 CHECK_TRUE(require_non_empty_opt(opt_dest_zone_id), "ERROR: --dest-zone not provided for directional flow rule, or is empty", EINVAL);
8309
8310 group.data_flow.remove_directional(*opt_source_zone_id, *opt_dest_zone_id);
8311 }
8312
8313 ret = sync_policy_ctx.write_policy();
8314 if (ret < 0) {
8315 return -ret;
8316 }
8317
8318 show_result(sync_policy, zone_formatter, cout);
8319 }
8320
8321 if (opt_cmd == OPT::SYNC_GROUP_PIPE_CREATE ||
8322 opt_cmd == OPT::SYNC_GROUP_PIPE_MODIFY) {
8323 CHECK_TRUE(require_opt(opt_group_id), "ERROR: --group-id not specified", EINVAL);
8324 CHECK_TRUE(require_opt(opt_pipe_id), "ERROR: --pipe-id not specified", EINVAL);
8325 if (opt_cmd == OPT::SYNC_GROUP_PIPE_CREATE) {
8326 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);
8327 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);
8328 }
8329
8330 SyncPolicyContext sync_policy_ctx(zonegroup_id, zonegroup_name, opt_bucket);
8331 ret = sync_policy_ctx.init();
8332 if (ret < 0) {
8333 return -ret;
8334 }
8335 auto& sync_policy = sync_policy_ctx.get_policy();
8336
8337 auto iter = sync_policy.groups.find(*opt_group_id);
8338 if (iter == sync_policy.groups.end()) {
8339 cerr << "ERROR: could not find group '" << *opt_group_id << "'" << std::endl;
8340 return ENOENT;
8341 }
8342
8343 auto& group = iter->second;
8344
8345 rgw_sync_bucket_pipes *pipe;
8346
8347 if (opt_cmd == OPT::SYNC_GROUP_PIPE_CREATE) {
8348 group.find_pipe(*opt_pipe_id, true, &pipe);
8349 } else {
8350 if (!group.find_pipe(*opt_pipe_id, false, &pipe)) {
8351 cerr << "ERROR: could not find pipe '" << *opt_pipe_id << "'" << std::endl;
8352 return ENOENT;
8353 }
8354 }
8355
8356 pipe->source.add_zones(*opt_source_zone_ids);
8357 pipe->source.set_bucket(opt_source_tenant,
8358 opt_source_bucket_name,
8359 opt_source_bucket_id);
8360 pipe->dest.add_zones(*opt_dest_zone_ids);
8361 pipe->dest.set_bucket(opt_dest_tenant,
8362 opt_dest_bucket_name,
8363 opt_dest_bucket_id);
8364
8365 pipe->params.source.filter.set_prefix(opt_prefix, !!opt_prefix_rm);
8366 pipe->params.source.filter.set_tags(tags_add, tags_rm);
8367 if (opt_dest_owner) {
8368 pipe->params.dest.set_owner(*opt_dest_owner);
8369 }
8370 if (opt_storage_class) {
8371 pipe->params.dest.set_storage_class(*opt_storage_class);
8372 }
8373 if (opt_priority) {
8374 pipe->params.priority = *opt_priority;
8375 }
8376 if (opt_mode) {
8377 if (*opt_mode == "system") {
8378 pipe->params.mode = rgw_sync_pipe_params::MODE_SYSTEM;
8379 } else if (*opt_mode == "user") {
8380 pipe->params.mode = rgw_sync_pipe_params::MODE_USER;
8381 } else {
8382 cerr << "ERROR: bad mode value: should be one of the following: system, user" << std::endl;
8383 return EINVAL;
8384 }
8385 }
8386
8387 if (!user_id.empty()) {
8388 pipe->params.user = user_id;
8389 } else if (pipe->params.user.empty()) {
8390 auto owner = sync_policy_ctx.get_owner();
8391 if (owner) {
8392 pipe->params.user = *owner;
8393 }
8394 }
8395
8396 ret = sync_policy_ctx.write_policy();
8397 if (ret < 0) {
8398 return -ret;
8399 }
8400
8401 show_result(sync_policy, zone_formatter, cout);
8402 }
8403
8404 if (opt_cmd == OPT::SYNC_GROUP_PIPE_REMOVE) {
8405 CHECK_TRUE(require_opt(opt_group_id), "ERROR: --group-id not specified", EINVAL);
8406 CHECK_TRUE(require_opt(opt_pipe_id), "ERROR: --pipe-id not specified", EINVAL);
8407
8408 SyncPolicyContext sync_policy_ctx(zonegroup_id, zonegroup_name, opt_bucket);
8409 ret = sync_policy_ctx.init();
8410 if (ret < 0) {
8411 return -ret;
8412 }
8413 auto& sync_policy = sync_policy_ctx.get_policy();
8414
8415 auto iter = sync_policy.groups.find(*opt_group_id);
8416 if (iter == sync_policy.groups.end()) {
8417 cerr << "ERROR: could not find group '" << *opt_group_id << "'" << std::endl;
8418 return ENOENT;
8419 }
8420
8421 auto& group = iter->second;
8422
8423 rgw_sync_bucket_pipes *pipe;
8424
8425 if (!group.find_pipe(*opt_pipe_id, false, &pipe)) {
8426 cerr << "ERROR: could not find pipe '" << *opt_pipe_id << "'" << std::endl;
8427 return ENOENT;
8428 }
8429
8430 if (opt_source_zone_ids) {
8431 pipe->source.remove_zones(*opt_source_zone_ids);
8432 }
8433
8434 pipe->source.remove_bucket(opt_source_tenant,
8435 opt_source_bucket_name,
8436 opt_source_bucket_id);
8437 if (opt_dest_zone_ids) {
8438 pipe->dest.remove_zones(*opt_dest_zone_ids);
8439 }
8440 pipe->dest.remove_bucket(opt_dest_tenant,
8441 opt_dest_bucket_name,
8442 opt_dest_bucket_id);
8443
8444 if (!(opt_source_zone_ids ||
8445 opt_source_tenant ||
8446 opt_source_bucket ||
8447 opt_source_bucket_id ||
8448 opt_dest_zone_ids ||
8449 opt_dest_tenant ||
8450 opt_dest_bucket ||
8451 opt_dest_bucket_id)) {
8452 group.remove_pipe(*opt_pipe_id);
8453 }
8454
8455 ret = sync_policy_ctx.write_policy();
8456 if (ret < 0) {
8457 return -ret;
8458 }
8459
8460 show_result(sync_policy, zone_formatter, cout);
8461 }
8462
8463 if (opt_cmd == OPT::SYNC_POLICY_GET) {
8464 SyncPolicyContext sync_policy_ctx(zonegroup_id, zonegroup_name, opt_bucket);
8465 ret = sync_policy_ctx.init();
8466 if (ret < 0) {
8467 return -ret;
8468 }
8469 auto& sync_policy = sync_policy_ctx.get_policy();
8470
8471 show_result(sync_policy, zone_formatter, cout);
8472 }
8473
8474 if (opt_cmd == OPT::BILOG_TRIM) {
8475 if (bucket_name.empty()) {
8476 cerr << "ERROR: bucket not specified" << std::endl;
8477 return EINVAL;
8478 }
8479 RGWBucketInfo bucket_info;
8480 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
8481 if (ret < 0) {
8482 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
8483 return -ret;
8484 }
8485 ret = store->svc()->bilog_rados->log_trim(bucket_info, shard_id, start_marker, end_marker);
8486 if (ret < 0) {
8487 cerr << "ERROR: trim_bi_log_entries(): " << cpp_strerror(-ret) << std::endl;
8488 return -ret;
8489 }
8490 }
8491
8492 if (opt_cmd == OPT::BILOG_STATUS) {
8493 if (bucket_name.empty()) {
8494 cerr << "ERROR: bucket not specified" << std::endl;
8495 return EINVAL;
8496 }
8497 RGWBucketInfo bucket_info;
8498 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
8499 if (ret < 0) {
8500 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
8501 return -ret;
8502 }
8503 map<int, string> markers;
8504 ret = store->svc()->bilog_rados->get_log_status(bucket_info, shard_id, &markers);
8505 if (ret < 0) {
8506 cerr << "ERROR: get_bi_log_status(): " << cpp_strerror(-ret) << std::endl;
8507 return -ret;
8508 }
8509 formatter->open_object_section("entries");
8510 encode_json("markers", markers, formatter);
8511 formatter->close_section();
8512 formatter->flush(cout);
8513 }
8514
8515 if (opt_cmd == OPT::BILOG_AUTOTRIM) {
8516 RGWCoroutinesManager crs(store->ctx(), store->getRados()->get_cr_registry());
8517 RGWHTTPManager http(store->ctx(), crs.get_completion_mgr());
8518 int ret = http.start();
8519 if (ret < 0) {
8520 cerr << "failed to initialize http client with " << cpp_strerror(ret) << std::endl;
8521 return -ret;
8522 }
8523
8524 rgw::BucketTrimConfig config;
8525 configure_bucket_trim(store->ctx(), config);
8526
8527 rgw::BucketTrimManager trim(store, config);
8528 ret = trim.init();
8529 if (ret < 0) {
8530 cerr << "trim manager init failed with " << cpp_strerror(ret) << std::endl;
8531 return -ret;
8532 }
8533 ret = crs.run(trim.create_admin_bucket_trim_cr(&http));
8534 if (ret < 0) {
8535 cerr << "automated bilog trim failed with " << cpp_strerror(ret) << std::endl;
8536 return -ret;
8537 }
8538 }
8539
8540 if (opt_cmd == OPT::DATALOG_LIST) {
8541 formatter->open_array_section("entries");
8542 bool truncated;
8543 int count = 0;
8544 if (max_entries < 0)
8545 max_entries = 1000;
8546
8547 utime_t start_time, end_time;
8548
8549 int ret = parse_date_str(start_date, start_time);
8550 if (ret < 0)
8551 return -ret;
8552
8553 ret = parse_date_str(end_date, end_time);
8554 if (ret < 0)
8555 return -ret;
8556
8557 auto datalog_svc = store->svc()->datalog_rados;
8558 RGWDataChangesLog::LogMarker log_marker;
8559
8560 do {
8561 list<rgw_data_change_log_entry> entries;
8562 if (specified_shard_id) {
8563 ret = datalog_svc->list_entries(shard_id, start_time.to_real_time(), end_time.to_real_time(), max_entries - count, entries, marker, NULL, &truncated);
8564 } else {
8565 ret = datalog_svc->list_entries(start_time.to_real_time(), end_time.to_real_time(), max_entries - count, entries, log_marker, &truncated);
8566 }
8567 if (ret < 0) {
8568 cerr << "ERROR: list_bi_log_entries(): " << cpp_strerror(-ret) << std::endl;
8569 return -ret;
8570 }
8571
8572 count += entries.size();
8573
8574 for (list<rgw_data_change_log_entry>::iterator iter = entries.begin(); iter != entries.end(); ++iter) {
8575 rgw_data_change_log_entry& entry = *iter;
8576 if (!extra_info) {
8577 encode_json("entry", entry.entry, formatter);
8578 } else {
8579 encode_json("entry", entry, formatter);
8580 }
8581 }
8582 formatter->flush(cout);
8583 } while (truncated && count < max_entries);
8584
8585 formatter->close_section();
8586 formatter->flush(cout);
8587 }
8588
8589 if (opt_cmd == OPT::DATALOG_STATUS) {
8590 int i = (specified_shard_id ? shard_id : 0);
8591
8592 formatter->open_array_section("entries");
8593 for (; i < g_ceph_context->_conf->rgw_data_log_num_shards; i++) {
8594 list<cls_log_entry> entries;
8595
8596 RGWDataChangesLogInfo info;
8597 store->svc()->datalog_rados->get_info(i, &info);
8598
8599 ::encode_json("info", info, formatter);
8600
8601 if (specified_shard_id)
8602 break;
8603 }
8604
8605 formatter->close_section();
8606 formatter->flush(cout);
8607 }
8608
8609 if (opt_cmd == OPT::DATALOG_AUTOTRIM) {
8610 RGWCoroutinesManager crs(store->ctx(), store->getRados()->get_cr_registry());
8611 RGWHTTPManager http(store->ctx(), crs.get_completion_mgr());
8612 int ret = http.start();
8613 if (ret < 0) {
8614 cerr << "failed to initialize http client with " << cpp_strerror(ret) << std::endl;
8615 return -ret;
8616 }
8617
8618 auto num_shards = g_conf()->rgw_data_log_num_shards;
8619 std::vector<std::string> markers(num_shards);
8620 ret = crs.run(create_admin_data_log_trim_cr(store, &http, num_shards, markers));
8621 if (ret < 0) {
8622 cerr << "automated datalog trim failed with " << cpp_strerror(ret) << std::endl;
8623 return -ret;
8624 }
8625 }
8626
8627 if (opt_cmd == OPT::DATALOG_TRIM) {
8628 utime_t start_time, end_time;
8629
8630 int ret = parse_date_str(start_date, start_time);
8631 if (ret < 0)
8632 return -ret;
8633
8634 ret = parse_date_str(end_date, end_time);
8635 if (ret < 0)
8636 return -ret;
8637
8638 if (!specified_shard_id) {
8639 cerr << "ERROR: requires a --shard-id" << std::endl;
8640 return EINVAL;
8641 }
8642
8643 // loop until -ENODATA
8644 do {
8645 auto datalog = store->svc()->datalog_rados;
8646 ret = datalog->trim_entries(shard_id, start_time.to_real_time(),
8647 end_time.to_real_time(),
8648 start_marker, end_marker);
8649 } while (ret == 0);
8650
8651 if (ret < 0 && ret != -ENODATA) {
8652 cerr << "ERROR: trim_entries(): " << cpp_strerror(-ret) << std::endl;
8653 return -ret;
8654 }
8655 }
8656
8657 bool quota_op = (opt_cmd == OPT::QUOTA_SET || opt_cmd == OPT::QUOTA_ENABLE || opt_cmd == OPT::QUOTA_DISABLE);
8658
8659 if (quota_op) {
8660 if (bucket_name.empty() && user_id.empty()) {
8661 cerr << "ERROR: bucket name or uid is required for quota operation" << std::endl;
8662 return EINVAL;
8663 }
8664
8665 if (!bucket_name.empty()) {
8666 if (!quota_scope.empty() && quota_scope != "bucket") {
8667 cerr << "ERROR: invalid quota scope specification." << std::endl;
8668 return EINVAL;
8669 }
8670 set_bucket_quota(store, opt_cmd, tenant, bucket_name,
8671 max_size, max_objects, have_max_size, have_max_objects);
8672 } else if (!user_id.empty()) {
8673 if (quota_scope == "bucket") {
8674 return set_user_bucket_quota(opt_cmd, user, user_op, max_size, max_objects, have_max_size, have_max_objects);
8675 } else if (quota_scope == "user") {
8676 return set_user_quota(opt_cmd, user, user_op, max_size, max_objects, have_max_size, have_max_objects);
8677 } else {
8678 cerr << "ERROR: invalid quota scope specification. Please specify either --quota-scope=bucket, or --quota-scope=user" << std::endl;
8679 return EINVAL;
8680 }
8681 }
8682 }
8683
8684 if (opt_cmd == OPT::MFA_CREATE) {
8685 rados::cls::otp::otp_info_t config;
8686
8687 if (user_id.empty()) {
8688 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
8689 return EINVAL;
8690 }
8691
8692 if (totp_serial.empty()) {
8693 cerr << "ERROR: TOTP device serial number was not provided (via --totp-serial)" << std::endl;
8694 return EINVAL;
8695 }
8696
8697 if (totp_seed.empty()) {
8698 cerr << "ERROR: TOTP device seed was not provided (via --totp-seed)" << std::endl;
8699 return EINVAL;
8700 }
8701
8702
8703 rados::cls::otp::SeedType seed_type;
8704 if (totp_seed_type == "hex") {
8705 seed_type = rados::cls::otp::OTP_SEED_HEX;
8706 } else if (totp_seed_type == "base32") {
8707 seed_type = rados::cls::otp::OTP_SEED_BASE32;
8708 } else {
8709 cerr << "ERROR: invalid seed type: " << totp_seed_type << std::endl;
8710 return EINVAL;
8711 }
8712
8713 config.id = totp_serial;
8714 config.seed = totp_seed;
8715 config.seed_type = seed_type;
8716
8717 if (totp_seconds > 0) {
8718 config.step_size = totp_seconds;
8719 }
8720
8721 if (totp_window > 0) {
8722 config.window = totp_window;
8723 }
8724
8725 real_time mtime = real_clock::now();
8726 string oid = store->svc()->cls->mfa.get_mfa_oid(user_id);
8727
8728 int ret = store->ctl()->meta.mgr->mutate(RGWSI_MetaBackend_OTP::get_meta_key(user_id),
8729 mtime, &objv_tracker,
8730 null_yield,
8731 MDLOG_STATUS_WRITE,
8732 [&] {
8733 return store->svc()->cls->mfa.create_mfa(user_id, config, &objv_tracker, mtime, null_yield);
8734 });
8735 if (ret < 0) {
8736 cerr << "MFA creation failed, error: " << cpp_strerror(-ret) << std::endl;
8737 return -ret;
8738 }
8739
8740 RGWUserInfo& user_info = user_op.get_user_info();
8741 user_info.mfa_ids.insert(totp_serial);
8742 user_op.set_mfa_ids(user_info.mfa_ids);
8743 string err;
8744 ret = user.modify(user_op, &err);
8745 if (ret < 0) {
8746 cerr << "ERROR: failed storing user info, error: " << err << std::endl;
8747 return -ret;
8748 }
8749 }
8750
8751 if (opt_cmd == OPT::MFA_REMOVE) {
8752 if (user_id.empty()) {
8753 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
8754 return EINVAL;
8755 }
8756
8757 if (totp_serial.empty()) {
8758 cerr << "ERROR: TOTP device serial number was not provided (via --totp-serial)" << std::endl;
8759 return EINVAL;
8760 }
8761
8762 real_time mtime = real_clock::now();
8763
8764 int ret = store->ctl()->meta.mgr->mutate(RGWSI_MetaBackend_OTP::get_meta_key(user_id),
8765 mtime, &objv_tracker,
8766 null_yield,
8767 MDLOG_STATUS_WRITE,
8768 [&] {
8769 return store->svc()->cls->mfa.remove_mfa(user_id, totp_serial, &objv_tracker, mtime, null_yield);
8770 });
8771 if (ret < 0) {
8772 cerr << "MFA removal failed, error: " << cpp_strerror(-ret) << std::endl;
8773 return -ret;
8774 }
8775
8776 RGWUserInfo& user_info = user_op.get_user_info();
8777 user_info.mfa_ids.erase(totp_serial);
8778 user_op.set_mfa_ids(user_info.mfa_ids);
8779 string err;
8780 ret = user.modify(user_op, &err);
8781 if (ret < 0) {
8782 cerr << "ERROR: failed storing user info, error: " << err << std::endl;
8783 return -ret;
8784 }
8785 }
8786
8787 if (opt_cmd == OPT::MFA_GET) {
8788 if (user_id.empty()) {
8789 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
8790 return EINVAL;
8791 }
8792
8793 if (totp_serial.empty()) {
8794 cerr << "ERROR: TOTP device serial number was not provided (via --totp-serial)" << std::endl;
8795 return EINVAL;
8796 }
8797
8798 rados::cls::otp::otp_info_t result;
8799 int ret = store->svc()->cls->mfa.get_mfa(user_id, totp_serial, &result, null_yield);
8800 if (ret < 0) {
8801 if (ret == -ENOENT || ret == -ENODATA) {
8802 cerr << "MFA serial id not found" << std::endl;
8803 } else {
8804 cerr << "MFA retrieval failed, error: " << cpp_strerror(-ret) << std::endl;
8805 }
8806 return -ret;
8807 }
8808 formatter->open_object_section("result");
8809 encode_json("entry", result, formatter);
8810 formatter->close_section();
8811 formatter->flush(cout);
8812 }
8813
8814 if (opt_cmd == OPT::MFA_LIST) {
8815 if (user_id.empty()) {
8816 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
8817 return EINVAL;
8818 }
8819
8820 list<rados::cls::otp::otp_info_t> result;
8821 int ret = store->svc()->cls->mfa.list_mfa(user_id, &result, null_yield);
8822 if (ret < 0) {
8823 cerr << "MFA listing failed, error: " << cpp_strerror(-ret) << std::endl;
8824 return -ret;
8825 }
8826 formatter->open_object_section("result");
8827 encode_json("entries", result, formatter);
8828 formatter->close_section();
8829 formatter->flush(cout);
8830 }
8831
8832 if (opt_cmd == OPT::MFA_CHECK) {
8833 if (user_id.empty()) {
8834 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
8835 return EINVAL;
8836 }
8837
8838 if (totp_serial.empty()) {
8839 cerr << "ERROR: TOTP device serial number was not provided (via --totp-serial)" << std::endl;
8840 return EINVAL;
8841 }
8842
8843 if (totp_pin.empty()) {
8844 cerr << "ERROR: TOTP device serial number was not provided (via --totp-pin)" << std::endl;
8845 return EINVAL;
8846 }
8847
8848 list<rados::cls::otp::otp_info_t> result;
8849 int ret = store->svc()->cls->mfa.check_mfa(user_id, totp_serial, totp_pin.front(), null_yield);
8850 if (ret < 0) {
8851 cerr << "MFA check failed, error: " << cpp_strerror(-ret) << std::endl;
8852 return -ret;
8853 }
8854
8855 cout << "ok" << std::endl;
8856 }
8857
8858 if (opt_cmd == OPT::MFA_RESYNC) {
8859 if (user_id.empty()) {
8860 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
8861 return EINVAL;
8862 }
8863
8864 if (totp_serial.empty()) {
8865 cerr << "ERROR: TOTP device serial number was not provided (via --totp-serial)" << std::endl;
8866 return EINVAL;
8867 }
8868
8869 if (totp_pin.size() != 2) {
8870 cerr << "ERROR: missing two --totp-pin params (--totp-pin=<first> --totp-pin=<second>)" << std::endl;
8871 }
8872
8873 rados::cls::otp::otp_info_t config;
8874 int ret = store->svc()->cls->mfa.get_mfa(user_id, totp_serial, &config, null_yield);
8875 if (ret < 0) {
8876 if (ret == -ENOENT || ret == -ENODATA) {
8877 cerr << "MFA serial id not found" << std::endl;
8878 } else {
8879 cerr << "MFA retrieval failed, error: " << cpp_strerror(-ret) << std::endl;
8880 }
8881 return -ret;
8882 }
8883
8884 ceph::real_time now;
8885
8886 ret = store->svc()->cls->mfa.otp_get_current_time(user_id, &now, null_yield);
8887 if (ret < 0) {
8888 cerr << "ERROR: failed to fetch current time from osd: " << cpp_strerror(-ret) << std::endl;
8889 return -ret;
8890 }
8891 time_t time_ofs;
8892
8893 ret = scan_totp(store->ctx(), now, config, totp_pin, &time_ofs);
8894 if (ret < 0) {
8895 if (ret == -ENOENT) {
8896 cerr << "failed to resync, TOTP values not found in range" << std::endl;
8897 } else {
8898 cerr << "ERROR: failed to scan for TOTP values: " << cpp_strerror(-ret) << std::endl;
8899 }
8900 return -ret;
8901 }
8902
8903 config.time_ofs = time_ofs;
8904
8905 /* now update the backend */
8906 real_time mtime = real_clock::now();
8907
8908 ret = store->ctl()->meta.mgr->mutate(RGWSI_MetaBackend_OTP::get_meta_key(user_id),
8909 mtime, &objv_tracker,
8910 null_yield,
8911 MDLOG_STATUS_WRITE,
8912 [&] {
8913 return store->svc()->cls->mfa.create_mfa(user_id, config, &objv_tracker, mtime, null_yield);
8914 });
8915 if (ret < 0) {
8916 cerr << "MFA update failed, error: " << cpp_strerror(-ret) << std::endl;
8917 return -ret;
8918 }
8919
8920 }
8921
8922 if (opt_cmd == OPT::RESHARD_STALE_INSTANCES_LIST) {
8923 if (!store->svc()->zone->can_reshard() && !yes_i_really_mean_it) {
8924 cerr << "Resharding disabled in a multisite env, stale instances unlikely from resharding" << std::endl;
8925 cerr << "These instances may not be safe to delete." << std::endl;
8926 cerr << "Use --yes-i-really-mean-it to force displaying these instances." << std::endl;
8927 return EINVAL;
8928 }
8929
8930 ret = RGWBucketAdminOp::list_stale_instances(store, bucket_op,f);
8931 if (ret < 0) {
8932 cerr << "ERROR: listing stale instances" << cpp_strerror(-ret) << std::endl;
8933 }
8934 }
8935
8936 if (opt_cmd == OPT::RESHARD_STALE_INSTANCES_DELETE) {
8937 if (!store->svc()->zone->can_reshard()) {
8938 cerr << "Resharding disabled in a multisite env. Stale instances are not safe to be deleted." << std::endl;
8939 return EINVAL;
8940 }
8941
8942 ret = RGWBucketAdminOp::clear_stale_instances(store, bucket_op,f);
8943 if (ret < 0) {
8944 cerr << "ERROR: deleting stale instances" << cpp_strerror(-ret) << std::endl;
8945 }
8946 }
8947
8948 if (opt_cmd == OPT::PUBSUB_TOPICS_LIST) {
8949 if (get_tier_type(store) != "pubsub") {
8950 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
8951 return EINVAL;
8952 }
8953 if (user_id.empty()) {
8954 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
8955 return EINVAL;
8956 }
8957 RGWUserInfo& user_info = user_op.get_user_info();
8958
8959 RGWUserPubSub ups(store, user_info.user_id);
8960
8961 rgw_bucket bucket;
8962
8963 if (!bucket_name.empty()) {
8964 rgw_pubsub_bucket_topics result;
8965 RGWBucketInfo bucket_info;
8966 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
8967 if (ret < 0) {
8968 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
8969 return -ret;
8970 }
8971
8972 auto b = ups.get_bucket(bucket_info.bucket);
8973 ret = b->get_topics(&result);
8974 if (ret < 0) {
8975 cerr << "ERROR: could not get topics: " << cpp_strerror(-ret) << std::endl;
8976 return -ret;
8977 }
8978 encode_json("result", result, formatter);
8979 } else {
8980 rgw_pubsub_user_topics result;
8981 int ret = ups.get_user_topics(&result);
8982 if (ret < 0) {
8983 cerr << "ERROR: could not get topics: " << cpp_strerror(-ret) << std::endl;
8984 return -ret;
8985 }
8986 encode_json("result", result, formatter);
8987 }
8988 formatter->flush(cout);
8989 }
8990
8991 if (opt_cmd == OPT::PUBSUB_TOPIC_CREATE) {
8992 if (get_tier_type(store) != "pubsub") {
8993 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
8994 return EINVAL;
8995 }
8996 if (topic_name.empty()) {
8997 cerr << "ERROR: topic name was not provided (via --topic)" << std::endl;
8998 return EINVAL;
8999 }
9000 if (user_id.empty()) {
9001 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
9002 return EINVAL;
9003 }
9004 RGWUserInfo& user_info = user_op.get_user_info();
9005 RGWUserPubSub ups(store, user_info.user_id);
9006
9007 ret = ups.create_topic(topic_name);
9008 if (ret < 0) {
9009 cerr << "ERROR: could not create topic: " << cpp_strerror(-ret) << std::endl;
9010 return -ret;
9011 }
9012 }
9013
9014 if (opt_cmd == OPT::PUBSUB_TOPIC_GET) {
9015 if (get_tier_type(store) != "pubsub") {
9016 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
9017 return EINVAL;
9018 }
9019 if (topic_name.empty()) {
9020 cerr << "ERROR: topic name was not provided (via --topic)" << std::endl;
9021 return EINVAL;
9022 }
9023 if (user_id.empty()) {
9024 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
9025 return EINVAL;
9026 }
9027 RGWUserInfo& user_info = user_op.get_user_info();
9028 RGWUserPubSub ups(store, user_info.user_id);
9029
9030 rgw_pubsub_topic_subs topic;
9031 ret = ups.get_topic(topic_name, &topic);
9032 if (ret < 0) {
9033 cerr << "ERROR: could not create topic: " << cpp_strerror(-ret) << std::endl;
9034 return -ret;
9035 }
9036 encode_json("topic", topic, formatter);
9037 formatter->flush(cout);
9038 }
9039
9040 if (opt_cmd == OPT::PUBSUB_NOTIFICATION_CREATE) {
9041 if (get_tier_type(store) != "pubsub") {
9042 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
9043 return EINVAL;
9044 }
9045 if (topic_name.empty()) {
9046 cerr << "ERROR: topic name was not provided (via --topic)" << std::endl;
9047 return EINVAL;
9048 }
9049 if (user_id.empty()) {
9050 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
9051 return EINVAL;
9052 }
9053 if (bucket_name.empty()) {
9054 cerr << "ERROR: bucket name was not provided (via --bucket)" << std::endl;
9055 return EINVAL;
9056 }
9057 RGWUserInfo& user_info = user_op.get_user_info();
9058 RGWUserPubSub ups(store, user_info.user_id);
9059
9060 rgw_bucket bucket;
9061
9062 RGWBucketInfo bucket_info;
9063 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
9064 if (ret < 0) {
9065 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
9066 return -ret;
9067 }
9068
9069 auto b = ups.get_bucket(bucket_info.bucket);
9070 ret = b->create_notification(topic_name, event_types);
9071 if (ret < 0) {
9072 cerr << "ERROR: could not publish bucket: " << cpp_strerror(-ret) << std::endl;
9073 return -ret;
9074 }
9075 }
9076
9077 if (opt_cmd == OPT::PUBSUB_NOTIFICATION_RM) {
9078 if (get_tier_type(store) != "pubsub") {
9079 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
9080 return EINVAL;
9081 }
9082 if (topic_name.empty()) {
9083 cerr << "ERROR: topic name was not provided (via --topic)" << std::endl;
9084 return EINVAL;
9085 }
9086 if (user_id.empty()) {
9087 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
9088 return EINVAL;
9089 }
9090 if (bucket_name.empty()) {
9091 cerr << "ERROR: bucket name was not provided (via --bucket)" << std::endl;
9092 return EINVAL;
9093 }
9094 RGWUserInfo& user_info = user_op.get_user_info();
9095 RGWUserPubSub ups(store, user_info.user_id);
9096
9097 rgw_bucket bucket;
9098
9099 RGWBucketInfo bucket_info;
9100 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
9101 if (ret < 0) {
9102 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
9103 return -ret;
9104 }
9105
9106 auto b = ups.get_bucket(bucket_info.bucket);
9107 ret = b->remove_notification(topic_name);
9108 if (ret < 0) {
9109 cerr << "ERROR: could not publish bucket: " << cpp_strerror(-ret) << std::endl;
9110 return -ret;
9111 }
9112 }
9113
9114 if (opt_cmd == OPT::PUBSUB_TOPIC_RM) {
9115 if (get_tier_type(store) != "pubsub") {
9116 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
9117 return EINVAL;
9118 }
9119 if (topic_name.empty()) {
9120 cerr << "ERROR: topic name was not provided (via --topic)" << std::endl;
9121 return EINVAL;
9122 }
9123 if (user_id.empty()) {
9124 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
9125 return EINVAL;
9126 }
9127 RGWUserInfo& user_info = user_op.get_user_info();
9128 RGWUserPubSub ups(store, user_info.user_id);
9129
9130 ret = ups.remove_topic(topic_name);
9131 if (ret < 0) {
9132 cerr << "ERROR: could not remove topic: " << cpp_strerror(-ret) << std::endl;
9133 return -ret;
9134 }
9135 }
9136
9137 if (opt_cmd == OPT::PUBSUB_SUB_GET) {
9138 if (get_tier_type(store) != "pubsub") {
9139 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
9140 return EINVAL;
9141 }
9142 if (user_id.empty()) {
9143 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
9144 return EINVAL;
9145 }
9146 if (sub_name.empty()) {
9147 cerr << "ERROR: subscription name was not provided (via --sub-name)" << std::endl;
9148 return EINVAL;
9149 }
9150 RGWUserInfo& user_info = user_op.get_user_info();
9151 RGWUserPubSub ups(store, user_info.user_id);
9152
9153 rgw_pubsub_sub_config sub_conf;
9154
9155 auto sub = ups.get_sub(sub_name);
9156 ret = sub->get_conf(&sub_conf);
9157 if (ret < 0) {
9158 cerr << "ERROR: could not get subscription info: " << cpp_strerror(-ret) << std::endl;
9159 return -ret;
9160 }
9161 encode_json("sub", sub_conf, formatter);
9162 formatter->flush(cout);
9163 }
9164
9165 if (opt_cmd == OPT::PUBSUB_SUB_CREATE) {
9166 if (get_tier_type(store) != "pubsub") {
9167 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
9168 return EINVAL;
9169 }
9170 if (user_id.empty()) {
9171 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
9172 return EINVAL;
9173 }
9174 if (sub_name.empty()) {
9175 cerr << "ERROR: subscription name was not provided (via --sub-name)" << std::endl;
9176 return EINVAL;
9177 }
9178 if (topic_name.empty()) {
9179 cerr << "ERROR: topic name was not provided (via --topic)" << std::endl;
9180 return EINVAL;
9181 }
9182 RGWUserInfo& user_info = user_op.get_user_info();
9183 RGWUserPubSub ups(store, user_info.user_id);
9184
9185 rgw_pubsub_topic_subs topic;
9186 int ret = ups.get_topic(topic_name, &topic);
9187 if (ret < 0) {
9188 cerr << "ERROR: topic not found" << std::endl;
9189 return EINVAL;
9190 }
9191
9192 rgw_pubsub_sub_dest dest_config;
9193 dest_config.bucket_name = sub_dest_bucket;
9194 dest_config.oid_prefix = sub_oid_prefix;
9195 dest_config.push_endpoint = sub_push_endpoint;
9196
9197 auto psmodule = static_cast<RGWPSSyncModuleInstance *>(store->getRados()->get_sync_module().get());
9198 auto conf = psmodule->get_effective_conf();
9199
9200 if (dest_config.bucket_name.empty()) {
9201 dest_config.bucket_name = string(conf["data_bucket_prefix"]) + user_info.user_id.to_str() + "-" + topic.topic.name;
9202 }
9203 if (dest_config.oid_prefix.empty()) {
9204 dest_config.oid_prefix = conf["data_oid_prefix"];
9205 }
9206 auto sub = ups.get_sub(sub_name);
9207 ret = sub->subscribe(topic_name, dest_config);
9208 if (ret < 0) {
9209 cerr << "ERROR: could not store subscription info: " << cpp_strerror(-ret) << std::endl;
9210 return -ret;
9211 }
9212 }
9213
9214 if (opt_cmd == OPT::PUBSUB_SUB_RM) {
9215 if (get_tier_type(store) != "pubsub") {
9216 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
9217 return EINVAL;
9218 }
9219 if (user_id.empty()) {
9220 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
9221 return EINVAL;
9222 }
9223 if (sub_name.empty()) {
9224 cerr << "ERROR: subscription name was not provided (via --sub-name)" << std::endl;
9225 return EINVAL;
9226 }
9227 RGWUserInfo& user_info = user_op.get_user_info();
9228 RGWUserPubSub ups(store, user_info.user_id);
9229
9230 auto sub = ups.get_sub(sub_name);
9231 ret = sub->unsubscribe(topic_name);
9232 if (ret < 0) {
9233 cerr << "ERROR: could not get subscription info: " << cpp_strerror(-ret) << std::endl;
9234 return -ret;
9235 }
9236 }
9237
9238 if (opt_cmd == OPT::PUBSUB_SUB_PULL) {
9239 if (get_tier_type(store) != "pubsub") {
9240 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
9241 return EINVAL;
9242 }
9243 if (user_id.empty()) {
9244 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
9245 return EINVAL;
9246 }
9247 if (sub_name.empty()) {
9248 cerr << "ERROR: subscription name was not provided (via --sub-name)" << std::endl;
9249 return EINVAL;
9250 }
9251 RGWUserInfo& user_info = user_op.get_user_info();
9252 RGWUserPubSub ups(store, user_info.user_id);
9253
9254 if (!max_entries_specified) {
9255 max_entries = RGWUserPubSub::Sub::DEFAULT_MAX_EVENTS;
9256 }
9257 auto sub = ups.get_sub(sub_name);
9258 ret = sub->list_events(marker, max_entries);
9259 if (ret < 0) {
9260 cerr << "ERROR: could not list events: " << cpp_strerror(-ret) << std::endl;
9261 return -ret;
9262 }
9263 encode_json("result", *sub, formatter);
9264 formatter->flush(cout);
9265 }
9266
9267 if (opt_cmd == OPT::PUBSUB_EVENT_RM) {
9268 if (get_tier_type(store) != "pubsub") {
9269 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
9270 return EINVAL;
9271 }
9272 if (user_id.empty()) {
9273 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
9274 return EINVAL;
9275 }
9276 if (sub_name.empty()) {
9277 cerr << "ERROR: subscription name was not provided (via --sub-name)" << std::endl;
9278 return EINVAL;
9279 }
9280 if (event_id.empty()) {
9281 cerr << "ERROR: event id was not provided (via --event-id)" << std::endl;
9282 return EINVAL;
9283 }
9284 RGWUserInfo& user_info = user_op.get_user_info();
9285 RGWUserPubSub ups(store, user_info.user_id);
9286
9287 auto sub = ups.get_sub(sub_name);
9288 ret = sub->remove_event(event_id);
9289 if (ret < 0) {
9290 cerr << "ERROR: could not remove event: " << cpp_strerror(-ret) << std::endl;
9291 return -ret;
9292 }
9293 }
9294
9295 return 0;
9296 }