radosgw-admin 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,3 +1,4 @@
1
+
1
2
  Apache License
2
3
  Version 2.0, January 2004
3
4
  http://www.apache.org/licenses/
@@ -32,9 +33,10 @@
32
33
  not limited to compiled object code, generated documentation,
33
34
  and conversions to other media types.
34
35
 
35
- "Work" shall mean the work of authorship made available under
36
- the License, as indicated by a copyright notice that is included in
37
- or attached to the work (an example is provided in the Appendix below).
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
38
40
 
39
41
  "Derivative Works" shall mean any work, whether in Source or Object
40
42
  form, that is based on (or derived from) the Work and for which the
@@ -44,21 +46,23 @@
44
46
  separable from, or merely link (or bind by name) to the interfaces of,
45
47
  the Work and Derivative Works thereof.
46
48
 
47
- "Contribution" shall mean, as submitted to the Licensor for inclusion
48
- in the Work by the copyright owner or by an individual or Legal Entity
49
- authorized to submit on behalf of the copyright owner. For the purposes
50
- of this definition, "submitted" means any form of electronic, verbal,
51
- or written communication sent to the Licensor or its representatives,
52
- including but not limited to communication on electronic mailing lists,
53
- source code control systems, and issue tracking systems that are managed
54
- by, or on behalf of, the Licensor for the purpose of discussing and
55
- improving the Work, but excluding communication that is conspicuously
56
- marked or designated in writing by the copyright owner as "Not a
57
- Contribution."
58
-
59
- "Contributor" shall mean Licensor and any Legal Entity on behalf of
60
- whom a Contribution has been received by the Licensor and included
61
- within the Work.
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
62
66
 
63
67
  2. Grant of Copyright License. Subject to the terms and conditions of
64
68
  this License, each Contributor hereby grants to You a perpetual,
@@ -72,21 +76,24 @@
72
76
  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
73
77
  (except as stated in this section) patent license to make, have made,
74
78
  use, offer to sell, sell, import, and otherwise transfer the Work,
75
- where such license applies only to those patent contributions
76
- Licensors made to the Work. If You institute patent litigation against
77
- any entity (including a cross-claim or counterclaim in a lawsuit)
78
- alleging that the Work or a Contribution incorporated within the Work
79
- constitutes direct or contributory patent infringement, then any patent
80
- licenses granted to You under this License for that Work shall
81
- terminate as of the date such litigation is filed.
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
82
89
 
83
90
  4. Redistribution. You may reproduce and distribute copies of the
84
91
  Work or Derivative Works thereof in any medium, with or without
85
92
  modifications, and in Source or Object form, provided that You
86
93
  meet the following conditions:
87
94
 
88
- (a) You must give any other recipients of the Work or Derivative
89
- Works a copy of this License; and
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
90
97
 
91
98
  (b) You must cause any modified files to carry prominent notices
92
99
  stating that You changed the files; and
@@ -98,26 +105,28 @@
98
105
  the Derivative Works; and
99
106
 
100
107
  (d) If the Work includes a "NOTICE" text file as part of its
101
- distribution, You must include a readable copy of the
102
- attribution notices contained within such NOTICE file, in
103
- at least one of the following places: within a NOTICE text
104
- file distributed as part of the Derivative Works; within
105
- the Source form or documentation, if provided along with the
106
- Derivative Works; or, within a display generated by the
107
- Derivative Works, if and wherever such third-party notices
108
- normally appear. The contents of the NOTICE file are for
109
- informational purposes only and do not modify the License.
110
- You may add Your own attribution notices within Derivative
111
- Works that You distribute, alongside or in addition to the
112
- NOTICE text from the Work, provided that such additional
113
- attribution notices cannot be construed as modifying the
114
- License.
115
-
116
- You may add Your own license statement for Your modifications and
117
- may provide additional grant of rights to use, copy, modify, merge,
118
- publish, distribute, sublicense, and/or sell copies of the
119
- Derivative Works, and to permit persons to whom the Derivative Works
120
- is furnished to do so, subject to Your own terms and conditions.
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
121
130
 
122
131
  5. Submission of Contributions. Unless You explicitly state otherwise,
123
132
  any Contribution intentionally submitted for inclusion in the Work
@@ -139,7 +148,7 @@
139
148
  implied, including, without limitation, any warranties or conditions
140
149
  of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
141
150
  PARTICULAR PURPOSE. You are solely responsible for determining the
142
- appropriateness of using or reproducing the Work and assume any
151
+ appropriateness of using or redistributing the Work and assume any
143
152
  risks associated with Your exercise of permissions under this License.
144
153
 
145
154
  8. Limitation of Liability. In no event and under no legal theory,
@@ -147,27 +156,38 @@
147
156
  unless required by applicable law (such as deliberate and grossly
148
157
  negligent acts) or agreed to in writing, shall any Contributor be
149
158
  liable to You for damages, including any direct, indirect, special,
150
- incidental, or exemplary damages of any character arising as a
159
+ incidental, or consequential damages of any character arising as a
151
160
  result of this License or out of the use or inability to use the
152
161
  Work (including but not limited to damages for loss of goodwill,
153
- work stoppage, computer failure or malfunction, or all other
154
- commercial damages or losses), even if such Contributor has been
155
- advised of the possibility of such damages.
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
156
165
 
157
166
  9. Accepting Warranty or Additional Liability. While redistributing
158
167
  the Work or Derivative Works thereof, You may choose to offer,
159
168
  and charge a fee for, acceptance of support, warranty, indemnity,
160
169
  or other liability obligations and/or rights consistent with this
161
- License. However, in accepting such obligations, You may offer such
162
- conditions only on Your own behalf and on Your sole responsibility,
163
- not on behalf of any other Contributor, and only if You agree to
164
- indemnify, defend, and hold each Contributor harmless for any
165
- liability incurred by, or claims asserted against, such Contributor
166
- by reason of your accepting any such warranty or additional liability.
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
167
176
 
168
177
  END OF TERMS AND CONDITIONS
169
178
 
170
- Copyright 2026 nycanshu <hkg43700@gmail.com>
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
171
191
 
172
192
  Licensed under the Apache License, Version 2.0 (the "License");
173
193
  you may not use this file except in compliance with the License.
package/README.md CHANGED
@@ -1,9 +1,11 @@
1
1
  # radosgw-admin
2
2
 
3
- > Modern, zero-dependency TypeScript client for the Ceph RADOS Gateway Admin Ops API.
3
+ > Node.js SDK for the Ceph RADOS Gateway Admin Ops API — manage users, buckets, quotas, rate limits and access keys programmatically.
4
4
 
5
5
  [![CI](https://github.com/nycanshu/radosgw-admin/actions/workflows/ci.yml/badge.svg)](https://github.com/nycanshu/radosgw-admin/actions/workflows/ci.yml)
6
+ [![codecov](https://codecov.io/gh/nycanshu/radosgw-admin/graph/badge.svg)](https://codecov.io/gh/nycanshu/radosgw-admin)
6
7
  [![npm version](https://img.shields.io/npm/v/radosgw-admin)](https://www.npmjs.com/package/radosgw-admin)
8
+ [![npm downloads](https://img.shields.io/npm/dm/radosgw-admin)](https://www.npmjs.com/package/radosgw-admin)
7
9
  [![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)
8
10
  [![TypeScript](https://img.shields.io/badge/TypeScript-strict-blue)](https://www.typescriptlang.org/)
9
11
 
@@ -15,17 +17,25 @@ The only existing npm package for RGW Admin Ops (`rgw-admin-client`) was last pu
15
17
 
16
18
  **What you get:**
17
19
 
18
- - [RGW Admin Ops API](https://docs.ceph.com/en/latest/radosgw/adminops/) coverage — users, keys, subusers, buckets, quotas, rate limits
19
- - Strict TypeScript with zero `any` — every request and response is fully typed
20
+ - Full [RGW Admin Ops API](https://docs.ceph.com/en/latest/radosgw/adminops/) coverage — users, keys, subusers, buckets, quotas, rate limits
20
21
  - Zero runtime dependencies — AWS SigV4 signing uses only `node:crypto`
21
- - Dual ESM + CJS build works in every Node.js environment
22
- - Automatic snake_case/camelCase conversion idiomatic JS API over RGW's REST interface
22
+ - Request hooks add logging, Prometheus metrics, or audit trails via `onBeforeRequest`/`onAfterResponse`
23
+ - Health check`rgw.healthCheck()` for one-liner connectivity verification
23
24
  - Structured error hierarchy — catch specific failures, not generic HTTP errors
25
+ - Automatic snake_case/camelCase conversion — idiomatic JS API over RGW's REST interface
26
+ - TypeScript with strict types and zero `any` — every request and response is fully typed
27
+ - Dual ESM + CJS build — works in every Node.js environment
24
28
 
25
29
  ## Install
26
30
 
27
31
  ```bash
28
32
  npm install radosgw-admin
33
+ # or
34
+ yarn add radosgw-admin
35
+ # or
36
+ pnpm add radosgw-admin
37
+ # or
38
+ bun add radosgw-admin
29
39
  ```
30
40
 
31
41
  Requires **Node.js >= 18** and a Ceph RGW instance with the Admin Ops API enabled.
@@ -78,7 +88,10 @@ const rgw = new RadosGWAdminClient({
78
88
  insecure: false, // Optional — skip TLS verification (default: false)
79
89
  debug: false, // Optional — enable request/response logging (default: false)
80
90
  maxRetries: 3, // Optional — retry transient errors (default: 0)
81
- retryDelay: 200, // Optional — base delay for exponential backoff in ms (default: 200)
91
+ retryDelay: 200, // Optional — base delay for exponential backoff w/ jitter in ms (default: 200)
92
+ userAgent: 'my-app/1.0', // Optional — custom User-Agent (default: "radosgw-admin/<ver> node/<ver>")
93
+ onBeforeRequest: [(ctx) => {}], // Optional — hooks called before each request
94
+ onAfterResponse: [(ctx) => {}], // Optional — hooks called after each response
82
95
  });
83
96
  ```
84
97
 
@@ -369,16 +382,67 @@ try {
369
382
  }
370
383
  ```
371
384
 
372
- | Error Class | HTTP Status | Condition |
373
- | -------------------- | --------------- | ---------------------------------------- |
374
- | `RGWValidationError` | _(pre-request)_ | Invalid input (missing uid, bad params) |
375
- | `RGWNotFoundError` | 404 | Resource does not exist |
376
- | `RGWConflictError` | 409 | Resource already exists |
377
- | `RGWAuthError` | 403 | Insufficient credentials or capabilities |
378
- | `RGWError` | 5xx | Server-side failure |
385
+ | Error Class | HTTP Status | Retryable | Condition |
386
+ | -------------------- | --------------- | --------- | ---------------------------------------- |
387
+ | `RGWValidationError` | 400 / _(pre-request)_ | No | Invalid input (missing uid, bad params) |
388
+ | `RGWNotFoundError` | 404 | No | Resource does not exist |
389
+ | `RGWConflictError` | 409 | No | Resource already exists |
390
+ | `RGWAuthError` | 403 | No | Insufficient credentials or capabilities |
391
+ | `RGWRateLimitError` | 429 | Yes | Rate limit exceeded |
392
+ | `RGWServiceError` | 5xx | Yes | RGW server error |
393
+
394
+ All errors include a `code` field with the RGW error code (e.g., `NoSuchUser`, `BucketAlreadyExists`, `SlowDown`).
379
395
 
380
396
  > **Note:** Destructive operations (`purgeData`, `purgeObjects`) emit a `console.warn` before executing. To suppress in CI/automation, redirect stderr or patch `console.warn`.
381
397
 
398
+ ## Health Check
399
+
400
+ Verify RGW connectivity before running operations:
401
+
402
+ ```typescript
403
+ const ok = await rgw.healthCheck();
404
+ if (!ok) throw new Error('Cannot reach RGW');
405
+ ```
406
+
407
+ ## Request Hooks
408
+
409
+ Add logging, metrics, or telemetry without modifying the SDK:
410
+
411
+ ```typescript
412
+ const rgw = new RadosGWAdminClient({
413
+ host: 'http://rgw:8080',
414
+ accessKey: '...',
415
+ secretKey: '...',
416
+ onBeforeRequest: [
417
+ (ctx) => console.log(`→ ${ctx.method} ${ctx.path}`),
418
+ ],
419
+ onAfterResponse: [
420
+ (ctx) => console.log(`← ${ctx.status} in ${ctx.durationMs}ms`),
421
+ ],
422
+ });
423
+ ```
424
+
425
+ Hooks run on **every request across all modules**. If a hook throws, the error is swallowed — hooks never break RGW operations.
426
+
427
+ Hook context includes: `method`, `path`, `url`, `query`, `attempt` (retry number), `startTime`, and for after-hooks: `status`, `durationMs`, `error`.
428
+
429
+ > **Security note:** Hook context includes the full request URL which may contain sensitive query parameters (e.g. `secret-key` when creating users with pre-specified credentials). If you log or send hook data to external systems, redact sensitive fields. The SDK already redacts `secret-key` from its own debug logs, but hooks receive the raw URL.
430
+
431
+ ## Request Cancellation
432
+
433
+ Pass an `AbortSignal` to cancel in-flight requests:
434
+
435
+ ```typescript
436
+ const controller = new AbortController();
437
+ setTimeout(() => controller.abort(), 5000);
438
+
439
+ await rgw._client.request({
440
+ method: 'GET',
441
+ path: '/user',
442
+ signal: controller.signal,
443
+ });
444
+ ```
445
+
382
446
  ## Compatibility
383
447
 
384
448
  Tested against Ceph **Quincy (v17)** and **Reef (v18)**. The Admin Ops API is available in all Ceph releases with RGW.
@@ -389,6 +453,102 @@ Tested against Ceph **Quincy (v17)** and **Reef (v18)**. The Admin Ops API is av
389
453
  - Admin Ops API must be accessible (default path: `/admin`)
390
454
  - For `insecure: true` — only use with self-signed certificates in dev/test environments
391
455
 
456
+ ## FAQ
457
+
458
+ <details>
459
+ <summary><strong>How do I connect to an RGW with a self-signed certificate?</strong></summary>
460
+
461
+ Set `insecure: true` in the client config. This skips TLS certificate verification — use only in dev/test environments:
462
+
463
+ ```typescript
464
+ const rgw = new RadosGWAdminClient({
465
+ host: 'https://rgw.internal',
466
+ accessKey: '...',
467
+ secretKey: '...',
468
+ insecure: true, // skips TLS verification
469
+ });
470
+ ```
471
+
472
+ </details>
473
+
474
+ <details>
475
+ <summary><strong>Which Ceph versions are supported?</strong></summary>
476
+
477
+ The Admin Ops API has been available since Ceph **Luminous (v12)**. This package is tested against **Quincy (v17)** and **Reef (v18)**.
478
+
479
+ | Feature | Minimum Ceph Version |
480
+ |---|---|
481
+ | Users, keys, subusers, buckets | Luminous (v12) |
482
+ | Quotas | Luminous (v12) |
483
+ | Rate limits | Pacific (v16) |
484
+ | Usage logging | Luminous (v12) |
485
+
486
+ </details>
487
+
488
+ <details>
489
+ <summary><strong>How do I troubleshoot connection issues?</strong></summary>
490
+
491
+ Enable debug mode to see full HTTP request/response details:
492
+
493
+ ```typescript
494
+ const rgw = new RadosGWAdminClient({
495
+ host: 'http://rgw.example.com',
496
+ accessKey: '...',
497
+ secretKey: '...',
498
+ debug: true, // logs request method, URL, headers, and response
499
+ });
500
+ ```
501
+
502
+ Common issues:
503
+ - **403 AccessDenied** — admin user lacks required capabilities. Grant with: `radosgw-admin caps add --uid=admin --caps="users=*;buckets=*"`
504
+ - **Connection refused** — check host/port and that the RGW daemon is running
505
+ - **Timeout** — increase the `timeout` value (default: 10000ms) or check network connectivity
506
+
507
+ </details>
508
+
509
+ <details>
510
+ <summary><strong>Can I use this with Rook-Ceph on Kubernetes?</strong></summary>
511
+
512
+ Yes. Port-forward or expose the RGW service, then point the client at it:
513
+
514
+ ```bash
515
+ kubectl port-forward svc/rook-ceph-rgw-my-store 8080:80 -n rook-ceph
516
+ ```
517
+
518
+ ```typescript
519
+ const rgw = new RadosGWAdminClient({
520
+ host: 'http://localhost',
521
+ port: 8080,
522
+ accessKey: '...',
523
+ secretKey: '...',
524
+ });
525
+ ```
526
+
527
+ To get admin credentials from Rook:
528
+ ```bash
529
+ kubectl get secret rook-ceph-dashboard-admin-gateway -n rook-ceph -o jsonpath='{.data.accessKey}' | base64 -d
530
+ kubectl get secret rook-ceph-dashboard-admin-gateway -n rook-ceph -o jsonpath='{.data.secretKey}' | base64 -d
531
+ ```
532
+
533
+ </details>
534
+
535
+ <details>
536
+ <summary><strong>Does this package work with OpenShift Data Foundation (ODF)?</strong></summary>
537
+
538
+ Yes. ODF uses Ceph under the hood. Point the client at the RGW route or service endpoint. The admin credentials are stored in the `ocs-storagecluster-ceph-rgw-admin-ops-user` secret in the `openshift-storage` namespace.
539
+
540
+ </details>
541
+
542
+ <details>
543
+ <summary><strong>Why zero dependencies?</strong></summary>
544
+
545
+ AWS SigV4 signing is implemented using only `node:crypto` (built-in). No `aws-sdk`, no `axios`, no `node-fetch`. This means:
546
+ - Smaller `node_modules` footprint
547
+ - No supply chain risk from transitive dependencies
548
+ - No version conflicts with other packages in your project
549
+
550
+ </details>
551
+
392
552
  ## Development
393
553
 
394
554
  ```bash