s3db.js 13.4.0 → 13.6.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/README.md +25 -10
- package/dist/{s3db.cjs.js → s3db.cjs} +38801 -32446
- package/dist/s3db.cjs.map +1 -0
- package/dist/s3db.es.js +38653 -32291
- package/dist/s3db.es.js.map +1 -1
- package/package.json +218 -22
- package/src/concerns/id.js +90 -6
- package/src/concerns/index.js +2 -1
- package/src/concerns/password-hashing.js +150 -0
- package/src/database.class.js +6 -2
- package/src/plugins/api/auth/basic-auth.js +40 -10
- package/src/plugins/api/auth/index.js +49 -3
- package/src/plugins/api/auth/oauth2-auth.js +171 -0
- package/src/plugins/api/auth/oidc-auth.js +789 -0
- package/src/plugins/api/auth/oidc-client.js +462 -0
- package/src/plugins/api/auth/path-auth-matcher.js +284 -0
- package/src/plugins/api/concerns/event-emitter.js +134 -0
- package/src/plugins/api/concerns/failban-manager.js +651 -0
- package/src/plugins/api/concerns/guards-helpers.js +402 -0
- package/src/plugins/api/concerns/metrics-collector.js +346 -0
- package/src/plugins/api/index.js +510 -57
- package/src/plugins/api/middlewares/failban.js +305 -0
- package/src/plugins/api/middlewares/rate-limit.js +301 -0
- package/src/plugins/api/middlewares/request-id.js +74 -0
- package/src/plugins/api/middlewares/security-headers.js +120 -0
- package/src/plugins/api/middlewares/session-tracking.js +194 -0
- package/src/plugins/api/routes/auth-routes.js +119 -78
- package/src/plugins/api/routes/resource-routes.js +73 -30
- package/src/plugins/api/server.js +1139 -45
- package/src/plugins/api/utils/custom-routes.js +102 -0
- package/src/plugins/api/utils/guards.js +213 -0
- package/src/plugins/api/utils/mime-types.js +154 -0
- package/src/plugins/api/utils/openapi-generator.js +91 -12
- package/src/plugins/api/utils/path-matcher.js +173 -0
- package/src/plugins/api/utils/static-filesystem.js +262 -0
- package/src/plugins/api/utils/static-s3.js +231 -0
- package/src/plugins/api/utils/template-engine.js +188 -0
- package/src/plugins/cloud-inventory/drivers/alibaba-driver.js +853 -0
- package/src/plugins/cloud-inventory/drivers/aws-driver.js +2554 -0
- package/src/plugins/cloud-inventory/drivers/azure-driver.js +637 -0
- package/src/plugins/cloud-inventory/drivers/base-driver.js +99 -0
- package/src/plugins/cloud-inventory/drivers/cloudflare-driver.js +620 -0
- package/src/plugins/cloud-inventory/drivers/digitalocean-driver.js +698 -0
- package/src/plugins/cloud-inventory/drivers/gcp-driver.js +645 -0
- package/src/plugins/cloud-inventory/drivers/hetzner-driver.js +559 -0
- package/src/plugins/cloud-inventory/drivers/linode-driver.js +614 -0
- package/src/plugins/cloud-inventory/drivers/mock-drivers.js +449 -0
- package/src/plugins/cloud-inventory/drivers/mongodb-atlas-driver.js +771 -0
- package/src/plugins/cloud-inventory/drivers/oracle-driver.js +768 -0
- package/src/plugins/cloud-inventory/drivers/vultr-driver.js +636 -0
- package/src/plugins/cloud-inventory/index.js +20 -0
- package/src/plugins/cloud-inventory/registry.js +146 -0
- package/src/plugins/cloud-inventory/terraform-exporter.js +362 -0
- package/src/plugins/cloud-inventory.plugin.js +1333 -0
- package/src/plugins/concerns/plugin-dependencies.js +62 -2
- package/src/plugins/eventual-consistency/analytics.js +1 -0
- package/src/plugins/eventual-consistency/consolidation.js +2 -2
- package/src/plugins/eventual-consistency/garbage-collection.js +2 -2
- package/src/plugins/eventual-consistency/install.js +2 -2
- package/src/plugins/identity/README.md +335 -0
- package/src/plugins/identity/concerns/mfa-manager.js +204 -0
- package/src/plugins/identity/concerns/password.js +138 -0
- package/src/plugins/identity/concerns/resource-schemas.js +273 -0
- package/src/plugins/identity/concerns/token-generator.js +172 -0
- package/src/plugins/identity/email-service.js +422 -0
- package/src/plugins/identity/index.js +1052 -0
- package/src/plugins/identity/oauth2-server.js +1033 -0
- package/src/plugins/identity/oidc-discovery.js +285 -0
- package/src/plugins/identity/rsa-keys.js +323 -0
- package/src/plugins/identity/server.js +500 -0
- package/src/plugins/identity/session-manager.js +453 -0
- package/src/plugins/identity/ui/layouts/base.js +251 -0
- package/src/plugins/identity/ui/middleware.js +135 -0
- package/src/plugins/identity/ui/pages/admin/client-form.js +247 -0
- package/src/plugins/identity/ui/pages/admin/clients.js +179 -0
- package/src/plugins/identity/ui/pages/admin/dashboard.js +181 -0
- package/src/plugins/identity/ui/pages/admin/user-form.js +283 -0
- package/src/plugins/identity/ui/pages/admin/users.js +263 -0
- package/src/plugins/identity/ui/pages/consent.js +262 -0
- package/src/plugins/identity/ui/pages/forgot-password.js +104 -0
- package/src/plugins/identity/ui/pages/login.js +144 -0
- package/src/plugins/identity/ui/pages/mfa-backup-codes.js +180 -0
- package/src/plugins/identity/ui/pages/mfa-enrollment.js +187 -0
- package/src/plugins/identity/ui/pages/mfa-verification.js +178 -0
- package/src/plugins/identity/ui/pages/oauth-error.js +225 -0
- package/src/plugins/identity/ui/pages/profile.js +361 -0
- package/src/plugins/identity/ui/pages/register.js +226 -0
- package/src/plugins/identity/ui/pages/reset-password.js +128 -0
- package/src/plugins/identity/ui/pages/verify-email.js +172 -0
- package/src/plugins/identity/ui/routes.js +2541 -0
- package/src/plugins/identity/ui/styles/main.css +465 -0
- package/src/plugins/index.js +4 -1
- package/src/plugins/ml/base-model.class.js +65 -16
- package/src/plugins/ml/classification-model.class.js +1 -1
- package/src/plugins/ml/timeseries-model.class.js +3 -1
- package/src/plugins/ml.plugin.js +584 -31
- package/src/plugins/shared/error-handler.js +147 -0
- package/src/plugins/shared/index.js +9 -0
- package/src/plugins/shared/middlewares/compression.js +117 -0
- package/src/plugins/shared/middlewares/cors.js +49 -0
- package/src/plugins/shared/middlewares/index.js +11 -0
- package/src/plugins/shared/middlewares/logging.js +54 -0
- package/src/plugins/shared/middlewares/rate-limit.js +73 -0
- package/src/plugins/shared/middlewares/security.js +158 -0
- package/src/plugins/shared/response-formatter.js +264 -0
- package/src/plugins/state-machine.plugin.js +57 -2
- package/src/resource.class.js +140 -12
- package/src/schema.class.js +30 -1
- package/src/validator.class.js +57 -6
- package/dist/s3db.cjs.js.map +0 -1
|
@@ -0,0 +1,636 @@
|
|
|
1
|
+
import { BaseCloudDriver } from './base-driver.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Production-ready Vultr inventory driver using official @vultr/vultr-node SDK.
|
|
5
|
+
*
|
|
6
|
+
* Covers 12+ services with 15+ resource types:
|
|
7
|
+
* - Compute (instances, bare metal)
|
|
8
|
+
* - Kubernetes (VKE clusters)
|
|
9
|
+
* - Storage (block storage, snapshots, object storage)
|
|
10
|
+
* - Networking (load balancers, firewalls, VPC)
|
|
11
|
+
* - DNS (domains, records)
|
|
12
|
+
* - Databases (managed databases)
|
|
13
|
+
* - SSH Keys
|
|
14
|
+
*
|
|
15
|
+
* @see https://www.vultr.com/api/
|
|
16
|
+
* @see https://github.com/vultr/vultr-node
|
|
17
|
+
*/
|
|
18
|
+
export class VultrInventoryDriver extends BaseCloudDriver {
|
|
19
|
+
constructor(options = {}) {
|
|
20
|
+
super({ ...options, driver: options.driver || 'vultr' });
|
|
21
|
+
|
|
22
|
+
this._apiKey = null;
|
|
23
|
+
this._client = null;
|
|
24
|
+
this._accountId = this.config?.accountId || 'vultr';
|
|
25
|
+
|
|
26
|
+
// Services to collect (can be filtered via config.services)
|
|
27
|
+
this._services = this.config?.services || [
|
|
28
|
+
'instances',
|
|
29
|
+
'baremetal',
|
|
30
|
+
'kubernetes',
|
|
31
|
+
'blockstorage',
|
|
32
|
+
'snapshots',
|
|
33
|
+
'loadbalancers',
|
|
34
|
+
'firewalls',
|
|
35
|
+
'vpc',
|
|
36
|
+
'dns',
|
|
37
|
+
'databases',
|
|
38
|
+
'sshkeys',
|
|
39
|
+
'objectstorage'
|
|
40
|
+
];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Initialize the Vultr API client.
|
|
45
|
+
*/
|
|
46
|
+
async _initializeClient() {
|
|
47
|
+
if (this._client) return;
|
|
48
|
+
|
|
49
|
+
const credentials = this.credentials || {};
|
|
50
|
+
this._apiKey = credentials.apiKey || credentials.token || process.env.VULTR_API_KEY;
|
|
51
|
+
|
|
52
|
+
if (!this._apiKey) {
|
|
53
|
+
throw new Error('Vultr API key is required. Provide via credentials.apiKey or VULTR_API_KEY env var.');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Lazy import to keep core package lightweight
|
|
57
|
+
const { VultrNode } = await import('@vultr/vultr-node');
|
|
58
|
+
|
|
59
|
+
this._client = VultrNode.initialize({ apiKey: this._apiKey });
|
|
60
|
+
|
|
61
|
+
this.logger('info', 'Vultr API client initialized', {
|
|
62
|
+
accountId: this._accountId,
|
|
63
|
+
services: this._services.length
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Main entry point - lists all resources from configured services.
|
|
69
|
+
*/
|
|
70
|
+
async *listResources(options = {}) {
|
|
71
|
+
await this._initializeClient();
|
|
72
|
+
|
|
73
|
+
const serviceCollectors = {
|
|
74
|
+
instances: () => this._collectInstances(),
|
|
75
|
+
baremetal: () => this._collectBareMetal(),
|
|
76
|
+
kubernetes: () => this._collectKubernetes(),
|
|
77
|
+
blockstorage: () => this._collectBlockStorage(),
|
|
78
|
+
snapshots: () => this._collectSnapshots(),
|
|
79
|
+
loadbalancers: () => this._collectLoadBalancers(),
|
|
80
|
+
firewalls: () => this._collectFirewalls(),
|
|
81
|
+
vpc: () => this._collectVPC(),
|
|
82
|
+
dns: () => this._collectDNS(),
|
|
83
|
+
databases: () => this._collectDatabases(),
|
|
84
|
+
sshkeys: () => this._collectSSHKeys(),
|
|
85
|
+
objectstorage: () => this._collectObjectStorage()
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
for (const service of this._services) {
|
|
89
|
+
const collector = serviceCollectors[service];
|
|
90
|
+
if (!collector) {
|
|
91
|
+
this.logger('warn', `Unknown Vultr service: ${service}`, { service });
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
this.logger('info', `Collecting Vultr ${service} resources`, { service });
|
|
97
|
+
yield* collector();
|
|
98
|
+
} catch (err) {
|
|
99
|
+
// Continue with next service instead of failing entire sync
|
|
100
|
+
this.logger('error', `Vultr service collection failed, skipping to next service`, {
|
|
101
|
+
service,
|
|
102
|
+
error: err.message,
|
|
103
|
+
errorName: err.name,
|
|
104
|
+
stack: err.stack
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Collect Compute Instances (VPS).
|
|
112
|
+
*/
|
|
113
|
+
async *_collectInstances() {
|
|
114
|
+
try {
|
|
115
|
+
const response = await this._client.instances.listInstances();
|
|
116
|
+
const instances = response.instances || [];
|
|
117
|
+
|
|
118
|
+
for (const instance of instances) {
|
|
119
|
+
yield {
|
|
120
|
+
provider: 'vultr',
|
|
121
|
+
accountId: this._accountId,
|
|
122
|
+
region: instance.region,
|
|
123
|
+
service: 'instances',
|
|
124
|
+
resourceType: 'vultr.compute.instance',
|
|
125
|
+
resourceId: instance.id,
|
|
126
|
+
name: instance.label || instance.hostname || instance.id,
|
|
127
|
+
tags: instance.tags || [],
|
|
128
|
+
configuration: this._sanitize(instance)
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
this.logger('info', `Collected ${instances.length} Vultr instances`);
|
|
133
|
+
} catch (err) {
|
|
134
|
+
this.logger('error', 'Failed to collect Vultr instances', {
|
|
135
|
+
error: err.message,
|
|
136
|
+
stack: err.stack
|
|
137
|
+
});
|
|
138
|
+
throw err;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Collect Bare Metal servers.
|
|
144
|
+
*/
|
|
145
|
+
async *_collectBareMetal() {
|
|
146
|
+
try {
|
|
147
|
+
const response = await this._client.bareMetal.listBareMetalServers();
|
|
148
|
+
const servers = response.bare_metals || [];
|
|
149
|
+
|
|
150
|
+
for (const server of servers) {
|
|
151
|
+
yield {
|
|
152
|
+
provider: 'vultr',
|
|
153
|
+
accountId: this._accountId,
|
|
154
|
+
region: server.region,
|
|
155
|
+
service: 'baremetal',
|
|
156
|
+
resourceType: 'vultr.baremetal.server',
|
|
157
|
+
resourceId: server.id,
|
|
158
|
+
name: server.label || server.id,
|
|
159
|
+
tags: server.tags || [],
|
|
160
|
+
configuration: this._sanitize(server)
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
this.logger('info', `Collected ${servers.length} Vultr bare metal servers`);
|
|
165
|
+
} catch (err) {
|
|
166
|
+
this.logger('error', 'Failed to collect Vultr bare metal', {
|
|
167
|
+
error: err.message,
|
|
168
|
+
stack: err.stack
|
|
169
|
+
});
|
|
170
|
+
throw err;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Collect Kubernetes clusters (VKE).
|
|
176
|
+
*/
|
|
177
|
+
async *_collectKubernetes() {
|
|
178
|
+
try {
|
|
179
|
+
const response = await this._client.kubernetes.listKubernetesClusters();
|
|
180
|
+
const clusters = response.vke_clusters || [];
|
|
181
|
+
|
|
182
|
+
for (const cluster of clusters) {
|
|
183
|
+
yield {
|
|
184
|
+
provider: 'vultr',
|
|
185
|
+
accountId: this._accountId,
|
|
186
|
+
region: cluster.region,
|
|
187
|
+
service: 'kubernetes',
|
|
188
|
+
resourceType: 'vultr.kubernetes.cluster',
|
|
189
|
+
resourceId: cluster.id,
|
|
190
|
+
name: cluster.label || cluster.id,
|
|
191
|
+
tags: [],
|
|
192
|
+
configuration: this._sanitize(cluster)
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
// Collect node pools
|
|
196
|
+
try {
|
|
197
|
+
const npResponse = await this._client.kubernetes.listNodePools({ 'vke-id': cluster.id });
|
|
198
|
+
const nodePools = npResponse.node_pools || [];
|
|
199
|
+
|
|
200
|
+
for (const nodePool of nodePools) {
|
|
201
|
+
yield {
|
|
202
|
+
provider: 'vultr',
|
|
203
|
+
accountId: this._accountId,
|
|
204
|
+
region: cluster.region,
|
|
205
|
+
service: 'kubernetes',
|
|
206
|
+
resourceType: 'vultr.kubernetes.nodepool',
|
|
207
|
+
resourceId: nodePool.id,
|
|
208
|
+
name: nodePool.label || nodePool.id,
|
|
209
|
+
tags: [],
|
|
210
|
+
metadata: { clusterId: cluster.id, clusterLabel: cluster.label },
|
|
211
|
+
configuration: this._sanitize(nodePool)
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
} catch (npErr) {
|
|
215
|
+
this.logger('warn', `Failed to collect node pools for cluster ${cluster.id}`, {
|
|
216
|
+
clusterId: cluster.id,
|
|
217
|
+
error: npErr.message
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
this.logger('info', `Collected ${clusters.length} Vultr Kubernetes clusters`);
|
|
223
|
+
} catch (err) {
|
|
224
|
+
this.logger('error', 'Failed to collect Vultr Kubernetes', {
|
|
225
|
+
error: err.message,
|
|
226
|
+
stack: err.stack
|
|
227
|
+
});
|
|
228
|
+
throw err;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Collect Block Storage volumes.
|
|
234
|
+
*/
|
|
235
|
+
async *_collectBlockStorage() {
|
|
236
|
+
try {
|
|
237
|
+
const response = await this._client.blockStorage.listBlockStorages();
|
|
238
|
+
const volumes = response.blocks || [];
|
|
239
|
+
|
|
240
|
+
for (const volume of volumes) {
|
|
241
|
+
yield {
|
|
242
|
+
provider: 'vultr',
|
|
243
|
+
accountId: this._accountId,
|
|
244
|
+
region: volume.region,
|
|
245
|
+
service: 'blockstorage',
|
|
246
|
+
resourceType: 'vultr.blockstorage.volume',
|
|
247
|
+
resourceId: volume.id,
|
|
248
|
+
name: volume.label || volume.id,
|
|
249
|
+
tags: [],
|
|
250
|
+
configuration: this._sanitize(volume)
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
this.logger('info', `Collected ${volumes.length} Vultr block storage volumes`);
|
|
255
|
+
} catch (err) {
|
|
256
|
+
this.logger('error', 'Failed to collect Vultr block storage', {
|
|
257
|
+
error: err.message,
|
|
258
|
+
stack: err.stack
|
|
259
|
+
});
|
|
260
|
+
throw err;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Collect Snapshots.
|
|
266
|
+
*/
|
|
267
|
+
async *_collectSnapshots() {
|
|
268
|
+
try {
|
|
269
|
+
const response = await this._client.snapshots.listSnapshots();
|
|
270
|
+
const snapshots = response.snapshots || [];
|
|
271
|
+
|
|
272
|
+
for (const snapshot of snapshots) {
|
|
273
|
+
yield {
|
|
274
|
+
provider: 'vultr',
|
|
275
|
+
accountId: this._accountId,
|
|
276
|
+
region: null, // Snapshots are global
|
|
277
|
+
service: 'snapshots',
|
|
278
|
+
resourceType: 'vultr.snapshot',
|
|
279
|
+
resourceId: snapshot.id,
|
|
280
|
+
name: snapshot.description || snapshot.id,
|
|
281
|
+
tags: [],
|
|
282
|
+
configuration: this._sanitize(snapshot)
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
this.logger('info', `Collected ${snapshots.length} Vultr snapshots`);
|
|
287
|
+
} catch (err) {
|
|
288
|
+
this.logger('error', 'Failed to collect Vultr snapshots', {
|
|
289
|
+
error: err.message,
|
|
290
|
+
stack: err.stack
|
|
291
|
+
});
|
|
292
|
+
throw err;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Collect Load Balancers.
|
|
298
|
+
*/
|
|
299
|
+
async *_collectLoadBalancers() {
|
|
300
|
+
try {
|
|
301
|
+
const response = await this._client.loadBalancers.listLoadBalancers();
|
|
302
|
+
const lbs = response.load_balancers || [];
|
|
303
|
+
|
|
304
|
+
for (const lb of lbs) {
|
|
305
|
+
yield {
|
|
306
|
+
provider: 'vultr',
|
|
307
|
+
accountId: this._accountId,
|
|
308
|
+
region: lb.region,
|
|
309
|
+
service: 'loadbalancers',
|
|
310
|
+
resourceType: 'vultr.loadbalancer',
|
|
311
|
+
resourceId: lb.id,
|
|
312
|
+
name: lb.label || lb.id,
|
|
313
|
+
tags: [],
|
|
314
|
+
configuration: this._sanitize(lb)
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
this.logger('info', `Collected ${lbs.length} Vultr load balancers`);
|
|
319
|
+
} catch (err) {
|
|
320
|
+
this.logger('error', 'Failed to collect Vultr load balancers', {
|
|
321
|
+
error: err.message,
|
|
322
|
+
stack: err.stack
|
|
323
|
+
});
|
|
324
|
+
throw err;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Collect Firewall Groups.
|
|
330
|
+
*/
|
|
331
|
+
async *_collectFirewalls() {
|
|
332
|
+
try {
|
|
333
|
+
const response = await this._client.firewalls.listFirewallGroups();
|
|
334
|
+
const firewalls = response.firewall_groups || [];
|
|
335
|
+
|
|
336
|
+
for (const firewall of firewalls) {
|
|
337
|
+
yield {
|
|
338
|
+
provider: 'vultr',
|
|
339
|
+
accountId: this._accountId,
|
|
340
|
+
region: null, // Firewalls are global
|
|
341
|
+
service: 'firewalls',
|
|
342
|
+
resourceType: 'vultr.firewall.group',
|
|
343
|
+
resourceId: firewall.id,
|
|
344
|
+
name: firewall.description || firewall.id,
|
|
345
|
+
tags: [],
|
|
346
|
+
configuration: this._sanitize(firewall)
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
// Collect firewall rules
|
|
350
|
+
try {
|
|
351
|
+
const rulesResponse = await this._client.firewalls.listFirewallGroupRules({
|
|
352
|
+
'firewall-group-id': firewall.id
|
|
353
|
+
});
|
|
354
|
+
const rules = rulesResponse.firewall_rules || [];
|
|
355
|
+
|
|
356
|
+
for (const rule of rules) {
|
|
357
|
+
yield {
|
|
358
|
+
provider: 'vultr',
|
|
359
|
+
accountId: this._accountId,
|
|
360
|
+
region: null,
|
|
361
|
+
service: 'firewalls',
|
|
362
|
+
resourceType: 'vultr.firewall.rule',
|
|
363
|
+
resourceId: `${firewall.id}/${rule.id}`,
|
|
364
|
+
name: `${firewall.description || firewall.id} - Rule ${rule.id}`,
|
|
365
|
+
tags: [],
|
|
366
|
+
metadata: { firewallGroupId: firewall.id },
|
|
367
|
+
configuration: this._sanitize(rule)
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
} catch (rulesErr) {
|
|
371
|
+
this.logger('warn', `Failed to collect firewall rules for ${firewall.id}`, {
|
|
372
|
+
firewallId: firewall.id,
|
|
373
|
+
error: rulesErr.message
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
this.logger('info', `Collected ${firewalls.length} Vultr firewall groups`);
|
|
379
|
+
} catch (err) {
|
|
380
|
+
this.logger('error', 'Failed to collect Vultr firewalls', {
|
|
381
|
+
error: err.message,
|
|
382
|
+
stack: err.stack
|
|
383
|
+
});
|
|
384
|
+
throw err;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Collect VPC/VPC 2.0 networks.
|
|
390
|
+
*/
|
|
391
|
+
async *_collectVPC() {
|
|
392
|
+
try {
|
|
393
|
+
// VPC 2.0 (newer)
|
|
394
|
+
try {
|
|
395
|
+
const response = await this._client.vpc2.listVPC2s();
|
|
396
|
+
const vpcs = response.vpcs || [];
|
|
397
|
+
|
|
398
|
+
for (const vpc of vpcs) {
|
|
399
|
+
yield {
|
|
400
|
+
provider: 'vultr',
|
|
401
|
+
accountId: this._accountId,
|
|
402
|
+
region: vpc.region,
|
|
403
|
+
service: 'vpc',
|
|
404
|
+
resourceType: 'vultr.vpc.network',
|
|
405
|
+
resourceId: vpc.id,
|
|
406
|
+
name: vpc.description || vpc.id,
|
|
407
|
+
tags: [],
|
|
408
|
+
configuration: this._sanitize(vpc)
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
this.logger('info', `Collected ${vpcs.length} Vultr VPC 2.0 networks`);
|
|
413
|
+
} catch (vpc2Err) {
|
|
414
|
+
this.logger('warn', 'Failed to collect VPC 2.0, trying legacy VPC', {
|
|
415
|
+
error: vpc2Err.message
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
// Fallback to legacy VPC
|
|
419
|
+
const legacyResponse = await this._client.vpc.listVPCs();
|
|
420
|
+
const legacyVpcs = legacyResponse.vpcs || [];
|
|
421
|
+
|
|
422
|
+
for (const vpc of legacyVpcs) {
|
|
423
|
+
yield {
|
|
424
|
+
provider: 'vultr',
|
|
425
|
+
accountId: this._accountId,
|
|
426
|
+
region: vpc.region,
|
|
427
|
+
service: 'vpc',
|
|
428
|
+
resourceType: 'vultr.vpc.network.legacy',
|
|
429
|
+
resourceId: vpc.id,
|
|
430
|
+
name: vpc.description || vpc.id,
|
|
431
|
+
tags: [],
|
|
432
|
+
configuration: this._sanitize(vpc)
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
this.logger('info', `Collected ${legacyVpcs.length} Vultr legacy VPC networks`);
|
|
437
|
+
}
|
|
438
|
+
} catch (err) {
|
|
439
|
+
this.logger('error', 'Failed to collect Vultr VPC', {
|
|
440
|
+
error: err.message,
|
|
441
|
+
stack: err.stack
|
|
442
|
+
});
|
|
443
|
+
throw err;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Collect DNS domains and records.
|
|
449
|
+
*/
|
|
450
|
+
async *_collectDNS() {
|
|
451
|
+
try {
|
|
452
|
+
const response = await this._client.dns.listDomains();
|
|
453
|
+
const domains = response.domains || [];
|
|
454
|
+
|
|
455
|
+
for (const domain of domains) {
|
|
456
|
+
yield {
|
|
457
|
+
provider: 'vultr',
|
|
458
|
+
accountId: this._accountId,
|
|
459
|
+
region: null, // DNS is global
|
|
460
|
+
service: 'dns',
|
|
461
|
+
resourceType: 'vultr.dns.domain',
|
|
462
|
+
resourceId: domain.domain,
|
|
463
|
+
name: domain.domain,
|
|
464
|
+
tags: [],
|
|
465
|
+
configuration: this._sanitize(domain)
|
|
466
|
+
};
|
|
467
|
+
|
|
468
|
+
// Collect DNS records for this domain
|
|
469
|
+
try {
|
|
470
|
+
const recordsResponse = await this._client.dns.listRecords({ 'dns-domain': domain.domain });
|
|
471
|
+
const records = recordsResponse.records || [];
|
|
472
|
+
|
|
473
|
+
for (const record of records) {
|
|
474
|
+
yield {
|
|
475
|
+
provider: 'vultr',
|
|
476
|
+
accountId: this._accountId,
|
|
477
|
+
region: null,
|
|
478
|
+
service: 'dns',
|
|
479
|
+
resourceType: 'vultr.dns.record',
|
|
480
|
+
resourceId: record.id,
|
|
481
|
+
name: `${record.name}.${domain.domain}`,
|
|
482
|
+
tags: [],
|
|
483
|
+
metadata: { domain: domain.domain },
|
|
484
|
+
configuration: this._sanitize(record)
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
} catch (recordsErr) {
|
|
488
|
+
this.logger('warn', `Failed to collect DNS records for ${domain.domain}`, {
|
|
489
|
+
domain: domain.domain,
|
|
490
|
+
error: recordsErr.message
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
this.logger('info', `Collected ${domains.length} Vultr DNS domains`);
|
|
496
|
+
} catch (err) {
|
|
497
|
+
this.logger('error', 'Failed to collect Vultr DNS', {
|
|
498
|
+
error: err.message,
|
|
499
|
+
stack: err.stack
|
|
500
|
+
});
|
|
501
|
+
throw err;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* Collect Managed Databases.
|
|
507
|
+
*/
|
|
508
|
+
async *_collectDatabases() {
|
|
509
|
+
try {
|
|
510
|
+
const response = await this._client.databases.listDatabases();
|
|
511
|
+
const databases = response.databases || [];
|
|
512
|
+
|
|
513
|
+
for (const db of databases) {
|
|
514
|
+
yield {
|
|
515
|
+
provider: 'vultr',
|
|
516
|
+
accountId: this._accountId,
|
|
517
|
+
region: db.region,
|
|
518
|
+
service: 'databases',
|
|
519
|
+
resourceType: 'vultr.database',
|
|
520
|
+
resourceId: db.id,
|
|
521
|
+
name: db.label || db.id,
|
|
522
|
+
tags: db.tag ? [db.tag] : [],
|
|
523
|
+
configuration: this._sanitize(db)
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
this.logger('info', `Collected ${databases.length} Vultr managed databases`);
|
|
528
|
+
} catch (err) {
|
|
529
|
+
this.logger('error', 'Failed to collect Vultr databases', {
|
|
530
|
+
error: err.message,
|
|
531
|
+
stack: err.stack
|
|
532
|
+
});
|
|
533
|
+
throw err;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
/**
|
|
538
|
+
* Collect SSH Keys.
|
|
539
|
+
*/
|
|
540
|
+
async *_collectSSHKeys() {
|
|
541
|
+
try {
|
|
542
|
+
const response = await this._client.sshKeys.listSshKeys();
|
|
543
|
+
const keys = response.ssh_keys || [];
|
|
544
|
+
|
|
545
|
+
for (const key of keys) {
|
|
546
|
+
yield {
|
|
547
|
+
provider: 'vultr',
|
|
548
|
+
accountId: this._accountId,
|
|
549
|
+
region: null, // SSH keys are global
|
|
550
|
+
service: 'sshkeys',
|
|
551
|
+
resourceType: 'vultr.sshkey',
|
|
552
|
+
resourceId: key.id,
|
|
553
|
+
name: key.name || key.id,
|
|
554
|
+
tags: [],
|
|
555
|
+
configuration: this._sanitize(key)
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
this.logger('info', `Collected ${keys.length} Vultr SSH keys`);
|
|
560
|
+
} catch (err) {
|
|
561
|
+
this.logger('error', 'Failed to collect Vultr SSH keys', {
|
|
562
|
+
error: err.message,
|
|
563
|
+
stack: err.stack
|
|
564
|
+
});
|
|
565
|
+
throw err;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* Collect Object Storage buckets.
|
|
571
|
+
*/
|
|
572
|
+
async *_collectObjectStorage() {
|
|
573
|
+
try {
|
|
574
|
+
// List object storage clusters first
|
|
575
|
+
const clustersResponse = await this._client.objectStorage.listObjectStorageClusters();
|
|
576
|
+
const clusters = clustersResponse.clusters || [];
|
|
577
|
+
|
|
578
|
+
// For each cluster, list object storage instances
|
|
579
|
+
for (const cluster of clusters) {
|
|
580
|
+
try {
|
|
581
|
+
const response = await this._client.objectStorage.listObjectStorages();
|
|
582
|
+
const storages = response.object_storages || [];
|
|
583
|
+
|
|
584
|
+
for (const storage of storages) {
|
|
585
|
+
// Filter by cluster if needed
|
|
586
|
+
if (storage.object_storage_cluster_id === cluster.id) {
|
|
587
|
+
yield {
|
|
588
|
+
provider: 'vultr',
|
|
589
|
+
accountId: this._accountId,
|
|
590
|
+
region: cluster.region,
|
|
591
|
+
service: 'objectstorage',
|
|
592
|
+
resourceType: 'vultr.objectstorage.bucket',
|
|
593
|
+
resourceId: storage.id,
|
|
594
|
+
name: storage.label || storage.id,
|
|
595
|
+
tags: [],
|
|
596
|
+
metadata: { clusterId: cluster.id, clusterRegion: cluster.region },
|
|
597
|
+
configuration: this._sanitize(storage)
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
} catch (storageErr) {
|
|
602
|
+
this.logger('warn', `Failed to collect object storage for cluster ${cluster.id}`, {
|
|
603
|
+
clusterId: cluster.id,
|
|
604
|
+
error: storageErr.message
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
this.logger('info', `Collected object storage from ${clusters.length} Vultr clusters`);
|
|
610
|
+
} catch (err) {
|
|
611
|
+
this.logger('error', 'Failed to collect Vultr object storage', {
|
|
612
|
+
error: err.message,
|
|
613
|
+
stack: err.stack
|
|
614
|
+
});
|
|
615
|
+
throw err;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* Sanitize configuration by removing sensitive data.
|
|
621
|
+
*/
|
|
622
|
+
_sanitize(config) {
|
|
623
|
+
if (!config || typeof config !== 'object') return config;
|
|
624
|
+
|
|
625
|
+
const sanitized = { ...config };
|
|
626
|
+
const sensitiveFields = ['api_key', 'password', 'secret', 'token', 'ssh_key', 'private_key'];
|
|
627
|
+
|
|
628
|
+
for (const field of sensitiveFields) {
|
|
629
|
+
if (field in sanitized) {
|
|
630
|
+
sanitized[field] = '***REDACTED***';
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
return sanitized;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export {
|
|
2
|
+
registerCloudDriver,
|
|
3
|
+
createCloudDriver,
|
|
4
|
+
listCloudDrivers,
|
|
5
|
+
validateCloudDefinition,
|
|
6
|
+
BaseCloudDriver
|
|
7
|
+
} from './registry.js';
|
|
8
|
+
|
|
9
|
+
export {
|
|
10
|
+
AwsInventoryDriver
|
|
11
|
+
} from './drivers/aws-driver.js';
|
|
12
|
+
|
|
13
|
+
export {
|
|
14
|
+
AwsMockDriver,
|
|
15
|
+
GcpMockDriver,
|
|
16
|
+
DigitalOceanMockDriver,
|
|
17
|
+
OracleMockDriver,
|
|
18
|
+
AzureMockDriver,
|
|
19
|
+
VultrMockDriver
|
|
20
|
+
} from './drivers/mock-drivers.js';
|