Compare commits

...

38 Commits

Author SHA1 Message Date
bc7a2ca5f1 5.0.4
Some checks failed
Docker (tags) / security (push) Successful in 48s
Docker (tags) / test (push) Successful in 1m56s
Docker (tags) / metadata (push) Successful in 3s
Docker (tags) / release (push) Failing after 14s
2025-04-25 18:20:18 +00:00
77d911e47a fix(platformservice/mta): Update getEmailStatus response schema: make details property optional 2025-04-25 18:20:18 +00:00
b9c9c2d0a9 5.0.3
Some checks failed
Docker (tags) / security (push) Successful in 49s
Docker (tags) / test (push) Successful in 1m55s
Docker (tags) / metadata (push) Successful in 3s
Docker (tags) / release (push) Failing after 14s
2025-04-25 17:02:48 +00:00
d5b91789d1 fix(mta): update email status response type in MTA platform service 2025-04-25 17:02:48 +00:00
eb8350f453 5.0.2
Some checks failed
Docker (tags) / security (push) Successful in 38s
Docker (tags) / test (push) Successful in 1m56s
Docker (tags) / metadata (push) Successful in 3s
Docker (tags) / release (push) Failing after 13s
2025-04-25 16:34:01 +00:00
b987ce27b8 fix(platformservice/mta): Refactor email status response in MTA service 2025-04-25 16:34:00 +00:00
630e363e53 5.0.1
Some checks failed
Docker (tags) / security (push) Successful in 48s
Docker (tags) / test (push) Successful in 1m54s
Docker (tags) / metadata (push) Successful in 3s
Docker (tags) / release (push) Failing after 14s
2025-04-25 16:27:48 +00:00
a602021952 fix(mta): Update email stats response interface in mta platform service to include totalEmailsSent, totalEmailsDelivered, totalEmailsBounced, averageDeliveryTimeMs, and lastUpdated timestamp. 2025-04-25 16:27:48 +00:00
80585437a0 5.0.0
Some checks failed
Docker (tags) / security (push) Successful in 47s
Docker (tags) / test (push) Successful in 1m54s
Docker (tags) / metadata (push) Successful in 3s
Docker (tags) / release (push) Failing after 41s
2025-04-25 15:57:35 +00:00
4674a20a2c BREAKING CHANGE(ts_interfaces/platformservice/mta): Rename mta interfaces and upgrade dependency versions 2025-04-25 15:57:35 +00:00
820cdfcd48 4.13.0
Some checks failed
Docker (tags) / security (push) Successful in 52s
Docker (tags) / test (push) Successful in 3m5s
Docker (tags) / metadata (push) Successful in 8s
Docker (tags) / release (push) Failing after 22s
2025-01-20 02:18:58 +01:00
6e5dd9b05a feat(service): Add support for service creation, update, and deletion. 2025-01-20 02:18:58 +01:00
f3d5c21fab 4.12.2
Some checks failed
Docker (tags) / security (push) Successful in 1m6s
Docker (tags) / test (push) Successful in 3m5s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 24s
2025-01-20 02:11:12 +01:00
04b278ee28 fix(service): Fix secret bundle and service management bugs 2025-01-20 02:11:12 +01:00
7084d76c43 4.12.1
Some checks failed
Docker (tags) / security (push) Successful in 51s
Docker (tags) / test (push) Successful in 2m53s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 20s
2025-01-02 04:07:43 +01:00
41d7550e89 fix(deps): Updated @git.zone/tspublish to version ^1.9.1 2025-01-02 04:07:43 +01:00
4bf361d3a6 4.12.0
Some checks failed
Docker (tags) / security (push) Successful in 1m1s
Docker (tags) / test (push) Successful in 2m57s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 31s
2025-01-02 03:58:09 +01:00
d70617a90c feat(cli): Add CLI support and external registries view 2025-01-02 03:58:09 +01:00
62ad1655d5 4.11.0
Some checks failed
Docker (tags) / security (push) Successful in 1m7s
Docker (tags) / test (push) Successful in 3m0s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 23s
2024-12-30 00:01:27 +01:00
caf3a095f2 feat(external-registry): Introduce external registry management 2024-12-30 00:01:26 +01:00
89e44b2e5f 4.10.0
Some checks failed
Docker (tags) / security (push) Successful in 1m3s
Docker (tags) / test (push) Successful in 2m59s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 22s
2024-12-29 13:40:51 +01:00
a617f51b19 feat(apiclient): Added support for managing external registries in the API client. 2024-12-29 13:40:51 +01:00
355e04fd1d 4.9.0
Some checks failed
Docker (tags) / security (push) Successful in 1m6s
Docker (tags) / test (push) Successful in 3m2s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 30s
2024-12-29 13:19:46 +01:00
89bd767bea feat(apiclient): Add external registry management capabilities to Cloudly API client. 2024-12-29 13:19:46 +01:00
e567ebbf21 4.8.1
Some checks failed
Docker (tags) / security (push) Successful in 53s
Docker (tags) / test (push) Successful in 2m58s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 22s
2024-12-28 21:48:57 +01:00
33311348e2 fix(interfaces): Fix image location schema in IImage interface 2024-12-28 21:48:57 +01:00
d6e914edab 4.8.0
Some checks failed
Docker (tags) / security (push) Successful in 1m5s
Docker (tags) / test (push) Successful in 2m58s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 22s
2024-12-28 21:39:44 +01:00
da7b866f23 feat(manager.registry): Add external registry management 2024-12-28 21:39:44 +01:00
7654d780b1 4.7.1
Some checks failed
Docker (tags) / security (push) Successful in 1m10s
Docker (tags) / test (push) Successful in 3m1s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 23s
2024-12-28 19:50:30 +01:00
dbd9b661c6 fix(secretmanagement): Refactor secret bundle actions and improve authorization handling 2024-12-28 19:50:29 +01:00
e19d0b4deb 4.7.0
Some checks failed
Docker (tags) / security (push) Successful in 53s
Docker (tags) / test (push) Successful in 3m3s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 22s
2024-12-22 20:09:23 +01:00
f0ebb719f7 feat(apiclient): Add method to flatten secret bundles into key-value objects. 2024-12-22 20:09:23 +01:00
c8e0666bc6 4.6.0
Some checks failed
Docker (tags) / security (push) Successful in 54s
Docker (tags) / test (push) Successful in 3m0s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 23s
2024-12-22 20:03:11 +01:00
0d0b106f90 feat(cloudlyapiclient): Extend CloudlyApiClient with cluster, secretbundle, and secretgroup methods 2024-12-22 20:03:11 +01:00
c9073df7cd 4.5.5
Some checks failed
Docker (tags) / security (push) Successful in 1m4s
Docker (tags) / test (push) Successful in 3m0s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 23s
2024-12-22 19:55:56 +01:00
f65200703d fix(apiclient): Fixed image creation method in cloudlyApiClient 2024-12-22 19:55:56 +01:00
57970b3d10 4.5.4
Some checks failed
Docker (tags) / security (push) Successful in 1m6s
Docker (tags) / test (push) Successful in 2m58s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 23s
2024-12-21 22:14:45 +01:00
b4d9f40c41 fix(ts_web): Fix action type and data fields in appstate for CRUD operations 2024-12-21 22:14:45 +01:00
44 changed files with 3976 additions and 2403 deletions

View File

@ -1,5 +1,124 @@
# Changelog # Changelog
## 2025-04-25 - 5.0.4 - fix(platformservice/mta)
Update getEmailStatus response schema: make details property optional
- Changed details property from required with fixed message to optional with a flexible message structure in IReq_GetEMailStats response
## 2025-04-25 - 5.0.3 - fix(mta)
update email status response type in MTA platform service
- Changed the response 'status' field in IRequest_CheckEmailStatus from a literal 'unknown' to a generic string for improved flexibility
## 2025-04-25 - 5.0.2 - fix(platformservice/mta)
Refactor email status response in MTA service
- Updated IReq_CheckEmailStatus response: replaced union type ('ok' | 'not ok') with fixed status 'unknown' and added a details object with message 'Email not found'.
## 2025-04-25 - 5.0.1 - fix(mta)
Update email stats response interface in mta platform service to include totalEmailsSent, totalEmailsDelivered, totalEmailsBounced, averageDeliveryTimeMs, and lastUpdated timestamp.
- Modified IReq_GetEMailStats response in ts_interfaces/platformservice/mta.ts from an empty status object to a detailed email statistics structure.
## 2025-04-25 - 5.0.0 - BREAKING CHANGE(ts_interfaces/platformservice/mta)
Rename mta interfaces and upgrade dependency versions
- Upgraded devDependencies: @git.zone/tsbuild, tsbundle, tsdoc, tstest, tswatch, and @push.rocks/tapbundle to newer versions.
- Upgraded dependencies: @design.estate/dees-catalog, dees-domtools, dees-element, @push.rocks/smartdata, smartexpect, smartfile, smartpromise, smartrequest, smartrx, and tsclass (v4.2.0 to v9.0.0).
- Added new packageManager field in package.json and introduced pnpm-workspace.yaml for additional workspace configuration.
- Refactored mta API interfaces: renamed IRequest_SendEmail to IReq_SendEmail and IRequestRegisterRecipient to IReq_RegisterRecipient; added IReq_CheckEmailStatus and IReq_GetEMailStats.
## 2025-01-20 - 4.13.0 - feat(service)
Add support for service creation, update, and deletion.
- Implemented TypedHandlers for creating a new service.
- Added features to update existing service details.
- Enabled deletion of services by their unique ID.
## 2025-01-20 - 4.12.2 - fix(service)
Fix secret bundle and service management bugs
- Corrected the field name from 'includedImages' to 'imageClaims' in secret bundles.
- Implemented 'getFlatKeyValueObject' for secret bundles and modified related API interactions.
- Enhanced the Service class with methods for handling secret bundle data by resolving related groups and environments.
## 2025-01-02 - 4.12.1 - fix(deps)
Updated @git.zone/tspublish to version ^1.9.1
## 2025-01-02 - 4.12.0 - feat(cli)
Add CLI support and external registries view
- Adds CLI client functionality
- Introduces a new view for External Registries in the dashboard
## 2024-12-30 - 4.11.0 - feat(external-registry)
Introduce external registry management
- Added ExternalRegistryManager to handle external registry operations.
- Implemented ability to create, retrieve, and delete external registries.
- Enhanced Cloudly class to include ExternalRegistryManager.
## 2024-12-29 - 4.10.0 - feat(apiclient)
Added support for managing external registries in the API client.
- Introduced methods to get a registry by ID, get all registries, and create a new registry in the externalRegistry object.
- Updated external registry request interfaces to match new API client capabilities.
## 2024-12-29 - 4.9.0 - feat(apiclient)
Add external registry management capabilities to Cloudly API client.
- Introduce ExternalRegistry class with methods for getting, creating, and updating external registries.
- Expand requests module to handle external registry management, including creation and deletion.
## 2024-12-28 - 4.8.1 - fix(interfaces)
Fix image location schema in IImage interface
- Refactored the 'external' object within IImage data to a 'location' object.
- Added 'internal' boolean to 'location' to specify internal/external status.
## 2024-12-28 - 4.8.0 - feat(manager.registry)
Add external registry management
- Introduced ExternalRegistry class for handling external registry configurations.
- Updated IExternalRegistry interface to include registry details.
- Enhanced IImage interface to support linking with external registries.
## 2024-12-28 - 4.7.1 - fix(secretmanagement)
Refactor secret bundle actions and improve authorization handling
- Refactored secret bundle handling by renaming methods and reorganizing static and instance methods in SecretBundle class.
- Added getSecretBundleByAuthorization method to SecretBundle.
- Improved getFlatKeyValueObjectForEnvironment to accurately retrieve key-value pairs for specified environments.
- Removed deprecated IEnvBundle interface and related request handler for better clarity and code usage.
- Updated request interfaces related to secret bundles for consistent method naming and arguments.
## 2024-12-22 - 4.7.0 - feat(apiclient)
Add method to flatten secret bundles into key-value objects.
- SecretBundle: Implemented toFlatKeyValueObject method to flatten secret groups into key-value pairs.
- Removed stale SecretManager class from apiclient.
## 2024-12-22 - 4.6.0 - feat(cloudlyapiclient)
Extend CloudlyApiClient with cluster, secretbundle, and secretgroup methods
- Added methods to CloudlyApiClient for managing clusters: getClusterById, getClusters, createCluster.
- Added methods to CloudlyApiClient for managing secret bundles: getSecretBundleById, getSecretBundles, createSecretBundle.
- Added methods to CloudlyApiClient for managing secret groups: getSecretGroupById, getSecretGroups, createSecretGroup.
## 2024-12-22 - 4.5.5 - fix(apiclient)
Fixed image creation method in cloudlyApiClient
- Corrected method call from 'images.createImage' to 'image.createImage' to ensure proper image creation.
- Updated cluster retrieval methods and ensured proper API routes are being called.
## 2024-12-21 - 4.5.4 - fix(ts_web)
Fix action type and data fields in appstate for CRUD operations
- Correct request method in createSecretGroupAction to accurately reflect the purpose.
- Align the deleteSecretGroupAction and deleteSecretBundleAction request types with proper interfaces.
- Ensure data payload matches backend requirements for secret group and secret bundle operations.
## 2024-12-21 - 4.5.3 - fix(secret-management) ## 2024-12-21 - 4.5.3 - fix(secret-management)
Refactor secret management to use distinct secret bundle and group APIs. Introduce API client classes for secret bundles and groups. Refactor secret management to use distinct secret bundle and group APIs. Introduce API client classes for secret bundles and groups.

View File

@ -1,6 +1,6 @@
{ {
"name": "@serve.zone/cloudly", "name": "@serve.zone/cloudly",
"version": "4.5.3", "version": "5.0.4",
"private": false, "private": false,
"description": "A comprehensive tool for managing containerized applications across multiple cloud providers using Docker Swarmkit, featuring web, CLI, and API interfaces.", "description": "A comprehensive tool for managing containerized applications across multiple cloud providers using Docker Swarmkit, featuring web, CLI, and API interfaces.",
"type": "module", "type": "module",
@ -22,27 +22,27 @@
"docs": "tsdoc aidoc" "docs": "tsdoc aidoc"
}, },
"devDependencies": { "devDependencies": {
"@git.zone/tsbuild": "^2.2.0", "@git.zone/tsbuild": "^2.3.2",
"@git.zone/tsbundle": "^2.1.0", "@git.zone/tsbundle": "^2.2.5",
"@git.zone/tsdoc": "^1.4.2", "@git.zone/tsdoc": "^1.4.4",
"@git.zone/tspublish": "^1.7.7", "@git.zone/tspublish": "^1.9.1",
"@git.zone/tstest": "^1.0.90", "@git.zone/tstest": "^1.0.96",
"@git.zone/tswatch": "^2.0.37", "@git.zone/tswatch": "^2.1.0",
"@push.rocks/tapbundle": "^5.5.3", "@push.rocks/tapbundle": "^5.6.3",
"@types/node": "^22.10.2" "@types/node": "^22.15.2"
}, },
"dependencies": { "dependencies": {
"@api.global/typedrequest": "3.1.10", "@api.global/typedrequest": "3.1.10",
"@api.global/typedrequest-interfaces": "^3.0.19", "@api.global/typedrequest-interfaces": "^3.0.19",
"@api.global/typedserver": "^3.0.51", "@api.global/typedserver": "^3.0.74",
"@api.global/typedsocket": "^3.0.1", "@api.global/typedsocket": "^3.0.1",
"@apiclient.xyz/cloudflare": "^6.0.1", "@apiclient.xyz/cloudflare": "^6.0.1",
"@apiclient.xyz/docker": "^1.2.7", "@apiclient.xyz/docker": "^1.3.0",
"@apiclient.xyz/hetznercloud": "^1.2.0", "@apiclient.xyz/hetznercloud": "^1.2.0",
"@apiclient.xyz/slack": "^3.0.9", "@apiclient.xyz/slack": "^3.0.9",
"@design.estate/dees-catalog": "^1.3.2", "@design.estate/dees-catalog": "^1.8.0",
"@design.estate/dees-domtools": "^2.0.64", "@design.estate/dees-domtools": "^2.3.2",
"@design.estate/dees-element": "^2.0.39", "@design.estate/dees-element": "^2.0.42",
"@git.zone/tsrun": "^1.3.3", "@git.zone/tsrun": "^1.3.3",
"@push.rocks/early": "^4.0.3", "@push.rocks/early": "^4.0.3",
"@push.rocks/npmextra": "^5.1.2", "@push.rocks/npmextra": "^5.1.2",
@ -52,11 +52,11 @@
"@push.rocks/smartbucket": "^3.3.7", "@push.rocks/smartbucket": "^3.3.7",
"@push.rocks/smartcli": "^4.0.11", "@push.rocks/smartcli": "^4.0.11",
"@push.rocks/smartclickhouse": "^2.0.17", "@push.rocks/smartclickhouse": "^2.0.17",
"@push.rocks/smartdata": "^5.2.10", "@push.rocks/smartdata": "^5.15.1",
"@push.rocks/smartdelay": "^3.0.5", "@push.rocks/smartdelay": "^3.0.5",
"@push.rocks/smartexit": "^1.0.23", "@push.rocks/smartexit": "^1.0.23",
"@push.rocks/smartexpect": "^1.2.1", "@push.rocks/smartexpect": "^1.6.1",
"@push.rocks/smartfile": "^11.0.23", "@push.rocks/smartfile": "^11.2.0",
"@push.rocks/smartguard": "^3.1.0", "@push.rocks/smartguard": "^3.1.0",
"@push.rocks/smartjson": "^5.0.19", "@push.rocks/smartjson": "^5.0.19",
"@push.rocks/smartjwt": "^2.2.1", "@push.rocks/smartjwt": "^2.2.1",
@ -64,9 +64,9 @@
"@push.rocks/smartlog-destination-clickhouse": "^1.0.13", "@push.rocks/smartlog-destination-clickhouse": "^1.0.13",
"@push.rocks/smartlog-interfaces": "^3.0.2", "@push.rocks/smartlog-interfaces": "^3.0.2",
"@push.rocks/smartpath": "^5.0.18", "@push.rocks/smartpath": "^5.0.18",
"@push.rocks/smartpromise": "^4.0.4", "@push.rocks/smartpromise": "^4.2.3",
"@push.rocks/smartrequest": "^2.0.23", "@push.rocks/smartrequest": "^2.1.0",
"@push.rocks/smartrx": "^3.0.7", "@push.rocks/smartrx": "^3.0.10",
"@push.rocks/smartssh": "^2.0.1", "@push.rocks/smartssh": "^2.0.1",
"@push.rocks/smartstate": "^2.0.19", "@push.rocks/smartstate": "^2.0.19",
"@push.rocks/smartstream": "^3.2.5", "@push.rocks/smartstream": "^3.2.5",
@ -74,7 +74,7 @@
"@push.rocks/smartunique": "^3.0.9", "@push.rocks/smartunique": "^3.0.9",
"@push.rocks/taskbuffer": "^3.0.2", "@push.rocks/taskbuffer": "^3.0.2",
"@push.rocks/webjwt": "^1.0.9", "@push.rocks/webjwt": "^1.0.9",
"@tsclass/tsclass": "^4.2.0" "@tsclass/tsclass": "^9.0.0"
}, },
"files": [ "files": [
"ts/**/*", "ts/**/*",
@ -126,5 +126,6 @@
"frontend", "frontend",
"backend", "backend",
"security" "security"
] ],
"packageManager": "pnpm@10.7.0+sha512.6b865ad4b62a1d9842b61d674a393903b871d9244954f652b8842c2b553c72176b278f64c463e52d40fff8aba385c235c8c9ecf5cc7de4fd78b8bb6d49633ab6"
} }

5048
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

4
pnpm-workspace.yaml Normal file
View File

@ -0,0 +1,4 @@
onlyBuiltDependencies:
- esbuild
- mongodb-memory-server
- puppeteer

View File

@ -57,7 +57,7 @@ tap.test('should get an identity', async () => {
let image: Image; let image: Image;
tap.test('should create and upload an image', async () => { tap.test('should create and upload an image', async () => {
image = await testClient.images.createImage({ image = await testClient.image.createImage({
name: 'test', name: 'test',
description: 'test' description: 'test'
}); });

View File

@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@serve.zone/cloudly', name: '@serve.zone/cloudly',
version: '4.5.3', version: '5.0.4',
description: 'A comprehensive tool for managing containerized applications across multiple cloud providers using Docker Swarmkit, featuring web, CLI, and API interfaces.' description: 'A comprehensive tool for managing containerized applications across multiple cloud providers using Docker Swarmkit, featuring web, CLI, and API interfaces.'
} }

View File

@ -63,7 +63,7 @@ for (let i = 0; i < demoSecretGroups.length; i++) {
id: `configBundleId${i + 1}`, id: `configBundleId${i + 1}`,
data: { data: {
name: `Demo Config Bundle ${i + 1}`, name: `Demo Config Bundle ${i + 1}`,
includedImages: [], imageClaims: [],
type: 'external', type: 'external',
description: 'Demo Purpose', description: 'Demo Purpose',
includedSecretGroupIds: [secretGroup.id], includedSecretGroupIds: [secretGroup.id],

View File

@ -20,6 +20,7 @@ import { CloudlyTaskmanager } from './manager.task/taskmanager.js';
import { CloudlySecretManager } from './manager.secret/classes.secretmanager.js'; import { CloudlySecretManager } from './manager.secret/classes.secretmanager.js';
import { CloudlyServerManager } from './manager.server/classes.servermanager.js'; import { CloudlyServerManager } from './manager.server/classes.servermanager.js';
import { ExternalApiManager } from './manager.status/statusmanager.js'; import { ExternalApiManager } from './manager.status/statusmanager.js';
import { ExternalRegistryManager } from './manager.externalregistry/index.js';
import { ImageManager } from './manager.image/classes.imagemanager.js'; import { ImageManager } from './manager.image/classes.imagemanager.js';
import { logger } from './logger.js'; import { logger } from './logger.js';
import { CloudlyAuthManager } from './manager.auth/classes.authmanager.js'; import { CloudlyAuthManager } from './manager.auth/classes.authmanager.js';
@ -54,6 +55,7 @@ export class Cloudly {
public clusterManager: ClusterManager; public clusterManager: ClusterManager;
public coreflowManager: CloudlyCoreflowManager; public coreflowManager: CloudlyCoreflowManager;
public externalApiManager: ExternalApiManager; public externalApiManager: ExternalApiManager;
public externalRegistryManager: ExternalRegistryManager;
public imageManager: ImageManager; public imageManager: ImageManager;
public taskManager: CloudlyTaskmanager; public taskManager: CloudlyTaskmanager;
public serverManager: CloudlyServerManager; public serverManager: CloudlyServerManager;
@ -80,6 +82,7 @@ export class Cloudly {
this.clusterManager = new ClusterManager(this); this.clusterManager = new ClusterManager(this);
this.coreflowManager = new CloudlyCoreflowManager(this); this.coreflowManager = new CloudlyCoreflowManager(this);
this.externalApiManager = new ExternalApiManager(this); this.externalApiManager = new ExternalApiManager(this);
this.externalRegistryManager = new ExternalRegistryManager(this);
this.imageManager = new ImageManager(this); this.imageManager = new ImageManager(this);
this.taskManager = new CloudlyTaskmanager(this); this.taskManager = new CloudlyTaskmanager(this);
this.secretManager = new CloudlySecretManager(this); this.secretManager = new CloudlySecretManager(this);

View File

@ -38,13 +38,13 @@ export class ClusterManager {
console.log(await cluster.createSavableObject()); console.log(await cluster.createSavableObject());
this.cloudlyRef.serverManager.ensureServerInfrastructure(); this.cloudlyRef.serverManager.ensureServerInfrastructure();
return { return {
clusterConfig: await cluster.createSavableObject(), cluster: await cluster.createSavableObject(),
}; };
}), }),
); );
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.cluster.IRequest_GetAllClusters>( this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.cluster.IReq_Any_Cloudly_GetClusters>(
new plugins.typedrequest.TypedHandler('getAllClusters', async (dataArg) => { new plugins.typedrequest.TypedHandler('getClusters', async (dataArg) => {
// TODO: do authentication here // TODO: do authentication here
const clusters = await this.getAllClusters(); const clusters = await this.getAllClusters();
return { return {
@ -56,12 +56,12 @@ export class ClusterManager {
); );
// delete cluster // delete cluster
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.cluster.IRequest_DeleteCluster>( this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.cluster.IReq_Any_Cloudly_DeleteClusterById>(
new plugins.typedrequest.TypedHandler('deleteCluster', async (reqDataArg, toolsArg) => { new plugins.typedrequest.TypedHandler('deleteClusterById', async (reqDataArg, toolsArg) => {
await toolsArg.passGuards([this.cloudlyRef.authManager.adminIdentityGuard], reqDataArg); await toolsArg.passGuards([this.cloudlyRef.authManager.adminIdentityGuard], reqDataArg);
await this.deleteCluster(reqDataArg.clusterId); await this.deleteCluster(reqDataArg.clusterId);
return { return {
success: true, ok: true,
}; };
}), }),
); );

View File

@ -0,0 +1,40 @@
import * as plugins from '../plugins.js';
import * as paths from '../paths.js';
import type { Cloudly } from 'ts/classes.cloudly.js';
import type { ExternalRegistryManager } from './classes.externalregistrymanager.js';
export class ExternalRegistry extends plugins.smartdata.SmartDataDbDoc<ExternalRegistry, plugins.servezoneInterfaces.data.IExternalRegistry, ExternalRegistryManager> {
// STATIC
public static async getRegistryById(registryIdArg: string) {
const externalRegistry = await this.getInstance({
id: registryIdArg,
});
return externalRegistry;
}
public static async getRegistries() {
const externalRegistries = await this.getInstances({});
return externalRegistries;
}
public static async createExternalRegistry(registryDataArg: Partial<plugins.servezoneInterfaces.data.IExternalRegistry['data']>) {
const externalRegistry = new ExternalRegistry();
externalRegistry.id = await ExternalRegistry.getNewId();
Object.assign(externalRegistry, registryDataArg);
await externalRegistry.save();
return externalRegistry;
}
// INSTANCE
@plugins.smartdata.svDb()
public id: string;
@plugins.smartdata.svDb()
public data: plugins.servezoneInterfaces.data.IExternalRegistry['data'];
constructor() {
super();
}
}

View File

@ -0,0 +1,51 @@
import * as plugins from '../plugins.js';
import { Cloudly } from '../classes.cloudly.js';
import { ExternalRegistry } from './classes.externalregistry.js';
export class ExternalRegistryManager {
public cloudlyRef: Cloudly;
public typedrouter = new plugins.typedrequest.TypedRouter();
public CExternalRegistry = plugins.smartdata.setDefaultManagerForDoc(this, ExternalRegistry);
get db() {
return this.cloudlyRef.mongodbConnector.smartdataDb;
}
constructor(cloudlyRef: Cloudly) {
this.cloudlyRef = cloudlyRef;
}
public async start() {
// lets set up a typedrouter
this.typedrouter.addTypedRouter(this.typedrouter);
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.externalRegistry.IReq_GetRegistryById>(
new plugins.typedrequest.TypedHandler('getExternalRegistryById', async (dataArg) => {
const registry = await ExternalRegistry.getRegistryById(dataArg.id);
return {
registry: await registry.createSavableObject(),
};
})
);
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.externalRegistry.IReq_GetRegistries>(
new plugins.typedrequest.TypedHandler('getExternalRegistries', async (dataArg) => {
const registries = await ExternalRegistry.getRegistries();
return {
registries: await Promise.all(
registries.map((registry) => registry.createSavableObject())
),
};
})
);
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.externalRegistry.IReq_CreateRegistry>(
new plugins.typedrequest.TypedHandler('createExternalRegistry', async (dataArg) => {
const registry = await ExternalRegistry.createExternalRegistry(dataArg.registryData);
return {
registry: await registry.createSavableObject(),
};
})
);
}
}

View File

@ -0,0 +1,2 @@
export * from './classes.externalregistrymanager.js';
export * from './classes.externalregistry.js';

View File

@ -59,4 +59,16 @@ export class SecretBundle extends plugins.smartdata.SmartDataDbDoc<
} }
return returnObject; return returnObject;
} }
public async getFlatKeyValueObject(environmentArg: string) {
if (!environmentArg) {
throw new Error('environment is required');
}
const secretGroups = await this.getSecretGroups();
const returnObject = {};
for (const secretGroup of secretGroups) {
returnObject[secretGroup.data.key] = secretGroup.data.environments[environmentArg].value;
}
return returnObject;
}
} }

View File

@ -148,30 +148,26 @@ export class CloudlySecretManager {
); );
this.typedrouter.addTypedHandler( this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.secretbundle.IReq_GetEnvBundle>( new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.secretbundle.IReq_GetFlatKeyValueObject>(
'getEnvBundle', 'getFlatKeyValueObject',
async (dataArg) => { async (dataArg) => {
const wantedBundle = await SecretBundle.getInstance({ const wantedBundle = await SecretBundle.getInstance({
data: { data: {
authorizations: { authorizations: {
// @ts-ignore // @ts-ignore
$elemMatch: { $elemMatch: {
secretAccessKey: dataArg.authorization, secretAccessKey: dataArg.secretBundleAuthorization.secretAccessKey,
}, },
}, },
}, },
}); });
const authorization = await wantedBundle.getAuthorizationFromAuthKey( const authorization = await wantedBundle.getAuthorizationFromAuthKey(
dataArg.authorization, dataArg.secretBundleAuthorization.secretAccessKey,
); );
return { return {
envBundle: { flatKeyValueObject: await wantedBundle.getKeyValueObjectForEnvironment(
configKeyValueObject: await wantedBundle.getKeyValueObjectForEnvironment( authorization.environment,
authorization.environment, ),
),
environment: authorization.environment,
timeSensitive: false,
},
}; };
}, },
), ),

View File

@ -1,3 +1,4 @@
import { SecretBundle } from 'ts/manager.secret/classes.secretbundle.js';
import * as plugins from '../plugins.js'; import * as plugins from '../plugins.js';
import { ServiceManager } from './classes.servicemanager.js'; import { ServiceManager } from './classes.servicemanager.js';
@ -6,9 +7,51 @@ export class Service extends plugins.smartdata.SmartDataDbDoc<
plugins.servezoneInterfaces.data.IService, plugins.servezoneInterfaces.data.IService,
ServiceManager ServiceManager
> { > {
// STATIC
public static async getServiceById(serviceIdArg: string) {
const service = await this.getInstance({
id: serviceIdArg,
});
return service;
}
public static async getServices() {
const services = await this.getInstances({});
return services;
}
public static async createService(serviceDataArg: Partial<plugins.servezoneInterfaces.data.IService['data']>) {
const service = new Service();
service.id = await Service.getNewId();
Object.assign(service, serviceDataArg);
await service.save();
return service;
}
// INSTANCE
@plugins.smartdata.svDb() @plugins.smartdata.svDb()
public id: string; public id: string;
@plugins.smartdata.svDb() @plugins.smartdata.svDb()
public data: plugins.servezoneInterfaces.data.IService['data']; public data: plugins.servezoneInterfaces.data.IService['data'];
/**
* a service runs in a specific environment
* so -> this method returns the secret bundles as a flat object accordingly.
* in other words, it resolves secret groups for the relevant environment
* @param environmentArg
*/
public async getSecretBundlesAsFlatObject(environmentArg: string = 'production') {
const secreBundleIds = this.data.additionalSecretBundleIds || [];
secreBundleIds.push(this.data.secretBundleId); // put this last, so it overwrites any other secret bundles.
let finalFlatObject = {};
for (const secretBundleId of secreBundleIds) {
const secretBundle = await SecretBundle.getInstance({
id: secretBundleId,
});
const flatObject = await secretBundle.getFlatKeyValueObject(environmentArg);
Object.assign(finalFlatObject, flatObject);
}
return finalFlatObject;
}
} }

View File

@ -35,5 +35,66 @@ export class ServiceManager {
} }
) )
); );
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.service.IRequest_Any_Cloudly_GetServiceSecretBundlesAsFlatObject>(
'getServiceSecretBundlesAsFlatObject',
async (dataArg) => {
const service = await Service.getInstance({
id: dataArg.serviceId,
});
const flatKeyValueObject = await service.getSecretBundlesAsFlatObject(dataArg.environment);
return {
flatKeyValueObject: flatKeyValueObject,
};
}
)
);
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.service.IRequest_Any_Cloudly_CreateService>(
'createService',
async (dataArg) => {
const service = await Service.createService(dataArg.serviceData);
return {
service: await service.createSavableObject(),
};
}
)
);
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.service.IRequest_Any_Cloudly_UpdateService>(
'updateService',
async (dataArg) => {
const service = await Service.getInstance({
id: dataArg.serviceId,
});
service.data = {
...service.data,
...dataArg.serviceData,
};
await service.save();
return {
service: await service.createSavableObject(),
};
}
)
);
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.service.IRequest_Any_Cloudly_DeleteServiceById>(
'deleteServiceById',
async (dataArg) => {
const service = await Service.getInstance({
id: dataArg.serviceId,
});
await service.delete();
return {
success: true,
};
}
)
);
} }
} }

View File

@ -4,6 +4,10 @@ export type TClientType = 'api' | 'ci' | 'coreflow' | 'cli' | 'serverconfig';
import { Image } from './classes.image.js'; import { Image } from './classes.image.js';
import { Service } from './classes.service.js'; import { Service } from './classes.service.js';
import { Cluster } from './classes.cluster.js';
import { SecretBundle } from './classes.secretbundle.js';
import { SecretGroup } from './classes.secretgroup.js';
import { ExternalRegistry } from './classes.externalregistry.js';
export class CloudlyApiClient { export class CloudlyApiClient {
private cloudlyUrl: string; private cloudlyUrl: string;
@ -156,7 +160,20 @@ export class CloudlyApiClient {
return typedResponse.certificate; return typedResponse.certificate;
} }
public images = { public externalRegistry = {
// ExternalRegistry
getRegistryById: async (registryNameArg: string) => {
return ExternalRegistry.getExternalRegistryById(this, registryNameArg);
},
getRegistries: async () => {
return ExternalRegistry.getExternalRegistries(this);
},
createRegistry: async (optionsArg: Parameters<typeof ExternalRegistry.createExternalRegistry>[1]) => {
return ExternalRegistry.createExternalRegistry(this, optionsArg);
}
}
public image = {
// Images // Images
getImageById: async (imageIdArg: string) => { getImageById: async (imageIdArg: string) => {
return Image.getImageById(this, imageIdArg); return Image.getImageById(this, imageIdArg);
@ -181,4 +198,43 @@ export class CloudlyApiClient {
return Service.createService(this, optionsArg); return Service.createService(this, optionsArg);
} }
} }
public cluster = {
// Clusters
getClusterById: async (clusterIdArg: string) => {
return Cluster.getClusterById(this, clusterIdArg);
},
getClusters: async () => {
return Cluster.getClusters(this);
},
createCluster: async (optionsArg: Parameters<typeof Cluster.createCluster>[1]) => {
return Cluster.createCluster(this, optionsArg);
}
}
public secretbundle = {
// SecretBundles
getSecretBundleById: async (secretBundleIdArg: string) => {
return SecretBundle.getSecretBundleById(this, secretBundleIdArg);
},
getSecretBundles: async () => {
return SecretBundle.getSecretBundles(this);
},
createSecretBundle: async (optionsArg: Parameters<typeof SecretBundle.createSecretBundle>[1]) => {
return SecretBundle.createSecretBundle(this, optionsArg);
}
}
public secretgroup = {
// SecretGroups
getSecretGroupById: async (secretGroupIdArg: string) => {
return SecretGroup.getSecretGroupById(this, secretGroupIdArg);
},
getSecretGroups: async () => {
return SecretGroup.getSecretGroups(this);
},
createSecretGroup: async (optionsArg: Parameters<typeof SecretGroup.createSecretGroup>[1]) => {
return SecretGroup.createSecretGroup(this, optionsArg);
}
}
} }

View File

@ -1,6 +1,84 @@
import { CloudlyApiClient } from './classes.cloudlyapiclient.js';
import * as plugins from './plugins.js'; import * as plugins from './plugins.js';
export class Cluster { export class Cluster implements plugins.servezoneInterfaces.data.ICluster {
public getServers() {} // STATIC
public static async getClusterById(cloudlyClientRef: CloudlyApiClient, clusterIdArg: string) {
const getClusterByIdTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.cluster.IReq_Any_Cloudly_GetClusterById>(
'getClusterById'
);
const response = await getClusterByIdTR.fire({
identity: cloudlyClientRef.identity,
clusterId: clusterIdArg,
});
const newCluster = new Cluster(cloudlyClientRef);
Object.assign(newCluster, response.cluster);
return newCluster;
}
public static async getClusters(cloudlyClientRef: CloudlyApiClient) {
const getClustersTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.cluster.IReq_Any_Cloudly_GetClusters>(
'getClusters'
);
const response = await getClustersTR.fire({
identity: cloudlyClientRef.identity,
});
const clusterConfigs: Cluster[] = [];
for (const clusterConfig of response.clusters) {
const newCluster = new Cluster(cloudlyClientRef);
Object.assign(newCluster, clusterConfig);
clusterConfigs.push(newCluster);
}
return clusterConfigs;
}
public static async createCluster(cloudlyClientRef: CloudlyApiClient, clusterNameArg: string) {
const createClusterTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.cluster.IRequest_CreateCluster>(
'createCluster'
);
const response = await createClusterTR.fire({
identity: cloudlyClientRef.identity,
clusterName: clusterNameArg,
});
const newCluster = new Cluster(cloudlyClientRef);
Object.assign(newCluster, response.cluster);
return newCluster;
}
// INSTANCE
public id: string;
public data: plugins.servezoneInterfaces.data.ICluster['data'];
public cloudlyClientRef: CloudlyApiClient;
constructor(cloudlyClientRef: CloudlyApiClient) {
this.cloudlyClientRef = cloudlyClientRef;
}
public async update() {
const updateClusterTR = this.cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.cluster.IReq_Any_Cloudly_UpdateCluster>(
'updateCluster'
);
const response = await updateClusterTR.fire({
identity: this.cloudlyClientRef.identity,
clusterData: this.data,
});
const resultClusterData = response.resultCluster.data;
plugins.smartexpect.expect(resultClusterData).toEqual(this.data);
return this;
}
public async delete(cloudlyClientRef: CloudlyApiClient, clusterIdArg: string) {
const deleteClusterTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.cluster.IReq_Any_Cloudly_DeleteClusterById>(
'deleteClusterById'
);
const response = await deleteClusterTR.fire({
identity: cloudlyClientRef.identity,
clusterId: this.id,
});
plugins.smartexpect.expect(response.ok).toBeTrue();
return null;
}
} }

View File

@ -0,0 +1,83 @@
import * as plugins from './plugins.js';
import type { CloudlyApiClient } from './classes.cloudlyapiclient.js';
export class ExternalRegistry implements plugins.servezoneInterfaces.data.IExternalRegistry {
// STATIC
public static async getExternalRegistryById(cloudlyClientRef: CloudlyApiClient, registryNameArg: string) {
const getRegistryByIdTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.externalRegistry.IReq_GetRegistryById>(
'getExternalRegistryById'
);
const response = await getRegistryByIdTR.fire({
identity: cloudlyClientRef.identity,
id: registryNameArg,
});
const newRegistry = new ExternalRegistry(cloudlyClientRef);
Object.assign(newRegistry, response.registry);
return newRegistry;
}
public static async getExternalRegistries(cloudlyClientRef: CloudlyApiClient) {
const getRegistriesTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.externalRegistry.IReq_GetRegistries>(
'getExternalRegistries'
);
const response = await getRegistriesTR.fire({
identity: cloudlyClientRef.identity,
});
const registryConfigs: ExternalRegistry[] = [];
for (const registryConfig of response.registries) {
const newRegistry = new ExternalRegistry(cloudlyClientRef);
Object.assign(newRegistry, registryConfig);
registryConfigs.push(newRegistry);
}
return registryConfigs;
}
public static async createExternalRegistry(cloudlyClientRef: CloudlyApiClient, registryDataArg: Partial<plugins.servezoneInterfaces.data.IExternalRegistry['data']>) {
const createRegistryTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.externalRegistry.IReq_CreateRegistry>(
'createExternalRegistry'
);
const response = await createRegistryTR.fire({
identity: cloudlyClientRef.identity,
registryData: registryDataArg as plugins.servezoneInterfaces.data.IExternalRegistry['data'],
});
const newRegistry = new ExternalRegistry(cloudlyClientRef);
Object.assign(newRegistry, response.registry);
return newRegistry;
}
// INSTANCE
public id: string;
public data: plugins.servezoneInterfaces.data.IExternalRegistry['data'];
public cloudlyClientRef: CloudlyApiClient;
constructor(cloudlyClientRef: CloudlyApiClient) {
this.cloudlyClientRef = cloudlyClientRef;
}
public async update() {
const updateRegistryTR = this.cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.externalRegistry.IReq_UpdateRegistry>(
'updateExternalRegistry'
);
const response = await updateRegistryTR.fire({
identity: this.cloudlyClientRef.identity,
registryData: this.data,
});
const resultRegistryData = response.resultRegistry.data;
plugins.smartexpect.expect(resultRegistryData).toEqual(this.data);
return this;
}
public async delete(cloudlyClientRef: CloudlyApiClient, registryIdArg: string) {
const deleteRegistryTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.externalRegistry.IReq_DeleteRegistryById>(
'deleteExternalRegistryById'
);
const response = await deleteRegistryTR.fire({
identity: cloudlyClientRef.identity,
registryId: this.id,
});
plugins.smartexpect.expect(response.ok).toBeTrue();
return null;
}
}

View File

@ -1,16 +1,9 @@
import * as plugins from './plugins.js'; import * as plugins from './plugins.js';
import type { CloudlyApiClient } from './classes.cloudlyapiclient.js'; import type { CloudlyApiClient } from './classes.cloudlyapiclient.js';
import { SecretGroup } from './classes.secretgroup.js';
export class SecretBundle implements plugins.servezoneInterfaces.data.ISecretBundle { export class SecretBundle implements plugins.servezoneInterfaces.data.ISecretBundle {
public cloudlyClientRef: CloudlyApiClient; // STATIC
public id: string;
public data: plugins.servezoneInterfaces.data.ISecretBundle['data'];
constructor(cloudlyClientRef: CloudlyApiClient) {
this.cloudlyClientRef = cloudlyClientRef;
}
public static async getSecretBundleById(cloudlyClientRef: CloudlyApiClient, secretBundleIdArg: string) { public static async getSecretBundleById(cloudlyClientRef: CloudlyApiClient, secretBundleIdArg: string) {
const getSecretBundleByIdTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretbundle.IReq_GetSecretBundleById>( const getSecretBundleByIdTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretbundle.IReq_GetSecretBundleById>(
'getSecretBundleById' 'getSecretBundleById'
@ -24,6 +17,19 @@ export class SecretBundle implements plugins.servezoneInterfaces.data.ISecretBun
return newSecretBundle; return newSecretBundle;
} }
public static async getSecretBundleByAuthorization(cloudlyClientRef: CloudlyApiClient, secretBundleAuthorizationArg: plugins.servezoneInterfaces.data.ISecretBundleAuthorization) {
const getSecretBundleByAuthorizationTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretbundle.IReq_GetSecretBundleByAuthorization>(
'getSecretBundleByAuthorization'
);
const response = await getSecretBundleByAuthorizationTR.fire({
identity: cloudlyClientRef.identity,
secretBundleAuthorization: secretBundleAuthorizationArg,
});
const newSecretBundle = new SecretBundle(cloudlyClientRef);
Object.assign(newSecretBundle, response.secretBundle);
return newSecretBundle;
}
public static async getSecretBundles(cloudlyClientRef: CloudlyApiClient) { public static async getSecretBundles(cloudlyClientRef: CloudlyApiClient) {
const getSecretBundlesTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretbundle.IReq_GetSecretBundles>( const getSecretBundlesTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretbundle.IReq_GetSecretBundles>(
'getSecretBundles' 'getSecretBundles'
@ -53,7 +59,7 @@ export class SecretBundle implements plugins.servezoneInterfaces.data.ISecretBun
description: secretBundleDataArg.description, description: secretBundleDataArg.description,
type: secretBundleDataArg.type, type: secretBundleDataArg.type,
authorizations: secretBundleDataArg.authorizations, authorizations: secretBundleDataArg.authorizations,
includedImages: secretBundleDataArg.includedImages, imageClaims: secretBundleDataArg.imageClaims,
includedSecretGroupIds: secretBundleDataArg.includedSecretGroupIds, includedSecretGroupIds: secretBundleDataArg.includedSecretGroupIds,
includedTags: secretBundleDataArg.includedTags, includedTags: secretBundleDataArg.includedTags,
}, },
@ -64,6 +70,17 @@ export class SecretBundle implements plugins.servezoneInterfaces.data.ISecretBun
return newSecretBundle; return newSecretBundle;
} }
// INSTANCE
public cloudlyClientRef: CloudlyApiClient;
public id: string;
public data: plugins.servezoneInterfaces.data.ISecretBundle['data'];
constructor(cloudlyClientRef: CloudlyApiClient) {
this.cloudlyClientRef = cloudlyClientRef;
}
public async update() { public async update() {
const updateSecretBundleTR = this.cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretbundle.IReq_UpdateSecretBundle>( const updateSecretBundleTR = this.cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretbundle.IReq_UpdateSecretBundle>(
'updateSecretBundle' 'updateSecretBundle'
@ -93,4 +110,26 @@ export class SecretBundle implements plugins.servezoneInterfaces.data.ISecretBun
plugins.smartexpect.expect(response.ok).toBeTrue(); plugins.smartexpect.expect(response.ok).toBeTrue();
return null; return null;
} }
public async getFlatKeyValueObjectForEnvironment(environmentArg: string = 'production') {
const bundleAuthorization = this.data.authorizations.find(authorization => {
return authorization.environment === environmentArg;
});
if (bundleAuthorization) {
throw new Error(`no matching environment >>${environmentArg} found in secret bundle`);
}
const getFlatKeyValueObjectTR = this.cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretbundle.IReq_GetFlatKeyValueObject>(
'getFlatKeyValueObject'
);
const response = await getFlatKeyValueObjectTR.fire({
identity: this.cloudlyClientRef.identity,
seccretBundleId: this.id,
secretBundleAuthorization: bundleAuthorization,
});
const flatKeyValueObject: {[key: string]: string} = response.flatKeyValueObject;
return flatKeyValueObject;
}
} }

View File

@ -72,14 +72,7 @@ export class SecretGroup implements plugins.servezoneInterfaces.data.ISecretGrou
identity: this.cloudlyClientRef.identity, identity: this.cloudlyClientRef.identity,
secretGroup: { secretGroup: {
id: this.id, id: this.id,
data: { data: this.data,
name: this.data.name,
description: this.data.description,
environments: this.data.environments,
key: this.data.key,
tags: this.data.tags,
priority: this.data.priority,
},
}, },
}); });

View File

@ -1,27 +0,0 @@
import * as plugins from './plugins.js';
import type { CloudlyApiClient } from './classes.cloudlyapiclient.js';
import { SecretBundle } from './classes.secretbundle.js';
import { SecretGroup } from './classes.secretgroup.js';
export class SecretManager {
// INSTANCE
cloudlyClientRef: CloudlyApiClient;
constructor(cloudlyClientRef: CloudlyApiClient) {
this.cloudlyClientRef = cloudlyClientRef;
}
public async getSecretGroupsAndBundles() {
}
/**
* The secret group has a secret bundle.
* This function essentially returns the secret bundle as a flat object.
* In other words, it resolves secret groups and
*/
public async getSecretBundleAsFlatObject(environmentArg: string = 'production') {
}
}

View File

@ -40,19 +40,7 @@ export class Service implements plugins.servezoneInterfaces.data.IService {
); );
const response = await createServiceTR.fire({ const response = await createServiceTR.fire({
identity: cloudlyClientRef.identity, identity: cloudlyClientRef.identity,
name: serviceDataArg.name, serviceData: serviceDataArg as plugins.servezoneInterfaces.data.IService['data'],
description: serviceDataArg.description,
imageId: serviceDataArg.imageId,
imageVersion: serviceDataArg.imageVersion,
environment: {},
secretBundleId: null,
scaleFactor: 1,
balancingStrategy: serviceDataArg.balancingStrategy,
ports: {
web: null,
},
resources: serviceDataArg.resources,
domains: [],
}); });
const newService = new Service(cloudlyClientRef); const newService = new Service(cloudlyClientRef);
Object.assign(newService, response.service); Object.assign(newService, response.service);
@ -75,6 +63,16 @@ export class Service implements plugins.servezoneInterfaces.data.IService {
* In other words, it resolves secret groups and * In other words, it resolves secret groups and
*/ */
public async getSecretBundleAsFlatObject(environmentArg: string = 'production') { public async getSecretBundleAsFlatObject(environmentArg: string = 'production') {
const getServiceSecretBundlesAsFlatObjectTR = this.cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.service.IRequest_Any_Cloudly_GetServiceSecretBundlesAsFlatObject>(
'getServiceSecretBundlesAsFlatObject'
);
const response = await getServiceSecretBundlesAsFlatObjectTR.fire({
identity: this.cloudlyClientRef.identity,
serviceId: this.id,
environment: environmentArg,
});
const flatKeyValueObject: {[key: string]: string} = response.flatKeyValueObject;
return flatKeyValueObject;
} }
} }

View File

@ -0,0 +1,15 @@
import * as plugins from './plugins.js';
import { CloudlyApiClient } from '@serve.zone/api';
export class CliClient {
public cloudlyApiClient: CloudlyApiClient;
constructor(cloudlyApiClientArg: CloudlyApiClient) {
this.cloudlyApiClient = cloudlyApiClientArg;
}
public async getClusters() {
const clusters = await this.cloudlyApiClient.cluster.getClusters();
console.log(clusters);
}
}

View File

@ -1 +1,11 @@
console.log('this is the cli client.'); import * as plugins from './plugins.js';
import { CliClient } from "./classes.cliclient.js";
export const runCli = async () => {
const cliQenv = new plugins.qenv.Qenv();
const apiClient = new plugins.servezoneApi.CloudlyApiClient({
registerAs: 'cli',
cloudlyUrl: await cliQenv.getEnvVarOnDemand('CLOUDLY_URL'),
});
const cliClient = new CliClient(apiClient);
};

17
ts_cliclient/plugins.ts Normal file
View File

@ -0,0 +1,17 @@
// @serve.zone scope
import * as servezoneApi from '@serve.zone/api';
import * as servezoneInterfaces from '@serve.zone/interfaces';
export {
servezoneApi,
servezoneInterfaces
}
// @push.rocks scope
import * as projectinfo from '@push.rocks/projectinfo';
import * as qenv from '@push.rocks/qenv';
export {
projectinfo,
qenv,
}

View File

@ -1,8 +1,15 @@
{ {
"name": "@serve.zone/cli", "name": "@serve.zone/cli",
"dependencies": [], "dependencies": [
"@serve.zone/api",
"@serve.zone/interfaces",
"@push.rocks/projectinfo",
"@push.rocks/qenv",
"@push.rocks/smartcli"
],
"registries": [ "registries": [
"registry.npmjs.org:public", "registry.npmjs.org:public",
"verdaccio.lossless.digital:public" "verdaccio.lossless.digital:public"
] ],
"bin": ["servezone"]
} }

View File

@ -1,6 +0,0 @@
export interface IEnvBundle {
environment: string;
timeSensitive: boolean;
configKeyValueObject: {[key: string]: string};
}

View File

@ -0,0 +1,12 @@
import * as plugins from '../plugins.js';
export interface IExternalRegistry {
id: string;
data: {
type: 'docker' | 'npm';
name: string;
url: string;
username: string;
password: string;
};
}

View File

@ -4,6 +4,11 @@ export interface IImage {
id: string; id: string;
data: { data: {
name: string; name: string;
location: {
internal: boolean;
externalRegistryId: string;
externalImageTag: string;
}
description: string; description: string;
versions: Array<{ versions: Array<{
versionString: string; versionString: string;

View File

@ -3,8 +3,8 @@ export * from './cluster.js';
export * from './config.js'; export * from './config.js';
export * from './deployment.js'; export * from './deployment.js';
export * from './docker.js'; export * from './docker.js';
export * from './env.js';
export * from './event.js'; export * from './event.js';
export * from './externalregistry.js';
export * from './image.js'; export * from './image.js';
export * from './secretbundle.js'; export * from './secretbundle.js';
export * from './secretgroup.js' export * from './secretgroup.js'

View File

@ -21,13 +21,19 @@ export interface ISecretBundle {
*/ */
type: 'service' | 'npmci' | 'gitzone' | 'external'; type: 'service' | 'npmci' | 'gitzone' | 'external';
/**
* set this if the secretBundle belongs to a service
*/
serviceId?: string;
/** /**
* You can add specific secret groups using this * You can add specific secret groups using this
*/ */
includedSecretGroupIds: string[]; includedSecretGroupIds: string[];
/** /**
* You can add specific tags using this * access to this secretBundle also grants access to resources with matching tags
*/ */
includedTags: { includedTags: {
key: string; key: string;
@ -35,19 +41,21 @@ export interface ISecretBundle {
}[]; }[];
/** /**
* add images * access to this secretBundle also grants access to the images
*/ */
includedImages: { imageClaims: {
imageId: string; imageId: string;
permissions: ('read' | 'write')[]; permissions: ('read' | 'write')[];
}[]; }[];
/** /**
* authrozations select a specific environment of a config bundle * authrozations select a specific environment of a config bundle
*/ */
authorizations: Array<{ authorizations: Array<ISecretBundleAuthorization>;
secretAccessKey: string;
environment: string;
}>;
}; };
} }
export interface ISecretBundleAuthorization {
secretAccessKey: string;
environment: string;
}

View File

@ -8,7 +8,15 @@ export interface IService {
imageId: string; imageId: string;
imageVersion: string; imageVersion: string;
environment: { [key: string]: string }; environment: { [key: string]: string };
/**
* the main secret bundle id, exclusive to the service
*/
secretBundleId: string; secretBundleId: string;
/**
* those secret bundle ids do not belong to the service itself
* and thus live past the service lifecycle
*/
additionalSecretBundleIds?: string[];
scaleFactor: number; scaleFactor: number;
balancingStrategy: 'round-robin' | 'least-connections'; balancingStrategy: 'round-robin' | 'least-connections';
ports: { ports: {

View File

@ -2,9 +2,9 @@ import * as plugins from '../plugins.js';
export type TTemplates = 'default' | 'linkaction' | 'notification'; export type TTemplates = 'default' | 'linkaction' | 'notification';
export interface IRequest_SendEmail extends plugins.typedrequestInterfaces.implementsTR< export interface IReq_SendEmail extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest, plugins.typedrequestInterfaces.ITypedRequest,
IRequest_SendEmail IReq_SendEmail
> { > {
method: 'sendEmail'; method: 'sendEmail';
request: { request: {
@ -25,9 +25,9 @@ export interface IRequest_SendEmail extends plugins.typedrequestInterfaces.imple
}; };
} }
export interface IRequestRegisterRecipient extends plugins.typedrequestInterfaces.implementsTR< export interface IReq_RegisterRecipient extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest, plugins.typedrequestInterfaces.ITypedRequest,
IRequestRegisterRecipient IReq_RegisterRecipient
> { > {
method: 'registerRecepient'; method: 'registerRecepient';
request: { request: {
@ -37,3 +37,34 @@ export interface IRequestRegisterRecipient extends plugins.typedrequestInterface
status: 'ok' | 'not ok'; status: 'ok' | 'not ok';
}; };
} }
export interface IReq_CheckEmailStatus extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_CheckEmailStatus
> {
method: 'checkEmailStatus';
request: {
emailId: string;
};
response: {
status: string,
details?: { message: string; }
};
}
export interface IReq_GetEMailStats extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_GetEMailStats
> {
method: 'getEmailStats';
request: {
jwt: string;
};
response: {
totalEmailsSent: number;
totalEmailsDelivered: number;
totalEmailsBounced: number;
averageDeliveryTimeMs: number;
lastUpdated: string;
};
}

View File

@ -5,11 +5,11 @@ import * as plugins from '../plugins.js';
/** /**
* get all clusters * get all clusters
*/ */
export interface IRequest_GetAllClusters extends plugins.typedrequestInterfaces.implementsTR< export interface IReq_Any_Cloudly_GetClusters extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest, plugins.typedrequestInterfaces.ITypedRequest,
IRequest_GetAllClusters IReq_Any_Cloudly_GetClusters
> { > {
method: 'getAllClusters'; method: 'getClusters';
request: { request: {
identity: userInterfaces.IIdentity; identity: userInterfaces.IIdentity;
}; };
@ -18,6 +18,21 @@ export interface IRequest_GetAllClusters extends plugins.typedrequestInterfaces.
}; };
} }
export interface IReq_Any_Cloudly_GetClusterById
extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_Any_Cloudly_GetClusterById
> {
method: 'getClusterById';
request: {
identity: userInterfaces.IIdentity;
clusterId: string;
};
response: {
cluster: clusterInterfaces.ICluster;
};
}
export interface IRequest_CreateCluster extends plugins.typedrequestInterfaces.implementsTR< export interface IRequest_CreateCluster extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest, plugins.typedrequestInterfaces.ITypedRequest,
IRequest_CreateCluster IRequest_CreateCluster
@ -28,40 +43,40 @@ export interface IRequest_CreateCluster extends plugins.typedrequestInterfaces.i
clusterName: string; clusterName: string;
}; };
response: { response: {
clusterConfig: clusterInterfaces.ICluster; cluster: clusterInterfaces.ICluster;
}; };
} }
/** /**
* updates a cluster * updates a cluster
*/ */
export interface IRequest_UpdateCluster extends plugins.typedrequestInterfaces.implementsTR< export interface IReq_Any_Cloudly_UpdateCluster extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest, plugins.typedrequestInterfaces.ITypedRequest,
IRequest_UpdateCluster IReq_Any_Cloudly_UpdateCluster
> { > {
method: 'updateCluster'; method: 'updateCluster';
request: { request: {
identity: userInterfaces.IIdentity; identity: userInterfaces.IIdentity;
clusterConfig: clusterInterfaces.ICluster; clusterData: clusterInterfaces.ICluster['data'];
}; };
response: { response: {
clusterConfig: clusterInterfaces.ICluster; resultCluster: clusterInterfaces.ICluster;
}; };
} }
/** /**
* deletes a cluster * deletes a cluster
*/ */
export interface IRequest_DeleteCluster extends plugins.typedrequestInterfaces.implementsTR< export interface IReq_Any_Cloudly_DeleteClusterById extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest, plugins.typedrequestInterfaces.ITypedRequest,
IRequest_DeleteCluster IReq_Any_Cloudly_DeleteClusterById
> { > {
method: 'deleteCluster'; method: 'deleteClusterById';
request: { request: {
identity: userInterfaces.IIdentity; identity: userInterfaces.IIdentity;
clusterId: string; clusterId: string;
}; };
response: { response: {
success: boolean; ok: boolean;
}; };
} }

View File

@ -0,0 +1,72 @@
import * as plugins from '../plugins.js';
import * as data from '../data/index.js';
import * as userInterfaces from '../data/user.js';
export interface IReq_GetRegistryById extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_GetRegistryById
> {
method: 'getExternalRegistryById';
request: {
identity: userInterfaces.IIdentity;
id: string;
};
response: {
registry: data.IExternalRegistry;
};
}
export interface IReq_GetRegistries extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_GetRegistries
> {
method: 'getExternalRegistries';
request: {
identity: userInterfaces.IIdentity;
};
response: {
registries: data.IExternalRegistry[];
};
}
export interface IReq_CreateRegistry extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_CreateRegistry
> {
method: 'createExternalRegistry';
request: {
identity: userInterfaces.IIdentity;
registryData: data.IExternalRegistry['data'];
};
response: {
registry: data.IExternalRegistry;
};
}
export interface IReq_UpdateRegistry extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_UpdateRegistry
> {
method: 'updateExternalRegistry';
request: {
identity: userInterfaces.IIdentity;
registryData: data.IExternalRegistry['data'];
};
response: {
resultRegistry: data.IExternalRegistry;
};
}
export interface IReq_DeleteRegistryById extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_DeleteRegistryById
> {
method: 'deleteExternalRegistryById';
request: {
identity: userInterfaces.IIdentity;
registryId: string;
};
response: {
ok: boolean;
};
}

View File

@ -4,6 +4,7 @@ import * as adminRequests from './admin.js';
import * as certificateRequests from './certificate.js'; import * as certificateRequests from './certificate.js';
import * as clusterRequests from './cluster.js'; import * as clusterRequests from './cluster.js';
import * as configRequests from './config.js'; import * as configRequests from './config.js';
import * as externalRegistryRequests from './externalregistry.js';
import * as identityRequests from './identity.js'; import * as identityRequests from './identity.js';
import * as imageRequests from './image.js'; import * as imageRequests from './image.js';
import * as informRequests from './inform.js'; import * as informRequests from './inform.js';
@ -22,6 +23,7 @@ export {
certificateRequests as certificate, certificateRequests as certificate,
clusterRequests as cluster, clusterRequests as cluster,
configRequests as config, configRequests as config,
externalRegistryRequests as externalRegistry,
identityRequests as identity, identityRequests as identity,
imageRequests as image, imageRequests as image,
informRequests as inform, informRequests as inform,

View File

@ -2,26 +2,6 @@ import * as plugins from '../plugins.js';
import * as data from '../data/index.js'; import * as data from '../data/index.js';
import * as userInterfaces from '../data/user.js'; import * as userInterfaces from '../data/user.js';
/**
* when retrieving secrets for actual use, you do this in the form of an envBundle.
*/
export interface IReq_GetEnvBundle extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_GetEnvBundle
> {
method: 'getEnvBundle';
request: {
authorization: string;
/**
* specify this if you want to get a warning, if the envBundle is for an unexpected environment
*/
environment?: string;
};
response: {
envBundle: data.IEnvBundle;
};
}
export interface IReq_GetSecretBundles extends plugins.typedrequestInterfaces.implementsTR< export interface IReq_GetSecretBundles extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest, plugins.typedrequestInterfaces.ITypedRequest,
IReq_GetSecretBundles IReq_GetSecretBundles
@ -36,6 +16,21 @@ export interface IReq_GetSecretBundles extends plugins.typedrequestInterfaces.im
} }
export interface IReq_GetSecretBundleById extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_GetSecretBundleById
> {
method: 'getSecretBundleById';
request: {
identity: userInterfaces.IIdentity;
secretBundleId: string;
};
response: {
secretBundle: data.ISecretBundle;
};
}
export interface IReq_CreateSecretBundle extends plugins.typedrequestInterfaces.implementsTR< export interface IReq_CreateSecretBundle extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest, plugins.typedrequestInterfaces.ITypedRequest,
IReq_CreateSecretBundle IReq_CreateSecretBundle
@ -77,3 +72,32 @@ export interface IReq_DeleteSecretBundleById extends plugins.typedrequestInterfa
ok: boolean; ok: boolean;
}; };
} }
export interface IReq_GetSecretBundleByAuthorization extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_GetSecretBundleByAuthorization
> {
method: 'getSecretBundleByAuthorization';
request: {
identity: userInterfaces.IIdentity;
secretBundleAuthorization: data.ISecretBundleAuthorization;
};
response: {
secretBundle: data.ISecretBundle;
};
}
export interface IReq_GetFlatKeyValueObject extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_GetFlatKeyValueObject
> {
method: 'getFlatKeyValueObject';
request: {
identity: userInterfaces.IIdentity;
seccretBundleId: string;
secretBundleAuthorization: data.ISecretBundleAuthorization;
};
response: {
flatKeyValueObject: {[key: string]: string};
};
}

View File

@ -40,24 +40,7 @@ extends plugins.typedrequestInterfaces.implementsTR<
method: 'createService'; method: 'createService';
request: { request: {
identity: IIdentity; identity: IIdentity;
name: string; serviceData: IService['data'];
description: string;
imageId: string;
imageVersion: string;
environment: { [key: string]: string };
secretBundleId: string;
scaleFactor: number;
balancingStrategy: 'round-robin' | 'least-connections';
ports: {
web: number;
custom?: { [domain: string]: string };
};
resources?: IServiceRessources;
domains: {
name: string;
port?: number;
protocol?: 'http' | 'https' | 'ssh';
}[];
}; };
response: { response: {
service: IService; service: IService;
@ -73,36 +56,19 @@ extends plugins.typedrequestInterfaces.implementsTR<
request: { request: {
identity: IIdentity; identity: IIdentity;
serviceId: string; serviceId: string;
name: string; serviceData: IService['data'];
description: string;
imageId: string;
imageVersion: string;
environment: { [key: string]: string };
secretBundleId: string;
scaleFactor: number;
balancingStrategy: 'round-robin' | 'least-connections';
ports: {
web: number;
custom?: { [domain: string]: string };
};
resources?: IServiceRessources;
domains: {
name: string;
port?: number;
protocol?: 'http' | 'https' | 'ssh';
}[];
}; };
response: { response: {
service: IService; service: IService;
}; };
} }
export interface IRequest_Any_Cloudly_DeleteService export interface IRequest_Any_Cloudly_DeleteServiceById
extends plugins.typedrequestInterfaces.implementsTR< extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest, plugins.typedrequestInterfaces.ITypedRequest,
IRequest_Any_Cloudly_DeleteService IRequest_Any_Cloudly_DeleteServiceById
> { > {
method: 'deleteService'; method: 'deleteServiceById';
request: { request: {
identity: IIdentity; identity: IIdentity;
serviceId: string; serviceId: string;
@ -111,3 +77,19 @@ extends plugins.typedrequestInterfaces.implementsTR<
success: boolean; success: boolean;
}; };
} }
export interface IRequest_Any_Cloudly_GetServiceSecretBundlesAsFlatObject
extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_Any_Cloudly_GetServiceSecretBundlesAsFlatObject
> {
method: 'getServiceSecretBundlesAsFlatObject';
request: {
identity: IIdentity;
serviceId: string;
environment: string;
};
response: {
flatKeyValueObject: {[key: string]: string};
};
}

View File

@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@serve.zone/cloudly', name: '@serve.zone/cloudly',
version: '4.5.3', version: '5.0.4',
description: 'A comprehensive tool for managing containerized applications across multiple cloud providers using Docker Swarmkit, featuring web, CLI, and API interfaces.' description: 'A comprehensive tool for managing containerized applications across multiple cloud providers using Docker Swarmkit, featuring web, CLI, and API interfaces.'
} }

View File

@ -123,9 +123,9 @@ export const getAllDataAction = dataState.createAction(async (statePartArg) => {
// Clusters // Clusters
const trGetClusters = const trGetClusters =
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.cluster.IRequest_GetAllClusters>( new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.cluster.IReq_Any_Cloudly_GetClusters>(
'/typedrequest', '/typedrequest',
'getAllClusters' 'getClusters'
); );
const responseClusters = await trGetClusters.fire({ const responseClusters = await trGetClusters.fire({
identity: loginStatePart.getState().identity, identity: loginStatePart.getState().identity,
@ -144,14 +144,13 @@ export const createSecretGroupAction = dataState.createAction(
async (statePartArg, payloadArg: plugins.interfaces.data.ISecretGroup) => { async (statePartArg, payloadArg: plugins.interfaces.data.ISecretGroup) => {
let currentState = statePartArg.getState(); let currentState = statePartArg.getState();
const trCreateSecretGroup = const trCreateSecretGroup =
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secret.IReq_Admin_CreateSecretBundlesAndGroups>( new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secretgroup.IReq_CreateSecretGroup>(
'/typedrequest', '/typedrequest',
'adminCreateSecretBundlesAndGroups' 'createSecretGroup'
); );
const response = await trCreateSecretGroup.fire({ const response = await trCreateSecretGroup.fire({
identity: loginStatePart.getState().identity, identity: loginStatePart.getState().identity,
secretBundles: [], secretGroup: payloadArg,
secretGroups: [payloadArg],
}); });
currentState = await dataState.dispatchAction(getAllDataAction, null); currentState = await dataState.dispatchAction(getAllDataAction, null);
return currentState; return currentState;
@ -163,14 +162,13 @@ export const deleteSecretGroupAction = dataState.createAction(
async (statePartArg, payloadArg: { secretGroupId: string }) => { async (statePartArg, payloadArg: { secretGroupId: string }) => {
let currentState = statePartArg.getState(); let currentState = statePartArg.getState();
const trDeleteSecretGroup = const trDeleteSecretGroup =
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secret.IReq_Admin_DeleteSecretBundlesAndGroups>( new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secretgroup.IReq_DeleteSecretGroupById>(
'/typedrequest', '/typedrequest',
'adminDeleteConfigBundlesAndSecretGroups' 'deleteSecretGroupById'
); );
const response = await trDeleteSecretGroup.fire({ const response = await trDeleteSecretGroup.fire({
identity: loginStatePart.getState().identity, identity: loginStatePart.getState().identity,
secretBundleIds: [], secretGroupId: payloadArg.secretGroupId,
secretGroupIds: [payloadArg.secretGroupId],
}); });
currentState = await dataState.dispatchAction(getAllDataAction, null); currentState = await dataState.dispatchAction(getAllDataAction, null);
return currentState; return currentState;
@ -182,14 +180,13 @@ export const deleteSecretBundleAction = dataState.createAction(
async (statePartArg, payloadArg: { configBundleId: string }) => { async (statePartArg, payloadArg: { configBundleId: string }) => {
let currentState = statePartArg.getState(); let currentState = statePartArg.getState();
const trDeleteConfigBundle = const trDeleteConfigBundle =
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secret.IReq_Admin_DeleteSecretBundlesAndGroups>( new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secretbundle.IReq_DeleteSecretBundleById>(
'/typedrequest', '/typedrequest',
'adminDeleteConfigBundlesAndSecretGroups' 'deleteSecretBundleById'
); );
const response = await trDeleteConfigBundle.fire({ const response = await trDeleteConfigBundle.fire({
identity: loginStatePart.getState().identity, identity: loginStatePart.getState().identity,
secretBundleIds: [payloadArg.configBundleId], secretBundleId: payloadArg.configBundleId,
secretGroupIds: [],
}); });
currentState = await dataState.dispatchAction(getAllDataAction, null); currentState = await dataState.dispatchAction(getAllDataAction, null);
return currentState; return currentState;
@ -263,7 +260,7 @@ export const addClusterAction = dataState.createAction(
currentState = { currentState = {
...currentState, ...currentState,
...{ ...{
clusters: [...currentState.clusters, response.clusterConfig], clusters: [...currentState.clusters, response.cluster],
}, },
} }
return currentState; return currentState;

View File

@ -24,6 +24,7 @@ import { CloudlyViewS3 } from './cloudly-view-s3.js';
import { CloudlyViewSecretBundles } from './cloudly-view-secretbundles.js'; import { CloudlyViewSecretBundles } from './cloudly-view-secretbundles.js';
import { CloudlyViewSecretGroups } from './cloudly-view-secretgroups.js'; import { CloudlyViewSecretGroups } from './cloudly-view-secretgroups.js';
import { CloudlyViewServices } from './cloudly-view-services.js'; import { CloudlyViewServices } from './cloudly-view-services.js';
import { CloudlyViewExternalRegistries } from './cloudly-view-externalregistries.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@ -89,6 +90,10 @@ export class CloudlyDashboard extends DeesElement {
name: 'Clusters', name: 'Clusters',
element: CloudlyViewClusters, element: CloudlyViewClusters,
}, },
{
name: 'ExternalRegistries',
element: CloudlyViewExternalRegistries,
},
{ {
name: 'Images', name: 'Images',
element: CloudlyViewImages, element: CloudlyViewImages,

View File

@ -0,0 +1,129 @@
import * as plugins from '../plugins.js';
import * as shared from '../elements/shared/index.js';
import {
DeesElement,
customElement,
html,
state,
css,
cssManager,
} from '@design.estate/dees-element';
import * as appstate from '../appstate.js';
@customElement('cloudly-view-externalregistries')
export class CloudlyViewExternalRegistries extends DeesElement {
@state()
private data: appstate.IDataState = {
secretGroups: [],
secretBundles: [],
};
constructor() {
super();
const subecription = appstate.dataState
.select((stateArg) => stateArg)
.subscribe((dataArg) => {
this.data = dataArg;
});
this.rxSubscriptions.push(subecription);
}
public static styles = [
cssManager.defaultStyles,
shared.viewHostCss,
css`
`,
];
public render() {
return html`
<cloudly-sectionheading>External Registries</cloudly-sectionheading>
<dees-table
.heading1=${'External Registries'}
.heading2=${'decoded in client'}
.data=${this.data.deployments}
.displayFunction=${(itemArg: plugins.interfaces.data.ICluster) => {
return {
id: itemArg.id,
serverAmount: itemArg.data.servers.length,
};
}}
.dataActions=${[
{
name: 'add configBundle',
iconName: 'plus',
type: ['header', 'footer'],
actionFunc: async (dataActionArg) => {
const modal = await plugins.deesCatalog.DeesModal.createAndShow({
heading: 'Add ConfigBundle',
content: html`
<dees-form>
<dees-input-text .key=${'id'} .label=${'ID'} .value=${''}></dees-input-text>
<dees-input-text
.key=${'data.secretGroupIds'}
.label=${'secretGroupIds'}
.value=${''}
></dees-input-text>
<dees-input-text
.key=${'data.includedTags'}
.label=${'includedTags'}
.value=${''}
></dees-input-text>
</dees-form>
`,
menuOptions: [
{ name: 'create', action: async (modalArg) => {} },
{
name: 'cancel',
action: async (modalArg) => {
modalArg.destroy();
},
},
],
});
},
},
{
name: 'delete',
iconName: 'trash',
type: ['contextmenu', 'inRow'],
actionFunc: async (actionDataArg) => {
plugins.deesCatalog.DeesModal.createAndShow({
heading: `Delete ConfigBundle ${actionDataArg.item.id}`,
content: html`
<div style="text-align:center">
Do you really want to delete the ConfigBundle?
</div>
<div
style="font-size: 0.8em; color: red; text-align:center; padding: 16px; margin-top: 24px; border: 1px solid #444; font-family: Intel One Mono; font-size: 16px;"
>
${actionDataArg.item.id}
</div>
`,
menuOptions: [
{
name: 'cancel',
action: async (modalArg) => {
await modalArg.destroy();
},
},
{
name: 'delete',
action: async (modalArg) => {
appstate.dataState.dispatchAction(appstate.deleteSecretBundleAction, {
configBundleId: actionDataArg.item.id,
});
await modalArg.destroy();
},
},
],
});
},
},
] as plugins.deesCatalog.ITableAction[]}
></dees-table>
`;
}
}

View File

@ -18,11 +18,28 @@ export class CloudlySectionheading extends DeesElement {
public static styles = [ public static styles = [
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
:host {
display: grid;
grid-template-columns: min-content min-content;
}
h1 { h1 {
font-family: 'Cal Sans'; font-family: 'Cal Sans';
letter-spacing: 0.025em; letter-spacing: 0.025em;
margin: 0px; margin: 0px;
margin-bottom: 16px; margin-bottom: 16px;
white-space: nowrap;
}
.flag {
border-radius: 4px;
background: #8a0183;
height: 20px;
padding: 2px 4px;
margin-left: 16px;
font-size: 12px;
transform: translateY(12px);
white-space: nowrap;
} }
`, `,
] ]
@ -30,6 +47,7 @@ export class CloudlySectionheading extends DeesElement {
public render() { public render() {
return html` return html`
<h1><slot></slot></h1> <h1><slot></slot></h1>
<div class="flag">stability: alpha</div>
`; `;
} }
} }