Compare commits

..

14 Commits

19 changed files with 7452 additions and 4760 deletions

@@ -8,8 +8,8 @@ on:
env: env:
IMAGE: code.foss.global/host.today/ht-docker-node:npmci IMAGE: code.foss.global/host.today/ht-docker-node:npmci
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@/${{gitea.repository}}.git NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@/${{gitea.repository}}.git
# NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}} NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}}
# NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}} NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}}
# NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}} # NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}}
# NPMCI_LOGIN_DOCKER_GITEA: ${{ github.server_url }}|${{ gitea.repository_owner }}|${{ secrets.GITEA_TOKEN }} # NPMCI_LOGIN_DOCKER_GITEA: ${{ github.server_url }}|${{ gitea.repository_owner }}|${{ secrets.GITEA_TOKEN }}
NPMCI_LOGIN_DOCKER_DOCKERREGISTRY: ${{ secrets.NPMCI_LOGIN_DOCKER_DOCKERREGISTRY }} NPMCI_LOGIN_DOCKER_DOCKERREGISTRY: ${{ secrets.NPMCI_LOGIN_DOCKER_DOCKERREGISTRY }}
@@ -90,8 +90,7 @@ jobs:
npmci docker login npmci docker login
npmci docker build npmci docker build
npmci docker test npmci docker test
# npmci docker push npmci docker push code.foss.global
npmci docker push
metadata: metadata:
needs: test needs: test

@@ -24,7 +24,7 @@ RUN rm -rf node_modules/ && pnpm install --prod
## STAGE 3 // rebuild dependencies for alpine ## STAGE 3 // rebuild dependencies for alpine
FROM code.foss.global/host.today/ht-docker-node:alpinenpmci as node3 FROM code.foss.global/host.today/ht-docker-node:alpine_npmci as node3
WORKDIR /app WORKDIR /app
COPY --from=node2 /app /app COPY --from=node2 /app /app
ARG NPMCI_TOKEN_NPM2 ARG NPMCI_TOKEN_NPM2

@@ -1,5 +1,48 @@
# Changelog # Changelog
## 2024-12-14 - 4.5.0 - feat(services)
Add service management functionalities
- Integrated service-related API client methods including getServices, getServiceById, and createService.
- Updated the deployment data structure in the service manager.
- Enhanced service interface to incorporate additional fields for comprehensive data handling.
- Ensured secure token generation for Cloudly authentication processes.
## 2024-11-18 - 4.4.0 - feat(api-client)
Add static method getImageById for Image class in api-client
- Introduced a static method getImageById in the Image class.
- Updated CloudlyApiClient to include the getImageById method in the images interface.
## 2024-11-18 - 4.3.21 - fix(interfaces)
Remove deprecated deployment directive and update related interfaces
- Removed IDeploymentDirective from data and requests.
- Updated IDeployment to remove references to directives.
- Changed IRequest_Any_Cloudly_GetClusterConfig to return services instead of deployment directives.
- Removed deploymentDirectiveIds from IService data structure.
## 2024-11-18 - 4.3.20 - fix(apiclient)
Ensure mandatory parameter in CloudlyApiClient constructor
- Made the 'optionsArg' parameter mandatory in the constructor of CloudlyApiClient class.
## 2024-11-18 - 4.3.19 - fix(docker)
Fix improper Docker push command preventing push to the correct registry.
- Corrected the docker push command in the '.gitea/workflows/docker_tags.yaml' file to push images to the 'code.foss.global' registry.
## 2024-11-17 - 4.3.18 - fix(docker_tags)
Updated Docker configuration to include NPM tokens.
- Restored NPMCI_TOKEN_NPM and NPMCI_TOKEN_NPM2 environment variables in docker_tags.yaml for authentication purposes.
## 2024-11-17 - 4.3.17 - fix(Dockerfile)
Corrected docker base image tag in Dockerfile for alpine compatibility.
- Updated Dockerfile to use the correct base image tag for Alpine.
- Resolved any potential build issues related to incorrect image tag usage.
## 2024-11-17 - 4.3.16 - fix(infrastructure) ## 2024-11-17 - 4.3.16 - fix(infrastructure)
Correct Docker image path in Dockerfile for improved build consistency. Correct Docker image path in Dockerfile for improved build consistency.

@@ -1,6 +1,6 @@
{ {
"name": "@serve.zone/cloudly", "name": "@serve.zone/cloudly",
"version": "4.3.16", "version": "4.5.0",
"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",
@@ -27,9 +27,9 @@
"@git.zone/tsdoc": "^1.4.2", "@git.zone/tsdoc": "^1.4.2",
"@git.zone/tspublish": "^1.7.7", "@git.zone/tspublish": "^1.7.7",
"@git.zone/tstest": "^1.0.90", "@git.zone/tstest": "^1.0.90",
"@git.zone/tswatch": "^2.0.25", "@git.zone/tswatch": "^2.0.36",
"@push.rocks/tapbundle": "^5.5.0", "@push.rocks/tapbundle": "^5.5.3",
"@types/node": "^22.9.0" "@types/node": "^22.10.1"
}, },
"dependencies": { "dependencies": {
"@api.global/typedrequest": "3.1.10", "@api.global/typedrequest": "3.1.10",
@@ -47,9 +47,9 @@
"@push.rocks/early": "^4.0.3", "@push.rocks/early": "^4.0.3",
"@push.rocks/npmextra": "^5.1.2", "@push.rocks/npmextra": "^5.1.2",
"@push.rocks/projectinfo": "^5.0.1", "@push.rocks/projectinfo": "^5.0.1",
"@push.rocks/qenv": "^6.0.5", "@push.rocks/qenv": "^6.1.0",
"@push.rocks/smartacme": "^5.0.0", "@push.rocks/smartacme": "^5.0.0",
"@push.rocks/smartbucket": "^3.0.23", "@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.2.10",
@@ -69,7 +69,7 @@
"@push.rocks/smartrx": "^3.0.7", "@push.rocks/smartrx": "^3.0.7",
"@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.4", "@push.rocks/smartstream": "^3.2.5",
"@push.rocks/smartstring": "^4.0.15", "@push.rocks/smartstring": "^4.0.15",
"@push.rocks/smartunique": "^3.0.9", "@push.rocks/smartunique": "^3.0.9",
"@push.rocks/taskbuffer": "^3.0.2", "@push.rocks/taskbuffer": "^3.0.2",

11885
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

@@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@serve.zone/cloudly', name: '@serve.zone/cloudly',
version: '4.3.16', version: '4.5.0',
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.'
} }

@@ -14,5 +14,26 @@ export class ServiceManager {
constructor(cloudlyRef: Cloudly) { constructor(cloudlyRef: Cloudly) {
this.cloudlyRef = cloudlyRef; this.cloudlyRef = cloudlyRef;
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.service.IRequest_Any_Cloudly_GetServices>(
'getServices',
async (reqArg) => {
await plugins.smartguard.passGuardsOrReject(reqArg, [
this.cloudlyRef.authManager.validIdentityGuard,
]);
const services = await this.CService.getInstances({});
return {
services: await Promise.all(
services.map((service) => {
return service.createSavableObject();
})
),
};
}
)
);
} }
} }

@@ -3,6 +3,7 @@ import * as plugins from './plugins.js';
export type TClientType = 'api' | 'ci' | 'coreflow' | 'cli' | 'serverconfig'; 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';
export class CloudlyApiClient { export class CloudlyApiClient {
private cloudlyUrl: string; private cloudlyUrl: string;
@@ -20,7 +21,7 @@ export class CloudlyApiClient {
plugins.servezoneInterfaces.requests.server.IRequest_TriggerServerAction['request'] plugins.servezoneInterfaces.requests.server.IRequest_TriggerServerAction['request']
>(); >();
constructor(optionsArg?: { constructor(optionsArg: {
registerAs: TClientType; registerAs: TClientType;
cloudlyUrl?: string; cloudlyUrl?: string;
}) { }) {
@@ -157,6 +158,9 @@ export class CloudlyApiClient {
public images = { public images = {
// Images // Images
getImageById: async (imageIdArg: string) => {
return Image.getImageById(this, imageIdArg);
},
getImages: async () => { getImages: async () => {
return Image.getImages(this); return Image.getImages(this);
}, },
@@ -164,4 +168,17 @@ export class CloudlyApiClient {
return Image.createImage(this, optionsArg); return Image.createImage(this, optionsArg);
} }
} }
public services = {
// Services
getServiceById: async (serviceIdArg: string) => {
return Service.getServiceById(this, serviceIdArg);
},
getServices: async () => {
return Service.getServices(this);
},
createService: async (optionsArg: Parameters<typeof Service.createService>[1]) => {
return Service.createService(this, optionsArg);
}
}
} }

@@ -18,6 +18,19 @@ export class Image implements plugins.servezoneInterfaces.data.IImage {
return resultImages; return resultImages;
} }
public static async getImageById(cloudlyClientRef: CloudlyApiClient, imageIdArg: string) {
const getImageByIdTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.image.IRequest_GetImage>(
'getImage'
);
const response = await getImageByIdTR.fire({
identity: cloudlyClientRef.identity,
imageId: imageIdArg,
});
const newImage = new Image(cloudlyClientRef);
Object.assign(newImage, response.image);
return newImage;
}
/** /**
* creates a new image * creates a new image
*/ */

@@ -1,5 +1,68 @@
import * as plugins from './plugins.js'; import * as plugins from './plugins.js';
import type { CloudlyApiClient } from './classes.cloudlyapiclient.js';
export class Service { export class Service {
public static async getServices(cloudlyClientRef: CloudlyApiClient) {
const getAllServicesTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.service.IRequest_Any_Cloudly_GetServices>(
'getServices'
);
const response = await getAllServicesTR.fire({
identity: cloudlyClientRef.identity,
});
const resultServices: Service[] = [];
for (const service of response.services) {
const newService = new Service(cloudlyClientRef);
Object.assign(newService, service);
resultServices.push(newService);
}
return resultServices;
}
public static async getServiceById(cloudlyClientRef: CloudlyApiClient, serviceIdArg: string) {
const getServiceByIdTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.service.IRequest_Any_Cloudly_GetServiceById>(
'getServiceById'
);
const response = await getServiceByIdTR.fire({
identity: cloudlyClientRef.identity,
serviceId: serviceIdArg,
});
const newService = new Service(cloudlyClientRef);
Object.assign(newService, response.service);
return newService;
}
/**
* creates a new service
*/
public static async createService(cloudlyClientRef: CloudlyApiClient, serviceDataArg: Partial<plugins.servezoneInterfaces.data.IService['data']>) {
const createServiceTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.service.IRequest_Any_Cloudly_CreateService>(
'createService'
);
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: [],
});
const newService = new Service(cloudlyClientRef);
Object.assign(newService, response.service);
return newService;
}
// INSTANCE
cloudlyClientRef: CloudlyApiClient;
constructor(cloudlyClientRef: CloudlyApiClient) {
this.cloudlyClientRef = cloudlyClientRef;
}
} }

@@ -1,12 +1,11 @@
import * as plugins from '../plugins.js'; import * as plugins from '../plugins.js';
/** /**
* results from a DeploymentDirective * a deployment happens when a service is deployed
* tracks the status of a deployment * tracks the status of a deployment
*/ */
export interface IDeployment { export interface IDeployment {
id: string; id: string;
deploymentDirectiveId: string;
affectedServiceIds: string[]; affectedServiceIds: string[];
usedImageId: string; usedImageId: string;
deploymentLog: string[]; deploymentLog: string[];

@@ -1,14 +0,0 @@
import type { IServiceRessources } from "./docker.js";
/**
* used for tellilng a cluster about a disired deployment
* and specifies its configuration
*/
export interface IDeploymentDirective {
id: string;
name: string;
imageClaim: string;
ports: { hostPort: number; containerPort: number }[];
environment: { [key: string]: string };
resources?: IServiceRessources;
}

@@ -2,7 +2,6 @@ export * from './cloudlyconfig.js';
export * from './cluster.js'; export * from './cluster.js';
export * from './config.js'; export * from './config.js';
export * from './deployment.js'; export * from './deployment.js';
export * from './deploymentdirective.js';
export * from './docker.js'; export * from './docker.js';
export * from './env.js'; export * from './env.js';
export * from './event.js'; export * from './event.js';

@@ -4,6 +4,7 @@ export interface IService {
id: string; id: string;
data: { data: {
name: string; name: string;
description: string;
imageId: string; imageId: string;
imageVersion: string; imageVersion: string;
environment: { [key: string]: string }; environment: { [key: string]: string };
@@ -21,6 +22,5 @@ export interface IService {
protocol?: 'http' | 'https' | 'ssh'; protocol?: 'http' | 'https' | 'ssh';
}[]; }[];
deploymentIds: string[]; deploymentIds: string[];
deploymentDirectiveIds: string[];
}; };
} }

@@ -3,7 +3,6 @@ import * as clusterInterfaces from '../data/cluster.js';
import * as serverInterfaces from '../data/server.js'; import * as serverInterfaces from '../data/server.js';
import * as userInterfaces from '../data/user.js'; import * as userInterfaces from '../data/user.js';
import type { IService } from '../data/service.js'; import type { IService } from '../data/service.js';
import type { IDeploymentDirective } from '../data/deploymentdirective.js';
export interface IRequest_Any_Cloudly_GetServerConfig export interface IRequest_Any_Cloudly_GetServerConfig
extends plugins.typedrequestInterfaces.implementsTR< extends plugins.typedrequestInterfaces.implementsTR<
@@ -31,7 +30,7 @@ extends plugins.typedrequestInterfaces.implementsTR<
}; };
response: { response: {
configData: clusterInterfaces.ICluster; configData: clusterInterfaces.ICluster;
deploymentDirectives: IDeploymentDirective[]; services: IService[];
}; };
} }
@@ -43,7 +42,7 @@ extends plugins.typedrequestInterfaces.implementsTR<
method: 'pushClusterConfig'; method: 'pushClusterConfig';
request: { request: {
configData: clusterInterfaces.ICluster; configData: clusterInterfaces.ICluster;
deploymentDirectives: IDeploymentDirective[]; services: IService[];
}; };
response: {}; response: {};
} }

@@ -18,6 +18,7 @@ export interface IRequest_GetAllImages extends plugins.typedrequestInterfaces.im
/** /**
* gets a single image * gets a single image
* authentication can happen via imageClaim or identity
*/ */
export interface IRequest_GetImage extends plugins.typedrequestInterfaces.implementsTR< export interface IRequest_GetImage extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest, plugins.typedrequestInterfaces.ITypedRequest,

@@ -11,6 +11,7 @@ import * as networkRequests from './network.js';
import * as routingRequests from './routing.js'; import * as routingRequests from './routing.js';
import * as secretRequests from './secret.js'; import * as secretRequests from './secret.js';
import * as serverRequests from './server.js'; import * as serverRequests from './server.js';
import * as serviceRequests from './service.js';
import * as statusRequests from './status.js'; import * as statusRequests from './status.js';
import * as versionRequests from './version.js'; import * as versionRequests from './version.js';
@@ -26,6 +27,7 @@ export {
routingRequests as routing, routingRequests as routing,
secretRequests as secret, secretRequests as secret,
serverRequests as server, serverRequests as server,
serviceRequests as service,
statusRequests as status, statusRequests as status,
versionRequests as version, versionRequests as version,
}; };

@@ -0,0 +1,113 @@
import * as plugins from '../plugins.js';
import type { IService } from '../data/service.js';
import type { IIdentity } from '../data/user.js';
import type { IServiceRessources } from '../data/docker.js';
export interface IRequest_Any_Cloudly_GetServiceById
extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_Any_Cloudly_GetServiceById
> {
method: 'getServiceById';
request: {
identity: IIdentity;
serviceId: string;
};
response: {
service: IService;
};
}
export interface IRequest_Any_Cloudly_GetServices
extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_Any_Cloudly_GetServices
> {
method: 'getServices';
request: {
identity: IIdentity;
};
response: {
services: IService[];
};
}
export interface IRequest_Any_Cloudly_CreateService
extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_Any_Cloudly_CreateService
> {
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';
}[];
};
response: {
service: IService;
};
}
export interface IRequest_Any_Cloudly_UpdateService
extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_Any_Cloudly_UpdateService
> {
method: 'updateService';
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';
}[];
};
response: {
service: IService;
};
}
export interface IRequest_Any_Cloudly_DeleteService
extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_Any_Cloudly_DeleteService
> {
method: 'deleteService';
request: {
identity: IIdentity;
serviceId: string;
};
response: {
success: boolean;
};
}

@@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@serve.zone/cloudly', name: '@serve.zone/cloudly',
version: '4.3.16', version: '4.5.0',
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.'
} }