Compare commits

...

36 Commits

Author SHA1 Message Date
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
a219725ff6 4.5.3
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 23m54s
2024-12-21 20:21:54 +01:00
4b993fc6b3 fix(secret-management): Refactor secret management to use distinct secret bundle and group APIs. Introduce API client classes for secret bundles and groups. 2024-12-21 20:21:54 +01:00
d453da709f 4.5.2
Some checks failed
Docker (tags) / security (push) Successful in 1m4s
Docker (tags) / test (push) Successful in 2m58s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 23m21s
2024-12-20 02:13:50 +01:00
50fac41c95 fix(apiclient): Implemented IService interface in Service class and improved secret bundle documentation. 2024-12-20 02:13:50 +01:00
affce1fcd1 4.5.1
Some checks failed
Docker (tags) / security (push) Successful in 1m4s
Docker (tags) / test (push) Successful in 3m4s
Docker (tags) / metadata (push) Successful in 7s
Docker (tags) / release (push) Failing after 16s
2024-12-17 19:51:11 +01:00
df67ebd27a fix(core): Updated dependencies in package.json to latest versions. 2024-12-17 19:51:10 +01:00
47 changed files with 4553 additions and 2555 deletions

View File

@ -1,5 +1,126 @@
# Changelog
## 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)
Refactor secret management to use distinct secret bundle and group APIs. Introduce API client classes for secret bundles and groups.
- Updated secret management logic to separate secret bundle and group APIs.
- Implemented new API client classes for managing secret bundles and groups.
- Fixed incorrect method usages for secret-related actions.
## 2024-12-20 - 4.5.2 - fix(apiclient)
Implemented IService interface in Service class and improved secret bundle documentation.
- Implemented plugins.servezoneInterfaces.data.IService interface in the Service class within ts_apiclient.
- Updated documentation comments for the type property in the ISecretBundle interface.
## 2024-12-17 - 4.5.1 - fix(core)
Updated dependencies in package.json to latest versions.
- Bumped @git.zone/tswatch to version ^2.0.37
- Bumped @types/node to version ^22.10.2
- Bumped @design.estate/dees-catalog to version ^1.3.2
- Bumped @push.rocks/smartfile to version ^11.0.23
- Bumped @tsclass/tsclass to version ^4.2.0
## 2024-12-14 - 4.5.0 - feat(services)
Add service management functionalities

View File

@ -1,6 +1,6 @@
{
"name": "@serve.zone/cloudly",
"version": "4.5.0",
"version": "5.0.0",
"private": false,
"description": "A comprehensive tool for managing containerized applications across multiple cloud providers using Docker Swarmkit, featuring web, CLI, and API interfaces.",
"type": "module",
@ -22,27 +22,27 @@
"docs": "tsdoc aidoc"
},
"devDependencies": {
"@git.zone/tsbuild": "^2.2.0",
"@git.zone/tsbundle": "^2.1.0",
"@git.zone/tsdoc": "^1.4.2",
"@git.zone/tspublish": "^1.7.7",
"@git.zone/tstest": "^1.0.90",
"@git.zone/tswatch": "^2.0.36",
"@push.rocks/tapbundle": "^5.5.3",
"@types/node": "^22.10.1"
"@git.zone/tsbuild": "^2.3.2",
"@git.zone/tsbundle": "^2.2.5",
"@git.zone/tsdoc": "^1.4.4",
"@git.zone/tspublish": "^1.9.1",
"@git.zone/tstest": "^1.0.96",
"@git.zone/tswatch": "^2.1.0",
"@push.rocks/tapbundle": "^5.6.3",
"@types/node": "^22.15.2"
},
"dependencies": {
"@api.global/typedrequest": "3.1.10",
"@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",
"@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/slack": "^3.0.9",
"@design.estate/dees-catalog": "^1.3.1",
"@design.estate/dees-domtools": "^2.0.64",
"@design.estate/dees-element": "^2.0.39",
"@design.estate/dees-catalog": "^1.8.0",
"@design.estate/dees-domtools": "^2.3.2",
"@design.estate/dees-element": "^2.0.42",
"@git.zone/tsrun": "^1.3.3",
"@push.rocks/early": "^4.0.3",
"@push.rocks/npmextra": "^5.1.2",
@ -52,11 +52,11 @@
"@push.rocks/smartbucket": "^3.3.7",
"@push.rocks/smartcli": "^4.0.11",
"@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/smartexit": "^1.0.23",
"@push.rocks/smartexpect": "^1.2.1",
"@push.rocks/smartfile": "^11.0.21",
"@push.rocks/smartexpect": "^1.6.1",
"@push.rocks/smartfile": "^11.2.0",
"@push.rocks/smartguard": "^3.1.0",
"@push.rocks/smartjson": "^5.0.19",
"@push.rocks/smartjwt": "^2.2.1",
@ -64,9 +64,9 @@
"@push.rocks/smartlog-destination-clickhouse": "^1.0.13",
"@push.rocks/smartlog-interfaces": "^3.0.2",
"@push.rocks/smartpath": "^5.0.18",
"@push.rocks/smartpromise": "^4.0.4",
"@push.rocks/smartrequest": "^2.0.23",
"@push.rocks/smartrx": "^3.0.7",
"@push.rocks/smartpromise": "^4.2.3",
"@push.rocks/smartrequest": "^2.1.0",
"@push.rocks/smartrx": "^3.0.10",
"@push.rocks/smartssh": "^2.0.1",
"@push.rocks/smartstate": "^2.0.19",
"@push.rocks/smartstream": "^3.2.5",
@ -74,7 +74,7 @@
"@push.rocks/smartunique": "^3.0.9",
"@push.rocks/taskbuffer": "^3.0.2",
"@push.rocks/webjwt": "^1.0.9",
"@tsclass/tsclass": "^4.1.2"
"@tsclass/tsclass": "^9.0.0"
},
"files": [
"ts/**/*",
@ -126,5 +126,6 @@
"frontend",
"backend",
"security"
]
],
"packageManager": "pnpm@10.7.0+sha512.6b865ad4b62a1d9842b61d674a393903b871d9244954f652b8842c2b553c72176b278f64c463e52d40fff8aba385c235c8c9ecf5cc7de4fd78b8bb6d49633ab6"
}

5220
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;
tap.test('should create and upload an image', async () => {
image = await testClient.images.createImage({
image = await testClient.image.createImage({
name: 'test',
description: 'test'
});

View File

@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@serve.zone/cloudly',
version: '4.5.0',
version: '5.0.0',
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}`,
data: {
name: `Demo Config Bundle ${i + 1}`,
includedImages: [],
imageClaims: [],
type: 'external',
description: 'Demo Purpose',
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 { CloudlyServerManager } from './manager.server/classes.servermanager.js';
import { ExternalApiManager } from './manager.status/statusmanager.js';
import { ExternalRegistryManager } from './manager.externalregistry/index.js';
import { ImageManager } from './manager.image/classes.imagemanager.js';
import { logger } from './logger.js';
import { CloudlyAuthManager } from './manager.auth/classes.authmanager.js';
@ -54,6 +55,7 @@ export class Cloudly {
public clusterManager: ClusterManager;
public coreflowManager: CloudlyCoreflowManager;
public externalApiManager: ExternalApiManager;
public externalRegistryManager: ExternalRegistryManager;
public imageManager: ImageManager;
public taskManager: CloudlyTaskmanager;
public serverManager: CloudlyServerManager;
@ -80,6 +82,7 @@ export class Cloudly {
this.clusterManager = new ClusterManager(this);
this.coreflowManager = new CloudlyCoreflowManager(this);
this.externalApiManager = new ExternalApiManager(this);
this.externalRegistryManager = new ExternalRegistryManager(this);
this.imageManager = new ImageManager(this);
this.taskManager = new CloudlyTaskmanager(this);
this.secretManager = new CloudlySecretManager(this);

View File

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

@ -35,20 +35,71 @@ export class CloudlySecretManager {
this.typedrouter = new plugins.typedrequest.TypedRouter();
this.cloudlyRef.typedrouter.addTypedRouter(this.typedrouter);
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.secret.IReq_Admin_GetConfigBundlesAndSecretGroups>(
'adminGetConfigBundlesAndSecretGroups',
// secretbundle routes
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.secretbundle.IReq_GetSecretBundles>(
new plugins.typedrequest.TypedHandler(
'getSecretBundles',
async (dataArg, toolsArg) => {
await toolsArg.passGuards([this.cloudlyRef.authManager.adminIdentityGuard], dataArg);
dataArg.identity.jwt;
const secretBundles = await SecretBundle.getInstances({});
const secretGroups = await SecretGroup.getInstances({});
return {
secretBundles: [
...(await Promise.all(
secretBundles.map((configBundle) => configBundle.createSavableObject()),
)),
],
};
},
),
);
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.secretbundle.IReq_CreateSecretBundle>(
new plugins.typedrequest.TypedHandler('createSecretBundle', async (dataArg) => {
const secretBundle = new SecretBundle();
secretBundle.id = plugins.smartunique.shortId(8);
secretBundle.data = dataArg.secretBundle.data;
await secretBundle.save();
return {
resultSecretBundle: await secretBundle.createSavableObject(),
};
}),
);
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.secretbundle.IReq_UpdateSecretBundle>(
new plugins.typedrequest.TypedHandler('updateSecretBundle', async (dataArg) => {
const secretBundle = await SecretBundle.getInstance({
id: dataArg.secretBundle.id,
});
secretBundle.data = dataArg.secretBundle.data;
await secretBundle.save();
return {
resultSecretBundle: await secretBundle.createSavableObject(),
};
}),
);
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.secretbundle.IReq_DeleteSecretBundleById>(
new plugins.typedrequest.TypedHandler('deleteSecretBundleById', async (dataArg) => {
const secretBundle = await SecretBundle.getInstance({
id: dataArg.secretBundleId,
});
await secretBundle.delete();
return {
ok: true,
};
}),
);
// secretgroup routes
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.secretgroup.IReq_GetSecretGroups>(
new plugins.typedrequest.TypedHandler(
'getSecretGroups',
async (dataArg, toolsArg) => {
await toolsArg.passGuards([this.cloudlyRef.authManager.adminIdentityGuard], dataArg);
dataArg.identity.jwt;
const secretGroups = await SecretGroup.getInstances({});
return {
secretGroups: [
...(await Promise.all(
secretGroups.map((secretGroup) => secretGroup.createSavableObject()),
@ -59,73 +110,64 @@ export class CloudlySecretManager {
),
);
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.secret.IReq_Admin_CreateConfigBundlesAndSecretGroups>(
new plugins.typedrequest.TypedHandler(
'adminCreateConfigBundlesAndSecretGroups',
async (dataArg) => {
for (const secretGroupObject of dataArg.secretGroups) {
const secretGroup = new SecretGroup();
secretGroup.id = plugins.smartunique.shortId(8);
secretGroup.data = secretGroupObject.data;
await secretGroup.save();
}
return {
ok: true,
};
},
),
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.secretgroup.IReq_CreateSecretGroup>(
new plugins.typedrequest.TypedHandler('createSecretGroup', async (dataArg) => {
const secretGroup = new SecretGroup();
secretGroup.id = plugins.smartunique.shortId(8);
secretGroup.data = dataArg.secretGroup.data;
await secretGroup.save();
return {
resultSecretGroup: await secretGroup.createSavableObject(),
};
}),
);
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.secretgroup.IReq_UpdateSecretGroup>(
new plugins.typedrequest.TypedHandler('updateSecretGroup', async (dataArg) => {
const secretGroup = await SecretGroup.getInstance({
id: dataArg.secretGroup.id,
});
secretGroup.data = dataArg.secretGroup.data;
await secretGroup.save();
return {
resultSecretGroup: await secretGroup.createSavableObject(),
};
}),
);
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.secretgroup.IReq_DeleteSecretGroupById>(
new plugins.typedrequest.TypedHandler('deleteSecretGroupById', async (dataArg) => {
const secretGroup = await SecretGroup.getInstance({
id: dataArg.secretGroupId,
});
await secretGroup.delete();
return {
ok: true,
};
}),
);
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.secret.IReq_Admin_DeleteConfigBundlesAndSecretGroups>(
'adminDeleteConfigBundlesAndSecretGroups',
async (dataArg) => {
for (const secretGroupId of dataArg.secretGroupIds) {
const secretGroup = await SecretGroup.getInstance({
id: secretGroupId,
});
await secretGroup.delete();
}
for (const secretBundleId of dataArg.secretBundleIds) {
const configBundle = await SecretBundle.getInstance({
id: secretBundleId,
});
await configBundle.delete();
console.log(`deleted configbundle ${secretBundleId}`);
}
return {
ok: true,
};
},
),
);
// lets add typedrouter routes for accessing the configvailt from apps
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.secret.IReq_GetEnvBundle>(
'getEnvBundle',
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.secretbundle.IReq_GetFlatKeyValueObject>(
'getFlatKeyValueObject',
async (dataArg) => {
const wantedBundle = await SecretBundle.getInstance({
data: {
authorizations: {
// @ts-ignore
$elemMatch: {
secretAccessKey: dataArg.authorization,
secretAccessKey: dataArg.secretBundleAuthorization.secretAccessKey,
},
},
},
});
const authorization = await wantedBundle.getAuthorizationFromAuthKey(
dataArg.authorization,
dataArg.secretBundleAuthorization.secretAccessKey,
);
return {
envBundle: {
configKeyValueObject: await wantedBundle.getKeyValueObjectForEnvironment(
authorization.environment,
),
environment: authorization.environment,
timeSensitive: false,
},
flatKeyValueObject: await wantedBundle.getKeyValueObjectForEnvironment(
authorization.environment,
),
};
},
),

View File

@ -1,3 +1,4 @@
import { SecretBundle } from 'ts/manager.secret/classes.secretbundle.js';
import * as plugins from '../plugins.js';
import { ServiceManager } from './classes.servicemanager.js';
@ -6,9 +7,51 @@ export class Service extends plugins.smartdata.SmartDataDbDoc<
plugins.servezoneInterfaces.data.IService,
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()
public id: string;
@plugins.smartdata.svDb()
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 { 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 {
private cloudlyUrl: string;
@ -156,7 +160,20 @@ export class CloudlyApiClient {
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
getImageById: async (imageIdArg: string) => {
return Image.getImageById(this, imageIdArg);
@ -181,4 +198,43 @@ export class CloudlyApiClient {
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';
export class Cluster {
public getServers() {}
export class Cluster implements plugins.servezoneInterfaces.data.ICluster {
// 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

@ -0,0 +1,135 @@
import * as plugins from './plugins.js';
import type { CloudlyApiClient } from './classes.cloudlyapiclient.js';
import { SecretGroup } from './classes.secretgroup.js';
export class SecretBundle implements plugins.servezoneInterfaces.data.ISecretBundle {
// STATIC
public static async getSecretBundleById(cloudlyClientRef: CloudlyApiClient, secretBundleIdArg: string) {
const getSecretBundleByIdTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretbundle.IReq_GetSecretBundleById>(
'getSecretBundleById'
);
const response = await getSecretBundleByIdTR.fire({
identity: cloudlyClientRef.identity,
secretBundleId: secretBundleIdArg,
});
const newSecretBundle = new SecretBundle(cloudlyClientRef);
Object.assign(newSecretBundle, response.secretBundle);
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) {
const getSecretBundlesTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretbundle.IReq_GetSecretBundles>(
'getSecretBundles'
);
const response = await getSecretBundlesTR.fire({
identity: cloudlyClientRef.identity,
});
const secretBundles: SecretBundle[] = [];
for (const secretBundle of response.secretBundles) {
const newSecretBundle = new SecretBundle(cloudlyClientRef);
Object.assign(newSecretBundle, secretBundle);
secretBundles.push(newSecretBundle);
}
return secretBundles;
}
public static async createSecretBundle(cloudlyClientRef: CloudlyApiClient, secretBundleDataArg: Partial<plugins.servezoneInterfaces.data.ISecretBundle['data']>) {
const createSecretBundleTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretbundle.IReq_CreateSecretBundle>(
'createSecretBundle'
);
const response = await createSecretBundleTR.fire({
identity: cloudlyClientRef.identity,
secretBundle: {
id: null,
data: {
name: secretBundleDataArg.name,
description: secretBundleDataArg.description,
type: secretBundleDataArg.type,
authorizations: secretBundleDataArg.authorizations,
imageClaims: secretBundleDataArg.imageClaims,
includedSecretGroupIds: secretBundleDataArg.includedSecretGroupIds,
includedTags: secretBundleDataArg.includedTags,
},
},
});
const newSecretBundle = new SecretBundle(cloudlyClientRef);
Object.assign(newSecretBundle, response.resultSecretBundle);
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() {
const updateSecretBundleTR = this.cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretbundle.IReq_UpdateSecretBundle>(
'updateSecretBundle'
);
const response = await updateSecretBundleTR.fire({
identity: this.cloudlyClientRef.identity,
secretBundle: {
id: this.id,
data: this.data,
},
});
const resultSecretBundleData = response.resultSecretBundle.data;
plugins.smartexpect.expect(resultSecretBundleData).toEqual(this.data);
return this;
}
public async delete(cloudlyClientRef: CloudlyApiClient, secretBundleIdArg: string) {
const deleteSecretBundleTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretbundle.IReq_DeleteSecretBundleById>(
'deleteSecretBundleById'
);
const response = await deleteSecretBundleTR.fire({
identity: cloudlyClientRef.identity,
secretBundleId: this.id,
});
plugins.smartexpect.expect(response.ok).toBeTrue();
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

@ -0,0 +1,96 @@
import * as plugins from './plugins.js';
import type { CloudlyApiClient } from './classes.cloudlyapiclient.js';
export class SecretGroup implements plugins.servezoneInterfaces.data.ISecretGroup {
public cloudlyClientRef: CloudlyApiClient;
public id: string;
public data: plugins.servezoneInterfaces.data.ISecretGroup['data'];
constructor(cloudlyClientRef: CloudlyApiClient) {
this.cloudlyClientRef = cloudlyClientRef;
}
public static async getSecretGroupById(cloudlyClientRef: CloudlyApiClient, secretGroupIdArg: string) {
const getSecretGroupByIdTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretgroup.IReq_GetSecretGroupById>(
'getSecretGroupById'
);
const response = await getSecretGroupByIdTR.fire({
identity: cloudlyClientRef.identity,
secretGroupId: secretGroupIdArg,
});
const newSecretGroup = new SecretGroup(cloudlyClientRef);
Object.assign(newSecretGroup, response.secretGroup);
return newSecretGroup;
}
public static async getSecretGroups(cloudlyClientRef: CloudlyApiClient) {
const getSecretGroupsTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretgroup.IReq_GetSecretGroups>(
'getSecretGroups'
);
const response = await getSecretGroupsTR.fire({
identity: cloudlyClientRef.identity,
});
const secretGroups: SecretGroup[] = [];
for (const secretGroup of response.secretGroups) {
const newSecretGroup = new SecretGroup(cloudlyClientRef);
Object.assign(newSecretGroup, secretGroup);
secretGroups.push(newSecretGroup);
}
return secretGroups;
}
public static async createSecretGroup(cloudlyClientRef: CloudlyApiClient, secretGroupDataArg: Partial<plugins.servezoneInterfaces.data.ISecretGroup['data']>) {
const createSecretGroupTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretgroup.IReq_CreateSecretGroup>(
'createSecretGroup'
);
const response = await createSecretGroupTR.fire({
identity: cloudlyClientRef.identity,
secretGroup: {
id: null,
data: {
name: secretGroupDataArg.name,
description: secretGroupDataArg.description,
environments: secretGroupDataArg.environments,
key: secretGroupDataArg.key,
tags: secretGroupDataArg.tags,
priority: secretGroupDataArg.priority,
},
},
});
const newSecretGroup = new SecretGroup(cloudlyClientRef);
Object.assign(newSecretGroup, response.resultSecretGroup);
return newSecretGroup;
}
// INSTANCE
public async update() {
const updateSecretGroupTR = this.cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretgroup.IReq_UpdateSecretGroup>(
'updateSecretGroup'
);
const response = await updateSecretGroupTR.fire({
identity: this.cloudlyClientRef.identity,
secretGroup: {
id: this.id,
data: this.data,
},
});
const resultSecretGroupData = response.resultSecretGroup.data;
plugins.smartexpect.expect(resultSecretGroupData).toEqual(this.data);
return this;
}
public async delete(cloudlyClientRef: CloudlyApiClient, secretGroupIdArg: string) {
const deleteSecretGroupTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.secretgroup.IReq_DeleteSecretGroupById>(
'deleteSecretGroupById'
);
const response = await deleteSecretGroupTR.fire({
identity: cloudlyClientRef.identity,
secretGroupId: this.id,
});
plugins.smartexpect.expect(response.ok).toBeTrue();
return null;
}
}

View File

@ -1,7 +1,7 @@
import * as plugins from './plugins.js';
import type { CloudlyApiClient } from './classes.cloudlyapiclient.js';
export class Service {
export class Service implements plugins.servezoneInterfaces.data.IService {
public static async getServices(cloudlyClientRef: CloudlyApiClient) {
const getAllServicesTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.service.IRequest_Any_Cloudly_GetServices>(
'getServices'
@ -40,19 +40,7 @@ export class Service {
);
const response = await createServiceTR.fire({
identity: cloudlyClientRef.identity,
name: serviceDataArg.name,
description: serviceDataArg.description,
imageId: serviceDataArg.imageId,
imageVersion: serviceDataArg.imageVersion,
environment: {},
secretBundleId: null,
scaleFactor: 1,
balancingStrategy: serviceDataArg.balancingStrategy,
ports: {
web: null,
},
resources: serviceDataArg.resources,
domains: [],
serviceData: serviceDataArg as plugins.servezoneInterfaces.data.IService['data'],
});
const newService = new Service(cloudlyClientRef);
Object.assign(newService, response.service);
@ -62,7 +50,29 @@ export class Service {
// INSTANCE
cloudlyClientRef: CloudlyApiClient;
public id: string;
public data: plugins.servezoneInterfaces.data.IService['data'];
constructor(cloudlyClientRef: CloudlyApiClient) {
this.cloudlyClientRef = cloudlyClientRef;
}
/**
* The service 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') {
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

@ -6,11 +6,13 @@ export {
}
// @push.rocks scope
import * as smartexpect from '@push.rocks/smartexpect';
import * as smartpromise from '@push.rocks/smartpromise';
import * as smartrx from '@push.rocks/smartrx';
import * as webstream from '@push.rocks/smartstream/web';
export {
smartexpect,
smartpromise,
smartrx,
webstream,

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",
"dependencies": [],
"dependencies": [
"@serve.zone/api",
"@serve.zone/interfaces",
"@push.rocks/projectinfo",
"@push.rocks/qenv",
"@push.rocks/smartcli"
],
"registries": [
"registry.npmjs.org: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;
data: {
name: string;
location: {
internal: boolean;
externalRegistryId: string;
externalImageTag: string;
}
description: string;
versions: Array<{
versionString: string;

View File

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

View File

@ -7,16 +7,33 @@ export interface ISecretBundle {
/**
* determines if the secret is a service or an external secret
* if external secret additional checks are put in place to protect the secret
*
* * service:
* the bundle belongs to a service and can only be used by that service
* * npmci:
* the bundle is a secret bundle that is used by an npmci pipeline
* production secrets will be omitted in any case
* * gitzone:
* the bundle is a secret bundle that is used by a gitzone.
* Only local environment variables are allowed
* * external:
* the bundle is a secret bundle that is used by an external service
*/
type: 'service' | 'npmci' | 'gitzone' | 'external';
/**
* set this if the secretBundle belongs to a service
*/
serviceId?: string;
/**
* You can add specific secret groups using this
*/
includedSecretGroupIds: string[];
/**
* You can add specific tags using this
* access to this secretBundle also grants access to resources with matching tags
*/
includedTags: {
key: string;
@ -24,19 +41,21 @@ export interface ISecretBundle {
}[];
/**
* add images
* access to this secretBundle also grants access to the images
*/
includedImages: {
imageClaims: {
imageId: string;
permissions: ('read' | 'write')[];
}[];
}[];
/**
* authrozations select a specific environment of a config bundle
*/
authorizations: Array<{
secretAccessKey: string;
environment: string;
}>;
authorizations: Array<ISecretBundleAuthorization>;
};
}
export interface ISecretBundleAuthorization {
secretAccessKey: string;
environment: string;
}

View File

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

View File

@ -2,9 +2,9 @@ import * as plugins from '../plugins.js';
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,
IRequest_SendEmail
IReq_SendEmail
> {
method: 'sendEmail';
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,
IRequestRegisterRecipient
IReq_RegisterRecipient
> {
method: 'registerRecepient';
request: {
@ -37,3 +37,29 @@ export interface IRequestRegisterRecipient extends plugins.typedrequestInterface
status: 'ok' | 'not ok';
};
}
export interface IReq_CheckEmailStatus extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_CheckEmailStatus
> {
method: 'checkEmailStatus';
request: {
emailId: string;
};
response: {
status: 'ok' | 'not ok';
};
}
export interface IReq_GetEMailStats extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_GetEMailStats
> {
method: 'getEmailStats';
request: {
jwt: string;
};
response: {
status: {};
};
}

View File

@ -0,0 +1,16 @@
import * as plugins from '../plugins.js';
import * as userInterfaces from '../data/user.js';
export interface IReq_Admin_LoginWithUsernameAndPassword extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_Admin_LoginWithUsernameAndPassword
> {
method: 'adminLoginWithUsernameAndPassword';
request: {
username: string;
password: string;
};
response: {
identity: userInterfaces.IIdentity;
}
}

View File

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

@ -1,31 +1,37 @@
import * as plugins from '../plugins.js';
import * as adminRequests from './admin.js';
import * as certificateRequests from './certificate.js';
import * as clusterRequests from './cluster.js';
import * as configRequests from './config.js';
import * as externalRegistryRequests from './externalregistry.js';
import * as identityRequests from './identity.js';
import * as imageRequests from './image.js';
import * as informRequests from './inform.js';
import * as logRequests from './log.js';
import * as networkRequests from './network.js';
import * as routingRequests from './routing.js';
import * as secretRequests from './secret.js';
import * as secretBundleRequests from './secretbundle.js';
import * as secretGroupRequests from './secretgroup.js';
import * as serverRequests from './server.js';
import * as serviceRequests from './service.js';
import * as statusRequests from './status.js';
import * as versionRequests from './version.js';
export {
adminRequests as admin,
certificateRequests as certificate,
clusterRequests as cluster,
configRequests as config,
externalRegistryRequests as externalRegistry,
identityRequests as identity,
imageRequests as image,
informRequests as inform,
logRequests as log,
networkRequests as network,
routingRequests as routing,
secretRequests as secret,
secretBundleRequests as secretbundle,
secretGroupRequests as secretgroup,
serverRequests as server,
serviceRequests as service,
statusRequests as status,

View File

@ -1,94 +0,0 @@
import * as plugins from '../plugins.js';
import * as data from '../data/index.js';
import * as userInterfaces from '../data/user.js';
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_Admin_LoginWithUsernameAndPassword extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_Admin_LoginWithUsernameAndPassword
> {
method: 'adminLoginWithUsernameAndPassword';
request: {
username: string;
password: string;
};
response: {
identity: userInterfaces.IIdentity;
}
}
export interface IReq_Admin_GetConfigBundlesAndSecretGroups extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_Admin_GetConfigBundlesAndSecretGroups
> {
method: 'adminGetConfigBundlesAndSecretGroups';
request: {
identity: userInterfaces.IIdentity;
};
response: {
secretBundles: data.ISecretBundle[];
secretGroups: data.ISecretGroup[];
};
}
export interface IReq_Admin_CreateConfigBundlesAndSecretGroups extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_Admin_CreateConfigBundlesAndSecretGroups
> {
method: 'adminCreateConfigBundlesAndSecretGroups';
request: {
identity: userInterfaces.IIdentity;
secretBundles: data.ISecretBundle[];
secretGroups: data.ISecretGroup[];
};
response: {
ok: boolean;
};
}
export interface IReq_Admin_UpdateConfigBundlesAndSecretGroups extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_Admin_UpdateConfigBundlesAndSecretGroups
> {
method: 'adminUpdateConfigBundlesAndSecretGroups';
request: {
identity: userInterfaces.IIdentity;
configBundles: data.ISecretBundle[];
secretGroups: data.ISecretGroup[];
};
response: {
ok: boolean;
};
}
export interface IReq_Admin_DeleteConfigBundlesAndSecretGroups extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_Admin_DeleteConfigBundlesAndSecretGroups
> {
method: 'adminDeleteConfigBundlesAndSecretGroups';
request: {
identity: userInterfaces.IIdentity;
secretBundleIds: string[];
secretGroupIds: string[];
};
response: {
ok: boolean;
};
}

View File

@ -0,0 +1,103 @@
import * as plugins from '../plugins.js';
import * as data from '../data/index.js';
import * as userInterfaces from '../data/user.js';
export interface IReq_GetSecretBundles extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_GetSecretBundles
> {
method: 'getSecretBundles';
request: {
identity: userInterfaces.IIdentity;
};
response: {
secretBundles: data.ISecretBundle[];
};
}
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<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_CreateSecretBundle
> {
method: 'createSecretBundle';
request: {
identity: userInterfaces.IIdentity;
secretBundle: data.ISecretBundle;
};
response: {
resultSecretBundle: data.ISecretBundle;
};
}
export interface IReq_UpdateSecretBundle extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_UpdateSecretBundle
> {
method: 'updateSecretBundle';
request: {
identity: userInterfaces.IIdentity;
secretBundle: data.ISecretBundle;
};
response: {
resultSecretBundle: data.ISecretBundle;
};
}
export interface IReq_DeleteSecretBundleById extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_DeleteSecretBundleById
> {
method: 'deleteSecretBundleById';
request: {
identity: userInterfaces.IIdentity;
secretBundleId: string;
};
response: {
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

@ -0,0 +1,74 @@
import * as plugins from '../plugins.js';
import * as data from '../data/index.js';
import * as userInterfaces from '../data/user.js';
export interface IReq_GetSecretGroups extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_GetSecretGroups
> {
method: 'getSecretGroups';
request: {
identity: userInterfaces.IIdentity;
};
response: {
secretGroups: data.ISecretGroup[];
};
}
export interface IReq_GetSecretGroupById extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_GetSecretGroupById
> {
method: 'getSecretGroupById';
request: {
identity: userInterfaces.IIdentity;
secretGroupId: string;
};
response: {
secretGroup: data.ISecretGroup;
};
}
export interface IReq_CreateSecretGroup extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_CreateSecretGroup
> {
method: 'createSecretGroup';
request: {
identity: userInterfaces.IIdentity;
secretGroup: data.ISecretGroup;
};
response: {
resultSecretGroup: data.ISecretGroup;
};
}
export interface IReq_UpdateSecretGroup extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_UpdateSecretGroup
> {
method: 'updateSecretGroup';
request: {
identity: userInterfaces.IIdentity;
secretGroup: data.ISecretGroup;
};
response: {
resultSecretGroup: data.ISecretGroup;
};
}
export interface IReq_DeleteSecretGroupById extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_DeleteSecretGroupById
> {
method: 'deleteSecretGroupById';
request: {
identity: userInterfaces.IIdentity;
secretGroupId: string;
};
response: {
ok: boolean;
};
}

View File

@ -40,24 +40,7 @@ extends plugins.typedrequestInterfaces.implementsTR<
method: 'createService';
request: {
identity: IIdentity;
name: string;
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';
}[];
serviceData: IService['data'];
};
response: {
service: IService;
@ -73,36 +56,19 @@ extends plugins.typedrequestInterfaces.implementsTR<
request: {
identity: IIdentity;
serviceId: string;
name: string;
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';
}[];
serviceData: IService['data'];
};
response: {
service: IService;
};
}
export interface IRequest_Any_Cloudly_DeleteService
export interface IRequest_Any_Cloudly_DeleteServiceById
extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_Any_Cloudly_DeleteService
IRequest_Any_Cloudly_DeleteServiceById
> {
method: 'deleteService';
method: 'deleteServiceById';
request: {
identity: IIdentity;
serviceId: string;
@ -111,3 +77,19 @@ extends plugins.typedrequestInterfaces.implementsTR<
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 = {
name: '@serve.zone/cloudly',
version: '4.5.0',
version: '5.0.0',
description: 'A comprehensive tool for managing containerized applications across multiple cloud providers using Docker Swarmkit, featuring web, CLI, and API interfaces.'
}

View File

@ -15,7 +15,7 @@ export const loginAction = loginStatePart.createAction<{ username: string; passw
async (statePartArg, payloadArg) => {
const currentState = statePartArg.getState();
const trLogin =
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secret.IReq_Admin_LoginWithUsernameAndPassword>(
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.admin.IReq_Admin_LoginWithUsernameAndPassword>(
'/typedrequest',
'adminLoginWithUsernameAndPassword'
);
@ -77,20 +77,34 @@ export const dataState = await appstate.getStatePart<IDataState>(
);
// Getting data
export const getAllDataAction = dataState.createAction(async (statePartArg, partialArg?: 'secrets' | 'images') => {
export const getAllDataAction = dataState.createAction(async (statePartArg) => {
let currentState = statePartArg.getState();
// Secrets
const trGetSecrets =
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secret.IReq_Admin_GetConfigBundlesAndSecretGroups>(
// SecretsGroups
const trGetSecretGroups =
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secretgroup.IReq_GetSecretGroups>(
'/typedrequest',
'adminGetConfigBundlesAndSecretGroups'
'getSecretGroups'
);
const response = await trGetSecrets.fire({
const response = await trGetSecretGroups.fire({
identity: loginStatePart.getState().identity,
});
currentState = {
...currentState,
...response,
secretGroups: response.secretGroups,
};
// SecretBundles
const trGetSecretBundles =
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secretbundle.IReq_GetSecretBundles>(
'/typedrequest',
'getSecretBundles'
);
const responseSecretBundles = await trGetSecretBundles.fire({
identity: loginStatePart.getState().identity,
});
currentState = {
...currentState,
secretBundles: responseSecretBundles.secretBundles,
};
// images
@ -104,14 +118,14 @@ export const getAllDataAction = dataState.createAction(async (statePartArg, part
});
currentState = {
...currentState,
...responseImages,
images: responseImages.images,
};
// Clusters
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',
'getAllClusters'
'getClusters'
);
const responseClusters = await trGetClusters.fire({
identity: loginStatePart.getState().identity,
@ -119,7 +133,7 @@ export const getAllDataAction = dataState.createAction(async (statePartArg, part
currentState = {
...currentState,
...responseClusters,
clusters: responseClusters.clusters,
}
return currentState;
@ -130,14 +144,13 @@ export const createSecretGroupAction = dataState.createAction(
async (statePartArg, payloadArg: plugins.interfaces.data.ISecretGroup) => {
let currentState = statePartArg.getState();
const trCreateSecretGroup =
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secret.IReq_Admin_CreateConfigBundlesAndSecretGroups>(
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secretgroup.IReq_CreateSecretGroup>(
'/typedrequest',
'adminCreateConfigBundlesAndSecretGroups'
'createSecretGroup'
);
const response = await trCreateSecretGroup.fire({
identity: loginStatePart.getState().identity,
secretBundles: [],
secretGroups: [payloadArg],
secretGroup: payloadArg,
});
currentState = await dataState.dispatchAction(getAllDataAction, null);
return currentState;
@ -149,14 +162,13 @@ export const deleteSecretGroupAction = dataState.createAction(
async (statePartArg, payloadArg: { secretGroupId: string }) => {
let currentState = statePartArg.getState();
const trDeleteSecretGroup =
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secret.IReq_Admin_DeleteConfigBundlesAndSecretGroups>(
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secretgroup.IReq_DeleteSecretGroupById>(
'/typedrequest',
'adminDeleteConfigBundlesAndSecretGroups'
'deleteSecretGroupById'
);
const response = await trDeleteSecretGroup.fire({
identity: loginStatePart.getState().identity,
secretBundleIds: [],
secretGroupIds: [payloadArg.secretGroupId],
secretGroupId: payloadArg.secretGroupId,
});
currentState = await dataState.dispatchAction(getAllDataAction, null);
return currentState;
@ -168,14 +180,13 @@ export const deleteSecretBundleAction = dataState.createAction(
async (statePartArg, payloadArg: { configBundleId: string }) => {
let currentState = statePartArg.getState();
const trDeleteConfigBundle =
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secret.IReq_Admin_DeleteConfigBundlesAndSecretGroups>(
new domtools.plugins.typedrequest.TypedRequest<plugins.interfaces.requests.secretbundle.IReq_DeleteSecretBundleById>(
'/typedrequest',
'adminDeleteConfigBundlesAndSecretGroups'
'deleteSecretBundleById'
);
const response = await trDeleteConfigBundle.fire({
identity: loginStatePart.getState().identity,
secretBundleIds: [payloadArg.configBundleId],
secretGroupIds: [],
secretBundleId: payloadArg.configBundleId,
});
currentState = await dataState.dispatchAction(getAllDataAction, null);
return currentState;
@ -249,7 +260,7 @@ export const addClusterAction = dataState.createAction(
currentState = {
...currentState,
...{
clusters: [...currentState.clusters, response.clusterConfig],
clusters: [...currentState.clusters, response.cluster],
},
}
return currentState;

View File

@ -24,6 +24,7 @@ import { CloudlyViewS3 } from './cloudly-view-s3.js';
import { CloudlyViewSecretBundles } from './cloudly-view-secretbundles.js';
import { CloudlyViewSecretGroups } from './cloudly-view-secretgroups.js';
import { CloudlyViewServices } from './cloudly-view-services.js';
import { CloudlyViewExternalRegistries } from './cloudly-view-externalregistries.js';
declare global {
interface HTMLElementTagNameMap {
@ -89,6 +90,10 @@ export class CloudlyDashboard extends DeesElement {
name: 'Clusters',
element: CloudlyViewClusters,
},
{
name: 'ExternalRegistries',
element: CloudlyViewExternalRegistries,
},
{
name: 'Images',
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 = [
cssManager.defaultStyles,
css`
:host {
display: grid;
grid-template-columns: min-content min-content;
}
h1 {
font-family: 'Cal Sans';
letter-spacing: 0.025em;
margin: 0px;
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() {
return html`
<h1><slot></slot></h1>
<div class="flag">stability: alpha</div>
`;
}
}