@lossless.org/objectstorage 10.7.1 → 11.1.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/.smartconfig.json +30 -10
- package/dist_rust/ruststorage_linux_amd64 +0 -0
- package/dist_rust/ruststorage_linux_amd64.tsrust-build.json +5 -5
- package/dist_rust/ruststorage_linux_amd64_musl +0 -0
- package/dist_rust/ruststorage_linux_amd64_musl.tsrust-build.json +5 -5
- package/dist_rust/ruststorage_linux_arm64 +0 -0
- package/dist_rust/ruststorage_linux_arm64.tsrust-build.json +5 -5
- package/dist_rust/ruststorage_linux_arm64_musl +0 -0
- package/dist_rust/ruststorage_linux_arm64_musl.tsrust-build.json +5 -5
- package/dist_rust/ruststorage_macos_amd64 +0 -0
- package/dist_rust/ruststorage_macos_amd64.tsrust-build.json +5 -5
- package/dist_rust/ruststorage_macos_arm64 +0 -0
- package/dist_rust/ruststorage_macos_arm64.tsrust-build.json +5 -5
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes.dashboard.d.ts +49 -0
- package/dist_ts/classes.dashboard.js +234 -0
- package/dist_ts/dashboard.bundled.d.ts +4 -0
- package/dist_ts/dashboard.bundled.js +20 -0
- package/dist_ts/dashboard.interfaces.d.ts +132 -0
- package/dist_ts/dashboard.interfaces.js +2 -0
- package/dist_ts/dashboard.plugins.d.ts +5 -0
- package/dist_ts/dashboard.plugins.js +10 -0
- package/dist_ts/index.d.ts +219 -1
- package/dist_ts/index.js +209 -8
- package/package.json +17 -16
- package/readme.md +711 -30
- package/third-party-notices.md +21 -5
- package/third_party_licenses/borsh-1.8.1-license.txt +23 -0
- package/third_party_licenses/borsh-derive-1.8.1-apache-2.0.txt +201 -0
- package/third_party_licenses/cargo-dependencies.html +420 -0
- package/third_party_licenses/dyn-clone-1.0.20-license.txt +23 -0
- package/third_party_licenses/equivalent-1.0.3-license.txt +25 -0
- package/third_party_licenses/hashbrown-0.17.1-license.txt +25 -0
- package/third_party_licenses/indexmap-2.14.2-license.txt +25 -0
- package/third_party_licenses/inventory.json +310 -8
- package/third_party_licenses/proc-macro-crate-3.5.0-license.txt +23 -0
- package/third_party_licenses/ref-cast-1.0.27-license.txt +23 -0
- package/third_party_licenses/ref-cast-impl-1.0.27-license.txt +23 -0
- package/third_party_licenses/schemars-1.2.3-license.txt +21 -0
- package/third_party_licenses/syn-3.0.9-license.txt +23 -0
- package/third_party_licenses/toml_datetime-1.1.2-license.txt +19 -0
- package/third_party_licenses/toml_edit-0.25.17-license.txt +19 -0
- package/third_party_licenses/toml_parser-1.1.5-license.txt +19 -0
- package/third_party_licenses/winnow-1.0.4-license.txt +18 -0
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.dashboard.ts +280 -0
- package/ts/dashboard.bundled.ts.third-party-notices.json +1741 -0
- package/ts/dashboard.bundled.ts.third-party-notices.txt +5015 -0
- package/ts/dashboard.interfaces.ts +148 -0
- package/ts/dashboard.plugins.ts +13 -0
- package/ts/index.ts +473 -14
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import type { ITypedRequest, implementsTR } from '@api.global/typedrequest-interfaces';
|
|
2
|
+
import type { ITypedSocketEvent } from '@api.global/typedsocket';
|
|
3
|
+
/**
|
|
4
|
+
* Engine snapshot shapes, as `ObjectStorage.getClusterSnapshot()` returns
|
|
5
|
+
* them. The engine builds them from memory only: the drive states the last
|
|
6
|
+
* heartbeat probe left, runtime stats, healing state, S3 listener counters
|
|
7
|
+
* and a bounded ring of recent events. Times are milliseconds since the Unix
|
|
8
|
+
* epoch; absent values are `null`.
|
|
9
|
+
*/
|
|
10
|
+
export interface IObjectStorageTelemetryEvent {
|
|
11
|
+
/** Numbered per node from 1; a gap means older events left the ring. */
|
|
12
|
+
seq: number;
|
|
13
|
+
at: number;
|
|
14
|
+
kind: 'engine' | 'peer' | 'drive' | 'healing';
|
|
15
|
+
severity: 'info' | 'warning' | 'error';
|
|
16
|
+
message: string;
|
|
17
|
+
}
|
|
18
|
+
/** S3 listener counters since the engine started; bytes include HTTP headers. */
|
|
19
|
+
export interface IObjectStorageTrafficCounters {
|
|
20
|
+
requestsTotal: number;
|
|
21
|
+
errorResponses: number;
|
|
22
|
+
bytesIn: number;
|
|
23
|
+
bytesOut: number;
|
|
24
|
+
}
|
|
25
|
+
export interface IObjectStorageStorageTotals {
|
|
26
|
+
bucketCount: number;
|
|
27
|
+
objectCount: number;
|
|
28
|
+
totalBytes: number;
|
|
29
|
+
}
|
|
30
|
+
export interface IObjectStorageDriveSnapshot {
|
|
31
|
+
index: number;
|
|
32
|
+
path: string;
|
|
33
|
+
status: 'online' | 'degraded' | 'offline' | 'healing';
|
|
34
|
+
totalBytes: number;
|
|
35
|
+
usedBytes: number;
|
|
36
|
+
availableBytes: number;
|
|
37
|
+
errorCount: number;
|
|
38
|
+
lastError: string | null;
|
|
39
|
+
lastCheck: number | null;
|
|
40
|
+
erasureSetId: number | null;
|
|
41
|
+
}
|
|
42
|
+
export interface IObjectStorageHealingSnapshot {
|
|
43
|
+
active: boolean;
|
|
44
|
+
scanIntervalMs: number;
|
|
45
|
+
lastRunStartedAt: number | null;
|
|
46
|
+
lastRunCompletedAt: number | null;
|
|
47
|
+
lastDurationMs: number | null;
|
|
48
|
+
shardsChecked: number | null;
|
|
49
|
+
shardsHealed: number | null;
|
|
50
|
+
shardsPending: number | null;
|
|
51
|
+
failed: number | null;
|
|
52
|
+
lastError: string | null;
|
|
53
|
+
}
|
|
54
|
+
/** What one node reports about itself; local and remote nodes share this shape. */
|
|
55
|
+
export interface IObjectStorageNodeSnapshot {
|
|
56
|
+
/** Absent in standalone mode. */
|
|
57
|
+
nodeId: string | null;
|
|
58
|
+
mode: 'standalone' | 'cluster';
|
|
59
|
+
startedAt: number;
|
|
60
|
+
capturedAt: number;
|
|
61
|
+
traffic: IObjectStorageTrafficCounters;
|
|
62
|
+
storage: IObjectStorageStorageTotals;
|
|
63
|
+
/** Local drives (cluster mode); empty in standalone mode. */
|
|
64
|
+
drives: IObjectStorageDriveSnapshot[];
|
|
65
|
+
healing: IObjectStorageHealingSnapshot | null;
|
|
66
|
+
/** Recent events, oldest first. */
|
|
67
|
+
events: IObjectStorageTelemetryEvent[];
|
|
68
|
+
}
|
|
69
|
+
export interface IObjectStoragePeerSnapshot {
|
|
70
|
+
nodeId: string;
|
|
71
|
+
status: 'online' | 'suspect' | 'offline';
|
|
72
|
+
quicAddress: string;
|
|
73
|
+
s3Address: string;
|
|
74
|
+
driveCount: number;
|
|
75
|
+
lastHeartbeat: number;
|
|
76
|
+
missedHeartbeats: number;
|
|
77
|
+
/** The peer's own snapshot, when it answered within a second. */
|
|
78
|
+
snapshot: IObjectStorageNodeSnapshot | null;
|
|
79
|
+
unavailableReason: string | null;
|
|
80
|
+
}
|
|
81
|
+
export interface IObjectStorageErasureSnapshot {
|
|
82
|
+
dataShards: number;
|
|
83
|
+
parityShards: number;
|
|
84
|
+
chunkSizeBytes: number;
|
|
85
|
+
totalShards: number;
|
|
86
|
+
readQuorum: number;
|
|
87
|
+
writeQuorum: number;
|
|
88
|
+
erasureSetCount: number;
|
|
89
|
+
}
|
|
90
|
+
export interface IObjectStorageClusterViewSnapshot {
|
|
91
|
+
nodeId: string;
|
|
92
|
+
quorumHealthy: boolean;
|
|
93
|
+
majorityHealthy: boolean;
|
|
94
|
+
erasure: IObjectStorageErasureSnapshot;
|
|
95
|
+
peers: IObjectStoragePeerSnapshot[];
|
|
96
|
+
}
|
|
97
|
+
export interface IObjectStorageClusterSnapshot {
|
|
98
|
+
capturedAt: number;
|
|
99
|
+
clusterEnabled: boolean;
|
|
100
|
+
local: IObjectStorageNodeSnapshot;
|
|
101
|
+
/** Absent in standalone mode. */
|
|
102
|
+
cluster: IObjectStorageClusterViewSnapshot | null;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Dashboard configuration. The dashboard is off unless `enabled` is true.
|
|
106
|
+
*/
|
|
107
|
+
export interface IObjectStorageDashboardConfig {
|
|
108
|
+
enabled: boolean;
|
|
109
|
+
/** Interface the dashboard listens on. Default `127.0.0.1`. */
|
|
110
|
+
address?: string;
|
|
111
|
+
/** TCP port; `0` asks the OS for one. Default 3001; must differ from the S3 port. */
|
|
112
|
+
port?: number;
|
|
113
|
+
}
|
|
114
|
+
/** One dashboard sample, as pushed to every connected dashboard. */
|
|
115
|
+
export interface IObjectStorageDashboardSample {
|
|
116
|
+
sampledAt: number;
|
|
117
|
+
/** The snapshot, or `null` when the engine could not answer. */
|
|
118
|
+
snapshot: IObjectStorageClusterSnapshot | null;
|
|
119
|
+
error: string | null;
|
|
120
|
+
/** Events were left out of peer snapshots to keep the sample within the push limit. */
|
|
121
|
+
eventsTruncated: boolean;
|
|
122
|
+
}
|
|
123
|
+
/** Answers with the latest sample, taking one when none exists yet. */
|
|
124
|
+
export interface IReq_ObjectStorageDashboardGetSample extends implementsTR<ITypedRequest, IReq_ObjectStorageDashboardGetSample> {
|
|
125
|
+
method: 'objectStorageDashboardGetSample';
|
|
126
|
+
request: Record<string, never>;
|
|
127
|
+
response: IObjectStorageDashboardSample;
|
|
128
|
+
}
|
|
129
|
+
/** Pushed every two seconds while at least one dashboard is connected. */
|
|
130
|
+
export interface IEvent_ObjectStorageDashboardSample extends ITypedSocketEvent<IObjectStorageDashboardSample> {
|
|
131
|
+
name: 'objectStorageDashboardSample';
|
|
132
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Loaded only by the dashboard module, which `ObjectStorage` imports
|
|
2
|
+
// dynamically when the dashboard is enabled.
|
|
3
|
+
// @api.global scope
|
|
4
|
+
import * as typedrequest from '@api.global/typedrequest';
|
|
5
|
+
import * as typedsocket from '@api.global/typedsocket';
|
|
6
|
+
export { typedrequest, typedsocket };
|
|
7
|
+
// @push.rocks scope
|
|
8
|
+
import * as smartserve from '@push.rocks/smartserve';
|
|
9
|
+
export { smartserve };
|
|
10
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGFzaGJvYXJkLnBsdWdpbnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9kYXNoYm9hcmQucGx1Z2lucy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxxRUFBcUU7QUFDckUsNkNBQTZDO0FBRTdDLG9CQUFvQjtBQUNwQixPQUFPLEtBQUssWUFBWSxNQUFNLDBCQUEwQixDQUFDO0FBQ3pELE9BQU8sS0FBSyxXQUFXLE1BQU0seUJBQXlCLENBQUM7QUFFdkQsT0FBTyxFQUFFLFlBQVksRUFBRSxXQUFXLEVBQUUsQ0FBQztBQUVyQyxvQkFBb0I7QUFDcEIsT0FBTyxLQUFLLFVBQVUsTUFBTSx3QkFBd0IsQ0FBQztBQUVyRCxPQUFPLEVBQUUsVUFBVSxFQUFFLENBQUMifQ==
|
package/dist_ts/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import * as plugins from './plugins.js';
|
|
2
|
+
import type { IObjectStorageClusterSnapshot, IObjectStorageDashboardConfig } from './dashboard.interfaces.js';
|
|
3
|
+
export * from './dashboard.interfaces.js';
|
|
2
4
|
/**
|
|
3
5
|
* Authentication configuration
|
|
4
6
|
*/
|
|
@@ -54,6 +56,11 @@ export interface ILimitsConfig {
|
|
|
54
56
|
export interface IMultipartConfig {
|
|
55
57
|
expirationDays?: number;
|
|
56
58
|
cleanupIntervalMinutes?: number;
|
|
59
|
+
/**
|
|
60
|
+
* Open multipart uploads that the prefix credentials of one scope (bucket
|
|
61
|
+
* and prefix) may hold together (default 100). Counted in memory.
|
|
62
|
+
*/
|
|
63
|
+
maxUploadsPerPrefixScope?: number;
|
|
57
64
|
}
|
|
58
65
|
/**
|
|
59
66
|
* Server configuration
|
|
@@ -100,6 +107,11 @@ export interface IStorageConfig {
|
|
|
100
107
|
export interface IErasureConfig {
|
|
101
108
|
dataShards?: number;
|
|
102
109
|
parityShards?: number;
|
|
110
|
+
/**
|
|
111
|
+
* Bytes per erasure-coded chunk, between 1 and 64 MiB (67,108,864 bytes);
|
|
112
|
+
* startup refuses a value outside that range, because every manifest
|
|
113
|
+
* refuses a larger chunk. Default 4,194,304 (4 MiB).
|
|
114
|
+
*/
|
|
103
115
|
chunkSizeBytes?: number;
|
|
104
116
|
}
|
|
105
117
|
/**
|
|
@@ -107,12 +119,41 @@ export interface IErasureConfig {
|
|
|
107
119
|
*/
|
|
108
120
|
export interface IDriveConfig {
|
|
109
121
|
paths: string[];
|
|
122
|
+
/**
|
|
123
|
+
* Accept drive roots that share a device (`st_dev`). Each drive root counts
|
|
124
|
+
* as one failure domain, so by default startup refuses two drive roots on
|
|
125
|
+
* one device. Set this only for dev and test clusters whose drive roots are
|
|
126
|
+
* directories on one filesystem. Default false.
|
|
127
|
+
*/
|
|
128
|
+
allowSharedDevice?: boolean;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Mutual TLS for the cluster transport. Every file is read once at startup and
|
|
132
|
+
* must lie outside the control and drive roots, at an absolute path without
|
|
133
|
+
* symbolic links; a restart reloads them.
|
|
134
|
+
*/
|
|
135
|
+
export interface IClusterTlsConfig {
|
|
136
|
+
/** PEM file with one or two CA certificates (two only during a CA rotation). */
|
|
137
|
+
caFile: string;
|
|
138
|
+
/**
|
|
139
|
+
* PEM file with this node's certificate, optionally followed by intermediates. It has one DNS SAN,
|
|
140
|
+
* equal to nodeId, and is valid for server and client authentication: an extended key usage
|
|
141
|
+
* extension listing serverAuth and clientAuth, or no extended key usage extension.
|
|
142
|
+
*/
|
|
143
|
+
certFile: string;
|
|
144
|
+
/** PEM private key of certFile; owned by the engine's user, mode 0600 or 0400. */
|
|
145
|
+
keyFile: string;
|
|
110
146
|
}
|
|
111
147
|
/**
|
|
112
148
|
* Cluster configuration for distributed mode
|
|
113
149
|
*/
|
|
114
150
|
export interface IClusterConfig {
|
|
115
151
|
enabled: boolean;
|
|
152
|
+
/**
|
|
153
|
+
* This node's id. Generated and persisted when omitted, except with `tls`:
|
|
154
|
+
* then it is required and must be a lowercase DNS name equal to the node
|
|
155
|
+
* certificate's DNS subject alternative name.
|
|
156
|
+
*/
|
|
116
157
|
nodeId?: string;
|
|
117
158
|
quicPort?: number;
|
|
118
159
|
seedNodes?: string[];
|
|
@@ -120,11 +161,27 @@ export interface IClusterConfig {
|
|
|
120
161
|
drives?: IDriveConfig;
|
|
121
162
|
heartbeatIntervalMs?: number;
|
|
122
163
|
heartbeatTimeoutMs?: number;
|
|
164
|
+
/**
|
|
165
|
+
* Longest a single GET may run, in milliseconds, from its start to its last
|
|
166
|
+
* byte, including the client's transfer time. A longer GET is aborted.
|
|
167
|
+
* Superseded and deleted object generations keep their shards for this
|
|
168
|
+
* deadline plus the smaller of the deadline and one hour, then cleanup frees
|
|
169
|
+
* them. Must be the same on every node: a mismatch can abort streams but
|
|
170
|
+
* never serves wrong bytes. Default 21,600,000 (6 hours); allowed from
|
|
171
|
+
* 60,000 (1 minute) to 604,800,000 (7 days).
|
|
172
|
+
*/
|
|
173
|
+
getDeadlineMs?: number;
|
|
174
|
+
/**
|
|
175
|
+
* Mutual TLS for the cluster transport. Without it the transport is
|
|
176
|
+
* encrypted but authenticates no peer. Every node of a cluster sets it, or
|
|
177
|
+
* none does: enabling it is a full stop of every node, not a rolling change.
|
|
178
|
+
*/
|
|
179
|
+
tls?: IClusterTlsConfig;
|
|
123
180
|
}
|
|
124
181
|
/**
|
|
125
182
|
* Configuration as the engine receives it: every section resolved.
|
|
126
183
|
*/
|
|
127
|
-
export type TObjectStorageResolvedConfig = Required<Omit<IObjectStorageConfig, 'binaryPath'>>;
|
|
184
|
+
export type TObjectStorageResolvedConfig = Required<Omit<IObjectStorageConfig, 'binaryPath' | 'dashboard'>>;
|
|
128
185
|
/**
|
|
129
186
|
* Complete objectstorage configuration
|
|
130
187
|
*/
|
|
@@ -144,6 +201,11 @@ export interface IObjectStorageConfig {
|
|
|
144
201
|
limits?: ILimitsConfig;
|
|
145
202
|
multipart?: IMultipartConfig;
|
|
146
203
|
cluster?: IClusterConfig;
|
|
204
|
+
/**
|
|
205
|
+
* The read-only visibility dashboard, served by this process on its own
|
|
206
|
+
* port. Off unless `enabled` is true; never sent to the engine.
|
|
207
|
+
*/
|
|
208
|
+
dashboard?: IObjectStorageDashboardConfig;
|
|
147
209
|
}
|
|
148
210
|
/**
|
|
149
211
|
* Logical bucket stats maintained by the Rust runtime.
|
|
@@ -281,6 +343,32 @@ export interface IBucketTenantMetadata {
|
|
|
281
343
|
region?: string;
|
|
282
344
|
retention?: IBucketRetentionReceipt;
|
|
283
345
|
}
|
|
346
|
+
export interface IPrefixCredentialInput {
|
|
347
|
+
bucketName: string;
|
|
348
|
+
/** Unreserved characters (RFC 3986) and `/`; ends with `/`, no leading `/`. */
|
|
349
|
+
prefix: string;
|
|
350
|
+
/** First node: lifetime in seconds, 1..43200. */
|
|
351
|
+
ttlSeconds?: number;
|
|
352
|
+
/** Fan-out to further nodes: the first node's expiresAt (epoch ms). */
|
|
353
|
+
expiresAt?: number;
|
|
354
|
+
/** Supply both together with expiresAt to install an existing credential on another node. */
|
|
355
|
+
accessKeyId?: string;
|
|
356
|
+
secretAccessKey?: string;
|
|
357
|
+
region?: string;
|
|
358
|
+
}
|
|
359
|
+
export interface IPrefixCredentialMetadata {
|
|
360
|
+
accessKeyId: string;
|
|
361
|
+
bucketName: string;
|
|
362
|
+
prefix: string;
|
|
363
|
+
region: string;
|
|
364
|
+
/** Epoch ms. */
|
|
365
|
+
createdAt: number;
|
|
366
|
+
/** Epoch ms; requests are refused from this instant and admitted ones end at it. */
|
|
367
|
+
expiresAt: number;
|
|
368
|
+
}
|
|
369
|
+
export interface IPrefixCredential extends IPrefixCredentialMetadata {
|
|
370
|
+
secretAccessKey: string;
|
|
371
|
+
}
|
|
284
372
|
export interface IBucketRetentionPolicyInput {
|
|
285
373
|
mode: 'compliance';
|
|
286
374
|
policyId: string;
|
|
@@ -622,6 +710,10 @@ export interface IObjectStorageHealth {
|
|
|
622
710
|
enabled: boolean;
|
|
623
711
|
credentialCount: number;
|
|
624
712
|
tenantCredentialCount: number;
|
|
713
|
+
prefixCredentialCount: number;
|
|
714
|
+
prefixCredentialTombstoneCount: number;
|
|
715
|
+
/** False when the prefix credential file is unreadable: every prefix credential is refused. */
|
|
716
|
+
prefixCredentialStoreAvailable: boolean;
|
|
625
717
|
};
|
|
626
718
|
bucketCount: number;
|
|
627
719
|
objectCount: number;
|
|
@@ -641,6 +733,12 @@ export declare class ObjectStorageResourceFenceError extends Error {
|
|
|
641
733
|
readonly code: TObjectStorageResourceFenceErrorCode;
|
|
642
734
|
constructor(codeArg: TObjectStorageResourceFenceErrorCode, messageArg: string, causeArg?: unknown);
|
|
643
735
|
}
|
|
736
|
+
export declare const objectStorageCredentialErrorCodes: readonly ['ECREDENTIAL_AUTH_DISABLED', 'ECREDENTIAL_INVALID_PREFIX', 'ECREDENTIAL_INVALID_TTL', 'ECREDENTIAL_INVALID_EXPIRY', 'ECREDENTIAL_INVALID_KEY', 'ECREDENTIAL_NO_SUCH_BUCKET', 'ECREDENTIAL_BUCKET_UNAVAILABLE', 'ECREDENTIAL_CONFLICT', 'ECREDENTIAL_REVOKED', 'ECREDENTIAL_NOT_PREFIX', 'ECREDENTIAL_LIMIT', 'ECREDENTIAL_PERSISTENCE', 'ECREDENTIAL_STORE_UNAVAILABLE'];
|
|
737
|
+
export type TObjectStorageCredentialErrorCode = (typeof objectStorageCredentialErrorCodes)[number];
|
|
738
|
+
export declare class ObjectStorageCredentialError extends Error {
|
|
739
|
+
readonly code: TObjectStorageCredentialErrorCode;
|
|
740
|
+
constructor(codeArg: TObjectStorageCredentialErrorCode, messageArg: string, causeArg?: unknown);
|
|
741
|
+
}
|
|
644
742
|
export interface IObjectStorageMetrics {
|
|
645
743
|
bucketCount: number;
|
|
646
744
|
objectCount: number;
|
|
@@ -662,6 +760,33 @@ export interface IClusterPeerHealth {
|
|
|
662
760
|
lastHeartbeat?: number;
|
|
663
761
|
missedHeartbeats?: number;
|
|
664
762
|
}
|
|
763
|
+
/**
|
|
764
|
+
* A drive's medium: `'rotational'` and `'flash'` (network volumes included),
|
|
765
|
+
* `'smr'` for drive-managed SMR, which reports itself as rotational and is
|
|
766
|
+
* never detected, and `'zoned'` for host-managed or host-aware SMR and ZNS.
|
|
767
|
+
*/
|
|
768
|
+
export type TDriveMedia = 'rotational' | 'smr' | 'flash' | 'zoned';
|
|
769
|
+
/**
|
|
770
|
+
* A drive's media.
|
|
771
|
+
*/
|
|
772
|
+
export interface IClusterDriveMedia {
|
|
773
|
+
/**
|
|
774
|
+
* The media the configuration declares for the drive. Not reported yet:
|
|
775
|
+
* drives cannot declare their media.
|
|
776
|
+
*/
|
|
777
|
+
declared?: TDriveMedia;
|
|
778
|
+
/**
|
|
779
|
+
* What the engine detected once at startup, from the whole disk behind the
|
|
780
|
+
* drive root's filesystem (Linux sysfs `queue/zoned` and `queue/rotational`;
|
|
781
|
+
* a partition counts as its disk). `'unknown'` for filesystems without a
|
|
782
|
+
* block device of their own (tmpfs, overlay, network filesystems),
|
|
783
|
+
* device-mapper, md, loop and other virtual block devices, and on every
|
|
784
|
+
* platform but Linux. Virtual and network block devices report the
|
|
785
|
+
* rotational flag their driver or hypervisor sets (QEMU disks show
|
|
786
|
+
* `'rotational'` unless configured with `rotation_rate=1`).
|
|
787
|
+
*/
|
|
788
|
+
detected: TDriveMedia | 'unknown';
|
|
789
|
+
}
|
|
665
790
|
/**
|
|
666
791
|
* Local drive health as measured by objectstorage's runtime probes.
|
|
667
792
|
*/
|
|
@@ -676,6 +801,7 @@ export interface IClusterDriveHealth {
|
|
|
676
801
|
lastError?: string;
|
|
677
802
|
lastCheck?: number;
|
|
678
803
|
erasureSetId?: number;
|
|
804
|
+
media: IClusterDriveMedia;
|
|
679
805
|
}
|
|
680
806
|
export interface IClusterErasureHealth {
|
|
681
807
|
dataShards: number;
|
|
@@ -694,9 +820,28 @@ export interface IClusterRepairHealth {
|
|
|
694
820
|
lastDurationMs?: number;
|
|
695
821
|
shardsChecked?: number;
|
|
696
822
|
shardsHealed?: number;
|
|
823
|
+
/** Pending shards (writes that failed at publication) the last scan left pending. */
|
|
824
|
+
shardsPending?: number;
|
|
697
825
|
failed?: number;
|
|
698
826
|
lastError?: string;
|
|
699
827
|
}
|
|
828
|
+
export interface IClusterTransportCertificate {
|
|
829
|
+
/** SHA-256 of the DER certificate, lowercase hex. */
|
|
830
|
+
sha256: string;
|
|
831
|
+
/** Milliseconds since the Unix epoch. */
|
|
832
|
+
notAfter: number;
|
|
833
|
+
}
|
|
834
|
+
/**
|
|
835
|
+
* How the cluster transport authenticates peers, and the certificates it
|
|
836
|
+
* loaded at startup.
|
|
837
|
+
*/
|
|
838
|
+
export interface IClusterTransportHealth {
|
|
839
|
+
mode: 'mutualTls' | 'unauthenticated';
|
|
840
|
+
/** This node's certificate; only in mode 'mutualTls'. */
|
|
841
|
+
certificate?: IClusterTransportCertificate;
|
|
842
|
+
/** The loaded CA bundle in file order; only in mode 'mutualTls'. */
|
|
843
|
+
caCertificates?: IClusterTransportCertificate[];
|
|
844
|
+
}
|
|
700
845
|
/**
|
|
701
846
|
* Cluster runtime health from the Rust core.
|
|
702
847
|
* When clustering is disabled, the response is `{ enabled: false }`.
|
|
@@ -712,6 +857,34 @@ export interface IClusterHealth {
|
|
|
712
857
|
drives?: IClusterDriveHealth[];
|
|
713
858
|
erasure?: IClusterErasureHealth;
|
|
714
859
|
repairs?: IClusterRepairHealth;
|
|
860
|
+
transport?: IClusterTransportHealth;
|
|
861
|
+
}
|
|
862
|
+
/**
|
|
863
|
+
* The result of one cluster healing scan, as `ObjectStorage.runHealingScan()`
|
|
864
|
+
* returns it. Times are milliseconds since the Unix epoch.
|
|
865
|
+
*/
|
|
866
|
+
export interface IClusterHealingScanResult {
|
|
867
|
+
/** When the scan started; always after the request arrived. */
|
|
868
|
+
startedAt: number;
|
|
869
|
+
completedAt: number;
|
|
870
|
+
durationMs: number;
|
|
871
|
+
/** Shard placements checked at their drives (placements on offline nodes are not). */
|
|
872
|
+
shardsChecked: number;
|
|
873
|
+
/** Shards written: missing placements rebuilt and pending shards completed. */
|
|
874
|
+
shardsHealed: number;
|
|
875
|
+
/** Pending shards (writes that failed at publication) this scan left pending. */
|
|
876
|
+
shardsPending: number;
|
|
877
|
+
/** Failed checks, rebuilds, writes and manifest stores. */
|
|
878
|
+
failed: number;
|
|
879
|
+
}
|
|
880
|
+
export interface IRunHealingScanOptions {
|
|
881
|
+
/**
|
|
882
|
+
* How long to wait for the scan, in milliseconds. Defaults to the bridge's
|
|
883
|
+
* request timeout (300,000). The engine cannot cancel a scan: one that
|
|
884
|
+
* outlasts this keeps running, its result is discarded, and a later call
|
|
885
|
+
* joins the next scan that starts after it.
|
|
886
|
+
*/
|
|
887
|
+
timeoutMs?: number;
|
|
715
888
|
}
|
|
716
889
|
/**
|
|
717
890
|
* Main ObjectStorage class - production-ready S3-compatible storage server
|
|
@@ -737,11 +910,15 @@ export declare class ObjectStorage {
|
|
|
737
910
|
private bridgeOwned;
|
|
738
911
|
private stopRequested;
|
|
739
912
|
private stopCompleted;
|
|
913
|
+
private readonly dashboardConfig;
|
|
914
|
+
private dashboard;
|
|
740
915
|
constructor(configArg?: IObjectStorageConfig);
|
|
741
916
|
start(): Promise<void>;
|
|
742
917
|
private startInternal;
|
|
743
918
|
/** Actual TCP port while running; the requested config port before/afterward. */
|
|
744
919
|
get port(): number;
|
|
920
|
+
/** The dashboard's bound TCP port while it runs; `undefined` otherwise. */
|
|
921
|
+
get dashboardPort(): number | undefined;
|
|
745
922
|
getStorageDescriptor(optionsArg?: Partial<plugins.tsclass.storage.IS3Descriptor>): Promise<plugins.tsclass.storage.IS3Descriptor>;
|
|
746
923
|
private getEndpoint;
|
|
747
924
|
private buildBucketTenantDescriptor;
|
|
@@ -757,6 +934,27 @@ export declare class ObjectStorage {
|
|
|
757
934
|
getBucketTenantDescriptor(optionsArg: {
|
|
758
935
|
bucketName: string;
|
|
759
936
|
}): Promise<IBucketTenantDescriptor>;
|
|
937
|
+
/**
|
|
938
|
+
* Creates a credential confined to one key prefix of one bucket until its
|
|
939
|
+
* expiry. The first node takes `ttlSeconds`; further nodes of a fan-out take
|
|
940
|
+
* the first result's `accessKeyId`, `secretAccessKey` and `expiresAt`. The
|
|
941
|
+
* secret is returned only here and never kept by this instance.
|
|
942
|
+
*/
|
|
943
|
+
createPrefixCredential(inputArg: IPrefixCredentialInput): Promise<IPrefixCredential>;
|
|
944
|
+
/**
|
|
945
|
+
* Revokes a prefix credential on this node. An unknown ID is recorded as
|
|
946
|
+
* revoked too, so a later create for it is refused; `revoked` is true only
|
|
947
|
+
* when a live credential was removed.
|
|
948
|
+
*/
|
|
949
|
+
revokePrefixCredential(optionsArg: {
|
|
950
|
+
accessKeyId: string;
|
|
951
|
+
}): Promise<{
|
|
952
|
+
revoked: boolean;
|
|
953
|
+
}>;
|
|
954
|
+
/** Lists this node's live prefix credentials, without secrets. */
|
|
955
|
+
listPrefixCredentials(optionsArg?: {
|
|
956
|
+
bucketName?: string;
|
|
957
|
+
}): Promise<IPrefixCredentialMetadata[]>;
|
|
760
958
|
getBucketRetentionCapability(): Promise<IBucketRetentionCapability>;
|
|
761
959
|
getBucketRetentionReceipt(optionsArg: {
|
|
762
960
|
bucketName: string;
|
|
@@ -789,6 +987,26 @@ export declare class ObjectStorage {
|
|
|
789
987
|
*/
|
|
790
988
|
replaceCredentials(credentials: IStorageCredential[]): Promise<void>;
|
|
791
989
|
getClusterHealth(): Promise<IClusterHealth>;
|
|
990
|
+
/**
|
|
991
|
+
* The dashboard's snapshot, built by the engine from memory only: it never
|
|
992
|
+
* probes a drive, syncs or walks storage. A cluster node also asks each
|
|
993
|
+
* online peer for its own snapshot, waiting up to a second per peer, in
|
|
994
|
+
* parallel; a peer that does not answer is reported unavailable. One
|
|
995
|
+
* snapshot runs at a time: a call while another runs rejects.
|
|
996
|
+
*/
|
|
997
|
+
getClusterSnapshot(): Promise<IObjectStorageClusterSnapshot>;
|
|
998
|
+
/**
|
|
999
|
+
* Runs a healing scan on this cluster node and resolves with its result.
|
|
1000
|
+
* The scan covers the manifests this node coordinated. The request joins
|
|
1001
|
+
* the next scan that starts after it arrives, never one already running,
|
|
1002
|
+
* and requests that arrive together share one scan. It rejects in
|
|
1003
|
+
* standalone mode, when the scan fails (for example without a majority of
|
|
1004
|
+
* the cluster, or when a bucket's manifests cannot be listed), when 16
|
|
1005
|
+
* requests already wait for a scan to start, and when the engine shuts down
|
|
1006
|
+
* before the scan completes. The engine answers other management calls
|
|
1007
|
+
* while the scan runs.
|
|
1008
|
+
*/
|
|
1009
|
+
runHealingScan(optionsArg?: IRunHealingScanOptions): Promise<IClusterHealingScanResult>;
|
|
792
1010
|
getHealth(): Promise<IObjectStorageHealth>;
|
|
793
1011
|
getMetrics(): Promise<IObjectStorageMetrics>;
|
|
794
1012
|
/**
|