]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/rgw_admin.cc
import ceph 15.2.14
[ceph.git] / ceph / src / rgw / rgw_admin.cc
CommitLineData
7c673cae 1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
9f95a23c 2// vim: ts=8 sw=2 smarttab ft=cpp
7c673cae
FG
3
4#include <errno.h>
5#include <iostream>
6#include <sstream>
7#include <string>
8
9#include <boost/optional.hpp>
10
11fdf7f2
TL
11extern "C" {
12#include <liboath/oath.h>
13}
14
7c673cae 15#include "auth/Crypto.h"
3efd9988 16#include "compressor/Compressor.h"
7c673cae
FG
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
11fdf7f2
TL
26#include "include/util.h"
27
92f5a8d4 28#include "cls/rgw/cls_rgw_types.h"
7c673cae
FG
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"
11fdf7f2 38#include "rgw_otp.h"
7c673cae
FG
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"
7c673cae
FG
46#include "rgw_orphan.h"
47#include "rgw_sync.h"
9f95a23c
TL
48#include "rgw_trim_bilog.h"
49#include "rgw_trim_datalog.h"
50#include "rgw_trim_mdlog.h"
7c673cae
FG
51#include "rgw_data_sync.h"
52#include "rgw_rest_conn.h"
53#include "rgw_realm_watcher.h"
54#include "rgw_role.h"
31f18b77 55#include "rgw_reshard.h"
94b18763 56#include "rgw_http_client_curl.h"
11fdf7f2
TL
57#include "rgw_zone.h"
58#include "rgw_pubsub.h"
59#include "rgw_sync_module_pubsub.h"
9f95a23c 60#include "rgw_bucket_sync.h"
7c673cae 61
11fdf7f2 62#include "services/svc_sync_modules.h"
9f95a23c
TL
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"
7c673cae
FG
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
9f95a23c 76static rgw::sal::RGWRadosStore *store = NULL;
7c673cae 77
11fdf7f2
TL
78static 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
9f95a23c
TL
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
d2e6a577 105void usage()
7c673cae
FG
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";
9f95a23c 112 cout << " user rename rename user\n";
7c673cae
FG
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";
494da23a
TL
126 cout << " bucket list list buckets (specify --allow-unordered for\n";
127 cout << " faster, unsorted listing)\n";
7c673cae
FG
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";
9f95a23c 134 cout << " bucket chown link bucket to specified user and update its object ACLs\n";
7c673cae 135 cout << " bucket reshard reshard bucket\n";
11fdf7f2 136 cout << " bucket rewrite rewrite all objects in the specified bucket\n";
c07f9fc5
FG
137 cout << " bucket sync disable disable bucket sync\n";
138 cout << " bucket sync enable enable bucket sync\n";
e306af50 139 cout << " bucket radoslist list rados objects backing bucket's objects\n";
7c673cae
FG
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";
11fdf7f2 143 cout << " bi purge purge bucket index entries\n";
7c673cae 144 cout << " object rm remove object\n";
11fdf7f2 145 cout << " object put put object\n";
7c673cae
FG
146 cout << " object stat stat an object for its metadata\n";
147 cout << " object unlink unlink object from bucket index\n";
11fdf7f2 148 cout << " object rewrite rewrite the specified object\n";
7c673cae 149 cout << " objects expire run expired objects cleanup\n";
81eedcae
TL
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";
11fdf7f2 152 cout << " period rm remove a period\n";
7c673cae
FG
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";
11fdf7f2 168 cout << " realm rm remove a realm\n";
7c673cae
FG
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";
7c673cae
FG
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";
9f95a23c 180 cout << " zonegroup delete delete a zone group info\n";
7c673cae
FG
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";
11fdf7f2 184 cout << " zonegroup rm remove a zone from a zonegroup\n";
7c673cae
FG
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";
92f5a8d4 188 cout << " zonegroup placement get get a placement target of a specific zonegroup\n";
7c673cae
FG
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";
11fdf7f2 194 cout << " zone rm remove a zone\n";
7c673cae
FG
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";
92f5a8d4 201 cout << " zone placement get get a zone placement target\n";
7c673cae
FG
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";
11fdf7f2
TL
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";
7c673cae
FG
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";
11fdf7f2
TL
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";
7c673cae
FG
224 cout << " gc list dump expired garbage collection objects (specify\n";
225 cout << " --include-all to list all entries, including unexpired)\n";
11fdf7f2
TL
226 cout << " gc process manually process garbage (specify\n";
227 cout << " --include-all to process all entries, including unexpired)\n";
7c673cae 228 cout << " lc list list all bucket lifecycle progress\n";
11fdf7f2 229 cout << " lc get get a lifecycle bucket configuration\n";
7c673cae 230 cout << " lc process manually process lifecycle\n";
11fdf7f2 231 cout << " lc reshard fix fix LC for a resharded bucket\n";
7c673cae
FG
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";
9f95a23c 242 cout << " bilog status read bucket index log status\n";
7c673cae
FG
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";
e306af50
TL
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";
7c673cae 250 cout << " role create create a AWS role for use with STS\n";
11fdf7f2 251 cout << " role rm remove a role\n";
7c673cae
FG
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";
11fdf7f2 258 cout << " role-policy rm remove policy attached to a role\n";
31f18b77 259 cout << " reshard add schedule a resharding of a bucket\n";
11fdf7f2
TL
260 cout << " reshard list list all bucket resharding or scheduled to be resharded\n";
261 cout << " reshard status read bucket resharding status\n";
31f18b77
FG
262 cout << " reshard process process of scheduled reshard jobs\n";
263 cout << " reshard cancel cancel resharding a bucket\n";
f64942e4
AA
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";
94b18763
FG
266 cout << " sync error list list sync error\n";
267 cout << " sync error trim trim sync error\n";
11fdf7f2
TL
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";
7c673cae
FG
274 cout << "options:\n";
275 cout << " --tenant=<tenant> tenant name\n";
276 cout << " --uid=<id> user id\n";
9f95a23c 277 cout << " --new-uid=<id> new user id\n";
7c673cae
FG
278 cout << " --subuser=<name> subuser name\n";
279 cout << " --access-key=<key> S3 access key\n";
11fdf7f2 280 cout << " --email=<email> user's email address\n";
7c673cae
FG
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";
11fdf7f2 289 cout << " --display-name=<name> user's display name\n";
c07f9fc5 290 cout << " --max-buckets max number of buckets for a user\n";
7c673cae
FG
291 cout << " --admin set the admin flag on the user\n";
292 cout << " --system set the system flag on the user\n";
11fdf7f2 293 cout << " --op-mask set the op mask on the user\n";
28e407b8
AA
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";
9f95a23c 297 cout << " --object-version=<version> object version\n";
28e407b8
AA
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";
9f95a23c
TL
302 cout << " --bucket-new-name=<bucket>\n";
303 cout << " for bucket link: optional new name\n";
28e407b8
AA
304 cout << " --shard-id=<shard-id> optional for: \n";
305 cout << " mdlog list\n";
306 cout << " data sync status\n";
7c673cae
FG
307 cout << " required for: \n";
308 cout << " mdlog trim\n";
28e407b8 309 cout << " --max-entries=<entries> max entries for listing operations\n";
7c673cae
FG
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";
11fdf7f2 313 cout << " --url=<url> url for pushing/pulling period/realm\n";
7c673cae
FG
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";
7c673cae
FG
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";
11fdf7f2 332 cout << " --redirect-zone specify zone id to redirect when response is 404 (not found)\n";
7c673cae 333 cout << " --placement-id placement id for zonegroup placement commands\n";
11fdf7f2 334 cout << " --storage-class storage class for zonegroup placement commands\n";
7c673cae
FG
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";
c07f9fc5 339 cout << " --index-pool=<pool> placement target index pool\n";
224ce89b
WB
340 cout << " --data-pool=<pool> placement target data pool\n";
341 cout << " --data-extra-pool=<pool> placement target data extra (non-ec) pool\n";
7c673cae
FG
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";
9f95a23c 355 cout << " --bucket-index-max-shards override a zone/zonegroup's default bucket index shard count\n";
7c673cae
FG
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";
94b18763 369 cout << " --reset-stats option to 'user stats', reset stats in accordance with user buckets\n";
7c673cae
FG
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";
7c673cae
FG
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";
9f95a23c 377 cout << " --op-mask=<op-mask> permission of user's operations (e.g., \"read, write, delete, *\")\n";
7c673cae
FG
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";
11fdf7f2
TL
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";
9f95a23c 391 cout << " --max-concurrent-ios maximum concurrent ios for bucket operations (default: 32)\n";
7c673cae
FG
392 cout << "\n";
393 cout << "<date> := \"YYYY-MM-DD[ hh:mm:ss]\"\n";
394 cout << "\nQuota options:\n";
7c673cae
FG
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";
7c673cae
FG
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";
11fdf7f2 402 cout << " --detail detailed mode, log and stat head objects as well\n";
7c673cae
FG
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";
11fdf7f2
TL
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";
7f7e6c64
TL
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";
7c673cae
FG
423 cout << "\n";
424 generic_client_usage();
425}
426
7c673cae 427
9f95a23c
TL
428class SimpleCmd {
429public:
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
438private:
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;
31f18b77 455 }
9f95a23c
TL
456 void init_alias_map(Aliases& aliases) {
457 for (auto& alias_set : aliases) {
458 std::optional<string> first;
31f18b77 459
9f95a23c
TL
460 for (auto& alias : alias_set) {
461 if (!first) {
462 first = alias;
463 } else {
464 alias_map[alias] = *first;
465 }
466 }
467 }
31f18b77 468 }
9f95a23c
TL
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;
7c673cae
FG
475 }
476
9f95a23c 477 Node root;
7c673cae 478
9f95a23c
TL
479public:
480 SimpleCmd() {}
7c673cae 481
9f95a23c
TL
482 SimpleCmd(std::optional<Commands> cmds,
483 std::optional<Aliases> aliases) {
484 if (aliases) {
485 add_aliases(*aliases);
7c673cae 486 }
9f95a23c
TL
487
488 if (cmds) {
489 add_commands(*cmds);
31f18b77 490 }
9f95a23c
TL
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;
7c673cae 518 }
9f95a23c
TL
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);
7c673cae 553 }
9f95a23c
TL
554
555 return true;
556 }
557};
558
559
560namespace rgw_admin {
561
562enum 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,
e306af50 596 BUCKET_RADOS_LIST,
9f95a23c
TL
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
7c673cae
FG
758}
759
9f95a23c
TL
760using namespace rgw_admin;
761
762static 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 },
e306af50
TL
796 { "bucket radoslist", OPT::BUCKET_RADOS_LIST },
797 { "bucket rados list", OPT::BUCKET_RADOS_LIST },
9f95a23c
TL
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
974static SimpleCmd::Aliases cmd_aliases = {
975 { "delete", "del" },
976 { "remove", "rm" },
977 { "rename", "mv" },
978};
979
980
981
7c673cae
FG
982BIIndexType get_bi_index_type(const string& type_str) {
983 if (type_str == "plain")
11fdf7f2 984 return BIIndexType::Plain;
7c673cae 985 if (type_str == "instance")
11fdf7f2 986 return BIIndexType::Instance;
7c673cae 987 if (type_str == "olh")
11fdf7f2 988 return BIIndexType::OLH;
7c673cae 989
11fdf7f2 990 return BIIndexType::Invalid;
7c673cae
FG
991}
992
993void dump_bi_entry(bufferlist& bl, BIIndexType index_type, Formatter *formatter)
994{
11fdf7f2 995 auto iter = bl.cbegin();
7c673cae 996 switch (index_type) {
11fdf7f2
TL
997 case BIIndexType::Plain:
998 case BIIndexType::Instance:
7c673cae
FG
999 {
1000 rgw_bucket_dir_entry entry;
11fdf7f2 1001 decode(entry, iter);
7c673cae
FG
1002 encode_json("entry", entry, formatter);
1003 }
1004 break;
11fdf7f2 1005 case BIIndexType::OLH:
7c673cae
FG
1006 {
1007 rgw_bucket_olh_entry entry;
11fdf7f2 1008 decode(entry, iter);
7c673cae
FG
1009 encode_json("entry", entry, formatter);
1010 }
1011 break;
1012 default:
1013 ceph_abort();
1014 break;
1015 }
1016}
1017
1018static 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
1025static 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
1033static 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
1043static 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
1051static 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
f64942e4
AA
1063static 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);
11fdf7f2 1072 formatter->dump_int("num_shards", entry.num_shards);
f64942e4
AA
1073 formatter->close_section();
1074 }
1075 formatter->close_section();
1076 formatter->flush(cout);
1077}
1078
7c673cae 1079class StoreDestructor {
9f95a23c 1080 rgw::sal::RGWRadosStore *store;
7c673cae 1081public:
9f95a23c 1082 explicit StoreDestructor(rgw::sal::RGWRadosStore *_s) : store(_s) {}
7c673cae
FG
1083 ~StoreDestructor() {
1084 RGWStoreManager::close_storage(store);
11fdf7f2 1085 rgw_http_client_cleanup();
7c673cae
FG
1086 }
1087};
1088
e306af50
TL
1089static 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)
7c673cae
FG
1095{
1096 if (!bucket_name.empty()) {
9f95a23c 1097 auto obj_ctx = store->svc()->sysobj->init_obj_ctx();
7c673cae
FG
1098 int r;
1099 if (bucket_id.empty()) {
9f95a23c 1100 r = store->getRados()->get_bucket_info(store->svc(), tenant_name, bucket_name, bucket_info, nullptr, null_yield, pattrs);
7c673cae
FG
1101 } else {
1102 string bucket_instance_id = bucket_name + ":" + bucket_id;
9f95a23c 1103 r = store->getRados()->get_bucket_instance_info(obj_ctx, bucket_instance_id, bucket_info, NULL, pattrs, null_yield);
7c673cae
FG
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
9f95a23c
TL
1114static 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
7c673cae
FG
1123static 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
1159template <class T>
1160static 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);
9f95a23c
TL
1176 } catch (const JSONDecoder::err& e) {
1177 cout << "failed to decode JSON input: " << e.what() << std::endl;
7c673cae
FG
1178 return -EINVAL;
1179 }
1180 return 0;
1181}
1182
1183template <class T, class K>
1184static 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);
9f95a23c
TL
1200 } catch (const JSONDecoder::err& e) {
1201 cout << "failed to decode JSON input: " << e.what() << std::endl;
7c673cae
FG
1202 return -EINVAL;
1203 }
1204 return 0;
1205}
1206
1207static 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
1225template <class T>
1226static bool decode_dump(const char *field_name, bufferlist& bl, Formatter *f)
1227{
1228 T t;
1229
11fdf7f2 1230 auto iter = bl.cbegin();
7c673cae
FG
1231
1232 try {
11fdf7f2 1233 decode(t, iter);
7c673cae
FG
1234 } catch (buffer::error& err) {
1235 return false;
1236 }
1237
1238 encode_json(field_name, t, f);
1239
1240 return true;
1241}
1242
1243static bool dump_string(const char *field_name, bufferlist& bl, Formatter *f)
1244{
11fdf7f2
TL
1245 string val = bl.to_str();
1246 f->dump_string(field_name, val.c_str() /* hide encoded null termination chars */);
7c673cae
FG
1247
1248 return true;
1249}
1250
9f95a23c 1251void set_quota_info(RGWQuotaInfo& quota, OPT opt_cmd, int64_t max_size, int64_t max_objects,
7c673cae
FG
1252 bool have_max_size, bool have_max_objects)
1253{
1254 switch (opt_cmd) {
9f95a23c
TL
1255 case OPT::QUOTA_ENABLE:
1256 case OPT::GLOBAL_QUOTA_ENABLE:
7c673cae
FG
1257 quota.enabled = true;
1258
1259 // falling through on purpose
1260
9f95a23c
TL
1261 case OPT::QUOTA_SET:
1262 case OPT::GLOBAL_QUOTA_SET:
7c673cae
FG
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;
9f95a23c
TL
1278 case OPT::QUOTA_DISABLE:
1279 case OPT::GLOBAL_QUOTA_DISABLE:
7c673cae
FG
1280 quota.enabled = false;
1281 break;
9f95a23c
TL
1282 default:
1283 break;
7c673cae
FG
1284 }
1285}
1286
9f95a23c 1287int set_bucket_quota(rgw::sal::RGWRadosStore *store, OPT opt_cmd,
7c673cae
FG
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;
9f95a23c 1294 int r = store->getRados()->get_bucket_info(store->svc(), tenant_name, bucket_name, bucket_info, NULL, null_yield, &attrs);
7c673cae
FG
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
9f95a23c 1302 r = store->getRados()->put_bucket_instance_info(bucket_info, false, real_time(), &attrs);
7c673cae
FG
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
9f95a23c 1310int set_user_bucket_quota(OPT opt_cmd, RGWUser& user, RGWUserAdminOpState& op_state, int64_t max_size, int64_t max_objects,
7c673cae
FG
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
9f95a23c 1328int set_user_quota(OPT opt_cmd, RGWUser& user, RGWUserAdminOpState& op_state, int64_t max_size, int64_t max_objects,
7c673cae
FG
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
9f95a23c 1346int check_min_obj_stripe_size(rgw::sal::RGWRadosStore *store, RGWBucketInfo& bucket_info, rgw_obj& obj, uint64_t min_stripe_size, bool *need_rewrite)
7c673cae
FG
1347{
1348 map<string, bufferlist> attrs;
1349 uint64_t obj_size;
1350
1351 RGWObjectCtx obj_ctx(store);
9f95a23c 1352 RGWRados::Object op_target(store->getRados(), bucket_info, obj_ctx, obj);
7c673cae
FG
1353 RGWRados::Object::Read read_op(&op_target);
1354
1355 read_op.params.attrs = &attrs;
1356 read_op.params.obj_size = &obj_size;
1357
9f95a23c 1358 int ret = read_op.prepare(null_yield);
7c673cae
FG
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;
11fdf7f2
TL
1375 auto biter = bl.cbegin();
1376 decode(manifest, biter);
7c673cae
FG
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
1398int 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
9f95a23c 1417 RGWRados::Object op_target(store->getRados(), bucket_info, obj_ctx, obj);
7c673cae
FG
1418 RGWRados::Object::Read read_op(&op_target);
1419
9f95a23c 1420 int ret = read_op.prepare(null_yield);
7c673cae
FG
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) {
9f95a23c 1428 ret = store->getRados()->fix_head_obj_locator(bucket_info, needs_fixing, remove_bad, key);
7c673cae
FG
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
1436done:
1437 f->dump_string("status", status);
1438
1439 f->close_section();
1440
1441 return 0;
1442}
1443
1444int 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
9f95a23c 1455 int ret = store->getRados()->fix_tail_obj_locator(bucket_info, key, fix, &needs_fixing, null_yield);
7c673cae
FG
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
1471int 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
9f95a23c 1501 RGWRados::Bucket target(store->getRados(), bucket_info);
7c673cae
FG
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 {
9f95a23c 1515 ret = list_op.list_objects(max_entries - count, &result, &common_prefixes, &truncated, null_yield);
7c673cae
FG
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);
11fdf7f2
TL
1532 if (ret < 0) {
1533 cerr << "ERROR: check_obj_tail_locator_underscore(): " << cpp_strerror(-ret) << std::endl;
1534 return -ret;
1535 }
7c673cae
FG
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
9f95a23c 1550static boost::optional<RGWRESTConn> get_remote_conn(rgw::sal::RGWRadosStore *store,
7c673cae
FG
1551 const RGWZoneGroup& zonegroup,
1552 const std::string& remote)
1553{
1554 boost::optional<RGWRESTConn> conn;
1555 if (remote == zonegroup.get_id()) {
9f95a23c 1556 conn.emplace(store->ctx(), store->svc()->zone, remote, zonegroup.endpoints);
7c673cae
FG
1557 } else {
1558 for (const auto& z : zonegroup.zones) {
1559 const auto& zone = z.second;
1560 if (remote == zone.id) {
9f95a23c 1561 conn.emplace(store->ctx(), store->svc()->zone, remote, zone.endpoints);
7c673cae
FG
1562 break;
1563 }
1564 }
1565 }
1566 return conn;
1567}
1568
1569/// search each zonegroup for a connection
9f95a23c 1570static boost::optional<RGWRESTConn> get_remote_conn(rgw::sal::RGWRadosStore *store,
7c673cae
FG
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
224ce89b
WB
1584// we expect a very small response
1585static constexpr size_t MAX_REST_RESPONSE = 128 * 1024;
1586
7c673cae
FG
1587static int send_to_remote_gateway(RGWRESTConn* conn, req_info& info,
1588 bufferlist& in_data, JSONParser& parser)
1589{
224ce89b
WB
1590 if (!conn) {
1591 return -EINVAL;
1592 }
1593
1594 ceph::bufferlist response;
7c673cae 1595 rgw_user user;
224ce89b 1596 int ret = conn->forward(user, info, nullptr, MAX_REST_RESPONSE, &in_data, &response);
7c673cae
FG
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
1606static 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;
11fdf7f2 1619 RGWRESTSimpleRequest req(g_ceph_context, info.method, url, NULL, &params);
7c673cae
FG
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
1632static 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
1643static int commit_period(RGWRealm& realm, RGWPeriod& period,
1644 string remote, const string& url,
1645 const string& access, const string& secret,
1646 bool force)
1647{
9f95a23c 1648 auto& master_zone = period.get_master_zone();
7c673cae
FG
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?
9f95a23c 1654 if (store->svc()->zone->zone_id() == master_zone) {
7c673cae
FG
1655 // read the current period
1656 RGWPeriod current_period;
9f95a23c 1657 int ret = current_period.init(g_ceph_context, store->svc()->sysobj, realm.get_id());
7c673cae
FG
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
11fdf7f2 1664 ret = period.commit(store, realm, current_period, cerr, force);
7c673cae
FG
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
9f95a23c 1673 remote = master_zone.id;
e306af50 1674 cerr << "Sending period to new master zone " << remote << std::endl;
7c673cae
FG
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
9f95a23c 1689 period.set_id(string());
7c673cae
FG
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);
9f95a23c
TL
1718 } catch (const JSONDecoder::err& e) {
1719 cout << "failed to decode JSON input: " << e.what() << std::endl;
7c673cae
FG
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
1748static 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);
9f95a23c 1755 int ret = realm.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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);
9f95a23c 1765 ret = period.init(g_ceph_context, store->svc()->sysobj, realm.get_id());
7c673cae
FG
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);
7c673cae
FG
1791 return 0;
1792}
1793
1794static 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
1808static 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 }
9f95a23c 1837 ret = period->init(g_ceph_context, store->svc()->sysobj, false);
7c673cae
FG
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);
9f95a23c
TL
1844 } catch (const JSONDecoder::err& e) {
1845 cout << "failed to decode JSON input: " << e.what() << std::endl;
7c673cae
FG
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 }
224ce89b
WB
1852 // store latest epoch (ignore errors)
1853 period->update_latest_epoch(period->get_epoch());
7c673cae
FG
1854 return 0;
1855}
1856
9f95a23c 1857static int read_current_period_id(rgw::sal::RGWRadosStore* store, const std::string& realm_id,
7c673cae
FG
1858 const std::string& realm_name,
1859 std::string* period_id)
1860{
1861 RGWRealm realm(realm_id, realm_name);
9f95a23c 1862 int ret = realm.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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
1871void 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
1879stringstream& 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
1888static void get_md_sync_status(list<string>& status)
1889{
9f95a23c 1890 RGWMetaSyncStatusManager sync(store, store->svc()->rados->get_async_processor());
7c673cae
FG
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;
28e407b8 1928 set<int> shards_behind_set;
7c673cae
FG
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;
11fdf7f2 1936 int shard_id = marker_iter.first;
28e407b8 1937 shards_behind_set.insert(shard_id);
7c673cae
FG
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
7c673cae 1955 map<int, RGWMetadataLogInfo> master_shards_info;
9f95a23c 1956 string master_period = store->svc()->zone->get_current_period_id();
7c673cae
FG
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;
28e407b8 1982 shards_behind_set.insert(shard_id);
7c673cae
FG
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";
28e407b8
AA
1992
1993 push_ss(ss, status) << "behind shards: " << "[" << shards_behind_set << "]";
7c673cae
FG
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 {
92f5a8d4
TL
2000 std::optional<std::pair<int, ceph::real_time>> oldest;
2001
7c673cae
FG
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();
92f5a8d4
TL
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);
7c673cae
FG
2011 }
2012 }
2013 }
2014
92f5a8d4
TL
2015 if (oldest) {
2016 push_ss(ss, status) << "oldest incremental change not applied: "
2017 << oldest->second << " [" << oldest->first << ']';
7c673cae
FG
2018 }
2019 }
2020 }
2021
2022 flush_ss(ss, status);
2023}
2024
9f95a23c 2025static void get_data_sync_status(const rgw_zone_id& source_zone, list<string>& status, int tab)
7c673cae
FG
2026{
2027 stringstream ss;
2028
11fdf7f2
TL
2029 RGWZone *sz;
2030
9f95a23c 2031 if (!store->svc()->zone->find_zone(source_zone, &sz)) {
7c673cae
FG
2032 push_ss(ss, status, tab) << string("zone not found");
2033 flush_ss(ss, status);
2034 return;
2035 }
7c673cae 2036
9f95a23c 2037 if (!store->svc()->zone->zone_syncs_from(store->svc()->zone->get_zone(), *sz)) {
7c673cae
FG
2038 push_ss(ss, status, tab) << string("not syncing from zone");
2039 flush_ss(ss, status);
2040 return;
2041 }
9f95a23c 2042 RGWDataSyncStatusManager sync(store, store->svc()->rados->get_async_processor(), source_zone, nullptr);
7c673cae
FG
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
28e407b8
AA
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
7c673cae
FG
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;
28e407b8 2088 set<int> shards_behind_set;
7c673cae
FG
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;
11fdf7f2 2096 int shard_id = marker_iter.first;
28e407b8 2097 shards_behind_set.insert(shard_id);
7c673cae
FG
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
7c673cae
FG
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;
28e407b8 2137 shards_behind_set.insert(shard_id);
7c673cae
FG
2138 }
2139 }
2140
2141 int total_behind = shards_behind.size() + (sync_status.sync_info.num_shards - num_inc);
28e407b8
AA
2142 int total_recovering = recovering_shards.size();
2143 if (total_behind == 0 && total_recovering == 0) {
7c673cae 2144 push_ss(ss, status, tab) << "data is caught up with source";
28e407b8 2145 } else if (total_behind > 0) {
7c673cae
FG
2146 push_ss(ss, status, tab) << "data is behind on " << total_behind << " shards";
2147
28e407b8
AA
2148 push_ss(ss, status, tab) << "behind shards: " << "[" << shards_behind_set << "]" ;
2149
7c673cae
FG
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 {
92f5a8d4
TL
2155 std::optional<std::pair<int, ceph::real_time>> oldest;
2156
7c673cae
FG
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();
92f5a8d4
TL
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);
7c673cae
FG
2166 }
2167 }
2168 }
2169
92f5a8d4
TL
2170 if (oldest) {
2171 push_ss(ss, status, tab) << "oldest incremental change not applied: "
2172 << oldest->second << " [" << oldest->first << ']';
7c673cae
FG
2173 }
2174 }
2175 }
2176
28e407b8
AA
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
7c673cae
FG
2182 flush_ss(ss, status);
2183}
2184
2185static 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
2196static void sync_status(Formatter *formatter)
2197{
9f95a23c
TL
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();
7c673cae
FG
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
9f95a23c 2210 if (store->svc()->zone->is_meta_master()) {
7c673cae
FG
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
9f95a23c 2220 auto& zone_conn_map = store->svc()->zone->get_zone_conn_map();
11fdf7f2
TL
2221
2222 for (auto iter : zone_conn_map) {
9f95a23c 2223 const rgw_zone_id& source_id = iter.first;
7c673cae 2224 string source_str = "source: ";
9f95a23c 2225 string s = source_str + source_id.id;
11fdf7f2 2226 RGWZone *sz;
9f95a23c 2227 if (store->svc()->zone->find_zone(source_id, &sz)) {
11fdf7f2 2228 s += string(" (") + sz->name + ")";
7c673cae
FG
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
28e407b8
AA
2237struct indented {
2238 int w; // indent width
11fdf7f2
TL
2239 std::string_view header;
2240 indented(int w, std::string_view header = "") : w(w), header(header) {}
28e407b8
AA
2241};
2242std::ostream& operator<<(std::ostream& out, const indented& h) {
2243 return out << std::setw(h.w) << h.header << std::setw(1) << ' ';
2244}
2245
9f95a23c 2246static int remote_bilog_markers(rgw::sal::RGWRadosStore *store, const RGWZone& source,
28e407b8
AA
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
9f95a23c 2271static int bucket_source_sync_status(rgw::sal::RGWRadosStore *store, const RGWZone& zone,
28e407b8
AA
2272 const RGWZone& source, RGWRESTConn *conn,
2273 const RGWBucketInfo& bucket_info,
9f95a23c 2274 rgw_sync_bucket_pipe pipe,
28e407b8
AA
2275 int width, std::ostream& out)
2276{
9f95a23c 2277 out << indented{width, "source zone"} << source.id << " (" << source.name << ")" << std::endl;
28e407b8
AA
2278
2279 // syncing from this zone?
494da23a 2280 if (!zone.syncs_from(source.name)) {
9f95a23c 2281 out << indented{width} << "does not sync from zone\n";
28e407b8
AA
2282 return 0;
2283 }
9f95a23c
TL
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
28e407b8 2301 std::vector<rgw_bucket_shard_sync_info> status;
9f95a23c 2302 r = rgw_bucket_sync_status(dpp(), store, pipe, bucket_info, &source_bucket_info, &status);
28e407b8
AA
2303 if (r < 0) {
2304 lderr(store->ctx()) << "failed to read bucket sync status: " << cpp_strerror(r) << dendl;
2305 return r;
2306 }
2307
9f95a23c
TL
2308 out << indented{width, "source bucket"} << source_bucket_info.bucket.get_key() << std::endl;
2309
28e407b8
AA
2310 int num_full = 0;
2311 int num_inc = 0;
2312 uint64_t full_complete = 0;
11fdf7f2 2313 const size_t total_shards = status.size();
28e407b8
AA
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;
9f95a23c 2333 r = remote_bilog_markers(store, source, conn, source_bucket_info, &remote_markers);
28e407b8
AA
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 }
eafe8130 2351 if (!shards_behind.empty()) {
28e407b8
AA
2352 out << indented{width} << "bucket is behind on " << shards_behind.size() << " shards\n";
2353 out << indented{width} << "behind shards: [" << shards_behind << "]\n" ;
eafe8130
TL
2354 } else if (!num_full) {
2355 out << indented{width} << "bucket is caught up with source\n";
28e407b8
AA
2356 }
2357 return 0;
2358}
2359
9f95a23c
TL
2360void 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
2372static 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
2382static 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
2400static 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
2414rgw_zone_id validate_zone_id(const rgw_zone_id& zone_id)
2415{
2416 return resolve_zone_id(zone_id.id);
2417}
2418
2419static 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
2533static int bucket_sync_info(rgw::sal::RGWRadosStore *store, const RGWBucketInfo& info,
28e407b8
AA
2534 std::ostream& out)
2535{
9f95a23c
TL
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();
28e407b8
AA
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
9f95a23c 2546 if (!store->ctl()->bucket->bucket_imports_data(info.bucket, null_yield)) {
28e407b8
AA
2547 out << "Sync is disabled for bucket " << info.bucket.name << '\n';
2548 return 0;
2549 }
2550
9f95a23c
TL
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
2572static 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
28e407b8
AA
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 }
11fdf7f2
TL
2612 auto c = zone_conn_map.find(source_zone_id);
2613 if (c == zone_conn_map.end()) {
28e407b8
AA
2614 lderr(store->ctx()) << "No connection to zone " << z->second.name << dendl;
2615 return -EINVAL;
2616 }
9f95a23c
TL
2617 zone_ids.insert(source_zone_id);
2618 } else {
2619 for (const auto& entry : zonegroup.zones) {
2620 zone_ids.insert(entry.second.id);
2621 }
28e407b8
AA
2622 }
2623
9f95a23c
TL
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 }
28e407b8
AA
2646 }
2647 }
9f95a23c 2648
28e407b8
AA
2649 return 0;
2650}
2651
31f18b77 2652static void parse_tier_config_param(const string& s, map<string, string, ltstr_nocase>& out)
7c673cae 2653{
11fdf7f2
TL
2654 int level = 0;
2655 string cur_conf;
7c673cae 2656 list<string> confs;
11fdf7f2
TL
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
7c673cae
FG
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
11fdf7f2
TL
2686static int check_pool_support_omap(const rgw_pool& pool)
2687{
2688 librados::IoCtx io_ctx;
9f95a23c 2689 int ret = store->getRados()->get_rados_handle()->ioctx_create(pool.to_str().c_str(), io_ctx);
11fdf7f2
TL
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
9f95a23c 2704int check_reshard_bucket_params(rgw::sal::RGWRadosStore *store,
31f18b77
FG
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;
7c673cae
FG
2718 }
2719
31f18b77
FG
2720 if (!num_shards_specified) {
2721 cerr << "ERROR: --num-shards not specified" << std::endl;
2722 return -EINVAL;
7c673cae
FG
2723 }
2724
9f95a23c
TL
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;
31f18b77 2732 return -EINVAL;
7c673cae
FG
2733 }
2734
31f18b77
FG
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;
f64942e4 2738 return ret;
7c673cae 2739 }
7c673cae 2740
9f95a23c 2741 if (bucket_info.reshard_status != cls_rgw_reshard_status::NOT_RESHARDING) {
92f5a8d4
TL
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
31f18b77 2748 int num_source_shards = (bucket_info.num_shards > 0 ? bucket_info.num_shards : 1);
7c673cae 2749
31f18b77
FG
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;
7c673cae 2754 }
31f18b77
FG
2755 return 0;
2756}
7c673cae 2757
11fdf7f2
TL
2758static 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}
7c673cae 2804
91327a77
AA
2805static 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 (;;) {
9f95a23c
TL
2814 int ret = store->svc()->cls->timelog.trim(oid, start_time, end_time,
2815 start_marker, end_marker, nullptr,
2816 null_yield);
91327a77
AA
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
9f95a23c
TL
2830const string& get_tier_type(rgw::sal::RGWRadosStore *store) {
2831 return store->svc()->zone->get_zone().tier_type;
2832}
2833
2834static bool symmetrical_flow_opt(const string& opt)
2835{
2836 return (opt == "symmetrical" || opt == "symmetric");
2837}
2838
2839static bool directional_flow_opt(const string& opt)
2840{
2841 return (opt == "directional" || opt == "direction");
2842}
2843
2844template <class T>
2845static 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
2853template <class T>
2854static 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
2862template <class T>
2863static 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
2872void 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
2891class 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
2903public:
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
2967void 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}
2978void 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
2994static 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;
11fdf7f2
TL
3003}
3004
9f95a23c
TL
3005class 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;
3023public:
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
7c673cae 3036int main(int argc, const char **argv)
7c673cae
FG
3037{
3038 vector<const char*> args;
3039 argv_to_vec(argc, (const char **)argv, args);
11fdf7f2
TL
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 }
7c673cae
FG
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())
11fdf7f2
TL
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());
7c673cae
FG
3055 }
3056
3057 common_init_finish(g_ceph_context);
3058
3059 rgw_user user_id;
3060 string tenant;
9f95a23c 3061 rgw_user new_user_id;
7c673cae
FG
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;
11fdf7f2 3069 std::string master_zone;
7c673cae
FG
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;
11fdf7f2
TL
3075 std::string redirect_zone;
3076 bool redirect_zone_set = false;
7c673cae
FG
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;
7c673cae
FG
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;
9f95a23c 3096 OPT opt_cmd = OPT::NO_CMD;
7c673cae
FG
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;
9f95a23c 3103 string new_bucket_name;
7c673cae 3104 Formatter *formatter = NULL;
9f95a23c 3105 Formatter *zone_formatter = nullptr;
7c673cae 3106 int purge_data = false;
7c673cae
FG
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;
181888fb 3131 bool max_entries_specified = false;
7c673cae
FG
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;
7c673cae
FG
3138 string client_id;
3139 string op_id;
7c673cae
FG
3140 string op_mask_str;
3141 string quota_scope;
3142 string object_version;
3143 string placement_id;
9f95a23c 3144 std::optional<string> opt_storage_class;
7c673cae
FG
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;
494da23a 3154 int allow_unordered = false;
7c673cae
FG
3155
3156 int sync_stats = false;
94b18763 3157 int reset_stats = false;
7c673cae
FG
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
11fdf7f2 3170 BIIndexType bi_index_type = BIIndexType::Plain;
7c673cae
FG
3171
3172 string job_id;
3173 int num_shards = 0;
3174 bool num_shards_specified = false;
9f95a23c 3175 std::optional<int> bucket_index_max_shards;
7c673cae
FG
3176 int max_concurrent_ios = 32;
3177 uint64_t orphan_stale_secs = (24 * 3600);
11fdf7f2 3178 int detail = false;
7c673cae
FG
3179
3180 std::string val;
3181 std::ostringstream errs;
3182 string err;
7c673cae
FG
3183
3184 string source_zone_name;
9f95a23c 3185 rgw_zone_id source_zone; /* zone id */
7c673cae
FG
3186
3187 string tier_type;
3188 bool tier_type_specified = false;
3189
31f18b77
FG
3190 map<string, string, ltstr_nocase> tier_config_add;
3191 map<string, string, ltstr_nocase> tier_config_rm;
7c673cae
FG
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
11fdf7f2
TL
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;
91327a77
AA
3207 int trim_delay_ms = 0;
3208
11fdf7f2
TL
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;
9f95a23c
TL
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
eafe8130 3253 rgw::notify::EventTypeList event_types;
11fdf7f2 3254
9f95a23c
TL
3255 SimpleCmd cmd(all_cmds, cmd_aliases);
3256
7f7e6c64
TL
3257 std::optional<std::string> rgw_obj_fs; // radoslist field separator
3258
7c673cae
FG
3259 for (std::vector<const char*>::iterator i = args.begin(); i != args.end(); ) {
3260 if (ceph_argparse_double_dash(args, i)) {
3261 break;
7c673cae
FG
3262 } else if (ceph_argparse_witharg(args, i, &val, "-i", "--uid", (char*)NULL)) {
3263 user_id.from_str(val);
eafe8130
TL
3264 if (user_id.empty()) {
3265 cerr << "no value for uid" << std::endl;
3266 exit(1);
3267 }
9f95a23c
TL
3268 } else if (ceph_argparse_witharg(args, i, &val, "-i", "--new-uid", (char*)NULL)) {
3269 new_user_id.from_str(val);
7c673cae
FG
3270 } else if (ceph_argparse_witharg(args, i, &val, "--tenant", (char*)NULL)) {
3271 tenant = val;
9f95a23c 3272 opt_tenant = val;
7c673cae
FG
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;
9f95a23c 3286 opt_bucket_name = val;
7c673cae
FG
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;
7c673cae
FG
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;
11fdf7f2 3308 exit(1);
7c673cae
FG
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
11fdf7f2 3316 } else if (ceph_argparse_binary_flag(args, i, &show_log_entries, NULL, "--show-log-entries", (char*)NULL)) {
7c673cae 3317 // do nothing
11fdf7f2 3318 } else if (ceph_argparse_binary_flag(args, i, &show_log_sum, NULL, "--show-log-sum", (char*)NULL)) {
7c673cae 3319 // do nothing
11fdf7f2 3320 } else if (ceph_argparse_binary_flag(args, i, &skip_zero_entries, NULL, "--skip-zero-entries", (char*)NULL)) {
7c673cae
FG
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
7c673cae
FG
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);
181888fb 3347 max_entries_specified = true;
7c673cae
FG
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)) {
f64942e4 3353 max_size = strict_iec_cast<long long>(val.c_str(), &err);
7c673cae
FG
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;
9f95a23c
TL
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 }
7c673cae
FG
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;
7c673cae
FG
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;
9f95a23c 3418 opt_bucket_id = val;
7c673cae 3419 if (bucket_id.empty()) {
1911f103 3420 cerr << "no value for bucket-id" << std::endl;
11fdf7f2 3421 exit(1);
7c673cae 3422 }
9f95a23c
TL
3423 } else if (ceph_argparse_witharg(args, i, &val, "--bucket-new-name", (char*)NULL)) {
3424 new_bucket_name = val;
7c673cae
FG
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
94b18763
FG
3455 } else if (ceph_argparse_binary_flag(args, i, &reset_stats, NULL, "--reset-stats", (char*)NULL)) {
3456 // do nothing
7c673cae
FG
3457 } else if (ceph_argparse_binary_flag(args, i, &include_all, NULL, "--include-all", (char*)NULL)) {
3458 // do nothing
494da23a
TL
3459 } else if (ceph_argparse_binary_flag(args, i, &allow_unordered, NULL, "--allow-unordered", (char*)NULL)) {
3460 // do nothing
7c673cae
FG
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;
7c673cae
FG
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);
11fdf7f2 3486 if (bi_index_type == BIIndexType::Invalid) {
7c673cae
FG
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 */
11fdf7f2
TL
3495 } else if (ceph_argparse_witharg(args, i, &val, "--redirect-zone", (char*)NULL)) {
3496 redirect_zone = val;
3497 redirect_zone_set = true;
7c673cae
FG
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;
7c673cae
FG
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;
11fdf7f2 3521 } else if (ceph_argparse_witharg(args, i, &val, "--storage-class", (char*)NULL)) {
9f95a23c 3522 opt_storage_class = val;
7c673cae 3523 } else if (ceph_argparse_witharg(args, i, &val, "--tags", (char*)NULL)) {
9f95a23c 3524 get_str_list(val, ",", tags);
7c673cae 3525 } else if (ceph_argparse_witharg(args, i, &val, "--tags-add", (char*)NULL)) {
9f95a23c 3526 get_str_list(val, ",", tags_add);
7c673cae 3527 } else if (ceph_argparse_witharg(args, i, &val, "--tags-rm", (char*)NULL)) {
9f95a23c 3528 get_str_list(val, ",", tags_rm);
7c673cae
FG
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;
9f95a23c
TL
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;
7c673cae
FG
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;
11fdf7f2
TL
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());
91327a77
AA
3605 } else if (ceph_argparse_witharg(args, i, &val, "--trim-delay-ms", (char*)NULL)) {
3606 trim_delay_ms = atoi(val.c_str());
11fdf7f2
TL
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)) {
eafe8130 3620 rgw::notify::from_string_list(val, event_types);
9f95a23c
TL
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;
11fdf7f2
TL
3676 } else if (ceph_argparse_binary_flag(args, i, &detail, NULL, "--detail", (char*)NULL)) {
3677 // do nothing
7f7e6c64
TL
3678 } else if (ceph_argparse_witharg(args, i, &val, "--rgw-obj-fs", (char*)NULL)) {
3679 rgw_obj_fs = val;
7c673cae
FG
3680 } else if (strncmp(*i, "-", 1) == 0) {
3681 cerr << "ERROR: invalid flag " << *i << std::endl;
3682 return EINVAL;
3683 } else {
3684 ++i;
3685 }
3686 }
7c673cae
FG
3687
3688 if (args.empty()) {
d2e6a577 3689 usage();
11fdf7f2 3690 exit(1);
7c673cae
FG
3691 }
3692 else {
9f95a23c
TL
3693 std::vector<string> extra_args;
3694 std::vector<string> expected;
7c673cae 3695
9f95a23c
TL
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 }
11fdf7f2 3715 exit(1);
d2e6a577 3716 }
7c673cae 3717
9f95a23c
TL
3718 opt_cmd = std::any_cast<OPT>(_opt_cmd);
3719
7c673cae 3720 /* some commands may have an optional extra param */
9f95a23c 3721 if (!extra_args.empty()) {
7c673cae 3722 switch (opt_cmd) {
9f95a23c
TL
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];
7c673cae
FG
3728 break;
3729 default:
3730 break;
3731 }
3732 }
3733
9f95a23c
TL
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
31f18b77
FG
3741 if (tenant.empty()) {
3742 tenant = user_id.tenant;
3743 } else {
9f95a23c
TL
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) {
31f18b77
FG
3756 cerr << "ERROR: --tenant is set, but there's no user ID" << std::endl;
3757 return EINVAL;
3758 }
3759 user_id.tenant = tenant;
3760 }
9f95a23c
TL
3761
3762 if (!new_user_id.empty() && !tenant.empty()) {
3763 new_user_id.tenant = tenant;
3764 }
3765
7c673cae
FG
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;
11fdf7f2 3789 exit(1);
7c673cae
FG
3790 }
3791
9f95a23c
TL
3792 zone_formatter = new JSONFormatter_PrettyZone(pretty_format);
3793
11fdf7f2
TL
3794 realm_name = g_conf()->rgw_realm;
3795 zone_name = g_conf()->rgw_zone;
3796 zonegroup_name = g_conf()->rgw_zonegroup;
7c673cae
FG
3797
3798 RGWStreamFlusher f(formatter, cout);
3799
3800 // not a raw op if 'period update' needs to commit to master
9f95a23c 3801 bool raw_period_update = opt_cmd == OPT::PERIOD_UPDATE && !commit;
f91f0fd5
TL
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
9f95a23c
TL
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,
9f95a23c
TL
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,
28e407b8 3888 };
7c673cae 3889
9f95a23c 3890
7c673cae 3891 bool raw_storage_op = (raw_storage_ops_list.find(opt_cmd) != raw_storage_ops_list.end() ||
f91f0fd5 3892 raw_period_update || raw_period_pull);
28e407b8 3893 bool need_cache = readonly_ops_list.find(opt_cmd) == readonly_ops_list.end();
7c673cae
FG
3894
3895 if (raw_storage_op) {
3896 store = RGWStoreManager::get_raw_storage(g_ceph_context);
3897 } else {
28e407b8 3898 store = RGWStoreManager::get_storage(g_ceph_context, false, false, false, false, false,
11fdf7f2 3899 need_cache && g_conf()->rgw_cache_enabled);
7c673cae
FG
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()) {
9f95a23c 3907 if (!store->svc()->zone->find_zone_id_by_name(source_zone_name, &source_zone)) {
7c673cae
FG
3908 cerr << "WARNING: cannot find source zone id for name=" << source_zone_name << std::endl;
3909 source_zone = source_zone_name;
3910 }
3911 }
3912
11fdf7f2 3913 rgw_http_client_init(g_ceph_context);
7c673cae 3914
94b18763
FG
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
11fdf7f2
TL
3924 oath_init();
3925
7c673cae
FG
3926 StoreDestructor store_destructor(store);
3927
3928 if (raw_storage_op) {
3929 switch (opt_cmd) {
9f95a23c 3930 case OPT::PERIOD_DELETE:
7c673cae
FG
3931 {
3932 if (period_id.empty()) {
3933 cerr << "missing period id" << std::endl;
3934 return EINVAL;
3935 }
3936 RGWPeriod period(period_id);
9f95a23c 3937 int ret = period.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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;
9f95a23c 3950 case OPT::PERIOD_GET:
7c673cae
FG
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);
9f95a23c 3958 int ret = realm.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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);
9f95a23c 3969 int ret = period.init(g_ceph_context, store->svc()->sysobj, realm_id, realm_name);
7c673cae
FG
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);
7c673cae
FG
3976 }
3977 break;
9f95a23c 3978 case OPT::PERIOD_GET_CURRENT:
7c673cae
FG
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;
9f95a23c 3990 case OPT::PERIOD_LIST:
7c673cae
FG
3991 {
3992 list<string> periods;
9f95a23c 3993 int ret = store->svc()->zone->list_periods(periods);
7c673cae
FG
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);
7c673cae
FG
4002 }
4003 break;
9f95a23c 4004 case OPT::PERIOD_UPDATE:
7c673cae
FG
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;
9f95a23c 4014 case OPT::PERIOD_PULL:
7c673cae
FG
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);
9f95a23c 4021 int ret = realm.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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());
9f95a23c 4027 ret = current_period.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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
9f95a23c 4034 remote = current_period.get_master_zone().id;
7c673cae
FG
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);
7c673cae
FG
4056 }
4057 break;
9f95a23c
TL
4058 case OPT::GLOBAL_QUOTA_GET:
4059 case OPT::GLOBAL_QUOTA_SET:
4060 case OPT::GLOBAL_QUOTA_ENABLE:
4061 case OPT::GLOBAL_QUOTA_DISABLE:
7c673cae
FG
4062 {
4063 if (realm_id.empty()) {
9f95a23c 4064 RGWRealm realm(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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;
9f95a23c 4085 int ret = period_config.read(store->svc()->sysobj, realm_id);
7c673cae
FG
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);
9f95a23c 4103 } else if (quota_scope.empty() && opt_cmd == OPT::GLOBAL_QUOTA_GET) {
7c673cae
FG
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
9f95a23c 4114 if (opt_cmd != OPT::GLOBAL_QUOTA_GET) {
7c673cae 4115 // write the modified period config
9f95a23c 4116 ret = period_config.write(store->svc()->sysobj, realm_id);
7c673cae
FG
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);
7c673cae
FG
4133 }
4134 break;
9f95a23c 4135 case OPT::REALM_CREATE:
7c673cae
FG
4136 {
4137 if (realm_name.empty()) {
4138 cerr << "missing realm name" << std::endl;
4139 return EINVAL;
4140 }
4141
9f95a23c 4142 RGWRealm realm(realm_name, g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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);
7c673cae
FG
4158 }
4159 break;
9f95a23c 4160 case OPT::REALM_DELETE:
7c673cae
FG
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 }
9f95a23c 4167 int ret = realm.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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;
9f95a23c 4180 case OPT::REALM_GET:
7c673cae
FG
4181 {
4182 RGWRealm realm(realm_id, realm_name);
9f95a23c 4183 int ret = realm.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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);
7c673cae
FG
4194 }
4195 break;
9f95a23c 4196 case OPT::REALM_GET_DEFAULT:
7c673cae 4197 {
9f95a23c 4198 RGWRealm realm(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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;
9f95a23c 4211 case OPT::REALM_LIST:
7c673cae 4212 {
9f95a23c 4213 RGWRealm realm(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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;
9f95a23c 4220 ret = store->svc()->zone->list_realms(realms);
7c673cae
FG
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);
7c673cae
FG
4230 }
4231 break;
9f95a23c 4232 case OPT::REALM_LIST_PERIODS:
7c673cae
FG
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;
9f95a23c 4239 ret = store->svc()->zone->list_periods(period_id, periods);
7c673cae
FG
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);
7c673cae
FG
4249 }
4250 break;
4251
9f95a23c 4252 case OPT::REALM_RENAME:
7c673cae
FG
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 }
9f95a23c 4263 int ret = realm.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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;
9f95a23c 4278 case OPT::REALM_SET:
7c673cae
FG
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;
9f95a23c 4286 int ret = realm.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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
9f95a23c 4330 case OPT::REALM_DEFAULT:
7c673cae
FG
4331 {
4332 RGWRealm realm(realm_id, realm_name);
9f95a23c 4333 int ret = realm.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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;
9f95a23c 4345 case OPT::REALM_PULL:
7c673cae
FG
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;
9f95a23c 4375 realm.init(g_ceph_context, store->svc()->sysobj, false);
7c673cae
FG
4376 try {
4377 decode_json_obj(realm, &p);
9f95a23c
TL
4378 } catch (const JSONDecoder::err& e) {
4379 cerr << "failed to decode JSON response: " << e.what() << std::endl;
7c673cae
FG
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);
7c673cae 4416 }
11fdf7f2 4417 break;
7c673cae 4418
9f95a23c 4419 case OPT::ZONEGROUP_ADD:
7c673cae
FG
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);
9f95a23c 4427 int ret = zonegroup.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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);
9f95a23c 4434 ret = zone.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
4435 if (ret < 0) {
4436 cerr << "unable to initialize zone: " << cpp_strerror(-ret) << std::endl;
4437 return -ret;
4438 }
224ce89b
WB
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
7c673cae 4448 string *ptier_type = (tier_type_specified ? &tier_type : nullptr);
11fdf7f2
TL
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 }
7c673cae
FG
4457
4458 bool *psync_from_all = (sync_from_all_specified ? &sync_from_all : nullptr);
11fdf7f2 4459 string *predirect_zone = (redirect_zone_set ? &redirect_zone : nullptr);
7c673cae
FG
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,
11fdf7f2 4465 psync_from_all, sync_from, sync_from_rm,
9f95a23c
TL
4466 predirect_zone, bucket_index_max_shards,
4467 store->svc()->sync_modules->get_manager());
7c673cae
FG
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;
9f95a23c 4478 case OPT::ZONEGROUP_CREATE:
7c673cae
FG
4479 {
4480 if (zonegroup_name.empty()) {
4481 cerr << "Missing zonegroup name" << std::endl;
4482 return EINVAL;
4483 }
4484 RGWRealm realm(realm_id, realm_name);
9f95a23c 4485 int ret = realm.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
4486 if (ret < 0) {
4487 cerr << "failed to init realm: " << cpp_strerror(-ret) << std::endl;
4488 return -ret;
4489 }
4490
9f95a23c 4491 RGWZoneGroup zonegroup(zonegroup_name, is_master, g_ceph_context, store->svc()->sysobj, realm.get_id(), endpoints);
7c673cae
FG
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);
7c673cae
FG
4508 }
4509 break;
9f95a23c 4510 case OPT::ZONEGROUP_DEFAULT:
7c673cae
FG
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);
9f95a23c 4518 int ret = zonegroup.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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;
9f95a23c 4531 case OPT::ZONEGROUP_DELETE:
7c673cae
FG
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);
9f95a23c 4538 int ret = zonegroup.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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;
9f95a23c 4550 case OPT::ZONEGROUP_GET:
7c673cae
FG
4551 {
4552 RGWZoneGroup zonegroup(zonegroup_id, zonegroup_name);
9f95a23c 4553 int ret = zonegroup.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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);
7c673cae
FG
4561 }
4562 break;
9f95a23c 4563 case OPT::ZONEGROUP_LIST:
7c673cae
FG
4564 {
4565 RGWZoneGroup zonegroup;
9f95a23c 4566 int ret = zonegroup.init(g_ceph_context, store->svc()->sysobj, false);
7c673cae
FG
4567 if (ret < 0) {
4568 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
4569 return -ret;
4570 }
4571
4572 list<string> zonegroups;
9f95a23c 4573 ret = store->svc()->zone->list_zonegroups(zonegroups);
7c673cae
FG
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);
7c673cae
FG
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);
7c673cae
FG
4588 }
4589 break;
9f95a23c 4590 case OPT::ZONEGROUP_MODIFY:
7c673cae 4591 {
7c673cae 4592 RGWZoneGroup zonegroup(zonegroup_id, zonegroup_name);
9f95a23c 4593 int ret = zonegroup.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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
9f95a23c 4626 RGWRealm realm{g_ceph_context, store->svc()->sysobj};
7c673cae
FG
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
9f95a23c
TL
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
7c673cae
FG
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;
9f95a23c 4661 case OPT::ZONEGROUP_SET:
7c673cae
FG
4662 {
4663 RGWRealm realm(realm_id, realm_name);
9f95a23c 4664 int ret = realm.init(g_ceph_context, store->svc()->sysobj);
1adf2230
AA
4665 bool default_realm_not_exist = (ret == -ENOENT && realm_id.empty() && realm_name.empty());
4666
4667 if (ret < 0 && !default_realm_not_exist ) {
7c673cae
FG
4668 cerr << "failed to init realm: " << cpp_strerror(-ret) << std::endl;
4669 return -ret;
4670 }
4671
4672 RGWZoneGroup zonegroup;
9f95a23c 4673 ret = zonegroup.init(g_ceph_context, store->svc()->sysobj, false);
7c673cae
FG
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 }
1adf2230 4682 if (zonegroup.realm_id.empty() && !default_realm_not_exist) {
7c673cae
FG
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;
9f95a23c 4708 case OPT::ZONEGROUP_REMOVE:
7c673cae
FG
4709 {
4710 RGWZoneGroup zonegroup(zonegroup_id, zonegroup_name);
9f95a23c 4711 int ret = zonegroup.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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;
9f95a23c 4746 case OPT::ZONEGROUP_RENAME:
7c673cae
FG
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);
9f95a23c 4757 int ret = zonegroup.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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;
9f95a23c 4769 case OPT::ZONEGROUP_PLACEMENT_LIST:
7c673cae
FG
4770 {
4771 RGWZoneGroup zonegroup(zonegroup_id, zonegroup_name);
9f95a23c 4772 int ret = zonegroup.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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);
7c673cae
FG
4780 }
4781 break;
9f95a23c 4782 case OPT::ZONEGROUP_PLACEMENT_GET:
92f5a8d4
TL
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);
9f95a23c 4790 int ret = zonegroup.init(g_ceph_context, store->svc()->sysobj);
92f5a8d4
TL
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;
9f95a23c
TL
4805 case OPT::ZONEGROUP_PLACEMENT_ADD:
4806 case OPT::ZONEGROUP_PLACEMENT_MODIFY:
4807 case OPT::ZONEGROUP_PLACEMENT_RM:
4808 case OPT::ZONEGROUP_PLACEMENT_DEFAULT:
7c673cae
FG
4809 {
4810 if (placement_id.empty()) {
4811 cerr << "ERROR: --placement-id not specified" << std::endl;
4812 return EINVAL;
4813 }
4814
11fdf7f2
TL
4815 rgw_placement_rule rule;
4816 rule.from_str(placement_id);
4817
9f95a23c
TL
4818 if (!rule.storage_class.empty() && opt_storage_class &&
4819 rule.storage_class != *opt_storage_class) {
11fdf7f2
TL
4820 cerr << "ERROR: provided contradicting storage class configuration" << std::endl;
4821 return EINVAL;
4822 } else if (rule.storage_class.empty()) {
9f95a23c 4823 rule.storage_class = opt_storage_class.value_or(string());
11fdf7f2
TL
4824 }
4825
7c673cae 4826 RGWZoneGroup zonegroup(zonegroup_id, zonegroup_name);
9f95a23c 4827 int ret = zonegroup.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
4828 if (ret < 0) {
4829 cerr << "failed to init zonegroup: " << cpp_strerror(-ret) << std::endl;
4830 return -ret;
4831 }
4832
9f95a23c
TL
4833 if (opt_cmd == OPT::ZONEGROUP_PLACEMENT_ADD ||
4834 opt_cmd == OPT::ZONEGROUP_PLACEMENT_MODIFY) {
7c673cae
FG
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 }
11fdf7f2 4849 target.storage_classes.insert(rule.get_storage_class());
9f95a23c
TL
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) {
7c673cae
FG
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 }
11fdf7f2 4867 zonegroup.default_placement = rule;
7c673cae
FG
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;
9f95a23c 4881 case OPT::ZONE_CREATE:
7c673cae
FG
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()) {
9f95a23c 4891 ret = zonegroup.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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);
9f95a23c 4902 ret = zone.init(g_ceph_context, store->svc()->sysobj, false);
7c673cae
FG
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;
11fdf7f2
TL
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 }
7c673cae
FG
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);
11fdf7f2 4928 string *predirect_zone = (redirect_zone_set ? &redirect_zone : nullptr);
7c673cae
FG
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,
11fdf7f2 4935 sync_from, sync_from_rm,
9f95a23c
TL
4936 predirect_zone, bucket_index_max_shards,
4937 store->svc()->sync_modules->get_manager());
7c673cae
FG
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);
7c673cae
FG
4954 }
4955 break;
9f95a23c 4956 case OPT::ZONE_DEFAULT:
7c673cae
FG
4957 {
4958 RGWZoneGroup zonegroup(zonegroup_id,zonegroup_name);
9f95a23c 4959 int ret = zonegroup.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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);
9f95a23c 4968 ret = zone.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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;
9f95a23c 4980 case OPT::ZONE_DELETE:
7c673cae
FG
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);
9f95a23c 4987 int ret = zone.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
4988 if (ret < 0) {
4989 cerr << "unable to initialize zone: " << cpp_strerror(-ret) << std::endl;
4990 return -ret;
4991 }
4992
4993 list<string> zonegroups;
9f95a23c 4994 ret = store->svc()->zone->list_zonegroups(zonegroups);
7c673cae
FG
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);
9f95a23c 5002 int ret = zonegroup.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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;
9f95a23c 5021 case OPT::ZONE_GET:
7c673cae
FG
5022 {
5023 RGWZoneParams zone(zone_id, zone_name);
9f95a23c 5024 int ret = zone.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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;
9f95a23c 5033 case OPT::ZONE_SET:
7c673cae
FG
5034 {
5035 RGWZoneParams zone(zone_name);
9f95a23c 5036 int ret = zone.init(g_ceph_context, store->svc()->sysobj, false);
7c673cae
FG
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);
9f95a23c 5056 int ret = realm.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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;
9f95a23c 5116 case OPT::ZONE_LIST:
7c673cae
FG
5117 {
5118 list<string> zones;
9f95a23c 5119 int ret = store->svc()->zone->list_zones(zones);
7c673cae
FG
5120 if (ret < 0) {
5121 cerr << "failed to list zones: " << cpp_strerror(-ret) << std::endl;
5122 return -ret;
5123 }
5124
5125 RGWZoneParams zone;
9f95a23c 5126 ret = zone.init(g_ceph_context, store->svc()->sysobj, false);
7c673cae
FG
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);
7c673cae
FG
5141 }
5142 break;
9f95a23c 5143 case OPT::ZONE_MODIFY:
7c673cae
FG
5144 {
5145 RGWZoneParams zone(zone_id, zone_name);
9f95a23c 5146 int ret = zone.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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
9f95a23c 5168 RGWRealm realm{g_ceph_context, store->svc()->sysobj};
7c673cae
FG
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
11fdf7f2
TL
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 }
7c673cae
FG
5185 need_zone_update = true;
5186 }
5187
5188 for (auto rm : tier_config_rm) {
11fdf7f2
TL
5189 if (!rm.first.empty()) { /* otherwise will remove the entire config */
5190 zone.tier_config.erase(rm.first);
5191 need_zone_update = true;
5192 }
7c673cae
FG
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);
9f95a23c 5204 ret = zonegroup.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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);
11fdf7f2 5212 string *predirect_zone = (redirect_zone_set ? &redirect_zone : nullptr);
7c673cae
FG
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,
11fdf7f2 5218 psync_from_all, sync_from, sync_from_rm,
9f95a23c
TL
5219 predirect_zone, bucket_index_max_shards,
5220 store->svc()->sync_modules->get_manager());
7c673cae
FG
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;
9f95a23c 5243 case OPT::ZONE_RENAME:
7c673cae
FG
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()) {
9f95a23c 5250 cerr << "no zone name or id provided" << std::endl;
7c673cae
FG
5251 return EINVAL;
5252 }
5253 RGWZoneParams zone(zone_id,zone_name);
9f95a23c 5254 int ret = zone.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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);
9f95a23c 5266 ret = zonegroup.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
5267 if (ret < 0) {
5268 cerr << "WARNING: failed to initialize zonegroup " << zonegroup_name << std::endl;
5269 } else {
5270 ret = zonegroup.rename_zone(zone);
11fdf7f2 5271 if (ret < 0) {
7c673cae
FG
5272 cerr << "Error in zonegroup rename for " << zone_name << ": " << cpp_strerror(-ret) << std::endl;
5273 return -ret;
5274 }
5275 }
5276 }
5277 break;
9f95a23c
TL
5278 case OPT::ZONE_PLACEMENT_ADD:
5279 case OPT::ZONE_PLACEMENT_MODIFY:
5280 case OPT::ZONE_PLACEMENT_RM:
7c673cae
FG
5281 {
5282 if (placement_id.empty()) {
5283 cerr << "ERROR: --placement-id not specified" << std::endl;
5284 return EINVAL;
5285 }
3efd9988
FG
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
7c673cae 5293 RGWZoneParams zone(zone_id, zone_name);
9f95a23c 5294 int ret = zone.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
5295 if (ret < 0) {
5296 cerr << "failed to init zone: " << cpp_strerror(-ret) << std::endl;
5297 return -ret;
5298 }
5299
9f95a23c
TL
5300 if (opt_cmd == OPT::ZONE_PLACEMENT_ADD ||
5301 opt_cmd == OPT::ZONE_PLACEMENT_MODIFY) {
11fdf7f2 5302 RGWZoneGroup zonegroup(zonegroup_id, zonegroup_name);
9f95a23c 5303 ret = zonegroup.init(g_ceph_context, store->svc()->sysobj);
11fdf7f2
TL
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
9f95a23c 5315 string storage_class = rgw_placement_rule::get_canonical_storage_class(opt_storage_class.value_or(string()));
11fdf7f2
TL
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 }
7c673cae
FG
5320
5321 RGWZonePlacementInfo& info = zone.placement_pools[placement_id];
5322
11fdf7f2
TL
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
7c673cae
FG
5351 if (data_extra_pool) {
5352 info.data_extra_pool = *data_extra_pool;
5353 }
5354 if (index_type_specified) {
11fdf7f2 5355 info.index_type = placement_index_type;
7c673cae 5356 }
11fdf7f2
TL
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;
7c673cae 5363 }
9f95a23c
TL
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 }
7c673cae
FG
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;
9f95a23c 5387 case OPT::ZONE_PLACEMENT_LIST:
7c673cae
FG
5388 {
5389 RGWZoneParams zone(zone_id, zone_name);
9f95a23c 5390 int ret = zone.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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;
9f95a23c 5399 case OPT::ZONE_PLACEMENT_GET:
92f5a8d4
TL
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);
9f95a23c 5407 int ret = zone.init(g_ceph_context, store->svc()->sysobj);
92f5a8d4
TL
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 }
9f95a23c 5420 default:
92f5a8d4 5421 break;
7c673cae
FG
5422 }
5423 return 0;
5424 }
5425
9f95a23c
TL
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};
494da23a
TL
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
7c673cae
FG
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
9f95a23c
TL
5466 if (!user_id.empty()) {
5467 user_op.set_new_user_id(new_user_id);
5468 }
5469
7c673cae
FG
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
9f95a23c 5527 if (opt_cmd == OPT::USER_ENABLE)
7c673cae 5528 user_op.set_suspension(false);
9f95a23c 5529 else if (opt_cmd == OPT::USER_SUSPEND)
7c673cae
FG
5530 user_op.set_suspension(true);
5531
9f95a23c
TL
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
7c673cae
FG
5548 // RGWUser to use for user operations
5549 RGWUser user;
5550 int ret = 0;
eafe8130 5551 if (!(user_id.empty() && access_key.empty()) || !subuser.empty()) {
7c673cae
FG
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) {
9f95a23c 5573 case OPT::USER_INFO:
eafe8130
TL
5574 if (user_id.empty() && access_key.empty()) {
5575 cerr << "ERROR: --uid or --access-key required" << std::endl;
11fdf7f2
TL
5576 return EINVAL;
5577 }
7c673cae 5578 break;
9f95a23c 5579 case OPT::USER_CREATE:
7c673cae
FG
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;
d2e6a577
FG
5586 if (ret == -ERR_INVALID_TENANT_NAME)
5587 ret = -EINVAL;
5588
7c673cae
FG
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;
9f95a23c
TL
5599 case OPT::USER_RM:
5600 ret = user.remove(user_op, null_yield, &err_msg);
31f18b77 5601 if (ret < 0) {
7c673cae
FG
5602 cerr << "could not remove user: " << err_msg << std::endl;
5603 return -ret;
5604 }
5605
5606 output_user_info = false;
5607 break;
9f95a23c
TL
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:
7c673cae
FG
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;
9f95a23c 5632 case OPT::SUBUSER_CREATE:
7c673cae
FG
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;
9f95a23c 5640 case OPT::SUBUSER_MODIFY:
7c673cae
FG
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;
9f95a23c 5648 case OPT::SUBUSER_RM:
7c673cae
FG
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;
9f95a23c 5656 case OPT::CAPS_ADD:
7c673cae
FG
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;
9f95a23c 5664 case OPT::CAPS_RM:
7c673cae
FG
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;
9f95a23c 5672 case OPT::KEY_CREATE:
7c673cae
FG
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;
9f95a23c 5680 case OPT::KEY_RM:
7c673cae
FG
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;
9f95a23c 5687 case OPT::PERIOD_PUSH:
7c673cae
FG
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);
9f95a23c 5706 int ret = period.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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;
9f95a23c 5726 case OPT::PERIOD_UPDATE:
7c673cae
FG
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;
9f95a23c 5736 case OPT::PERIOD_COMMIT:
7c673cae
FG
5737 {
5738 // read realm and staging period
5739 RGWRealm realm(realm_id, realm_name);
9f95a23c 5740 int ret = realm.init(g_ceph_context, store->svc()->sysobj);
7c673cae
FG
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);
9f95a23c 5746 ret = period.init(g_ceph_context, store->svc()->sysobj, realm.get_id());
7c673cae
FG
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);
7c673cae
FG
5760 }
5761 return 0;
9f95a23c 5762 case OPT::ROLE_CREATE:
7c673cae 5763 {
31f18b77
FG
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;
7c673cae
FG
5771 return -EINVAL;
5772 }
11fdf7f2
TL
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;
7c673cae
FG
5778 return -EINVAL;
5779 }
9f95a23c 5780 RGWRole role(g_ceph_context, store->getRados()->pctl, role_name, path, assume_role_doc, tenant);
7c673cae
FG
5781 ret = role.create(true);
5782 if (ret < 0) {
5783 return -ret;
5784 }
5785 show_role_info(role, formatter);
5786 return 0;
5787 }
9f95a23c 5788 case OPT::ROLE_DELETE:
7c673cae
FG
5789 {
5790 if (role_name.empty()) {
5791 cerr << "ERROR: empty role name" << std::endl;
5792 return -EINVAL;
5793 }
9f95a23c 5794 RGWRole role(g_ceph_context, store->getRados()->pctl, role_name, tenant);
7c673cae
FG
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 }
9f95a23c 5802 case OPT::ROLE_GET:
7c673cae
FG
5803 {
5804 if (role_name.empty()) {
5805 cerr << "ERROR: empty role name" << std::endl;
5806 return -EINVAL;
5807 }
9f95a23c 5808 RGWRole role(g_ceph_context, store->getRados()->pctl, role_name, tenant);
7c673cae
FG
5809 ret = role.get();
5810 if (ret < 0) {
5811 return -ret;
5812 }
5813 show_role_info(role, formatter);
5814 return 0;
5815 }
9f95a23c 5816 case OPT::ROLE_MODIFY:
7c673cae 5817 {
31f18b77
FG
5818 if (role_name.empty()) {
5819 cerr << "ERROR: role name is empty" << std::endl;
7c673cae
FG
5820 return -EINVAL;
5821 }
31f18b77
FG
5822
5823 if (assume_role_doc.empty()) {
5824 cerr << "ERROR: assume role policy document is empty" << std::endl;
5825 return -EINVAL;
5826 }
5827
11fdf7f2
TL
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;
7c673cae
FG
5833 return -EINVAL;
5834 }
11fdf7f2 5835
9f95a23c 5836 RGWRole role(g_ceph_context, store->getRados()->pctl, role_name, tenant);
7c673cae
FG
5837 ret = role.get();
5838 if (ret < 0) {
5839 return -ret;
5840 }
11fdf7f2 5841 role.update_trust_policy(assume_role_doc);
7c673cae
FG
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 }
9f95a23c 5849 case OPT::ROLE_LIST:
7c673cae
FG
5850 {
5851 vector<RGWRole> result;
9f95a23c 5852 ret = RGWRole::get_roles_by_path_prefix(store->getRados(), g_ceph_context, path_prefix, tenant, result);
7c673cae
FG
5853 if (ret < 0) {
5854 return -ret;
5855 }
5856 show_roles_info(result, formatter);
5857 return 0;
5858 }
9f95a23c 5859 case OPT::ROLE_POLICY_PUT:
7c673cae 5860 {
31f18b77
FG
5861 if (role_name.empty()) {
5862 cerr << "role name is empty" << std::endl;
7c673cae
FG
5863 return -EINVAL;
5864 }
31f18b77
FG
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
11fdf7f2
TL
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;
7c673cae
FG
5881 return -EINVAL;
5882 }
7c673cae 5883
9f95a23c 5884 RGWRole role(g_ceph_context, store->getRados()->pctl, role_name, tenant);
7c673cae
FG
5885 ret = role.get();
5886 if (ret < 0) {
5887 return -ret;
5888 }
11fdf7f2 5889 role.set_perm_policy(policy_name, perm_policy_doc);
7c673cae
FG
5890 ret = role.update();
5891 if (ret < 0) {
5892 return -ret;
5893 }
5894 cout << "Permission policy attached successfully" << std::endl;
5895 return 0;
5896 }
9f95a23c 5897 case OPT::ROLE_POLICY_LIST:
7c673cae
FG
5898 {
5899 if (role_name.empty()) {
5900 cerr << "ERROR: Role name is empty" << std::endl;
5901 return -EINVAL;
5902 }
9f95a23c 5903 RGWRole role(g_ceph_context, store->getRados()->pctl, role_name, tenant);
7c673cae
FG
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 }
9f95a23c 5912 case OPT::ROLE_POLICY_GET:
7c673cae 5913 {
31f18b77
FG
5914 if (role_name.empty()) {
5915 cerr << "ERROR: role name is empty" << std::endl;
7c673cae
FG
5916 return -EINVAL;
5917 }
31f18b77
FG
5918
5919 if (policy_name.empty()) {
5920 cerr << "ERROR: policy name is empty" << std::endl;
5921 return -EINVAL;
5922 }
9f95a23c 5923 RGWRole role(g_ceph_context, store->getRados()->pctl, role_name, tenant);
7c673cae
FG
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 }
9f95a23c 5936 case OPT::ROLE_POLICY_DELETE:
7c673cae 5937 {
31f18b77
FG
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;
7c673cae
FG
5945 return -EINVAL;
5946 }
9f95a23c 5947 RGWRole role(g_ceph_context, store->getRados()->pctl, role_name, tenant);
7c673cae
FG
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
9f95a23c 5978 if (opt_cmd == OPT::POLICY) {
7c673cae
FG
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
9f95a23c 5994 if (opt_cmd == OPT::BUCKET_LIMIT_CHECK) {
7c673cae
FG
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 */
9f95a23c 6010 ret = store->ctl()->meta.mgr->list_keys_init(metadata_key, &handle);
7c673cae
FG
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 {
9f95a23c 6018 ret = store->ctl()->meta.mgr->list_keys_next(handle, max, user_ids,
7c673cae
FG
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);
9f95a23c 6034 store->ctl()->meta.mgr->list_keys_complete(handle);
7c673cae
FG
6035 }
6036 return -ret;
9f95a23c 6037 } /* OPT::BUCKET_LIMIT_CHECK */
7c673cae 6038
9f95a23c 6039 if (opt_cmd == OPT::BUCKETS_LIST) {
7c673cae 6040 if (bucket_name.empty()) {
eafe8130
TL
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 }
7c673cae
FG
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");
f91f0fd5
TL
6056
6057 bool truncated = false;
7c673cae 6058 int count = 0;
f91f0fd5
TL
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);
7c673cae
FG
6067
6068 string prefix;
6069 string delim;
6070 vector<rgw_bucket_dir_entry> result;
6071 map<string, bool> common_prefixes;
6072 string ns;
6073
9f95a23c 6074 RGWRados::Bucket target(store->getRados(), bucket_info);
7c673cae
FG
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;
494da23a 6083 list_op.params.allow_unordered = bool(allow_unordered);
7c673cae
FG
6084
6085 do {
f91f0fd5
TL
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);
7c673cae
FG
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
f91f0fd5 6097 for (const auto& entry : result) {
7c673cae
FG
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 */
9f95a23c 6106 } /* OPT::BUCKETS_LIST */
7c673cae 6107
e306af50
TL
6108 if (opt_cmd == OPT::BUCKET_RADOS_LIST) {
6109 RGWRadosList lister(store,
6110 max_concurrent_ios, orphan_stale_secs, tenant);
7f7e6c64
TL
6111 if (rgw_obj_fs) {
6112 lister.set_field_separator(*rgw_obj_fs);
6113 }
6114
e306af50
TL
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
9f95a23c 6135 if (opt_cmd == OPT::BUCKET_STATS) {
1911f103
TL
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 }
7c673cae
FG
6145 bucket_op.set_fetch_stats(true);
6146
31f18b77
FG
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 }
7c673cae
FG
6152 }
6153
9f95a23c 6154 if (opt_cmd == OPT::BUCKET_LINK) {
7c673cae 6155 bucket_op.set_bucket_id(bucket_id);
9f95a23c 6156 bucket_op.set_new_bucket_name(new_bucket_name);
7c673cae
FG
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
9f95a23c 6165 if (opt_cmd == OPT::BUCKET_UNLINK) {
7c673cae
FG
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
9f95a23c 6173 if (opt_cmd == OPT::BUCKET_CHOWN) {
ec96510d
FG
6174 if (bucket_name.empty()) {
6175 cerr << "ERROR: bucket name not specified" << std::endl;
6176 return EINVAL;
6177 }
9f95a23c
TL
6178
6179 bucket_op.set_bucket_name(bucket_name);
6180 bucket_op.set_new_bucket_name(new_bucket_name);
6181 string err;
6182 string marker;
6183
6184 int r = RGWBucketAdminOp::chown(store, bucket_op, marker, &err);
6185 if (r < 0) {
6186 cerr << "failure: " << cpp_strerror(-r) << ": " << err << std::endl;
6187 return -r;
6188 }
6189 }
6190
6191 if (opt_cmd == OPT::LOG_LIST) {
7c673cae
FG
6192 // filter by date?
6193 if (date.size() && date.size() != 10) {
6194 cerr << "bad date format for '" << date << "', expect YYYY-MM-DD" << std::endl;
6195 return EINVAL;
6196 }
6197
6198 formatter->reset();
6199 formatter->open_array_section("logs");
6200 RGWAccessHandle h;
9f95a23c 6201 int r = store->getRados()->log_list_init(date, &h);
7c673cae
FG
6202 if (r == -ENOENT) {
6203 // no logs.
6204 } else {
6205 if (r < 0) {
6206 cerr << "log list: error " << r << std::endl;
6207 return -r;
6208 }
6209 while (true) {
6210 string name;
9f95a23c 6211 int r = store->getRados()->log_list_next(h, &name);
7c673cae
FG
6212 if (r == -ENOENT)
6213 break;
6214 if (r < 0) {
6215 cerr << "log list: error " << r << std::endl;
6216 return -r;
6217 }
6218 formatter->dump_string("object", name);
6219 }
6220 }
6221 formatter->close_section();
6222 formatter->flush(cout);
6223 cout << std::endl;
6224 }
6225
9f95a23c 6226 if (opt_cmd == OPT::LOG_SHOW || opt_cmd == OPT::LOG_RM) {
7c673cae
FG
6227 if (object.empty() && (date.empty() || bucket_name.empty() || bucket_id.empty())) {
6228 cerr << "specify an object or a date, bucket and bucket-id" << std::endl;
11fdf7f2 6229 exit(1);
7c673cae
FG
6230 }
6231
6232 string oid;
6233 if (!object.empty()) {
6234 oid = object;
6235 } else {
6236 oid = date;
6237 oid += "-";
6238 oid += bucket_id;
6239 oid += "-";
6240 oid += bucket_name;
6241 }
6242
9f95a23c 6243 if (opt_cmd == OPT::LOG_SHOW) {
7c673cae
FG
6244 RGWAccessHandle h;
6245
9f95a23c 6246 int r = store->getRados()->log_show_init(oid, &h);
7c673cae
FG
6247 if (r < 0) {
6248 cerr << "error opening log " << oid << ": " << cpp_strerror(-r) << std::endl;
6249 return -r;
6250 }
6251
6252 formatter->reset();
6253 formatter->open_object_section("log");
6254
6255 struct rgw_log_entry entry;
6256
6257 // peek at first entry to get bucket metadata
9f95a23c 6258 r = store->getRados()->log_show_next(h, &entry);
7c673cae
FG
6259 if (r < 0) {
6260 cerr << "error reading log " << oid << ": " << cpp_strerror(-r) << std::endl;
6261 return -r;
6262 }
6263 formatter->dump_string("bucket_id", entry.bucket_id);
6264 formatter->dump_string("bucket_owner", entry.bucket_owner.to_str());
6265 formatter->dump_string("bucket", entry.bucket);
6266
6267 uint64_t agg_time = 0;
6268 uint64_t agg_bytes_sent = 0;
6269 uint64_t agg_bytes_received = 0;
6270 uint64_t total_entries = 0;
6271
6272 if (show_log_entries)
6273 formatter->open_array_section("log_entries");
6274
6275 do {
11fdf7f2
TL
6276 using namespace std::chrono;
6277 uint64_t total_time = duration_cast<milliseconds>(entry.total_time).count();
7c673cae
FG
6278
6279 agg_time += total_time;
6280 agg_bytes_sent += entry.bytes_sent;
6281 agg_bytes_received += entry.bytes_received;
6282 total_entries++;
6283
6284 if (skip_zero_entries && entry.bytes_sent == 0 &&
6285 entry.bytes_received == 0)
6286 goto next;
6287
6288 if (show_log_entries) {
6289
6290 rgw_format_ops_log_entry(entry, formatter);
6291 formatter->flush(cout);
6292 }
6293next:
9f95a23c 6294 r = store->getRados()->log_show_next(h, &entry);
7c673cae
FG
6295 } while (r > 0);
6296
6297 if (r < 0) {
6298 cerr << "error reading log " << oid << ": " << cpp_strerror(-r) << std::endl;
6299 return -r;
6300 }
6301 if (show_log_entries)
6302 formatter->close_section();
6303
6304 if (show_log_sum) {
6305 formatter->open_object_section("log_sum");
6306 formatter->dump_int("bytes_sent", agg_bytes_sent);
6307 formatter->dump_int("bytes_received", agg_bytes_received);
6308 formatter->dump_int("total_time", agg_time);
6309 formatter->dump_int("total_entries", total_entries);
6310 formatter->close_section();
6311 }
6312 formatter->close_section();
6313 formatter->flush(cout);
6314 cout << std::endl;
6315 }
9f95a23c
TL
6316 if (opt_cmd == OPT::LOG_RM) {
6317 int r = store->getRados()->log_remove(oid);
7c673cae
FG
6318 if (r < 0) {
6319 cerr << "error removing log " << oid << ": " << cpp_strerror(-r) << std::endl;
6320 return -r;
6321 }
6322 }
6323 }
6324
9f95a23c 6325 if (opt_cmd == OPT::POOL_ADD) {
7c673cae
FG
6326 if (pool_name.empty()) {
6327 cerr << "need to specify pool to add!" << std::endl;
11fdf7f2 6328 exit(1);
7c673cae
FG
6329 }
6330
9f95a23c 6331 int ret = store->svc()->zone->add_bucket_placement(pool);
7c673cae
FG
6332 if (ret < 0)
6333 cerr << "failed to add bucket placement: " << cpp_strerror(-ret) << std::endl;
6334 }
6335
9f95a23c 6336 if (opt_cmd == OPT::POOL_RM) {
7c673cae
FG
6337 if (pool_name.empty()) {
6338 cerr << "need to specify pool to remove!" << std::endl;
11fdf7f2 6339 exit(1);
7c673cae
FG
6340 }
6341
9f95a23c 6342 int ret = store->svc()->zone->remove_bucket_placement(pool);
7c673cae
FG
6343 if (ret < 0)
6344 cerr << "failed to remove bucket placement: " << cpp_strerror(-ret) << std::endl;
6345 }
6346
9f95a23c 6347 if (opt_cmd == OPT::POOLS_LIST) {
7c673cae 6348 set<rgw_pool> pools;
9f95a23c 6349 int ret = store->svc()->zone->list_placement_set(pools);
7c673cae
FG
6350 if (ret < 0) {
6351 cerr << "could not list placement set: " << cpp_strerror(-ret) << std::endl;
6352 return -ret;
6353 }
6354 formatter->reset();
6355 formatter->open_array_section("pools");
6356 for (auto siter = pools.begin(); siter != pools.end(); ++siter) {
6357 formatter->open_object_section("pool");
6358 formatter->dump_string("name", siter->to_str());
6359 formatter->close_section();
6360 }
6361 formatter->close_section();
6362 formatter->flush(cout);
6363 cout << std::endl;
6364 }
6365
9f95a23c 6366 if (opt_cmd == OPT::USAGE_SHOW) {
7c673cae
FG
6367 uint64_t start_epoch = 0;
6368 uint64_t end_epoch = (uint64_t)-1;
6369
6370 int ret;
6371
6372 if (!start_date.empty()) {
6373 ret = utime_t::parse_date(start_date, &start_epoch, NULL);
6374 if (ret < 0) {
6375 cerr << "ERROR: failed to parse start date" << std::endl;
6376 return 1;
6377 }
6378 }
6379 if (!end_date.empty()) {
6380 ret = utime_t::parse_date(end_date, &end_epoch, NULL);
6381 if (ret < 0) {
6382 cerr << "ERROR: failed to parse end date" << std::endl;
6383 return 1;
6384 }
6385 }
6386
6387
9f95a23c 6388 ret = RGWUsage::show(store->getRados(), user_id, bucket_name, start_epoch, end_epoch,
7c673cae
FG
6389 show_log_entries, show_log_sum, &categories,
6390 f);
6391 if (ret < 0) {
6392 cerr << "ERROR: failed to show usage" << std::endl;
6393 return 1;
6394 }
6395 }
6396
9f95a23c 6397 if (opt_cmd == OPT::USAGE_TRIM) {
11fdf7f2
TL
6398 if (user_id.empty() && bucket_name.empty() &&
6399 start_date.empty() && end_date.empty() && !yes_i_really_mean_it) {
6400 cerr << "usage trim without user/date/bucket specified will remove *all* users data" << std::endl;
7c673cae
FG
6401 cerr << "do you really mean it? (requires --yes-i-really-mean-it)" << std::endl;
6402 return 1;
6403 }
6404 int ret;
6405 uint64_t start_epoch = 0;
6406 uint64_t end_epoch = (uint64_t)-1;
6407
6408
6409 if (!start_date.empty()) {
6410 ret = utime_t::parse_date(start_date, &start_epoch, NULL);
6411 if (ret < 0) {
6412 cerr << "ERROR: failed to parse start date" << std::endl;
6413 return 1;
6414 }
6415 }
6416
6417 if (!end_date.empty()) {
6418 ret = utime_t::parse_date(end_date, &end_epoch, NULL);
6419 if (ret < 0) {
6420 cerr << "ERROR: failed to parse end date" << std::endl;
6421 return 1;
6422 }
6423 }
6424
9f95a23c 6425 ret = RGWUsage::trim(store->getRados(), user_id, bucket_name, start_epoch, end_epoch);
7c673cae
FG
6426 if (ret < 0) {
6427 cerr << "ERROR: read_usage() returned ret=" << ret << std::endl;
6428 return 1;
6429 }
6430 }
6431
9f95a23c 6432 if (opt_cmd == OPT::USAGE_CLEAR) {
11fdf7f2
TL
6433 if (!yes_i_really_mean_it) {
6434 cerr << "usage clear would remove *all* users usage data for all time" << std::endl;
6435 cerr << "do you really mean it? (requires --yes-i-really-mean-it)" << std::endl;
6436 return 1;
6437 }
6438
9f95a23c 6439 ret = RGWUsage::clear(store->getRados());
11fdf7f2
TL
6440 if (ret < 0) {
6441 return ret;
6442 }
6443 }
6444
6445
9f95a23c 6446 if (opt_cmd == OPT::OLH_GET || opt_cmd == OPT::OLH_READLOG) {
7c673cae
FG
6447 if (bucket_name.empty()) {
6448 cerr << "ERROR: bucket not specified" << std::endl;
6449 return EINVAL;
6450 }
6451 if (object.empty()) {
6452 cerr << "ERROR: object not specified" << std::endl;
6453 return EINVAL;
6454 }
7c673cae
FG
6455 }
6456
9f95a23c 6457 if (opt_cmd == OPT::OLH_GET) {
7c673cae
FG
6458 RGWBucketInfo bucket_info;
6459 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
6460 if (ret < 0) {
6461 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
6462 return -ret;
6463 }
6464 RGWOLHInfo olh;
6465 rgw_obj obj(bucket, object);
9f95a23c 6466 ret = store->getRados()->get_olh(bucket_info, obj, &olh);
7c673cae
FG
6467 if (ret < 0) {
6468 cerr << "ERROR: failed reading olh: " << cpp_strerror(-ret) << std::endl;
6469 return -ret;
6470 }
6471 encode_json("olh", olh, formatter);
6472 formatter->flush(cout);
6473 }
6474
9f95a23c 6475 if (opt_cmd == OPT::OLH_READLOG) {
7c673cae
FG
6476 RGWBucketInfo bucket_info;
6477 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
6478 if (ret < 0) {
6479 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
6480 return -ret;
6481 }
6482 map<uint64_t, vector<rgw_bucket_olh_log_entry> > log;
6483 bool is_truncated;
6484
6485 RGWObjectCtx rctx(store);
6486 rgw_obj obj(bucket, object);
6487
6488 RGWObjState *state;
6489
9f95a23c 6490 ret = store->getRados()->get_obj_state(&rctx, bucket_info, obj, &state, false, null_yield); /* don't follow olh */
7c673cae
FG
6491 if (ret < 0) {
6492 return -ret;
6493 }
6494
9f95a23c 6495 ret = store->getRados()->bucket_index_read_olh_log(bucket_info, *state, obj, 0, &log, &is_truncated);
7c673cae
FG
6496 if (ret < 0) {
6497 cerr << "ERROR: failed reading olh: " << cpp_strerror(-ret) << std::endl;
6498 return -ret;
6499 }
6500 formatter->open_object_section("result");
6501 encode_json("is_truncated", is_truncated, formatter);
6502 encode_json("log", log, formatter);
6503 formatter->close_section();
6504 formatter->flush(cout);
6505 }
6506
9f95a23c 6507 if (opt_cmd == OPT::BI_GET) {
11fdf7f2
TL
6508 if (bucket_name.empty()) {
6509 cerr << "ERROR: bucket name not specified" << std::endl;
6510 return EINVAL;
6511 }
6512 if (object.empty()) {
6513 cerr << "ERROR: object not specified" << std::endl;
6514 return EINVAL;
6515 }
7c673cae
FG
6516 RGWBucketInfo bucket_info;
6517 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
6518 if (ret < 0) {
6519 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
6520 return -ret;
6521 }
6522 rgw_obj obj(bucket, object);
6523 if (!object_version.empty()) {
6524 obj.key.set_instance(object_version);
6525 }
6526
6527 rgw_cls_bi_entry entry;
6528
9f95a23c 6529 ret = store->getRados()->bi_get(bucket_info, obj, bi_index_type, &entry);
7c673cae
FG
6530 if (ret < 0) {
6531 cerr << "ERROR: bi_get(): " << cpp_strerror(-ret) << std::endl;
6532 return -ret;
6533 }
6534
6535 encode_json("entry", entry, formatter);
6536 formatter->flush(cout);
6537 }
6538
9f95a23c 6539 if (opt_cmd == OPT::BI_PUT) {
11fdf7f2
TL
6540 if (bucket_name.empty()) {
6541 cerr << "ERROR: bucket name not specified" << std::endl;
6542 return EINVAL;
6543 }
7c673cae
FG
6544 RGWBucketInfo bucket_info;
6545 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
6546 if (ret < 0) {
6547 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
6548 return -ret;
6549 }
6550
6551 rgw_cls_bi_entry entry;
6552 cls_rgw_obj_key key;
6553 ret = read_decode_json(infile, entry, &key);
6554 if (ret < 0) {
6555 return 1;
6556 }
6557
6558 rgw_obj obj(bucket, key);
6559
9f95a23c 6560 ret = store->getRados()->bi_put(bucket, obj, entry);
7c673cae
FG
6561 if (ret < 0) {
6562 cerr << "ERROR: bi_put(): " << cpp_strerror(-ret) << std::endl;
6563 return -ret;
6564 }
6565 }
6566
9f95a23c 6567 if (opt_cmd == OPT::BI_LIST) {
7c673cae
FG
6568 if (bucket_name.empty()) {
6569 cerr << "ERROR: bucket name not specified" << std::endl;
6570 return EINVAL;
6571 }
6572 RGWBucketInfo bucket_info;
6573 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
6574 if (ret < 0) {
6575 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
6576 return -ret;
6577 }
6578
6579 list<rgw_cls_bi_entry> entries;
6580 bool is_truncated;
6581 if (max_entries < 0) {
6582 max_entries = 1000;
6583 }
6584
6585 int max_shards = (bucket_info.num_shards > 0 ? bucket_info.num_shards : 1);
6586
6587 formatter->open_array_section("entries");
6588
9f95a23c
TL
6589 int i = (specified_shard_id ? shard_id : 0);
6590 for (; i < max_shards; i++) {
6591 RGWRados::BucketShard bs(store->getRados());
7c673cae 6592 int shard_id = (bucket_info.num_shards > 0 ? i : -1);
f64942e4 6593 int ret = bs.init(bucket, shard_id, nullptr /* no RGWBucketInfo */);
7c673cae
FG
6594 marker.clear();
6595
6596 if (ret < 0) {
6597 cerr << "ERROR: bs.init(bucket=" << bucket << ", shard=" << shard_id << "): " << cpp_strerror(-ret) << std::endl;
6598 return -ret;
6599 }
6600
6601 do {
6602 entries.clear();
9f95a23c 6603 ret = store->getRados()->bi_list(bs, object, marker, max_entries, &entries, &is_truncated);
7c673cae
FG
6604 if (ret < 0) {
6605 cerr << "ERROR: bi_list(): " << cpp_strerror(-ret) << std::endl;
6606 return -ret;
6607 }
6608
6609 list<rgw_cls_bi_entry>::iterator iter;
6610 for (iter = entries.begin(); iter != entries.end(); ++iter) {
6611 rgw_cls_bi_entry& entry = *iter;
6612 encode_json("entry", entry, formatter);
6613 marker = entry.idx;
6614 }
6615 formatter->flush(cout);
6616 } while (is_truncated);
6617 formatter->flush(cout);
9f95a23c
TL
6618
6619 if (specified_shard_id)
6620 break;
7c673cae
FG
6621 }
6622 formatter->close_section();
6623 formatter->flush(cout);
6624 }
6625
9f95a23c 6626 if (opt_cmd == OPT::BI_PURGE) {
7c673cae
FG
6627 if (bucket_name.empty()) {
6628 cerr << "ERROR: bucket name not specified" << std::endl;
6629 return EINVAL;
6630 }
6631 RGWBucketInfo bucket_info;
6632 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
6633 if (ret < 0) {
6634 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
6635 return -ret;
6636 }
6637
6638 RGWBucketInfo cur_bucket_info;
6639 rgw_bucket cur_bucket;
6640 ret = init_bucket(tenant, bucket_name, string(), cur_bucket_info, cur_bucket);
6641 if (ret < 0) {
6642 cerr << "ERROR: could not init current bucket info for bucket_name=" << bucket_name << ": " << cpp_strerror(-ret) << std::endl;
6643 return -ret;
6644 }
6645
6646 if (cur_bucket_info.bucket.bucket_id == bucket_info.bucket.bucket_id && !yes_i_really_mean_it) {
6647 cerr << "specified bucket instance points to a current bucket instance" << std::endl;
6648 cerr << "do you really mean it? (requires --yes-i-really-mean-it)" << std::endl;
6649 return EINVAL;
6650 }
6651
6652 int max_shards = (bucket_info.num_shards > 0 ? bucket_info.num_shards : 1);
6653
6654 for (int i = 0; i < max_shards; i++) {
9f95a23c 6655 RGWRados::BucketShard bs(store->getRados());
7c673cae 6656 int shard_id = (bucket_info.num_shards > 0 ? i : -1);
f64942e4 6657 int ret = bs.init(bucket, shard_id, nullptr /* no RGWBucketInfo */);
7c673cae
FG
6658 if (ret < 0) {
6659 cerr << "ERROR: bs.init(bucket=" << bucket << ", shard=" << shard_id << "): " << cpp_strerror(-ret) << std::endl;
6660 return -ret;
6661 }
6662
9f95a23c 6663 ret = store->getRados()->bi_remove(bs);
7c673cae
FG
6664 if (ret < 0) {
6665 cerr << "ERROR: failed to remove bucket index object: " << cpp_strerror(-ret) << std::endl;
6666 return -ret;
6667 }
6668 }
6669 }
6670
9f95a23c 6671 if (opt_cmd == OPT::OBJECT_PUT) {
11fdf7f2
TL
6672 if (bucket_name.empty()) {
6673 cerr << "ERROR: bucket not specified" << std::endl;
6674 return EINVAL;
6675 }
6676 if (object.empty()) {
6677 cerr << "ERROR: object not specified" << std::endl;
6678 return EINVAL;
6679 }
6680
6681 RGWDataAccess data_access(store);
6682 rgw_obj_key key(object, object_version);
6683
6684 RGWDataAccess::BucketRef b;
6685 RGWDataAccess::ObjectRef obj;
6686
6687 int ret = data_access.get_bucket(tenant, bucket_name, bucket_id, &b);
6688 if (ret < 0) {
6689 cerr << "ERROR: failed to init bucket: " << cpp_strerror(-ret) << std::endl;
6690 return -ret;
6691 }
6692
6693 ret = b->get_object(key, &obj);
6694 if (ret < 0) {
6695 cerr << "ERROR: failed to get object: " << cpp_strerror(-ret) << std::endl;
6696 return -ret;
6697 }
6698
6699 bufferlist bl;
6700 ret = read_input(infile, bl);
6701 if (ret < 0) {
6702 cerr << "ERROR: failed to read input: " << cpp_strerror(-ret) << std::endl;
6703 }
6704
6705 map<string, bufferlist> attrs;
9f95a23c 6706 ret = obj->put(bl, attrs, dpp(), null_yield);
11fdf7f2
TL
6707 if (ret < 0) {
6708 cerr << "ERROR: put object returned error: " << cpp_strerror(-ret) << std::endl;
6709 }
6710 }
6711
9f95a23c 6712 if (opt_cmd == OPT::OBJECT_RM) {
7c673cae
FG
6713 RGWBucketInfo bucket_info;
6714 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
6715 if (ret < 0) {
6716 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
6717 return -ret;
6718 }
6719 rgw_obj_key key(object, object_version);
6720 ret = rgw_remove_object(store, bucket_info, bucket, key);
6721
6722 if (ret < 0) {
6723 cerr << "ERROR: object remove returned: " << cpp_strerror(-ret) << std::endl;
6724 return -ret;
6725 }
6726 }
6727
9f95a23c 6728 if (opt_cmd == OPT::OBJECT_REWRITE) {
7c673cae
FG
6729 if (bucket_name.empty()) {
6730 cerr << "ERROR: bucket not specified" << std::endl;
6731 return EINVAL;
6732 }
6733 if (object.empty()) {
6734 cerr << "ERROR: object not specified" << std::endl;
6735 return EINVAL;
6736 }
6737
6738 RGWBucketInfo bucket_info;
6739 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
6740 if (ret < 0) {
6741 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
6742 return -ret;
6743 }
6744
6745 rgw_obj obj(bucket, object);
6746 obj.key.set_instance(object_version);
6747 bool need_rewrite = true;
6748 if (min_rewrite_stripe_size > 0) {
6749 ret = check_min_obj_stripe_size(store, bucket_info, obj, min_rewrite_stripe_size, &need_rewrite);
6750 if (ret < 0) {
6751 ldout(store->ctx(), 0) << "WARNING: check_min_obj_stripe_size failed, r=" << ret << dendl;
6752 }
6753 }
6754 if (need_rewrite) {
9f95a23c 6755 ret = store->getRados()->rewrite_obj(bucket_info, obj, dpp(), null_yield);
7c673cae
FG
6756 if (ret < 0) {
6757 cerr << "ERROR: object rewrite returned: " << cpp_strerror(-ret) << std::endl;
6758 return -ret;
6759 }
6760 } else {
6761 ldout(store->ctx(), 20) << "skipped object" << dendl;
6762 }
6763 }
6764
9f95a23c
TL
6765 if (opt_cmd == OPT::OBJECTS_EXPIRE) {
6766 if (!store->getRados()->process_expire_objects()) {
1adf2230 6767 cerr << "ERROR: process_expire_objects() processing returned error." << std::endl;
7c673cae
FG
6768 return 1;
6769 }
6770 }
6771
9f95a23c 6772 if (opt_cmd == OPT::OBJECTS_EXPIRE_STALE_LIST) {
81eedcae
TL
6773 ret = RGWBucketAdminOp::fix_obj_expiry(store, bucket_op, f, true);
6774 if (ret < 0) {
6775 cerr << "ERROR: listing returned " << cpp_strerror(-ret) << std::endl;
6776 return -ret;
6777 }
6778 }
6779
9f95a23c 6780 if (opt_cmd == OPT::OBJECTS_EXPIRE_STALE_RM) {
81eedcae
TL
6781 ret = RGWBucketAdminOp::fix_obj_expiry(store, bucket_op, f, false);
6782 if (ret < 0) {
6783 cerr << "ERROR: removing returned " << cpp_strerror(-ret) << std::endl;
6784 return -ret;
6785 }
6786 }
6787
9f95a23c 6788 if (opt_cmd == OPT::BUCKET_REWRITE) {
7c673cae
FG
6789 if (bucket_name.empty()) {
6790 cerr << "ERROR: bucket not specified" << std::endl;
6791 return EINVAL;
6792 }
6793
6794 RGWBucketInfo bucket_info;
6795 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
6796 if (ret < 0) {
6797 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
6798 return -ret;
6799 }
6800
6801 uint64_t start_epoch = 0;
6802 uint64_t end_epoch = 0;
6803
6804 if (!end_date.empty()) {
6805 int ret = utime_t::parse_date(end_date, &end_epoch, NULL);
6806 if (ret < 0) {
6807 cerr << "ERROR: failed to parse end date" << std::endl;
6808 return EINVAL;
6809 }
6810 }
6811 if (!start_date.empty()) {
6812 int ret = utime_t::parse_date(start_date, &start_epoch, NULL);
6813 if (ret < 0) {
6814 cerr << "ERROR: failed to parse start date" << std::endl;
6815 return EINVAL;
6816 }
6817 }
6818
6819 bool is_truncated = true;
9f95a23c 6820 bool cls_filtered = true;
7c673cae
FG
6821
6822 rgw_obj_index_key marker;
9f95a23c
TL
6823 string empty_prefix;
6824 string empty_delimiter;
7c673cae
FG
6825
6826 formatter->open_object_section("result");
6827 formatter->dump_string("bucket", bucket_name);
6828 formatter->open_array_section("objects");
7c673cae 6829
9f95a23c
TL
6830 constexpr uint32_t NUM_ENTRIES = 1000;
6831 uint16_t expansion_factor = 1;
6832 while (is_truncated) {
6833 RGWRados::ent_map_t result;
6834 result.reserve(NUM_ENTRIES);
6835
6836 int r = store->getRados()->cls_bucket_list_ordered(
6837 bucket_info, RGW_NO_SHARD,
6838 marker, empty_prefix, empty_delimiter,
6839 NUM_ENTRIES, true, expansion_factor,
6840 result, &is_truncated, &cls_filtered, &marker,
6841 null_yield,
6842 rgw_bucket_object_check_filter);
7c673cae
FG
6843 if (r < 0 && r != -ENOENT) {
6844 cerr << "ERROR: failed operation r=" << r << std::endl;
9f95a23c
TL
6845 } else if (r == -ENOENT) {
6846 break;
7c673cae
FG
6847 }
6848
9f95a23c
TL
6849 if (result.size() < NUM_ENTRIES / 8) {
6850 ++expansion_factor;
6851 } else if (result.size() > NUM_ENTRIES * 7 / 8 &&
6852 expansion_factor > 1) {
6853 --expansion_factor;
6854 }
7c673cae 6855
9f95a23c 6856 for (auto iter = result.begin(); iter != result.end(); ++iter) {
7c673cae
FG
6857 rgw_obj_key key = iter->second.key;
6858 rgw_bucket_dir_entry& entry = iter->second;
6859
6860 formatter->open_object_section("object");
6861 formatter->dump_string("name", key.name);
6862 formatter->dump_string("instance", key.instance);
6863 formatter->dump_int("size", entry.meta.size);
6864 utime_t ut(entry.meta.mtime);
6865 ut.gmtime(formatter->dump_stream("mtime"));
6866
6867 if ((entry.meta.size < min_rewrite_size) ||
6868 (entry.meta.size > max_rewrite_size) ||
6869 (start_epoch > 0 && start_epoch > (uint64_t)ut.sec()) ||
6870 (end_epoch > 0 && end_epoch < (uint64_t)ut.sec())) {
6871 formatter->dump_string("status", "Skipped");
6872 } else {
6873 rgw_obj obj(bucket, key);
6874
6875 bool need_rewrite = true;
6876 if (min_rewrite_stripe_size > 0) {
6877 r = check_min_obj_stripe_size(store, bucket_info, obj, min_rewrite_stripe_size, &need_rewrite);
6878 if (r < 0) {
6879 ldout(store->ctx(), 0) << "WARNING: check_min_obj_stripe_size failed, r=" << r << dendl;
6880 }
6881 }
6882 if (!need_rewrite) {
6883 formatter->dump_string("status", "Skipped");
6884 } else {
9f95a23c 6885 r = store->getRados()->rewrite_obj(bucket_info, obj, dpp(), null_yield);
7c673cae
FG
6886 if (r == 0) {
6887 formatter->dump_string("status", "Success");
6888 } else {
6889 formatter->dump_string("status", cpp_strerror(-r));
6890 }
6891 }
6892 }
6893 formatter->dump_int("flags", entry.flags);
6894
6895 formatter->close_section();
6896 formatter->flush(cout);
6897 }
6898 }
6899 formatter->close_section();
6900 formatter->close_section();
6901 formatter->flush(cout);
6902 }
6903
9f95a23c 6904 if (opt_cmd == OPT::BUCKET_RESHARD) {
31f18b77 6905 rgw_bucket bucket;
7c673cae
FG
6906 RGWBucketInfo bucket_info;
6907 map<string, bufferlist> attrs;
31f18b77
FG
6908
6909 int ret = check_reshard_bucket_params(store,
6910 bucket_name,
6911 tenant,
6912 bucket_id,
6913 num_shards_specified,
6914 num_shards,
6915 yes_i_really_mean_it,
6916 bucket,
6917 bucket_info,
6918 attrs);
7c673cae 6919 if (ret < 0) {
31f18b77 6920 return ret;
7c673cae
FG
6921 }
6922
f64942e4 6923 RGWBucketReshard br(store, bucket_info, attrs, nullptr /* no callback */);
7c673cae 6924
31f18b77
FG
6925#define DEFAULT_RESHARD_MAX_ENTRIES 1000
6926 if (max_entries < 1) {
6927 max_entries = DEFAULT_RESHARD_MAX_ENTRIES;
7c673cae
FG
6928 }
6929
31f18b77
FG
6930 return br.execute(num_shards, max_entries,
6931 verbose, &cout, formatter);
6932 }
7c673cae 6933
9f95a23c 6934 if (opt_cmd == OPT::RESHARD_ADD) {
31f18b77
FG
6935 rgw_bucket bucket;
6936 RGWBucketInfo bucket_info;
6937 map<string, bufferlist> attrs;
7c673cae 6938
31f18b77
FG
6939 int ret = check_reshard_bucket_params(store,
6940 bucket_name,
6941 tenant,
6942 bucket_id,
6943 num_shards_specified,
6944 num_shards,
6945 yes_i_really_mean_it,
6946 bucket,
6947 bucket_info,
6948 attrs);
7c673cae 6949 if (ret < 0) {
31f18b77 6950 return ret;
7c673cae
FG
6951 }
6952
31f18b77 6953 int num_source_shards = (bucket_info.num_shards > 0 ? bucket_info.num_shards : 1);
7c673cae 6954
31f18b77
FG
6955 RGWReshard reshard(store);
6956 cls_rgw_reshard_entry entry;
6957 entry.time = real_clock::now();
6958 entry.tenant = tenant;
6959 entry.bucket_name = bucket_name;
6960 entry.bucket_id = bucket_info.bucket.bucket_id;
6961 entry.old_num_shards = num_source_shards;
6962 entry.new_num_shards = num_shards;
7c673cae 6963
31f18b77
FG
6964 return reshard.add(entry);
6965 }
7c673cae 6966
9f95a23c 6967 if (opt_cmd == OPT::RESHARD_LIST) {
31f18b77
FG
6968 list<cls_rgw_reshard_entry> entries;
6969 int ret;
6970 int count = 0;
6971 if (max_entries < 0) {
6972 max_entries = 1000;
7c673cae
FG
6973 }
6974
11fdf7f2
TL
6975 int num_logshards =
6976 store->ctx()->_conf.get_val<uint64_t>("rgw_reshard_num_logs");
7c673cae 6977
31f18b77 6978 RGWReshard reshard(store);
7c673cae 6979
31f18b77
FG
6980 formatter->open_array_section("reshard");
6981 for (int i = 0; i < num_logshards; i++) {
7c673cae 6982 bool is_truncated = true;
31f18b77
FG
6983 string marker;
6984 do {
7c673cae 6985 entries.clear();
9f95a23c 6986 ret = reshard.list(i, marker, max_entries - count, entries, &is_truncated);
7c673cae 6987 if (ret < 0) {
31f18b77
FG
6988 cerr << "Error listing resharding buckets: " << cpp_strerror(-ret) << std::endl;
6989 return ret;
7c673cae 6990 }
31f18b77
FG
6991 for (auto iter=entries.begin(); iter != entries.end(); ++iter) {
6992 cls_rgw_reshard_entry& entry = *iter;
6993 encode_json("entry", entry, formatter);
6994 entry.get_key(&marker);
6995 }
6996 count += entries.size();
6997 formatter->flush(cout);
6998 } while (is_truncated && count < max_entries);
7c673cae 6999
31f18b77
FG
7000 if (count >= max_entries) {
7001 break;
7002 }
7003 }
7c673cae 7004
31f18b77
FG
7005 formatter->close_section();
7006 formatter->flush(cout);
7007 return 0;
7008 }
7c673cae 7009
9f95a23c 7010 if (opt_cmd == OPT::RESHARD_STATUS) {
31f18b77
FG
7011 if (bucket_name.empty()) {
7012 cerr << "ERROR: bucket not specified" << std::endl;
7013 return EINVAL;
7014 }
7c673cae 7015
31f18b77
FG
7016 rgw_bucket bucket;
7017 RGWBucketInfo bucket_info;
7018 map<string, bufferlist> attrs;
7019 ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket, &attrs);
7020 if (ret < 0) {
7021 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7022 return -ret;
7023 }
7c673cae 7024
f64942e4 7025 RGWBucketReshard br(store, bucket_info, attrs, nullptr /* no callback */);
31f18b77
FG
7026 list<cls_rgw_bucket_instance_entry> status;
7027 int r = br.get_status(&status);
7028 if (r < 0) {
f64942e4
AA
7029 cerr << "ERROR: could not get resharding status for bucket " <<
7030 bucket_name << std::endl;
31f18b77 7031 return -r;
7c673cae 7032 }
31f18b77 7033
f64942e4 7034 show_reshard_status(status, formatter);
31f18b77
FG
7035 }
7036
9f95a23c 7037 if (opt_cmd == OPT::RESHARD_PROCESS) {
31f18b77
FG
7038 RGWReshard reshard(store, true, &cout);
7039
7040 int ret = reshard.process_all_logshards();
7041 if (ret < 0) {
7042 cerr << "ERROR: failed to process reshard logs, error=" << cpp_strerror(-ret) << std::endl;
7043 return -ret;
7c673cae 7044 }
31f18b77 7045 }
7c673cae 7046
9f95a23c 7047 if (opt_cmd == OPT::RESHARD_CANCEL) {
31f18b77
FG
7048 if (bucket_name.empty()) {
7049 cerr << "ERROR: bucket not specified" << std::endl;
7050 return EINVAL;
7051 }
94b18763
FG
7052
7053 rgw_bucket bucket;
7054 RGWBucketInfo bucket_info;
7055 map<string, bufferlist> attrs;
92f5a8d4
TL
7056 bool bucket_initable = true;
7057 ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket,
7058 &attrs);
7c673cae 7059 if (ret < 0) {
92f5a8d4
TL
7060 if (yes_i_really_mean_it) {
7061 bucket_initable = false;
7062 } else {
7063 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) <<
7064 "; if you want to cancel the reshard request nonetheless, please "
7065 "use the --yes-i-really-mean-it option" << std::endl;
7066 return -ret;
7067 }
94b18763
FG
7068 }
7069
92f5a8d4
TL
7070 if (bucket_initable) {
7071 // we did not encounter an error, so let's work with the bucket
7072 RGWBucketReshard br(store, bucket_info, attrs,
7073 nullptr /* no callback */);
7074 int ret = br.cancel();
7075 if (ret < 0) {
7076 if (ret == -EBUSY) {
7077 cerr << "There is ongoing resharding, please retry after " <<
7078 store->ctx()->_conf.get_val<uint64_t>(
7079 "rgw_reshard_bucket_lock_duration") <<
7080 " seconds " << std::endl;
7081 } else {
7082 cerr << "Error canceling bucket " << bucket_name <<
7083 " resharding: " << cpp_strerror(-ret) << std::endl;
7084 }
7085 return ret;
94b18763 7086 }
7c673cae 7087 }
92f5a8d4 7088
94b18763 7089 RGWReshard reshard(store);
7c673cae 7090
94b18763 7091 cls_rgw_reshard_entry entry;
81eedcae 7092 entry.tenant = tenant;
94b18763
FG
7093 entry.bucket_name = bucket_name;
7094 //entry.bucket_id = bucket_id;
31f18b77 7095
94b18763
FG
7096 ret = reshard.remove(entry);
7097 if (ret < 0 && ret != -ENOENT) {
92f5a8d4
TL
7098 cerr << "Error in updating reshard log with bucket " <<
7099 bucket_name << ": " << cpp_strerror(-ret) << std::endl;
31f18b77 7100 return ret;
7c673cae 7101 }
92f5a8d4 7102 } // OPT_RESHARD_CANCEL
7c673cae 7103
9f95a23c 7104 if (opt_cmd == OPT::OBJECT_UNLINK) {
7c673cae
FG
7105 RGWBucketInfo bucket_info;
7106 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
7107 if (ret < 0) {
7108 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7109 return -ret;
7110 }
7111 list<rgw_obj_index_key> oid_list;
7112 rgw_obj_key key(object, object_version);
7113 rgw_obj_index_key index_key;
7114 key.get_index_key(&index_key);
7115 oid_list.push_back(index_key);
9f95a23c 7116 ret = store->getRados()->remove_objs_from_index(bucket_info, oid_list);
7c673cae
FG
7117 if (ret < 0) {
7118 cerr << "ERROR: remove_obj_from_index() returned error: " << cpp_strerror(-ret) << std::endl;
7119 return 1;
7120 }
7121 }
7122
9f95a23c 7123 if (opt_cmd == OPT::OBJECT_STAT) {
7c673cae
FG
7124 RGWBucketInfo bucket_info;
7125 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
7126 if (ret < 0) {
7127 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7128 return -ret;
7129 }
7130 rgw_obj obj(bucket, object);
7131 obj.key.set_instance(object_version);
7132
7133 uint64_t obj_size;
7134 map<string, bufferlist> attrs;
7135 RGWObjectCtx obj_ctx(store);
9f95a23c 7136 RGWRados::Object op_target(store->getRados(), bucket_info, obj_ctx, obj);
7c673cae
FG
7137 RGWRados::Object::Read read_op(&op_target);
7138
7139 read_op.params.attrs = &attrs;
7140 read_op.params.obj_size = &obj_size;
7141
9f95a23c 7142 ret = read_op.prepare(null_yield);
7c673cae
FG
7143 if (ret < 0) {
7144 cerr << "ERROR: failed to stat object, returned error: " << cpp_strerror(-ret) << std::endl;
7145 return 1;
7146 }
7147 formatter->open_object_section("object_metadata");
7148 formatter->dump_string("name", object);
7149 formatter->dump_unsigned("size", obj_size);
7150
7151 map<string, bufferlist>::iterator iter;
7152 map<string, bufferlist> other_attrs;
7153 for (iter = attrs.begin(); iter != attrs.end(); ++iter) {
7154 bufferlist& bl = iter->second;
7155 bool handled = false;
7156 if (iter->first == RGW_ATTR_MANIFEST) {
7157 handled = decode_dump<RGWObjManifest>("manifest", bl, formatter);
7158 } else if (iter->first == RGW_ATTR_ACL) {
7159 handled = decode_dump<RGWAccessControlPolicy>("policy", bl, formatter);
7160 } else if (iter->first == RGW_ATTR_ID_TAG) {
7161 handled = dump_string("tag", bl, formatter);
7162 } else if (iter->first == RGW_ATTR_ETAG) {
7163 handled = dump_string("etag", bl, formatter);
11fdf7f2
TL
7164 } else if (iter->first == RGW_ATTR_COMPRESSION) {
7165 handled = decode_dump<RGWCompressionInfo>("compression", bl, formatter);
81eedcae
TL
7166 } else if (iter->first == RGW_ATTR_DELETE_AT) {
7167 handled = decode_dump<utime_t>("delete_at", bl, formatter);
7c673cae
FG
7168 }
7169
7170 if (!handled)
7171 other_attrs[iter->first] = bl;
7172 }
7173
7174 formatter->open_object_section("attrs");
7175 for (iter = other_attrs.begin(); iter != other_attrs.end(); ++iter) {
7176 dump_string(iter->first.c_str(), iter->second, formatter);
7177 }
7178 formatter->close_section();
7179 formatter->close_section();
7180 formatter->flush(cout);
7181 }
7182
9f95a23c 7183 if (opt_cmd == OPT::BUCKET_CHECK) {
7c673cae
FG
7184 if (check_head_obj_locator) {
7185 if (bucket_name.empty()) {
7186 cerr << "ERROR: need to specify bucket name" << std::endl;
7187 return EINVAL;
7188 }
7189 do_check_object_locator(tenant, bucket_name, fix, remove_bad, formatter);
7190 } else {
9f95a23c 7191 RGWBucketAdminOp::check_index(store, bucket_op, f, null_yield);
7c673cae
FG
7192 }
7193 }
7194
9f95a23c 7195 if (opt_cmd == OPT::BUCKET_RM) {
11fdf7f2 7196 if (!inconsistent_index) {
9f95a23c 7197 RGWBucketAdminOp::remove_bucket(store, bucket_op, null_yield, bypass_gc, true);
7c673cae 7198 } else {
181888fb
FG
7199 if (!yes_i_really_mean_it) {
7200 cerr << "using --inconsistent_index can corrupt the bucket index " << std::endl
7201 << "do you really mean it? (requires --yes-i-really-mean-it)" << std::endl;
7202 return 1;
7203 }
9f95a23c 7204 RGWBucketAdminOp::remove_bucket(store, bucket_op, null_yield, bypass_gc, false);
7c673cae
FG
7205 }
7206 }
7207
9f95a23c 7208 if (opt_cmd == OPT::GC_LIST) {
7c673cae
FG
7209 int index = 0;
7210 bool truncated;
9f95a23c 7211 bool processing_queue = false;
7c673cae
FG
7212 formatter->open_array_section("entries");
7213
7214 do {
7215 list<cls_rgw_gc_obj_info> result;
9f95a23c 7216 int ret = store->getRados()->list_gc_objs(&index, marker, 1000, !include_all, result, &truncated, processing_queue);
7c673cae
FG
7217 if (ret < 0) {
7218 cerr << "ERROR: failed to list objs: " << cpp_strerror(-ret) << std::endl;
7219 return 1;
7220 }
7221
7222
7223 list<cls_rgw_gc_obj_info>::iterator iter;
7224 for (iter = result.begin(); iter != result.end(); ++iter) {
7225 cls_rgw_gc_obj_info& info = *iter;
7226 formatter->open_object_section("chain_info");
7227 formatter->dump_string("tag", info.tag);
7228 formatter->dump_stream("time") << info.time;
7229 formatter->open_array_section("objs");
7230 list<cls_rgw_obj>::iterator liter;
7231 cls_rgw_obj_chain& chain = info.chain;
7232 for (liter = chain.objs.begin(); liter != chain.objs.end(); ++liter) {
7233 cls_rgw_obj& obj = *liter;
7234 encode_json("obj", obj, formatter);
7235 }
7236 formatter->close_section(); // objs
7237 formatter->close_section(); // obj_chain
7238 formatter->flush(cout);
7239 }
7240 } while (truncated);
7241 formatter->close_section();
7242 formatter->flush(cout);
7243 }
7244
9f95a23c
TL
7245 if (opt_cmd == OPT::GC_PROCESS) {
7246 int ret = store->getRados()->process_gc(!include_all);
7c673cae
FG
7247 if (ret < 0) {
7248 cerr << "ERROR: gc processing returned error: " << cpp_strerror(-ret) << std::endl;
7249 return 1;
7250 }
7251 }
7252
9f95a23c 7253 if (opt_cmd == OPT::LC_LIST) {
7c673cae 7254 formatter->open_array_section("lifecycle_list");
f6b5b4d7 7255 vector<cls_rgw_lc_entry> bucket_lc_map;
7c673cae 7256 string marker;
f6b5b4d7 7257 int index{0};
7c673cae
FG
7258#define MAX_LC_LIST_ENTRIES 100
7259 if (max_entries < 0) {
7260 max_entries = MAX_LC_LIST_ENTRIES;
7261 }
7262 do {
f6b5b4d7
TL
7263 int ret = store->getRados()->list_lc_progress(marker, max_entries,
7264 bucket_lc_map, index);
7c673cae 7265 if (ret < 0) {
f6b5b4d7
TL
7266 cerr << "ERROR: failed to list objs: " << cpp_strerror(-ret)
7267 << std::endl;
7c673cae
FG
7268 return 1;
7269 }
f6b5b4d7 7270 for (const auto& entry : bucket_lc_map) {
7c673cae 7271 formatter->open_object_section("bucket_lc_info");
f6b5b4d7
TL
7272 formatter->dump_string("bucket", entry.bucket);
7273 char exp_buf[100];
7274 time_t t{time_t(entry.start_time)};
7275 if (std::strftime(
7276 exp_buf, sizeof(exp_buf),
7277 "%a, %d %b %Y %T %Z", std::gmtime(&t))) {
7278 formatter->dump_string("started", exp_buf);
7279 }
7280 string lc_status = LC_STATUS[entry.status];
7c673cae
FG
7281 formatter->dump_string("status", lc_status);
7282 formatter->close_section(); // objs
7283 formatter->flush(cout);
7c673cae
FG
7284 }
7285 } while (!bucket_lc_map.empty());
7286
7287 formatter->close_section(); //lifecycle list
7288 formatter->flush(cout);
7289 }
7290
7291
9f95a23c 7292 if (opt_cmd == OPT::LC_GET) {
11fdf7f2
TL
7293 if (bucket_name.empty()) {
7294 cerr << "ERROR: bucket not specified" << std::endl;
7295 return EINVAL;
7296 }
7297
7298 rgw_bucket bucket;
7299 RGWBucketInfo bucket_info;
7300 map<string, bufferlist> attrs;
7301 RGWLifecycleConfiguration config;
7302 ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket, &attrs);
7303 if (ret < 0) {
7304 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7305 return -ret;
7306 }
7307
7308 auto aiter = attrs.find(RGW_ATTR_LC);
7309 if (aiter == attrs.end()) {
7310 return -ENOENT;
7311 }
7312
7313 bufferlist::const_iterator iter{&aiter->second};
7314 try {
7315 config.decode(iter);
7316 } catch (const buffer::error& e) {
7317 cerr << "ERROR: decode life cycle config failed" << std::endl;
7318 return -EIO;
7319 }
7320
7321 encode_json("result", config, formatter);
7322 formatter->flush(cout);
7323 }
7324
9f95a23c
TL
7325 if (opt_cmd == OPT::LC_PROCESS) {
7326 int ret = store->getRados()->process_lc();
7c673cae
FG
7327 if (ret < 0) {
7328 cerr << "ERROR: lc processing returned error: " << cpp_strerror(-ret) << std::endl;
7329 return 1;
7330 }
7331 }
7332
11fdf7f2 7333
9f95a23c 7334 if (opt_cmd == OPT::LC_RESHARD_FIX) {
11fdf7f2
TL
7335 ret = RGWBucketAdminOp::fix_lc_shards(store, bucket_op,f);
7336 if (ret < 0) {
7337 cerr << "ERROR: listing stale instances" << cpp_strerror(-ret) << std::endl;
7338 }
7339
7340 }
7341
9f95a23c 7342 if (opt_cmd == OPT::ORPHANS_FIND) {
1adf2230 7343 if (!yes_i_really_mean_it) {
e306af50
TL
7344 cerr << "this command is now deprecated; please consider using the rgw-orphan-list tool; "
7345 << "accidental removal of active objects cannot be reversed; "
1adf2230
AA
7346 << "do you really mean it? (requires --yes-i-really-mean-it)"
7347 << std::endl;
7348 return EINVAL;
e306af50
TL
7349 } else {
7350 cerr << "IMPORTANT: this command is now deprecated; please consider using the rgw-orphan-list tool"
7351 << std::endl;
1adf2230
AA
7352 }
7353
7c673cae
FG
7354 RGWOrphanSearch search(store, max_concurrent_ios, orphan_stale_secs);
7355
7356 if (job_id.empty()) {
7357 cerr << "ERROR: --job-id not specified" << std::endl;
7358 return EINVAL;
7359 }
7360 if (pool_name.empty()) {
7361 cerr << "ERROR: --pool not specified" << std::endl;
7362 return EINVAL;
7363 }
7364
7365 RGWOrphanSearchInfo info;
7366
7367 info.pool = pool;
7368 info.job_name = job_id;
7369 info.num_shards = num_shards;
7370
11fdf7f2 7371 int ret = search.init(job_id, &info, detail);
7c673cae
FG
7372 if (ret < 0) {
7373 cerr << "could not init search, ret=" << ret << std::endl;
7374 return -ret;
7375 }
7376 ret = search.run();
7377 if (ret < 0) {
7378 return -ret;
7379 }
7380 }
7381
9f95a23c 7382 if (opt_cmd == OPT::ORPHANS_FINISH) {
e306af50
TL
7383 if (!yes_i_really_mean_it) {
7384 cerr << "this command is now deprecated; please consider using the rgw-orphan-list tool; "
7385 << "accidental removal of active objects cannot be reversed; "
7386 << "do you really mean it? (requires --yes-i-really-mean-it)"
7387 << std::endl;
7388 return EINVAL;
7389 } else {
7390 cerr << "IMPORTANT: this command is now deprecated; please consider using the rgw-orphan-list tool"
7391 << std::endl;
7392 }
7393
7c673cae
FG
7394 RGWOrphanSearch search(store, max_concurrent_ios, orphan_stale_secs);
7395
7396 if (job_id.empty()) {
7397 cerr << "ERROR: --job-id not specified" << std::endl;
7398 return EINVAL;
7399 }
7400 int ret = search.init(job_id, NULL);
7401 if (ret < 0) {
7402 if (ret == -ENOENT) {
7403 cerr << "job not found" << std::endl;
7404 }
7405 return -ret;
7406 }
7407 ret = search.finish();
7408 if (ret < 0) {
7409 return -ret;
7410 }
7411 }
7412
9f95a23c 7413 if (opt_cmd == OPT::ORPHANS_LIST_JOBS){
e306af50
TL
7414 if (!yes_i_really_mean_it) {
7415 cerr << "this command is now deprecated; please consider using the rgw-orphan-list tool; "
7416 << "do you really mean it? (requires --yes-i-really-mean-it)"
7417 << std::endl;
7418 return EINVAL;
7419 } else {
7420 cerr << "IMPORTANT: this command is now deprecated; please consider using the rgw-orphan-list tool"
7421 << std::endl;
7422 }
7423
7c673cae
FG
7424 RGWOrphanStore orphan_store(store);
7425 int ret = orphan_store.init();
7426 if (ret < 0){
7427 cerr << "connection to cluster failed!" << std::endl;
7428 return -ret;
7429 }
7430
7431 map <string,RGWOrphanSearchState> m;
7432 ret = orphan_store.list_jobs(m);
7433 if (ret < 0) {
7434 cerr << "job list failed" << std::endl;
7435 return -ret;
7436 }
7437 formatter->open_array_section("entries");
7438 for (const auto &it: m){
7439 if (!extra_info){
7440 formatter->dump_string("job-id",it.first);
7441 } else {
7442 encode_json("orphan_search_state", it.second, formatter);
7443 }
7444 }
7445 formatter->close_section();
7446 formatter->flush(cout);
7447 }
7448
9f95a23c 7449 if (opt_cmd == OPT::USER_CHECK) {
7c673cae
FG
7450 check_bad_user_bucket_mapping(store, user_id, fix);
7451 }
7452
9f95a23c 7453 if (opt_cmd == OPT::USER_STATS) {
94b18763
FG
7454 if (user_id.empty()) {
7455 cerr << "ERROR: uid not specified" << std::endl;
7456 return EINVAL;
7457 }
7458
94b18763 7459 if (reset_stats) {
eafe8130
TL
7460 if (!bucket_name.empty()) {
7461 cerr << "ERROR: --reset-stats does not work on buckets and "
7462 "bucket specified" << std::endl;
7463 return EINVAL;
7464 }
7465 if (sync_stats) {
7466 cerr << "ERROR: sync-stats includes the reset-stats functionality, "
7467 "so at most one of the two should be specified" << std::endl;
94b18763
FG
7468 return EINVAL;
7469 }
9f95a23c 7470 ret = store->ctl()->user->reset_stats(user_id);
94b18763 7471 if (ret < 0) {
eafe8130
TL
7472 cerr << "ERROR: could not reset user stats: " << cpp_strerror(-ret) <<
7473 std::endl;
94b18763
FG
7474 return -ret;
7475 }
7476 }
7477
7c673cae
FG
7478 if (sync_stats) {
7479 if (!bucket_name.empty()) {
9f95a23c
TL
7480 RGWBucketInfo bucket_info;
7481 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
7482 if (ret < 0) {
7483 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
7484 return -ret;
7485 }
7486 ret = store->ctl()->bucket->sync_user_stats(user_id, bucket_info);
7c673cae 7487 if (ret < 0) {
eafe8130
TL
7488 cerr << "ERROR: could not sync bucket stats: " <<
7489 cpp_strerror(-ret) << std::endl;
7c673cae
FG
7490 return -ret;
7491 }
7492 } else {
7493 int ret = rgw_user_sync_all_stats(store, user_id);
7494 if (ret < 0) {
eafe8130
TL
7495 cerr << "ERROR: could not sync user stats: " <<
7496 cpp_strerror(-ret) << std::endl;
7c673cae
FG
7497 return -ret;
7498 }
7499 }
7500 }
7501
9f95a23c
TL
7502 RGWStorageStats stats;
7503 ceph::real_time last_stats_sync;
7504 ceph::real_time last_stats_update;
7505 int ret = store->ctl()->user->read_stats(user_id, &stats, &last_stats_sync, &last_stats_update);
7c673cae
FG
7506 if (ret < 0) {
7507 if (ret == -ENOENT) { /* in case of ENOENT */
7508 cerr << "User has not been initialized or user does not exist" << std::endl;
7509 } else {
7510 cerr << "ERROR: can't read user: " << cpp_strerror(ret) << std::endl;
7511 }
7512 return -ret;
7513 }
7514
9f95a23c
TL
7515
7516 {
7517 Formatter::ObjectSection os(*formatter, "result");
7518 encode_json("stats", stats, formatter);
7519 utime_t last_sync_ut(last_stats_sync);
7520 encode_json("last_stats_sync", last_sync_ut, formatter);
7521 utime_t last_update_ut(last_stats_update);
7522 encode_json("last_stats_update", last_update_ut, formatter);
7523 }
7c673cae
FG
7524 formatter->flush(cout);
7525 }
7526
9f95a23c
TL
7527 if (opt_cmd == OPT::METADATA_GET) {
7528 int ret = store->ctl()->meta.mgr->get(metadata_key, formatter, null_yield);
7c673cae
FG
7529 if (ret < 0) {
7530 cerr << "ERROR: can't get key: " << cpp_strerror(-ret) << std::endl;
7531 return -ret;
7532 }
7533
7534 formatter->flush(cout);
7535 }
7536
9f95a23c 7537 if (opt_cmd == OPT::METADATA_PUT) {
7c673cae
FG
7538 bufferlist bl;
7539 int ret = read_input(infile, bl);
7540 if (ret < 0) {
7541 cerr << "ERROR: failed to read input: " << cpp_strerror(-ret) << std::endl;
7542 return -ret;
7543 }
9f95a23c 7544 ret = store->ctl()->meta.mgr->put(metadata_key, bl, null_yield, RGWMDLogSyncType::APPLY_ALWAYS);
7c673cae
FG
7545 if (ret < 0) {
7546 cerr << "ERROR: can't put key: " << cpp_strerror(-ret) << std::endl;
7547 return -ret;
7548 }
7549 }
7550
9f95a23c
TL
7551 if (opt_cmd == OPT::METADATA_RM) {
7552 int ret = store->ctl()->meta.mgr->remove(metadata_key, null_yield);
7c673cae
FG
7553 if (ret < 0) {
7554 cerr << "ERROR: can't remove key: " << cpp_strerror(-ret) << std::endl;
7555 return -ret;
7556 }
7557 }
7558
9f95a23c
TL
7559 if (opt_cmd == OPT::METADATA_LIST || opt_cmd == OPT::USER_LIST) {
7560 if (opt_cmd == OPT::USER_LIST) {
7c673cae
FG
7561 metadata_key = "user";
7562 }
7563 void *handle;
7564 int max = 1000;
9f95a23c 7565 int ret = store->ctl()->meta.mgr->list_keys_init(metadata_key, marker, &handle);
7c673cae
FG
7566 if (ret < 0) {
7567 cerr << "ERROR: can't get key: " << cpp_strerror(-ret) << std::endl;
7568 return -ret;
7569 }
7570
7571 bool truncated;
181888fb 7572 uint64_t count = 0;
7c673cae 7573
181888fb
FG
7574 if (max_entries_specified) {
7575 formatter->open_object_section("result");
7576 }
7c673cae
FG
7577 formatter->open_array_section("keys");
7578
181888fb 7579 uint64_t left;
7c673cae
FG
7580 do {
7581 list<string> keys;
181888fb 7582 left = (max_entries_specified ? max_entries - count : max);
9f95a23c 7583 ret = store->ctl()->meta.mgr->list_keys_next(handle, left, keys, &truncated);
7c673cae
FG
7584 if (ret < 0 && ret != -ENOENT) {
7585 cerr << "ERROR: lists_keys_next(): " << cpp_strerror(-ret) << std::endl;
7586 return -ret;
7587 } if (ret != -ENOENT) {
7588 for (list<string>::iterator iter = keys.begin(); iter != keys.end(); ++iter) {
7589 formatter->dump_string("key", *iter);
181888fb 7590 ++count;
7c673cae
FG
7591 }
7592 formatter->flush(cout);
7593 }
181888fb 7594 } while (truncated && left > 0);
7c673cae
FG
7595
7596 formatter->close_section();
181888fb
FG
7597
7598 if (max_entries_specified) {
7599 encode_json("truncated", truncated, formatter);
7600 encode_json("count", count, formatter);
7601 if (truncated) {
9f95a23c 7602 encode_json("marker", store->ctl()->meta.mgr->get_marker(handle), formatter);
181888fb
FG
7603 }
7604 formatter->close_section();
7605 }
7c673cae
FG
7606 formatter->flush(cout);
7607
9f95a23c 7608 store->ctl()->meta.mgr->list_keys_complete(handle);
7c673cae
FG
7609 }
7610
9f95a23c 7611 if (opt_cmd == OPT::MDLOG_LIST) {
7c673cae
FG
7612 utime_t start_time, end_time;
7613
7614 int ret = parse_date_str(start_date, start_time);
7615 if (ret < 0)
7616 return -ret;
7617
7618 ret = parse_date_str(end_date, end_time);
7619 if (ret < 0)
7620 return -ret;
7621
7622 int i = (specified_shard_id ? shard_id : 0);
7623
7624 if (period_id.empty()) {
7625 int ret = read_current_period_id(store, realm_id, realm_name, &period_id);
7626 if (ret < 0) {
7627 return -ret;
7628 }
7629 std::cerr << "No --period given, using current period="
7630 << period_id << std::endl;
7631 }
9f95a23c 7632 RGWMetadataLog *meta_log = store->svc()->mdlog->get_log(period_id);
7c673cae
FG
7633
7634 formatter->open_array_section("entries");
7635 for (; i < g_ceph_context->_conf->rgw_md_log_max_shards; i++) {
7636 void *handle;
7637 list<cls_log_entry> entries;
7638
7639
7640 meta_log->init_list_entries(i, start_time.to_real_time(), end_time.to_real_time(), marker, &handle);
7641 bool truncated;
7642 do {
7643 int ret = meta_log->list_entries(handle, 1000, entries, NULL, &truncated);
7644 if (ret < 0) {
7645 cerr << "ERROR: meta_log->list_entries(): " << cpp_strerror(-ret) << std::endl;
7646 return -ret;
7647 }
7648
7649 for (list<cls_log_entry>::iterator iter = entries.begin(); iter != entries.end(); ++iter) {
7650 cls_log_entry& entry = *iter;
9f95a23c 7651 store->ctl()->meta.mgr->dump_log_entry(entry, formatter);
7c673cae
FG
7652 }
7653 formatter->flush(cout);
7654 } while (truncated);
7655
7656 meta_log->complete_list_entries(handle);
7657
7658 if (specified_shard_id)
7659 break;
7660 }
7661
7662
7663 formatter->close_section();
7664 formatter->flush(cout);
7665 }
7666
9f95a23c 7667 if (opt_cmd == OPT::MDLOG_STATUS) {
7c673cae
FG
7668 int i = (specified_shard_id ? shard_id : 0);
7669
7670 if (period_id.empty()) {
7671 int ret = read_current_period_id(store, realm_id, realm_name, &period_id);
7672 if (ret < 0) {
7673 return -ret;
7674 }
7675 std::cerr << "No --period given, using current period="
7676 << period_id << std::endl;
7677 }
9f95a23c 7678 RGWMetadataLog *meta_log = store->svc()->mdlog->get_log(period_id);
7c673cae
FG
7679
7680 formatter->open_array_section("entries");
7681
7682 for (; i < g_ceph_context->_conf->rgw_md_log_max_shards; i++) {
7683 RGWMetadataLogInfo info;
7684 meta_log->get_info(i, &info);
7685
7686 ::encode_json("info", info, formatter);
7687
7688 if (specified_shard_id)
7689 break;
7690 }
7691
7692
7693 formatter->close_section();
7694 formatter->flush(cout);
7695 }
7696
9f95a23c 7697 if (opt_cmd == OPT::MDLOG_AUTOTRIM) {
7c673cae 7698 // need a full history for purging old mdlog periods
9f95a23c 7699 store->svc()->mdlog->init_oldest_log_period();
7c673cae 7700
9f95a23c 7701 RGWCoroutinesManager crs(store->ctx(), store->getRados()->get_cr_registry());
7c673cae 7702 RGWHTTPManager http(store->ctx(), crs.get_completion_mgr());
11fdf7f2 7703 int ret = http.start();
7c673cae
FG
7704 if (ret < 0) {
7705 cerr << "failed to initialize http client with " << cpp_strerror(ret) << std::endl;
7706 return -ret;
7707 }
7708
11fdf7f2
TL
7709 auto num_shards = g_conf()->rgw_md_log_max_shards;
7710 ret = crs.run(create_admin_meta_log_trim_cr(dpp(), store, &http, num_shards));
7c673cae
FG
7711 if (ret < 0) {
7712 cerr << "automated mdlog trim failed with " << cpp_strerror(ret) << std::endl;
7713 return -ret;
7714 }
7715 }
7716
9f95a23c 7717 if (opt_cmd == OPT::MDLOG_TRIM) {
7c673cae
FG
7718 utime_t start_time, end_time;
7719
7720 if (!specified_shard_id) {
7721 cerr << "ERROR: shard-id must be specified for trim operation" << std::endl;
7722 return EINVAL;
7723 }
7724
7725 int ret = parse_date_str(start_date, start_time);
7726 if (ret < 0)
7727 return -ret;
7728
7729 ret = parse_date_str(end_date, end_time);
7730 if (ret < 0)
7731 return -ret;
7732
7733 if (period_id.empty()) {
7734 std::cerr << "missing --period argument" << std::endl;
7735 return EINVAL;
7736 }
9f95a23c 7737 RGWMetadataLog *meta_log = store->svc()->mdlog->get_log(period_id);
7c673cae 7738
eafe8130
TL
7739 // trim until -ENODATA
7740 do {
7741 ret = meta_log->trim(shard_id, start_time.to_real_time(),
7742 end_time.to_real_time(), start_marker, end_marker);
7743 } while (ret == 0);
7744 if (ret < 0 && ret != -ENODATA) {
7c673cae
FG
7745 cerr << "ERROR: meta_log->trim(): " << cpp_strerror(-ret) << std::endl;
7746 return -ret;
7747 }
7748 }
7749
9f95a23c
TL
7750 if (opt_cmd == OPT::SYNC_INFO) {
7751 sync_info(opt_effective_zone_id, opt_bucket, zone_formatter);
7752 }
7753
7754 if (opt_cmd == OPT::SYNC_STATUS) {
7c673cae
FG
7755 sync_status(formatter);
7756 }
7757
9f95a23c
TL
7758 if (opt_cmd == OPT::METADATA_SYNC_STATUS) {
7759 RGWMetaSyncStatusManager sync(store, store->svc()->rados->get_async_processor());
7c673cae
FG
7760
7761 int ret = sync.init();
7762 if (ret < 0) {
7763 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
7764 return -ret;
7765 }
7766
7767 rgw_meta_sync_status sync_status;
7768 ret = sync.read_sync_status(&sync_status);
7769 if (ret < 0) {
7770 cerr << "ERROR: sync.read_sync_status() returned ret=" << ret << std::endl;
7771 return -ret;
7772 }
7773
7774 formatter->open_object_section("summary");
7775 encode_json("sync_status", sync_status, formatter);
7776
7777 uint64_t full_total = 0;
7778 uint64_t full_complete = 0;
7779
7780 for (auto marker_iter : sync_status.sync_markers) {
7781 full_total += marker_iter.second.total_entries;
7782 if (marker_iter.second.state == rgw_meta_sync_marker::SyncState::FullSync) {
7783 full_complete += marker_iter.second.pos;
7784 } else {
7785 full_complete += marker_iter.second.total_entries;
7786 }
7787 }
7788
7789 formatter->open_object_section("full_sync");
7790 encode_json("total", full_total, formatter);
7791 encode_json("complete", full_complete, formatter);
7792 formatter->close_section();
7793 formatter->close_section();
7794
7795 formatter->flush(cout);
7796
7797 }
7798
9f95a23c
TL
7799 if (opt_cmd == OPT::METADATA_SYNC_INIT) {
7800 RGWMetaSyncStatusManager sync(store, store->svc()->rados->get_async_processor());
7c673cae
FG
7801
7802 int ret = sync.init();
7803 if (ret < 0) {
7804 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
7805 return -ret;
7806 }
7807 ret = sync.init_sync_status();
7808 if (ret < 0) {
7809 cerr << "ERROR: sync.init_sync_status() returned ret=" << ret << std::endl;
7810 return -ret;
7811 }
7812 }
7813
7814
9f95a23c
TL
7815 if (opt_cmd == OPT::METADATA_SYNC_RUN) {
7816 RGWMetaSyncStatusManager sync(store, store->svc()->rados->get_async_processor());
7c673cae
FG
7817
7818 int ret = sync.init();
7819 if (ret < 0) {
7820 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
7821 return -ret;
7822 }
7823
7824 ret = sync.run();
7825 if (ret < 0) {
7826 cerr << "ERROR: sync.run() returned ret=" << ret << std::endl;
7827 return -ret;
7828 }
7829 }
7830
9f95a23c 7831 if (opt_cmd == OPT::DATA_SYNC_STATUS) {
7c673cae
FG
7832 if (source_zone.empty()) {
7833 cerr << "ERROR: source zone not specified" << std::endl;
7834 return EINVAL;
7835 }
9f95a23c 7836 RGWDataSyncStatusManager sync(store, store->svc()->rados->get_async_processor(), source_zone, nullptr);
7c673cae
FG
7837
7838 int ret = sync.init();
7839 if (ret < 0) {
7840 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
7841 return -ret;
7842 }
7843
7844 rgw_data_sync_status sync_status;
28e407b8
AA
7845 if (specified_shard_id) {
7846 set<string> pending_buckets;
7847 set<string> recovering_buckets;
7848 rgw_data_sync_marker sync_marker;
7849 ret = sync.read_shard_status(shard_id, pending_buckets, recovering_buckets, &sync_marker,
7850 max_entries_specified ? max_entries : 20);
7851 if (ret < 0 && ret != -ENOENT) {
7852 cerr << "ERROR: sync.read_shard_status() returned ret=" << ret << std::endl;
7853 return -ret;
7854 }
7855 formatter->open_object_section("summary");
7856 encode_json("shard_id", shard_id, formatter);
7857 encode_json("marker", sync_marker, formatter);
7858 encode_json("pending_buckets", pending_buckets, formatter);
7859 encode_json("recovering_buckets", recovering_buckets, formatter);
7860 formatter->close_section();
7861 formatter->flush(cout);
7862 } else {
7863 ret = sync.read_sync_status(&sync_status);
7864 if (ret < 0 && ret != -ENOENT) {
7865 cerr << "ERROR: sync.read_sync_status() returned ret=" << ret << std::endl;
7866 return -ret;
7867 }
7c673cae 7868
28e407b8
AA
7869 formatter->open_object_section("summary");
7870 encode_json("sync_status", sync_status, formatter);
7c673cae 7871
28e407b8
AA
7872 uint64_t full_total = 0;
7873 uint64_t full_complete = 0;
7c673cae 7874
28e407b8
AA
7875 for (auto marker_iter : sync_status.sync_markers) {
7876 full_total += marker_iter.second.total_entries;
7877 if (marker_iter.second.state == rgw_meta_sync_marker::SyncState::FullSync) {
7878 full_complete += marker_iter.second.pos;
7879 } else {
7880 full_complete += marker_iter.second.total_entries;
7881 }
7c673cae 7882 }
7c673cae 7883
28e407b8
AA
7884 formatter->open_object_section("full_sync");
7885 encode_json("total", full_total, formatter);
7886 encode_json("complete", full_complete, formatter);
7887 formatter->close_section();
7888 formatter->close_section();
7c673cae 7889
28e407b8
AA
7890 formatter->flush(cout);
7891 }
7c673cae
FG
7892 }
7893
9f95a23c 7894 if (opt_cmd == OPT::DATA_SYNC_INIT) {
7c673cae
FG
7895 if (source_zone.empty()) {
7896 cerr << "ERROR: source zone not specified" << std::endl;
7897 return EINVAL;
7898 }
94b18763 7899
9f95a23c 7900 RGWDataSyncStatusManager sync(store, store->svc()->rados->get_async_processor(), source_zone, nullptr);
7c673cae
FG
7901
7902 int ret = sync.init();
7903 if (ret < 0) {
7904 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
7905 return -ret;
7906 }
7907
7908 ret = sync.init_sync_status();
7909 if (ret < 0) {
7910 cerr << "ERROR: sync.init_sync_status() returned ret=" << ret << std::endl;
7911 return -ret;
7912 }
7913 }
7914
9f95a23c 7915 if (opt_cmd == OPT::DATA_SYNC_RUN) {
7c673cae
FG
7916 if (source_zone.empty()) {
7917 cerr << "ERROR: source zone not specified" << std::endl;
7918 return EINVAL;
7919 }
7c673cae 7920
94b18763 7921 RGWSyncModuleInstanceRef sync_module;
9f95a23c
TL
7922 int ret = store->svc()->sync_modules->get_manager()->create_instance(g_ceph_context, store->svc()->zone->get_zone().tier_type,
7923 store->svc()->zone->get_zone_params().tier_config, &sync_module);
94b18763
FG
7924 if (ret < 0) {
7925 lderr(cct) << "ERROR: failed to init sync module instance, ret=" << ret << dendl;
7926 return ret;
7927 }
7928
9f95a23c 7929 RGWDataSyncStatusManager sync(store, store->svc()->rados->get_async_processor(), source_zone, nullptr, sync_module);
94b18763
FG
7930
7931 ret = sync.init();
7c673cae
FG
7932 if (ret < 0) {
7933 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
7934 return -ret;
7935 }
7936
7937 ret = sync.run();
7938 if (ret < 0) {
7939 cerr << "ERROR: sync.run() returned ret=" << ret << std::endl;
7940 return -ret;
7941 }
7942 }
7943
9f95a23c 7944 if (opt_cmd == OPT::BUCKET_SYNC_INIT) {
7c673cae
FG
7945 if (source_zone.empty()) {
7946 cerr << "ERROR: source zone not specified" << std::endl;
7947 return EINVAL;
7948 }
7949 if (bucket_name.empty()) {
7950 cerr << "ERROR: bucket not specified" << std::endl;
7951 return EINVAL;
7952 }
7953 rgw_bucket bucket;
7954 int ret = init_bucket_for_sync(tenant, bucket_name, bucket_id, bucket);
7955 if (ret < 0) {
7956 return -ret;
7957 }
9f95a23c
TL
7958 auto opt_sb = opt_source_bucket;
7959 if (opt_sb && opt_sb->bucket_id.empty()) {
7960 string sbid;
7961 rgw_bucket sbuck;
7962 int ret = init_bucket_for_sync(opt_sb->tenant, opt_sb->name, sbid, sbuck);
7963 if (ret < 0) {
7964 return -ret;
7965 }
7966 opt_sb = sbuck;
7967 }
7968
7969 RGWBucketPipeSyncStatusManager sync(store, source_zone, opt_sb, bucket);
7c673cae
FG
7970
7971 ret = sync.init();
7972 if (ret < 0) {
7973 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
7974 return -ret;
7975 }
7976 ret = sync.init_sync_status();
7977 if (ret < 0) {
7978 cerr << "ERROR: sync.init_sync_status() returned ret=" << ret << std::endl;
7979 return -ret;
7980 }
7981 }
7982
9f95a23c 7983 if ((opt_cmd == OPT::BUCKET_SYNC_DISABLE) || (opt_cmd == OPT::BUCKET_SYNC_ENABLE)) {
c07f9fc5
FG
7984 if (bucket_name.empty()) {
7985 cerr << "ERROR: bucket not specified" << std::endl;
7986 return EINVAL;
9f95a23c
TL
7987 }
7988 if (opt_cmd == OPT::BUCKET_SYNC_DISABLE) {
7989 bucket_op.set_sync_bucket(false);
7990 } else {
7991 bucket_op.set_sync_bucket(true);
c07f9fc5 7992 }
9f95a23c
TL
7993 bucket_op.set_tenant(tenant);
7994 string err_msg;
7995 ret = RGWBucketAdminOp::sync_bucket(store, bucket_op, &err_msg);
c07f9fc5 7996 if (ret < 0) {
9f95a23c
TL
7997 cerr << err_msg << std::endl;
7998 return -ret;
c07f9fc5 7999 }
9f95a23c 8000 }
c07f9fc5 8001
9f95a23c
TL
8002 if (opt_cmd == OPT::BUCKET_SYNC_INFO) {
8003 if (bucket_name.empty()) {
8004 cerr << "ERROR: bucket not specified" << std::endl;
c07f9fc5
FG
8005 return EINVAL;
8006 }
9f95a23c
TL
8007 RGWBucketInfo bucket_info;
8008 rgw_bucket bucket;
8009 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
8010 if (ret < 0) {
c07f9fc5 8011 return -ret;
9f95a23c
TL
8012 }
8013 bucket_sync_info(store, bucket_info, std::cout);
28e407b8 8014 }
c07f9fc5 8015
9f95a23c 8016 if (opt_cmd == OPT::BUCKET_SYNC_STATUS) {
28e407b8
AA
8017 if (bucket_name.empty()) {
8018 cerr << "ERROR: bucket not specified" << std::endl;
8019 return EINVAL;
8020 }
8021 RGWBucketInfo bucket_info;
8022 rgw_bucket bucket;
8023 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
8024 if (ret < 0) {
8025 return -ret;
8026 }
9f95a23c 8027 bucket_sync_status(store, bucket_info, source_zone, opt_source_bucket, std::cout);
28e407b8
AA
8028 }
8029
9f95a23c 8030 if (opt_cmd == OPT::BUCKET_SYNC_MARKERS) {
7c673cae
FG
8031 if (source_zone.empty()) {
8032 cerr << "ERROR: source zone not specified" << std::endl;
8033 return EINVAL;
8034 }
8035 if (bucket_name.empty()) {
8036 cerr << "ERROR: bucket not specified" << std::endl;
8037 return EINVAL;
8038 }
8039 rgw_bucket bucket;
8040 int ret = init_bucket_for_sync(tenant, bucket_name, bucket_id, bucket);
8041 if (ret < 0) {
8042 return -ret;
8043 }
9f95a23c 8044 RGWBucketPipeSyncStatusManager sync(store, source_zone, opt_source_bucket, bucket);
7c673cae
FG
8045
8046 ret = sync.init();
8047 if (ret < 0) {
8048 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
8049 return -ret;
8050 }
8051 ret = sync.read_sync_status();
8052 if (ret < 0) {
8053 cerr << "ERROR: sync.read_sync_status() returned ret=" << ret << std::endl;
8054 return -ret;
8055 }
8056
8057 map<int, rgw_bucket_shard_sync_info>& sync_status = sync.get_sync_status();
8058
8059 encode_json("sync_status", sync_status, formatter);
8060 formatter->flush(cout);
8061 }
8062
9f95a23c 8063 if (opt_cmd == OPT::BUCKET_SYNC_RUN) {
7c673cae
FG
8064 if (source_zone.empty()) {
8065 cerr << "ERROR: source zone not specified" << std::endl;
8066 return EINVAL;
8067 }
8068 if (bucket_name.empty()) {
8069 cerr << "ERROR: bucket not specified" << std::endl;
8070 return EINVAL;
8071 }
8072 rgw_bucket bucket;
8073 int ret = init_bucket_for_sync(tenant, bucket_name, bucket_id, bucket);
8074 if (ret < 0) {
8075 return -ret;
8076 }
9f95a23c 8077 RGWBucketPipeSyncStatusManager sync(store, source_zone, opt_source_bucket, bucket);
7c673cae
FG
8078
8079 ret = sync.init();
8080 if (ret < 0) {
8081 cerr << "ERROR: sync.init() returned ret=" << ret << std::endl;
8082 return -ret;
8083 }
8084
8085 ret = sync.run();
8086 if (ret < 0) {
8087 cerr << "ERROR: sync.run() returned ret=" << ret << std::endl;
8088 return -ret;
8089 }
8090 }
8091
9f95a23c 8092 if (opt_cmd == OPT::BILOG_LIST) {
7c673cae
FG
8093 if (bucket_name.empty()) {
8094 cerr << "ERROR: bucket not specified" << std::endl;
8095 return EINVAL;
8096 }
8097 RGWBucketInfo bucket_info;
8098 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
8099 if (ret < 0) {
8100 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
8101 return -ret;
8102 }
8103 formatter->open_array_section("entries");
8104 bool truncated;
8105 int count = 0;
8106 if (max_entries < 0)
8107 max_entries = 1000;
8108
8109 do {
8110 list<rgw_bi_log_entry> entries;
9f95a23c 8111 ret = store->svc()->bilog_rados->log_list(bucket_info, shard_id, marker, max_entries - count, entries, &truncated);
7c673cae
FG
8112 if (ret < 0) {
8113 cerr << "ERROR: list_bi_log_entries(): " << cpp_strerror(-ret) << std::endl;
8114 return -ret;
8115 }
8116
8117 count += entries.size();
8118
8119 for (list<rgw_bi_log_entry>::iterator iter = entries.begin(); iter != entries.end(); ++iter) {
8120 rgw_bi_log_entry& entry = *iter;
8121 encode_json("entry", entry, formatter);
8122
8123 marker = entry.id;
8124 }
8125 formatter->flush(cout);
8126 } while (truncated && count < max_entries);
8127
8128 formatter->close_section();
8129 formatter->flush(cout);
8130 }
8131
9f95a23c 8132 if (opt_cmd == OPT::SYNC_ERROR_LIST) {
7c673cae
FG
8133 if (max_entries < 0) {
8134 max_entries = 1000;
8135 }
8136
8137 bool truncated;
8138 utime_t start_time, end_time;
8139
8140 int ret = parse_date_str(start_date, start_time);
8141 if (ret < 0)
8142 return -ret;
8143
8144 ret = parse_date_str(end_date, end_time);
8145 if (ret < 0)
8146 return -ret;
8147
8148 if (shard_id < 0) {
8149 shard_id = 0;
8150 }
8151
8152 formatter->open_array_section("entries");
8153
8154 for (; shard_id < ERROR_LOGGER_SHARDS; ++shard_id) {
8155 formatter->open_object_section("shard");
8156 encode_json("shard_id", shard_id, formatter);
8157 formatter->open_array_section("entries");
8158
8159 int count = 0;
8160 string oid = RGWSyncErrorLogger::get_shard_oid(RGW_SYNC_ERROR_LOG_SHARD_PREFIX, shard_id);
8161
8162 do {
8163 list<cls_log_entry> entries;
9f95a23c
TL
8164 ret = store->svc()->cls->timelog.list(oid, start_time.to_real_time(), end_time.to_real_time(),
8165 max_entries - count, entries, marker, &marker, &truncated,
8166 null_yield);
7c673cae
FG
8167 if (ret == -ENOENT) {
8168 break;
8169 }
8170 if (ret < 0) {
9f95a23c 8171 cerr << "ERROR: svc.cls->timelog.list(): " << cpp_strerror(-ret) << std::endl;
7c673cae
FG
8172 return -ret;
8173 }
8174
8175 count += entries.size();
8176
8177 for (auto& cls_entry : entries) {
8178 rgw_sync_error_info log_entry;
8179
11fdf7f2 8180 auto iter = cls_entry.data.cbegin();
7c673cae 8181 try {
11fdf7f2 8182 decode(log_entry, iter);
7c673cae
FG
8183 } catch (buffer::error& err) {
8184 cerr << "ERROR: failed to decode log entry" << std::endl;
8185 continue;
8186 }
8187 formatter->open_object_section("entry");
8188 encode_json("id", cls_entry.id, formatter);
8189 encode_json("section", cls_entry.section, formatter);
8190 encode_json("name", cls_entry.name, formatter);
8191 encode_json("timestamp", cls_entry.timestamp, formatter);
8192 encode_json("info", log_entry, formatter);
8193 formatter->close_section();
8194 formatter->flush(cout);
8195 }
8196 } while (truncated && count < max_entries);
8197
8198 formatter->close_section();
8199 formatter->close_section();
8200
8201 if (specified_shard_id) {
8202 break;
8203 }
8204 }
8205
8206 formatter->close_section();
8207 formatter->flush(cout);
8208 }
8209
9f95a23c 8210 if (opt_cmd == OPT::SYNC_ERROR_TRIM) {
94b18763
FG
8211 utime_t start_time, end_time;
8212 int ret = parse_date_str(start_date, start_time);
8213 if (ret < 0)
8214 return -ret;
8215
8216 ret = parse_date_str(end_date, end_time);
8217 if (ret < 0)
8218 return -ret;
8219
8220 if (shard_id < 0) {
8221 shard_id = 0;
8222 }
8223
8224 for (; shard_id < ERROR_LOGGER_SHARDS; ++shard_id) {
91327a77
AA
8225 ret = trim_sync_error_log(shard_id, start_time.to_real_time(),
8226 end_time.to_real_time(), start_marker,
8227 end_marker, trim_delay_ms);
8228 if (ret < 0) {
94b18763
FG
8229 cerr << "ERROR: sync error trim: " << cpp_strerror(-ret) << std::endl;
8230 return -ret;
8231 }
8232 if (specified_shard_id) {
8233 break;
8234 }
8235 }
8236 }
8237
9f95a23c
TL
8238 if (opt_cmd == OPT::SYNC_GROUP_CREATE ||
8239 opt_cmd == OPT::SYNC_GROUP_MODIFY) {
8240 CHECK_TRUE(require_opt(opt_group_id), "ERROR: --group-id not specified", EINVAL);
8241 CHECK_TRUE(require_opt(opt_status), "ERROR: --status is not specified (options: forbidden, allowed, enabled)", EINVAL);
8242
8243 SyncPolicyContext sync_policy_ctx(zonegroup_id, zonegroup_name, opt_bucket);
8244 ret = sync_policy_ctx.init();
8245 if (ret < 0) {
8246 return -ret;
8247 }
8248 auto& sync_policy = sync_policy_ctx.get_policy();
8249
8250 if (opt_cmd == OPT::SYNC_GROUP_MODIFY) {
8251 auto iter = sync_policy.groups.find(*opt_group_id);
8252 if (iter == sync_policy.groups.end()) {
8253 cerr << "ERROR: could not find group '" << *opt_group_id << "'" << std::endl;
8254 return ENOENT;
8255 }
8256 }
8257
8258 auto& group = sync_policy.groups[*opt_group_id];
8259 group.id = *opt_group_id;
8260
8261 if (opt_status) {
8262 if (!group.set_status(*opt_status)) {
8263 cerr << "ERROR: unrecognized status (options: forbidden, allowed, enabled)" << std::endl;
8264 return EINVAL;
8265 }
8266 }
8267
8268 ret = sync_policy_ctx.write_policy();
8269 if (ret < 0) {
8270 return -ret;
8271 }
8272
8273 show_result(sync_policy, zone_formatter, cout);
8274 }
8275
8276 if (opt_cmd == OPT::SYNC_GROUP_GET) {
8277 SyncPolicyContext sync_policy_ctx(zonegroup_id, zonegroup_name, opt_bucket);
8278 ret = sync_policy_ctx.init();
8279 if (ret < 0) {
8280 return -ret;
8281 }
8282 auto& sync_policy = sync_policy_ctx.get_policy();
8283
8284 auto& groups = sync_policy.groups;
8285
8286 if (!opt_group_id) {
8287 show_result(groups, zone_formatter, cout);
8288 } else {
8289 auto iter = sync_policy.groups.find(*opt_group_id);
8290 if (iter == sync_policy.groups.end()) {
8291 cerr << "ERROR: could not find group '" << *opt_group_id << "'" << std::endl;
8292 return ENOENT;
8293 }
8294
8295 show_result(iter->second, zone_formatter, cout);
8296 }
8297 }
8298
8299 if (opt_cmd == OPT::SYNC_GROUP_REMOVE) {
8300 CHECK_TRUE(require_opt(opt_group_id), "ERROR: --group-id not specified", EINVAL);
8301
8302 SyncPolicyContext sync_policy_ctx(zonegroup_id, zonegroup_name, opt_bucket);
8303 ret = sync_policy_ctx.init();
8304 if (ret < 0) {
8305 return -ret;
8306 }
8307 auto& sync_policy = sync_policy_ctx.get_policy();
8308
8309 sync_policy.groups.erase(*opt_group_id);
8310
8311 ret = sync_policy_ctx.write_policy();
8312 if (ret < 0) {
8313 return -ret;
8314 }
8315
8316 {
8317 Formatter::ObjectSection os(*zone_formatter, "result");
8318 encode_json("sync_policy", sync_policy, zone_formatter);
8319 }
8320
8321 zone_formatter->flush(cout);
8322 }
8323
8324 if (opt_cmd == OPT::SYNC_GROUP_FLOW_CREATE) {
8325 CHECK_TRUE(require_opt(opt_group_id), "ERROR: --group-id not specified", EINVAL);
8326 CHECK_TRUE(require_opt(opt_flow_id), "ERROR: --flow-id not specified", EINVAL);
8327 CHECK_TRUE(require_opt(opt_flow_type,
8328 (symmetrical_flow_opt(*opt_flow_type) ||
8329 directional_flow_opt(*opt_flow_type))),
8330 "ERROR: --flow-type not specified or invalid (options: symmetrical, directional)", EINVAL);
8331
8332 SyncPolicyContext sync_policy_ctx(zonegroup_id, zonegroup_name, opt_bucket);
8333 ret = sync_policy_ctx.init();
8334 if (ret < 0) {
8335 return -ret;
8336 }
8337 auto& sync_policy = sync_policy_ctx.get_policy();
8338
8339 auto iter = sync_policy.groups.find(*opt_group_id);
8340 if (iter == sync_policy.groups.end()) {
8341 cerr << "ERROR: could not find group '" << *opt_group_id << "'" << std::endl;
8342 return ENOENT;
8343 }
8344
8345 auto& group = iter->second;
8346
8347 if (symmetrical_flow_opt(*opt_flow_type)) {
8348 CHECK_TRUE(require_non_empty_opt(opt_zone_ids), "ERROR: --zones not provided for symmetrical flow, or is empty", EINVAL);
8349
8350 rgw_sync_symmetric_group *flow_group;
8351
8352 group.data_flow.find_or_create_symmetrical(*opt_flow_id, &flow_group);
8353
8354 for (auto& z : *opt_zone_ids) {
8355 flow_group->zones.insert(z);
8356 }
8357 } else { /* directional */
8358 CHECK_TRUE(require_non_empty_opt(opt_source_zone_id), "ERROR: --source-zone not provided for directional flow rule, or is empty", EINVAL);
8359 CHECK_TRUE(require_non_empty_opt(opt_dest_zone_id), "ERROR: --dest-zone not provided for directional flow rule, or is empty", EINVAL);
8360
8361 rgw_sync_directional_rule *flow_rule;
8362
8363 group.data_flow.find_or_create_directional(*opt_source_zone_id, *opt_dest_zone_id, &flow_rule);
8364 }
8365
8366 ret = sync_policy_ctx.write_policy();
8367 if (ret < 0) {
8368 return -ret;
8369 }
8370
8371 show_result(sync_policy, zone_formatter, cout);
8372 }
8373
8374 if (opt_cmd == OPT::SYNC_GROUP_FLOW_REMOVE) {
8375 CHECK_TRUE(require_opt(opt_group_id), "ERROR: --group-id not specified", EINVAL);
8376 CHECK_TRUE(require_opt(opt_flow_id), "ERROR: --flow-id not specified", EINVAL);
8377 CHECK_TRUE(require_opt(opt_flow_type,
8378 (symmetrical_flow_opt(*opt_flow_type) ||
8379 directional_flow_opt(*opt_flow_type))),
8380 "ERROR: --flow-type not specified or invalid (options: symmetrical, directional)", EINVAL);
8381
8382 SyncPolicyContext sync_policy_ctx(zonegroup_id, zonegroup_name, opt_bucket);
8383 ret = sync_policy_ctx.init();
8384 if (ret < 0) {
8385 return -ret;
8386 }
8387 auto& sync_policy = sync_policy_ctx.get_policy();
8388
8389 auto iter = sync_policy.groups.find(*opt_group_id);
8390 if (iter == sync_policy.groups.end()) {
8391 cerr << "ERROR: could not find group '" << *opt_group_id << "'" << std::endl;
8392 return ENOENT;
8393 }
8394
8395 auto& group = iter->second;
8396
8397 if (symmetrical_flow_opt(*opt_flow_type)) {
8398 group.data_flow.remove_symmetrical(*opt_flow_id, opt_zone_ids);
8399 } else { /* directional */
8400 CHECK_TRUE(require_non_empty_opt(opt_source_zone_id), "ERROR: --source-zone not provided for directional flow rule, or is empty", EINVAL);
8401 CHECK_TRUE(require_non_empty_opt(opt_dest_zone_id), "ERROR: --dest-zone not provided for directional flow rule, or is empty", EINVAL);
8402
8403 group.data_flow.remove_directional(*opt_source_zone_id, *opt_dest_zone_id);
8404 }
8405
8406 ret = sync_policy_ctx.write_policy();
8407 if (ret < 0) {
8408 return -ret;
8409 }
8410
8411 show_result(sync_policy, zone_formatter, cout);
8412 }
8413
8414 if (opt_cmd == OPT::SYNC_GROUP_PIPE_CREATE ||
8415 opt_cmd == OPT::SYNC_GROUP_PIPE_MODIFY) {
8416 CHECK_TRUE(require_opt(opt_group_id), "ERROR: --group-id not specified", EINVAL);
8417 CHECK_TRUE(require_opt(opt_pipe_id), "ERROR: --pipe-id not specified", EINVAL);
8418 if (opt_cmd == OPT::SYNC_GROUP_PIPE_CREATE) {
8419 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);
8420 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);
8421 }
8422
8423 SyncPolicyContext sync_policy_ctx(zonegroup_id, zonegroup_name, opt_bucket);
8424 ret = sync_policy_ctx.init();
8425 if (ret < 0) {
8426 return -ret;
8427 }
8428 auto& sync_policy = sync_policy_ctx.get_policy();
8429
8430 auto iter = sync_policy.groups.find(*opt_group_id);
8431 if (iter == sync_policy.groups.end()) {
8432 cerr << "ERROR: could not find group '" << *opt_group_id << "'" << std::endl;
8433 return ENOENT;
8434 }
8435
8436 auto& group = iter->second;
8437
8438 rgw_sync_bucket_pipes *pipe;
8439
8440 if (opt_cmd == OPT::SYNC_GROUP_PIPE_CREATE) {
8441 group.find_pipe(*opt_pipe_id, true, &pipe);
8442 } else {
8443 if (!group.find_pipe(*opt_pipe_id, false, &pipe)) {
8444 cerr << "ERROR: could not find pipe '" << *opt_pipe_id << "'" << std::endl;
8445 return ENOENT;
8446 }
8447 }
8448
8449 pipe->source.add_zones(*opt_source_zone_ids);
8450 pipe->source.set_bucket(opt_source_tenant,
8451 opt_source_bucket_name,
8452 opt_source_bucket_id);
8453 pipe->dest.add_zones(*opt_dest_zone_ids);
8454 pipe->dest.set_bucket(opt_dest_tenant,
8455 opt_dest_bucket_name,
8456 opt_dest_bucket_id);
8457
8458 pipe->params.source.filter.set_prefix(opt_prefix, !!opt_prefix_rm);
8459 pipe->params.source.filter.set_tags(tags_add, tags_rm);
8460 if (opt_dest_owner) {
8461 pipe->params.dest.set_owner(*opt_dest_owner);
8462 }
8463 if (opt_storage_class) {
8464 pipe->params.dest.set_storage_class(*opt_storage_class);
8465 }
8466 if (opt_priority) {
8467 pipe->params.priority = *opt_priority;
8468 }
8469 if (opt_mode) {
8470 if (*opt_mode == "system") {
8471 pipe->params.mode = rgw_sync_pipe_params::MODE_SYSTEM;
8472 } else if (*opt_mode == "user") {
8473 pipe->params.mode = rgw_sync_pipe_params::MODE_USER;
8474 } else {
8475 cerr << "ERROR: bad mode value: should be one of the following: system, user" << std::endl;
8476 return EINVAL;
8477 }
8478 }
8479
8480 if (!user_id.empty()) {
8481 pipe->params.user = user_id;
8482 } else if (pipe->params.user.empty()) {
8483 auto owner = sync_policy_ctx.get_owner();
8484 if (owner) {
8485 pipe->params.user = *owner;
8486 }
8487 }
8488
8489 ret = sync_policy_ctx.write_policy();
8490 if (ret < 0) {
8491 return -ret;
8492 }
8493
8494 show_result(sync_policy, zone_formatter, cout);
8495 }
8496
8497 if (opt_cmd == OPT::SYNC_GROUP_PIPE_REMOVE) {
8498 CHECK_TRUE(require_opt(opt_group_id), "ERROR: --group-id not specified", EINVAL);
8499 CHECK_TRUE(require_opt(opt_pipe_id), "ERROR: --pipe-id not specified", EINVAL);
8500
8501 SyncPolicyContext sync_policy_ctx(zonegroup_id, zonegroup_name, opt_bucket);
8502 ret = sync_policy_ctx.init();
8503 if (ret < 0) {
8504 return -ret;
8505 }
8506 auto& sync_policy = sync_policy_ctx.get_policy();
8507
8508 auto iter = sync_policy.groups.find(*opt_group_id);
8509 if (iter == sync_policy.groups.end()) {
8510 cerr << "ERROR: could not find group '" << *opt_group_id << "'" << std::endl;
8511 return ENOENT;
8512 }
8513
8514 auto& group = iter->second;
8515
8516 rgw_sync_bucket_pipes *pipe;
8517
8518 if (!group.find_pipe(*opt_pipe_id, false, &pipe)) {
8519 cerr << "ERROR: could not find pipe '" << *opt_pipe_id << "'" << std::endl;
8520 return ENOENT;
8521 }
8522
8523 if (opt_source_zone_ids) {
8524 pipe->source.remove_zones(*opt_source_zone_ids);
8525 }
8526
8527 pipe->source.remove_bucket(opt_source_tenant,
8528 opt_source_bucket_name,
8529 opt_source_bucket_id);
8530 if (opt_dest_zone_ids) {
8531 pipe->dest.remove_zones(*opt_dest_zone_ids);
8532 }
8533 pipe->dest.remove_bucket(opt_dest_tenant,
8534 opt_dest_bucket_name,
8535 opt_dest_bucket_id);
8536
8537 if (!(opt_source_zone_ids ||
8538 opt_source_tenant ||
8539 opt_source_bucket ||
8540 opt_source_bucket_id ||
8541 opt_dest_zone_ids ||
8542 opt_dest_tenant ||
8543 opt_dest_bucket ||
8544 opt_dest_bucket_id)) {
8545 group.remove_pipe(*opt_pipe_id);
8546 }
8547
8548 ret = sync_policy_ctx.write_policy();
8549 if (ret < 0) {
8550 return -ret;
8551 }
8552
8553 show_result(sync_policy, zone_formatter, cout);
8554 }
8555
8556 if (opt_cmd == OPT::SYNC_POLICY_GET) {
8557 SyncPolicyContext sync_policy_ctx(zonegroup_id, zonegroup_name, opt_bucket);
8558 ret = sync_policy_ctx.init();
8559 if (ret < 0) {
8560 return -ret;
8561 }
8562 auto& sync_policy = sync_policy_ctx.get_policy();
8563
8564 show_result(sync_policy, zone_formatter, cout);
8565 }
8566
8567 if (opt_cmd == OPT::BILOG_TRIM) {
7c673cae
FG
8568 if (bucket_name.empty()) {
8569 cerr << "ERROR: bucket not specified" << std::endl;
8570 return EINVAL;
8571 }
8572 RGWBucketInfo bucket_info;
8573 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
8574 if (ret < 0) {
8575 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
8576 return -ret;
8577 }
9f95a23c 8578 ret = store->svc()->bilog_rados->log_trim(bucket_info, shard_id, start_marker, end_marker);
7c673cae
FG
8579 if (ret < 0) {
8580 cerr << "ERROR: trim_bi_log_entries(): " << cpp_strerror(-ret) << std::endl;
8581 return -ret;
8582 }
8583 }
8584
9f95a23c 8585 if (opt_cmd == OPT::BILOG_STATUS) {
7c673cae
FG
8586 if (bucket_name.empty()) {
8587 cerr << "ERROR: bucket not specified" << std::endl;
8588 return EINVAL;
8589 }
8590 RGWBucketInfo bucket_info;
8591 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
8592 if (ret < 0) {
8593 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
8594 return -ret;
8595 }
8596 map<int, string> markers;
9f95a23c 8597 ret = store->svc()->bilog_rados->get_log_status(bucket_info, shard_id, &markers);
7c673cae 8598 if (ret < 0) {
31f18b77 8599 cerr << "ERROR: get_bi_log_status(): " << cpp_strerror(-ret) << std::endl;
7c673cae
FG
8600 return -ret;
8601 }
8602 formatter->open_object_section("entries");
8603 encode_json("markers", markers, formatter);
8604 formatter->close_section();
8605 formatter->flush(cout);
8606 }
8607
9f95a23c
TL
8608 if (opt_cmd == OPT::BILOG_AUTOTRIM) {
8609 RGWCoroutinesManager crs(store->ctx(), store->getRados()->get_cr_registry());
b32b8144 8610 RGWHTTPManager http(store->ctx(), crs.get_completion_mgr());
11fdf7f2 8611 int ret = http.start();
b32b8144
FG
8612 if (ret < 0) {
8613 cerr << "failed to initialize http client with " << cpp_strerror(ret) << std::endl;
8614 return -ret;
8615 }
8616
8617 rgw::BucketTrimConfig config;
8618 configure_bucket_trim(store->ctx(), config);
8619
8620 rgw::BucketTrimManager trim(store, config);
8621 ret = trim.init();
8622 if (ret < 0) {
8623 cerr << "trim manager init failed with " << cpp_strerror(ret) << std::endl;
8624 return -ret;
8625 }
8626 ret = crs.run(trim.create_admin_bucket_trim_cr(&http));
8627 if (ret < 0) {
8628 cerr << "automated bilog trim failed with " << cpp_strerror(ret) << std::endl;
8629 return -ret;
8630 }
8631 }
8632
9f95a23c 8633 if (opt_cmd == OPT::DATALOG_LIST) {
7c673cae
FG
8634 formatter->open_array_section("entries");
8635 bool truncated;
8636 int count = 0;
8637 if (max_entries < 0)
8638 max_entries = 1000;
8639
8640 utime_t start_time, end_time;
8641
8642 int ret = parse_date_str(start_date, start_time);
8643 if (ret < 0)
8644 return -ret;
8645
8646 ret = parse_date_str(end_date, end_time);
8647 if (ret < 0)
8648 return -ret;
8649
9f95a23c 8650 auto datalog_svc = store->svc()->datalog_rados;
11fdf7f2 8651 RGWDataChangesLog::LogMarker log_marker;
7c673cae
FG
8652
8653 do {
8654 list<rgw_data_change_log_entry> entries;
11fdf7f2 8655 if (specified_shard_id) {
e306af50 8656 ret = datalog_svc->list_entries(shard_id, start_time.to_real_time(), end_time.to_real_time(), max_entries - count, entries, marker, &marker, &truncated);
11fdf7f2 8657 } else {
9f95a23c 8658 ret = datalog_svc->list_entries(start_time.to_real_time(), end_time.to_real_time(), max_entries - count, entries, log_marker, &truncated);
11fdf7f2 8659 }
7c673cae
FG
8660 if (ret < 0) {
8661 cerr << "ERROR: list_bi_log_entries(): " << cpp_strerror(-ret) << std::endl;
8662 return -ret;
8663 }
8664
8665 count += entries.size();
8666
8667 for (list<rgw_data_change_log_entry>::iterator iter = entries.begin(); iter != entries.end(); ++iter) {
8668 rgw_data_change_log_entry& entry = *iter;
8669 if (!extra_info) {
8670 encode_json("entry", entry.entry, formatter);
8671 } else {
8672 encode_json("entry", entry, formatter);
8673 }
8674 }
8675 formatter->flush(cout);
8676 } while (truncated && count < max_entries);
8677
8678 formatter->close_section();
8679 formatter->flush(cout);
8680 }
8681
9f95a23c 8682 if (opt_cmd == OPT::DATALOG_STATUS) {
7c673cae
FG
8683 int i = (specified_shard_id ? shard_id : 0);
8684
8685 formatter->open_array_section("entries");
8686 for (; i < g_ceph_context->_conf->rgw_data_log_num_shards; i++) {
8687 list<cls_log_entry> entries;
8688
8689 RGWDataChangesLogInfo info;
9f95a23c 8690 store->svc()->datalog_rados->get_info(i, &info);
7c673cae
FG
8691
8692 ::encode_json("info", info, formatter);
8693
8694 if (specified_shard_id)
8695 break;
8696 }
8697
8698 formatter->close_section();
8699 formatter->flush(cout);
8700 }
8701
9f95a23c
TL
8702 if (opt_cmd == OPT::DATALOG_AUTOTRIM) {
8703 RGWCoroutinesManager crs(store->ctx(), store->getRados()->get_cr_registry());
a8e16298 8704 RGWHTTPManager http(store->ctx(), crs.get_completion_mgr());
11fdf7f2 8705 int ret = http.start();
a8e16298
TL
8706 if (ret < 0) {
8707 cerr << "failed to initialize http client with " << cpp_strerror(ret) << std::endl;
8708 return -ret;
8709 }
8710
11fdf7f2 8711 auto num_shards = g_conf()->rgw_data_log_num_shards;
a8e16298
TL
8712 std::vector<std::string> markers(num_shards);
8713 ret = crs.run(create_admin_data_log_trim_cr(store, &http, num_shards, markers));
8714 if (ret < 0) {
8715 cerr << "automated datalog trim failed with " << cpp_strerror(ret) << std::endl;
8716 return -ret;
8717 }
8718 }
8719
9f95a23c 8720 if (opt_cmd == OPT::DATALOG_TRIM) {
7c673cae
FG
8721 utime_t start_time, end_time;
8722
8723 int ret = parse_date_str(start_date, start_time);
8724 if (ret < 0)
8725 return -ret;
8726
8727 ret = parse_date_str(end_date, end_time);
8728 if (ret < 0)
8729 return -ret;
8730
eafe8130
TL
8731 if (!specified_shard_id) {
8732 cerr << "ERROR: requires a --shard-id" << std::endl;
8733 return EINVAL;
8734 }
8735
8736 // loop until -ENODATA
8737 do {
9f95a23c 8738 auto datalog = store->svc()->datalog_rados;
eafe8130
TL
8739 ret = datalog->trim_entries(shard_id, start_time.to_real_time(),
8740 end_time.to_real_time(),
8741 start_marker, end_marker);
8742 } while (ret == 0);
8743
8744 if (ret < 0 && ret != -ENODATA) {
7c673cae
FG
8745 cerr << "ERROR: trim_entries(): " << cpp_strerror(-ret) << std::endl;
8746 return -ret;
8747 }
8748 }
8749
9f95a23c 8750 bool quota_op = (opt_cmd == OPT::QUOTA_SET || opt_cmd == OPT::QUOTA_ENABLE || opt_cmd == OPT::QUOTA_DISABLE);
7c673cae 8751
11fdf7f2
TL
8752 if (quota_op) {
8753 if (bucket_name.empty() && user_id.empty()) {
8754 cerr << "ERROR: bucket name or uid is required for quota operation" << std::endl;
8755 return EINVAL;
8756 }
7c673cae 8757
11fdf7f2
TL
8758 if (!bucket_name.empty()) {
8759 if (!quota_scope.empty() && quota_scope != "bucket") {
8760 cerr << "ERROR: invalid quota scope specification." << std::endl;
8761 return EINVAL;
7c673cae 8762 }
11fdf7f2
TL
8763 set_bucket_quota(store, opt_cmd, tenant, bucket_name,
8764 max_size, max_objects, have_max_size, have_max_objects);
8765 } else if (!user_id.empty()) {
8766 if (quota_scope == "bucket") {
8767 return set_user_bucket_quota(opt_cmd, user, user_op, max_size, max_objects, have_max_size, have_max_objects);
8768 } else if (quota_scope == "user") {
8769 return set_user_quota(opt_cmd, user, user_op, max_size, max_objects, have_max_size, have_max_objects);
8770 } else {
8771 cerr << "ERROR: invalid quota scope specification. Please specify either --quota-scope=bucket, or --quota-scope=user" << std::endl;
8772 return EINVAL;
8773 }
8774 }
7c673cae
FG
8775 }
8776
9f95a23c 8777 if (opt_cmd == OPT::MFA_CREATE) {
11fdf7f2
TL
8778 rados::cls::otp::otp_info_t config;
8779
8780 if (user_id.empty()) {
8781 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
8782 return EINVAL;
8783 }
8784
8785 if (totp_serial.empty()) {
8786 cerr << "ERROR: TOTP device serial number was not provided (via --totp-serial)" << std::endl;
8787 return EINVAL;
8788 }
7c673cae 8789
11fdf7f2
TL
8790 if (totp_seed.empty()) {
8791 cerr << "ERROR: TOTP device seed was not provided (via --totp-seed)" << std::endl;
7c673cae
FG
8792 return EINVAL;
8793 }
11fdf7f2
TL
8794
8795
8796 rados::cls::otp::SeedType seed_type;
8797 if (totp_seed_type == "hex") {
8798 seed_type = rados::cls::otp::OTP_SEED_HEX;
8799 } else if (totp_seed_type == "base32") {
8800 seed_type = rados::cls::otp::OTP_SEED_BASE32;
8801 } else {
8802 cerr << "ERROR: invalid seed type: " << totp_seed_type << std::endl;
7c673cae
FG
8803 return EINVAL;
8804 }
11fdf7f2
TL
8805
8806 config.id = totp_serial;
8807 config.seed = totp_seed;
8808 config.seed_type = seed_type;
8809
8810 if (totp_seconds > 0) {
8811 config.step_size = totp_seconds;
8812 }
8813
8814 if (totp_window > 0) {
8815 config.window = totp_window;
8816 }
8817
8818 real_time mtime = real_clock::now();
9f95a23c
TL
8819 string oid = store->svc()->cls->mfa.get_mfa_oid(user_id);
8820
8821 int ret = store->ctl()->meta.mgr->mutate(RGWSI_MetaBackend_OTP::get_meta_key(user_id),
8822 mtime, &objv_tracker,
8823 null_yield,
8824 MDLOG_STATUS_WRITE,
8825 [&] {
8826 return store->svc()->cls->mfa.create_mfa(user_id, config, &objv_tracker, mtime, null_yield);
11fdf7f2 8827 });
7c673cae 8828 if (ret < 0) {
11fdf7f2 8829 cerr << "MFA creation failed, error: " << cpp_strerror(-ret) << std::endl;
7c673cae
FG
8830 return -ret;
8831 }
11fdf7f2
TL
8832
8833 RGWUserInfo& user_info = user_op.get_user_info();
8834 user_info.mfa_ids.insert(totp_serial);
8835 user_op.set_mfa_ids(user_info.mfa_ids);
8836 string err;
8837 ret = user.modify(user_op, &err);
8838 if (ret < 0) {
8839 cerr << "ERROR: failed storing user info, error: " << err << std::endl;
8840 return -ret;
8841 }
8842 }
7c673cae 8843
9f95a23c 8844 if (opt_cmd == OPT::MFA_REMOVE) {
11fdf7f2
TL
8845 if (user_id.empty()) {
8846 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
8847 return EINVAL;
8848 }
8849
8850 if (totp_serial.empty()) {
8851 cerr << "ERROR: TOTP device serial number was not provided (via --totp-serial)" << std::endl;
8852 return EINVAL;
8853 }
8854
8855 real_time mtime = real_clock::now();
11fdf7f2 8856
9f95a23c
TL
8857 int ret = store->ctl()->meta.mgr->mutate(RGWSI_MetaBackend_OTP::get_meta_key(user_id),
8858 mtime, &objv_tracker,
8859 null_yield,
8860 MDLOG_STATUS_WRITE,
8861 [&] {
8862 return store->svc()->cls->mfa.remove_mfa(user_id, totp_serial, &objv_tracker, mtime, null_yield);
11fdf7f2
TL
8863 });
8864 if (ret < 0) {
8865 cerr << "MFA removal failed, error: " << cpp_strerror(-ret) << std::endl;
8866 return -ret;
8867 }
8868
8869 RGWUserInfo& user_info = user_op.get_user_info();
8870 user_info.mfa_ids.erase(totp_serial);
8871 user_op.set_mfa_ids(user_info.mfa_ids);
8872 string err;
8873 ret = user.modify(user_op, &err);
8874 if (ret < 0) {
8875 cerr << "ERROR: failed storing user info, error: " << err << std::endl;
8876 return -ret;
8877 }
8878 }
8879
9f95a23c 8880 if (opt_cmd == OPT::MFA_GET) {
11fdf7f2
TL
8881 if (user_id.empty()) {
8882 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
8883 return EINVAL;
8884 }
8885
8886 if (totp_serial.empty()) {
8887 cerr << "ERROR: TOTP device serial number was not provided (via --totp-serial)" << std::endl;
8888 return EINVAL;
8889 }
8890
8891 rados::cls::otp::otp_info_t result;
9f95a23c 8892 int ret = store->svc()->cls->mfa.get_mfa(user_id, totp_serial, &result, null_yield);
11fdf7f2
TL
8893 if (ret < 0) {
8894 if (ret == -ENOENT || ret == -ENODATA) {
8895 cerr << "MFA serial id not found" << std::endl;
8896 } else {
8897 cerr << "MFA retrieval failed, error: " << cpp_strerror(-ret) << std::endl;
7c673cae 8898 }
11fdf7f2 8899 return -ret;
7c673cae 8900 }
11fdf7f2
TL
8901 formatter->open_object_section("result");
8902 encode_json("entry", result, formatter);
8903 formatter->close_section();
8904 formatter->flush(cout);
7c673cae 8905 }
7c673cae 8906
9f95a23c 8907 if (opt_cmd == OPT::MFA_LIST) {
11fdf7f2
TL
8908 if (user_id.empty()) {
8909 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
7c673cae
FG
8910 return EINVAL;
8911 }
11fdf7f2
TL
8912
8913 list<rados::cls::otp::otp_info_t> result;
9f95a23c 8914 int ret = store->svc()->cls->mfa.list_mfa(user_id, &result, null_yield);
7c673cae 8915 if (ret < 0) {
11fdf7f2 8916 cerr << "MFA listing failed, error: " << cpp_strerror(-ret) << std::endl;
7c673cae
FG
8917 return -ret;
8918 }
11fdf7f2
TL
8919 formatter->open_object_section("result");
8920 encode_json("entries", result, formatter);
8921 formatter->close_section();
8922 formatter->flush(cout);
7c673cae
FG
8923 }
8924
9f95a23c 8925 if (opt_cmd == OPT::MFA_CHECK) {
11fdf7f2
TL
8926 if (user_id.empty()) {
8927 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
8928 return EINVAL;
8929 }
8930
8931 if (totp_serial.empty()) {
8932 cerr << "ERROR: TOTP device serial number was not provided (via --totp-serial)" << std::endl;
8933 return EINVAL;
8934 }
8935
8936 if (totp_pin.empty()) {
8937 cerr << "ERROR: TOTP device serial number was not provided (via --totp-pin)" << std::endl;
7c673cae
FG
8938 return EINVAL;
8939 }
11fdf7f2
TL
8940
8941 list<rados::cls::otp::otp_info_t> result;
9f95a23c 8942 int ret = store->svc()->cls->mfa.check_mfa(user_id, totp_serial, totp_pin.front(), null_yield);
11fdf7f2
TL
8943 if (ret < 0) {
8944 cerr << "MFA check failed, error: " << cpp_strerror(-ret) << std::endl;
8945 return -ret;
8946 }
8947
8948 cout << "ok" << std::endl;
7c673cae
FG
8949 }
8950
9f95a23c 8951 if (opt_cmd == OPT::MFA_RESYNC) {
11fdf7f2
TL
8952 if (user_id.empty()) {
8953 cerr << "ERROR: user id was not provided (via --uid)" << std::endl;
8954 return EINVAL;
8955 }
7c673cae 8956
11fdf7f2
TL
8957 if (totp_serial.empty()) {
8958 cerr << "ERROR: TOTP device serial number was not provided (via --totp-serial)" << std::endl;
8959 return EINVAL;
8960 }
8961
8962 if (totp_pin.size() != 2) {
8963 cerr << "ERROR: missing two --totp-pin params (--totp-pin=<first> --totp-pin=<second>)" << std::endl;
8964 }
8965
8966 rados::cls::otp::otp_info_t config;
9f95a23c 8967 int ret = store->svc()->cls->mfa.get_mfa(user_id, totp_serial, &config, null_yield);
11fdf7f2
TL
8968 if (ret < 0) {
8969 if (ret == -ENOENT || ret == -ENODATA) {
8970 cerr << "MFA serial id not found" << std::endl;
8971 } else {
8972 cerr << "MFA retrieval failed, error: " << cpp_strerror(-ret) << std::endl;
7c673cae 8973 }
11fdf7f2
TL
8974 return -ret;
8975 }
8976
8977 ceph::real_time now;
8978
9f95a23c 8979 ret = store->svc()->cls->mfa.otp_get_current_time(user_id, &now, null_yield);
11fdf7f2
TL
8980 if (ret < 0) {
8981 cerr << "ERROR: failed to fetch current time from osd: " << cpp_strerror(-ret) << std::endl;
8982 return -ret;
8983 }
8984 time_t time_ofs;
8985
8986 ret = scan_totp(store->ctx(), now, config, totp_pin, &time_ofs);
8987 if (ret < 0) {
8988 if (ret == -ENOENT) {
8989 cerr << "failed to resync, TOTP values not found in range" << std::endl;
8990 } else {
8991 cerr << "ERROR: failed to scan for TOTP values: " << cpp_strerror(-ret) << std::endl;
7c673cae 8992 }
11fdf7f2
TL
8993 return -ret;
8994 }
8995
8996 config.time_ofs = time_ofs;
8997
8998 /* now update the backend */
8999 real_time mtime = real_clock::now();
11fdf7f2 9000
9f95a23c
TL
9001 ret = store->ctl()->meta.mgr->mutate(RGWSI_MetaBackend_OTP::get_meta_key(user_id),
9002 mtime, &objv_tracker,
9003 null_yield,
9004 MDLOG_STATUS_WRITE,
9005 [&] {
9006 return store->svc()->cls->mfa.create_mfa(user_id, config, &objv_tracker, mtime, null_yield);
11fdf7f2
TL
9007 });
9008 if (ret < 0) {
9009 cerr << "MFA update failed, error: " << cpp_strerror(-ret) << std::endl;
9010 return -ret;
9011 }
9012
9013 }
9014
9f95a23c
TL
9015 if (opt_cmd == OPT::RESHARD_STALE_INSTANCES_LIST) {
9016 if (!store->svc()->zone->can_reshard() && !yes_i_really_mean_it) {
11fdf7f2
TL
9017 cerr << "Resharding disabled in a multisite env, stale instances unlikely from resharding" << std::endl;
9018 cerr << "These instances may not be safe to delete." << std::endl;
9019 cerr << "Use --yes-i-really-mean-it to force displaying these instances." << std::endl;
9020 return EINVAL;
9021 }
9022
9023 ret = RGWBucketAdminOp::list_stale_instances(store, bucket_op,f);
9024 if (ret < 0) {
9025 cerr << "ERROR: listing stale instances" << cpp_strerror(-ret) << std::endl;
9026 }
9027 }
9028
9f95a23c
TL
9029 if (opt_cmd == OPT::RESHARD_STALE_INSTANCES_DELETE) {
9030 if (!store->svc()->zone->can_reshard()) {
11fdf7f2
TL
9031 cerr << "Resharding disabled in a multisite env. Stale instances are not safe to be deleted." << std::endl;
9032 return EINVAL;
9033 }
9034
9035 ret = RGWBucketAdminOp::clear_stale_instances(store, bucket_op,f);
9036 if (ret < 0) {
9037 cerr << "ERROR: deleting stale instances" << cpp_strerror(-ret) << std::endl;
9038 }
9039 }
9040
9f95a23c 9041 if (opt_cmd == OPT::PUBSUB_TOPICS_LIST) {
11fdf7f2
TL
9042 if (get_tier_type(store) != "pubsub") {
9043 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
9044 return EINVAL;
9045 }
11fdf7f2 9046
7f7e6c64 9047 RGWPubSub ps(store, tenant);
11fdf7f2
TL
9048
9049 rgw_bucket bucket;
9050
9051 if (!bucket_name.empty()) {
9052 rgw_pubsub_bucket_topics result;
7c673cae
FG
9053 RGWBucketInfo bucket_info;
9054 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
9055 if (ret < 0) {
9056 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
9057 return -ret;
9058 }
9059
7f7e6c64 9060 auto b = ps.get_bucket(bucket_info.bucket);
11fdf7f2
TL
9061 ret = b->get_topics(&result);
9062 if (ret < 0) {
9063 cerr << "ERROR: could not get topics: " << cpp_strerror(-ret) << std::endl;
7c673cae 9064 return -ret;
7c673cae 9065 }
11fdf7f2
TL
9066 encode_json("result", result, formatter);
9067 } else {
7f7e6c64
TL
9068 rgw_pubsub_topics result;
9069 int ret = ps.get_topics(&result);
7c673cae 9070 if (ret < 0) {
11fdf7f2 9071 cerr << "ERROR: could not get topics: " << cpp_strerror(-ret) << std::endl;
7c673cae
FG
9072 return -ret;
9073 }
11fdf7f2
TL
9074 encode_json("result", result, formatter);
9075 }
9076 formatter->flush(cout);
9077 }
7c673cae 9078
9f95a23c 9079 if (opt_cmd == OPT::PUBSUB_TOPIC_CREATE) {
11fdf7f2
TL
9080 if (get_tier_type(store) != "pubsub") {
9081 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
9082 return EINVAL;
9083 }
9084 if (topic_name.empty()) {
9085 cerr << "ERROR: topic name was not provided (via --topic)" << std::endl;
9086 return EINVAL;
9087 }
7f7e6c64 9088 RGWPubSub ps(store, tenant);
11fdf7f2 9089
7f7e6c64 9090 ret = ps.create_topic(topic_name);
11fdf7f2
TL
9091 if (ret < 0) {
9092 cerr << "ERROR: could not create topic: " << cpp_strerror(-ret) << std::endl;
9093 return -ret;
7c673cae
FG
9094 }
9095 }
9096
9f95a23c 9097 if (opt_cmd == OPT::PUBSUB_TOPIC_GET) {
11fdf7f2
TL
9098 if (get_tier_type(store) != "pubsub") {
9099 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
7c673cae
FG
9100 return EINVAL;
9101 }
11fdf7f2
TL
9102 if (topic_name.empty()) {
9103 cerr << "ERROR: topic name was not provided (via --topic)" << std::endl;
9104 return EINVAL;
9105 }
7f7e6c64
TL
9106
9107 RGWPubSub ps(store, tenant);
11fdf7f2
TL
9108
9109 rgw_pubsub_topic_subs topic;
7f7e6c64 9110 ret = ps.get_topic(topic_name, &topic);
7c673cae 9111 if (ret < 0) {
11fdf7f2
TL
9112 cerr << "ERROR: could not create topic: " << cpp_strerror(-ret) << std::endl;
9113 return -ret;
9114 }
9115 encode_json("topic", topic, formatter);
9116 formatter->flush(cout);
9117 }
9118
9f95a23c 9119 if (opt_cmd == OPT::PUBSUB_NOTIFICATION_CREATE) {
11fdf7f2
TL
9120 if (get_tier_type(store) != "pubsub") {
9121 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
7c673cae
FG
9122 return EINVAL;
9123 }
11fdf7f2
TL
9124 if (topic_name.empty()) {
9125 cerr << "ERROR: topic name was not provided (via --topic)" << std::endl;
9126 return EINVAL;
9127 }
11fdf7f2
TL
9128 if (bucket_name.empty()) {
9129 cerr << "ERROR: bucket name was not provided (via --bucket)" << std::endl;
9130 return EINVAL;
9131 }
7f7e6c64
TL
9132
9133 RGWPubSub ps(store, tenant);
7c673cae 9134
11fdf7f2 9135 rgw_bucket bucket;
7c673cae 9136
11fdf7f2
TL
9137 RGWBucketInfo bucket_info;
9138 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
9139 if (ret < 0) {
9140 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
9141 return -ret;
9142 }
9143
7f7e6c64 9144 auto b = ps.get_bucket(bucket_info.bucket);
11fdf7f2
TL
9145 ret = b->create_notification(topic_name, event_types);
9146 if (ret < 0) {
9147 cerr << "ERROR: could not publish bucket: " << cpp_strerror(-ret) << std::endl;
9148 return -ret;
7c673cae
FG
9149 }
9150 }
9151
9f95a23c 9152 if (opt_cmd == OPT::PUBSUB_NOTIFICATION_RM) {
11fdf7f2
TL
9153 if (get_tier_type(store) != "pubsub") {
9154 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
9155 return EINVAL;
9156 }
9157 if (topic_name.empty()) {
9158 cerr << "ERROR: topic name was not provided (via --topic)" << std::endl;
9159 return EINVAL;
9160 }
11fdf7f2
TL
9161 if (bucket_name.empty()) {
9162 cerr << "ERROR: bucket name was not provided (via --bucket)" << std::endl;
9163 return EINVAL;
9164 }
7f7e6c64 9165 RGWPubSub ups(store, tenant);
7c673cae 9166
11fdf7f2
TL
9167 rgw_bucket bucket;
9168
9169 RGWBucketInfo bucket_info;
9170 int ret = init_bucket(tenant, bucket_name, bucket_id, bucket_info, bucket);
9171 if (ret < 0) {
9172 cerr << "ERROR: could not init bucket: " << cpp_strerror(-ret) << std::endl;
9173 return -ret;
9174 }
9175
9176 auto b = ups.get_bucket(bucket_info.bucket);
9177 ret = b->remove_notification(topic_name);
9178 if (ret < 0) {
9179 cerr << "ERROR: could not publish bucket: " << cpp_strerror(-ret) << std::endl;
9180 return -ret;
9181 }
9182 }
9183
9f95a23c 9184 if (opt_cmd == OPT::PUBSUB_TOPIC_RM) {
11fdf7f2
TL
9185 if (get_tier_type(store) != "pubsub") {
9186 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
9187 return EINVAL;
9188 }
9189 if (topic_name.empty()) {
9190 cerr << "ERROR: topic name was not provided (via --topic)" << std::endl;
7c673cae
FG
9191 return EINVAL;
9192 }
9193
7f7e6c64
TL
9194 RGWPubSub ps(store, tenant);
9195
9196 ret = ps.remove_topic(topic_name);
11fdf7f2
TL
9197 if (ret < 0) {
9198 cerr << "ERROR: could not remove topic: " << cpp_strerror(-ret) << std::endl;
9199 return -ret;
7c673cae
FG
9200 }
9201 }
9202
9f95a23c 9203 if (opt_cmd == OPT::PUBSUB_SUB_GET) {
11fdf7f2
TL
9204 if (get_tier_type(store) != "pubsub") {
9205 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
9206 return EINVAL;
9207 }
11fdf7f2
TL
9208 if (sub_name.empty()) {
9209 cerr << "ERROR: subscription name was not provided (via --sub-name)" << std::endl;
9210 return EINVAL;
9211 }
7f7e6c64
TL
9212
9213 RGWPubSub ps(store, tenant);
f64942e4 9214
11fdf7f2
TL
9215 rgw_pubsub_sub_config sub_conf;
9216
7f7e6c64 9217 auto sub = ps.get_sub(sub_name);
11fdf7f2
TL
9218 ret = sub->get_conf(&sub_conf);
9219 if (ret < 0) {
9220 cerr << "ERROR: could not get subscription info: " << cpp_strerror(-ret) << std::endl;
9221 return -ret;
9222 }
9223 encode_json("sub", sub_conf, formatter);
9224 formatter->flush(cout);
9225 }
9226
9f95a23c 9227 if (opt_cmd == OPT::PUBSUB_SUB_CREATE) {
11fdf7f2
TL
9228 if (get_tier_type(store) != "pubsub") {
9229 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
9230 return EINVAL;
9231 }
11fdf7f2
TL
9232 if (sub_name.empty()) {
9233 cerr << "ERROR: subscription name was not provided (via --sub-name)" << std::endl;
9234 return EINVAL;
9235 }
9236 if (topic_name.empty()) {
9237 cerr << "ERROR: topic name was not provided (via --topic)" << std::endl;
9238 return EINVAL;
9239 }
7f7e6c64 9240 RGWPubSub ps(store, tenant);
11fdf7f2
TL
9241
9242 rgw_pubsub_topic_subs topic;
7f7e6c64 9243 int ret = ps.get_topic(topic_name, &topic);
11fdf7f2
TL
9244 if (ret < 0) {
9245 cerr << "ERROR: topic not found" << std::endl;
9246 return EINVAL;
9247 }
9248
9249 rgw_pubsub_sub_dest dest_config;
9250 dest_config.bucket_name = sub_dest_bucket;
9251 dest_config.oid_prefix = sub_oid_prefix;
9252 dest_config.push_endpoint = sub_push_endpoint;
9253
9f95a23c 9254 auto psmodule = static_cast<RGWPSSyncModuleInstance *>(store->getRados()->get_sync_module().get());
11fdf7f2
TL
9255 auto conf = psmodule->get_effective_conf();
9256
9257 if (dest_config.bucket_name.empty()) {
7f7e6c64 9258 dest_config.bucket_name = string(conf["data_bucket_prefix"]) + user_id.to_str() + "-" + topic.topic.name;
11fdf7f2
TL
9259 }
9260 if (dest_config.oid_prefix.empty()) {
9261 dest_config.oid_prefix = conf["data_oid_prefix"];
9262 }
7f7e6c64 9263 auto sub = ps.get_sub(sub_name);
11fdf7f2
TL
9264 ret = sub->subscribe(topic_name, dest_config);
9265 if (ret < 0) {
9266 cerr << "ERROR: could not store subscription info: " << cpp_strerror(-ret) << std::endl;
9267 return -ret;
9268 }
9269 }
9270
9f95a23c 9271 if (opt_cmd == OPT::PUBSUB_SUB_RM) {
11fdf7f2
TL
9272 if (get_tier_type(store) != "pubsub") {
9273 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
9274 return EINVAL;
9275 }
11fdf7f2
TL
9276 if (sub_name.empty()) {
9277 cerr << "ERROR: subscription name was not provided (via --sub-name)" << std::endl;
9278 return EINVAL;
9279 }
11fdf7f2 9280
7f7e6c64
TL
9281 RGWPubSub ps(store, tenant);
9282
9283 auto sub = ps.get_sub(sub_name);
11fdf7f2
TL
9284 ret = sub->unsubscribe(topic_name);
9285 if (ret < 0) {
9286 cerr << "ERROR: could not get subscription info: " << cpp_strerror(-ret) << std::endl;
9287 return -ret;
9288 }
9289 }
9290
9f95a23c 9291 if (opt_cmd == OPT::PUBSUB_SUB_PULL) {
11fdf7f2
TL
9292 if (get_tier_type(store) != "pubsub") {
9293 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
9294 return EINVAL;
9295 }
11fdf7f2
TL
9296 if (sub_name.empty()) {
9297 cerr << "ERROR: subscription name was not provided (via --sub-name)" << std::endl;
9298 return EINVAL;
9299 }
7f7e6c64
TL
9300
9301 RGWPubSub ps(store, tenant);
11fdf7f2 9302
11fdf7f2 9303 if (!max_entries_specified) {
7f7e6c64 9304 max_entries = RGWPubSub::Sub::DEFAULT_MAX_EVENTS;
11fdf7f2 9305 }
7f7e6c64 9306 auto sub = ps.get_sub_with_events(sub_name);
eafe8130 9307 ret = sub->list_events(marker, max_entries);
11fdf7f2
TL
9308 if (ret < 0) {
9309 cerr << "ERROR: could not list events: " << cpp_strerror(-ret) << std::endl;
9310 return -ret;
9311 }
eafe8130 9312 encode_json("result", *sub, formatter);
11fdf7f2 9313 formatter->flush(cout);
f64942e4
AA
9314 }
9315
9f95a23c 9316 if (opt_cmd == OPT::PUBSUB_EVENT_RM) {
11fdf7f2
TL
9317 if (get_tier_type(store) != "pubsub") {
9318 cerr << "ERROR: only pubsub tier type supports this command" << std::endl;
9319 return EINVAL;
9320 }
11fdf7f2
TL
9321 if (sub_name.empty()) {
9322 cerr << "ERROR: subscription name was not provided (via --sub-name)" << std::endl;
9323 return EINVAL;
9324 }
9325 if (event_id.empty()) {
9326 cerr << "ERROR: event id was not provided (via --event-id)" << std::endl;
9327 return EINVAL;
9328 }
11fdf7f2 9329
7f7e6c64
TL
9330 RGWPubSub ps(store, tenant);
9331
9332 auto sub = ps.get_sub_with_events(sub_name);
11fdf7f2
TL
9333 ret = sub->remove_event(event_id);
9334 if (ret < 0) {
9335 cerr << "ERROR: could not remove event: " << cpp_strerror(-ret) << std::endl;
9336 return -ret;
9337 }
9338 }
9339
9340 return 0;
7c673cae 9341}