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