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