fix(ci): Fix Docker images and npm registry URL in CI workflows

This commit is contained in:
Philipp Kunz 2024-10-27 19:50:39 +01:00
parent 320b3ed9eb
commit 8f49f0cb4f
79 changed files with 2052 additions and 823 deletions

@ -6,8 +6,8 @@ on:
- '**'
env:
IMAGE: registry.gitlab.com/hosttoday/ht-docker-node:npmci
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@gitea.lossless.digital/${{gitea.repository}}.git
IMAGE: code.foss.global/hosttoday/ht-docker-node:npmci
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@/${{gitea.repository}}.git
NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}}
NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}}
NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}}
@ -27,7 +27,7 @@ jobs:
- name: Install pnpm and npmci
run: |
pnpm install -g pnpm
pnpm install -g @shipzone/npmci
pnpm install -g @ship.zone/npmci
npmci npm prepare
- name: Audit production dependencies
@ -54,7 +54,7 @@ jobs:
- name: Prepare
run: |
pnpm install -g pnpm
pnpm install -g @shipzone/npmci
pnpm install -g @ship.zone/npmci
npmci npm prepare
- name: Test stable

@ -6,8 +6,8 @@ on:
- '*'
env:
IMAGE: registry.gitlab.com/hosttoday/ht-docker-node:npmci
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@gitea.lossless.digital/${{gitea.repository}}.git
IMAGE: code.foss.global/hosttoday/ht-docker-node:npmci
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@/${{gitea.repository}}.git
NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}}
NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}}
NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}}
@ -27,7 +27,7 @@ jobs:
- name: Prepare
run: |
pnpm install -g pnpm
pnpm install -g @shipzone/npmci
pnpm install -g @ship.zone/npmci
npmci npm prepare
- name: Audit production dependencies
@ -54,7 +54,7 @@ jobs:
- name: Prepare
run: |
pnpm install -g pnpm
pnpm install -g @shipzone/npmci
pnpm install -g @ship.zone/npmci
npmci npm prepare
- name: Test stable
@ -74,7 +74,7 @@ jobs:
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
container:
image: registry.gitlab.com/hosttoday/ht-docker-dbase:npmci
image: code.foss.global/hosttoday/ht-docker-dbase:npmci
steps:
- uses: actions/checkout@v3
@ -82,15 +82,15 @@ jobs:
- name: Prepare
run: |
pnpm install -g pnpm
pnpm install -g @shipzone/npmci
pnpm install -g @ship.zone/npmci
- name: Release
run: |
npmci docker login
npmci docker build
npmci docker test
# npmci docker push gitea.lossless.digital
npmci docker push dockerregistry.lossless.digital
# npmci docker push
npmci docker push
metadata:
needs: test

@ -1,6 +1,6 @@
# gitzone dockerfile_service
## STAGE 1 // BUILD
FROM registry.gitlab.com/hosttoday/ht-docker-node:npmci as node1
FROM code.foss.global/hosttoday/ht-docker-node:npmci as node1
COPY ./ /app
WORKDIR /app
ARG NPMCI_TOKEN_NPM2
@ -12,7 +12,7 @@ RUN pnpm run build
# gitzone dockerfile_service
## STAGE 2 // install production
FROM registry.gitlab.com/hosttoday/ht-docker-node:npmci as node2
FROM code.foss.global/hosttoday/ht-docker-node:npmci as node2
WORKDIR /app
COPY --from=node1 /app /app
RUN rm -rf .pnpm-store
@ -24,7 +24,7 @@ RUN rm -rf node_modules/ && pnpm install --prod
## STAGE 3 // rebuild dependencies for alpine
FROM registry.gitlab.com/hosttoday/ht-docker-node:alpinenpmci as node3
FROM code.foss.global/hosttoday/ht-docker-node:alpinenpmci as node3
WORKDIR /app
COPY --from=node2 /app /app
ARG NPMCI_TOKEN_NPM2
@ -34,7 +34,7 @@ RUN pnpm config set store-dir .pnpm-store
RUN pnpm rebuild -r
## STAGE 4 // the final production image with all dependencies in place
FROM registry.gitlab.com/hosttoday/ht-docker-node:alpine as node4
FROM code.foss.global/hosttoday/ht-docker-node:alpine as node4
WORKDIR /app
COPY --from=node3 /app /app

@ -1,5 +1,11 @@
# Changelog
## 2024-10-27 - 1.2.4 - fix(ci)
Fix Docker images and npm registry URL in CI workflows
- Updated Docker image registry URL from 'registry.gitlab.com' to 'code.foss.global'.
- Fixed npmci package installation path from '@shipzone/npmci' to '@ship.zone/npmci'.
## 2024-10-23 - 1.2.3 - fix(cli)
Set up CLI client definition and registry configuration

@ -18,19 +18,21 @@
"start": "node cli.js",
"startTs": "node cli.ts.js",
"watch": "tswatch website",
"publish": "tspublish"
"publish": "tspublish",
"buildDocs": "tsdoc"
},
"devDependencies": {
"@git.zone/tsbuild": "^2.1.84",
"@git.zone/tsbundle": "^2.0.15",
"@git.zone/tspublish": "^1.3.0",
"@git.zone/tsbuild": "^2.1.85",
"@git.zone/tsbundle": "^2.1.0",
"@git.zone/tspublish": "^1.4.0",
"@git.zone/tstest": "^1.0.90",
"@git.zone/tswatch": "^2.0.23",
"@git.zone/tswatch": "^2.0.25",
"@push.rocks/tapbundle": "^5.3.0",
"@types/node": "^22.7.7"
"@types/node": "^22.8.1"
},
"dependencies": {
"@api.global/typedrequest": "3.1.10",
"@api.global/typedrequest-interfaces": "^3.0.19",
"@api.global/typedserver": "^3.0.51",
"@api.global/typedsocket": "^3.0.1",
"@apiclient.xyz/cloudflare": "^6.0.1",
@ -40,7 +42,7 @@
"@design.estate/dees-catalog": "^1.2.0",
"@design.estate/dees-domtools": "^2.0.64",
"@design.estate/dees-element": "^2.0.39",
"@git.zone/tsrun": "^1.2.49",
"@git.zone/tsrun": "^1.3.3",
"@push.rocks/early": "^4.0.3",
"@push.rocks/npmextra": "^5.0.23",
"@push.rocks/projectinfo": "^5.0.1",
@ -59,6 +61,7 @@
"@push.rocks/smartjwt": "^2.2.1",
"@push.rocks/smartlog": "^3.0.7",
"@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.22",
@ -70,7 +73,6 @@
"@push.rocks/smartunique": "^3.0.9",
"@push.rocks/taskbuffer": "^3.0.2",
"@push.rocks/webjwt": "^1.0.9",
"@serve.zone/interfaces": "^1.1.2",
"@tsclass/tsclass": "^4.1.2"
},
"files": [
@ -125,4 +127,4 @@
"security",
"logging"
]
}
}

1288
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@serve.zone/cloudly',
version: '1.2.3',
version: '1.2.4',
description: 'A comprehensive multi-cloud manager leveraging Docker Swarmkit to orchestrate containerized applications across various cloud services and provide robust configuration and API integration.'
}

@ -17,7 +17,7 @@ import { MongodbConnector } from './connector.mongodb/connector.js';
import { CloudlyCoreflowManager } from './manager.coreflow/coreflowmanager.js';
import { ClusterManager } from './manager.cluster/classes.clustermanager.js';
import { CloudlyTaskmanager } from './manager.task/taskmanager.js';
import { CloudlySecretManager } from './manager.secret/classes.secretmanager.js'
import { CloudlySecretManager } from './manager.secret/classes.secretmanager.js';
import { CloudlyServerManager } from './manager.server/classes.servermanager.js';
import { ExternalApiManager } from './manager.status/statusmanager.js';
import { ImageManager } from './manager.image/classes.imagemanager.js';

@ -9,50 +9,53 @@ import type { Cloudly } from './classes.cloudly.js';
export class CloudlyConfig {
public cloudlyRef: Cloudly;
public appData: plugins.npmextra.AppData<plugins.servezoneInterfaces.data.ICloudlyConfig>;
public data: plugins.servezoneInterfaces.data.ICloudlyConfig
public data: plugins.servezoneInterfaces.data.ICloudlyConfig;
constructor(cloudlyRefArg: Cloudly) {
this.cloudlyRef = cloudlyRefArg;
}
public async init() {
this.appData = await plugins.npmextra.AppData.createAndInit<plugins.servezoneInterfaces.data.ICloudlyConfig>({
envMapping: {
cfToken: 'CF_TOKEN',
environment: 'SERVEZONE_ENVIRONMENT' as 'production' | 'integration',
letsEncryptEmail: 'hard:domains@lossless.org',
hetznerToken: 'HETZNER_API_TOKEN',
letsEncryptPrivateKey: null,
publicUrl: 'SERVEZONE_URL',
publicPort: 'SERVEZONE_PORT',
mongoDescriptor: {
mongoDbUrl: 'MONGODB_URL',
mongoDbName: 'MONGODB_DATABASE',
mongoDbUser: 'MONGODB_USER',
mongoDbPass: 'MONGODB_PASSWORD',
this.appData =
await plugins.npmextra.AppData.createAndInit<plugins.servezoneInterfaces.data.ICloudlyConfig>(
{
envMapping: {
cfToken: 'CF_TOKEN',
environment: 'SERVEZONE_ENVIRONMENT' as 'production' | 'integration',
letsEncryptEmail: 'hard:domains@lossless.org',
hetznerToken: 'HETZNER_API_TOKEN',
letsEncryptPrivateKey: null,
publicUrl: 'SERVEZONE_URL',
publicPort: 'SERVEZONE_PORT',
mongoDescriptor: {
mongoDbUrl: 'MONGODB_URL',
mongoDbName: 'MONGODB_DATABASE',
mongoDbUser: 'MONGODB_USER',
mongoDbPass: 'MONGODB_PASSWORD',
},
s3Descriptor: {
endpoint: 'S3_ENDPOINT',
accessKey: 'S3_ACCESSKEY',
accessSecret: 'S3_SECRETKEY',
port: 'S3_PORT', // Note: This will remain as a string. Ensure to parse it to an integer where it's used.
useSsl: true,
},
sslMode:
'SERVEZONE_SSLMODE' as plugins.servezoneInterfaces.data.ICloudlyConfig['sslMode'],
servezoneAdminaccount: 'SERVEZONE_ADMINACCOUNT',
},
requiredKeys: [
'cfToken',
'hetznerToken',
'letsEncryptEmail',
'publicUrl',
'publicPort',
'sslMode',
'environment',
'mongoDescriptor',
],
},
s3Descriptor: {
endpoint: 'S3_ENDPOINT',
accessKey: 'S3_ACCESSKEY',
accessSecret: 'S3_SECRETKEY',
port: 'S3_PORT', // Note: This will remain as a string. Ensure to parse it to an integer where it's used.
useSsl: true,
},
sslMode: 'SERVEZONE_SSLMODE' as plugins.servezoneInterfaces.data.ICloudlyConfig['sslMode'],
servezoneAdminaccount: 'SERVEZONE_ADMINACCOUNT',
},
requiredKeys: [
'cfToken',
'hetznerToken',
'letsEncryptEmail',
'publicUrl',
'publicPort',
'sslMode',
'environment',
'mongoDescriptor',
],
});
);
const kvStore = await this.appData.getKvStore();

@ -45,16 +45,16 @@ export class CloudlyServer {
logger.log('info', `Using letsencrypt for ssl mode. Trying to obtain a certificate...`);
logger.log('info', `This might take 10 minutes...`);
sslCert = await this.cloudlyRef.letsencryptConnector.getCertificateForDomain(
this.cloudlyRef.config.data.publicUrl
this.cloudlyRef.config.data.publicUrl,
);
logger.log(
'success',
`Successfully obtained certificate for cloudly domain ${this.cloudlyRef.config.data.publicUrl}`
`Successfully obtained certificate for cloudly domain ${this.cloudlyRef.config.data.publicUrl}`,
);
} else if (this.cloudlyRef.config.data.sslMode === 'external') {
logger.log(
'info',
`Using external certificate for ssl mode, meaning cloudly is not in charge of ssl termination.`
`Using external certificate for ssl mode, meaning cloudly is not in charge of ssl termination.`,
);
}
@ -95,7 +95,7 @@ export class CloudlyServer {
this.typedServer.typedrouter.addTypedRouter(this.typedrouter);
this.typedServer.server.addRoute(
'/curlfresh/:scriptname',
this.cloudlyRef.serverManager.curlfreshInstance.handler
this.cloudlyRef.serverManager.curlfreshInstance.handler,
);
await this.typedServer.start();
}

@ -24,19 +24,19 @@ export class LetsencryptConnector {
environment: this.cloudlyRef.config.data.environment,
setChallenge: async (dnsChallenge) => {
await this.cloudlyRef.cloudflareConnector.cloudflare.convenience.acmeSetDnsChallenge(
dnsChallenge
dnsChallenge,
);
},
removeChallenge: async (dnsChallenge) => {
await this.cloudlyRef.cloudflareConnector.cloudflare.convenience.acmeRemoveDnsChallenge(
dnsChallenge
dnsChallenge,
);
},
mongoDescriptor: this.cloudlyRef.config.data.mongoDescriptor,
});
await this.smartacme.start().catch(err => {
await this.smartacme.start().catch((err) => {
console.error('error in init', err);
console.log(`trying again in a few minutes`)
console.log(`trying again in a few minutes`);
});
}

@ -11,7 +11,9 @@ export class MongodbConnector {
}
public async init() {
this.smartdataDb = new plugins.smartdata.SmartdataDb(this.cloudlyRef.config.data.mongoDescriptor);
this.smartdataDb = new plugins.smartdata.SmartdataDb(
this.cloudlyRef.config.data.mongoDescriptor,
);
await this.smartdataDb.init();
}

@ -7,7 +7,6 @@ import { logger } from './logger.js';
const cloudlyQenv = new plugins.qenv.Qenv(paths.packageDir, paths.nogitDir, true);
early.stop();
/**
* starts the cloudly instance
*/
@ -17,7 +16,7 @@ const runCli = async () => {
logger.log(
'info',
`running in environment ${await cloudlyQenv.getEnvVarOnDemand('SERVEZONE_ENVIRONMENT')}`
`running in environment ${await cloudlyQenv.getEnvVarOnDemand('SERVEZONE_ENVIRONMENT')}`,
);
await cloudlyInstance.start();
@ -27,4 +26,4 @@ const runCli = async () => {
export { runCli, Cloudly };
type ICloudlyConfig = plugins.servezoneInterfaces.data.ICloudlyConfig;
export { type ICloudlyConfig }
export { type ICloudlyConfig };

@ -9,8 +9,8 @@ export const logger = new plugins.smartlog.Smartlog({
zone: null,
companyunit: null,
containerName: null,
}
},
});
logger.enableConsole({
captureAll: false
captureAll: false,
});

@ -5,7 +5,6 @@ import { logger } from '../logger.js';
import { Authorization } from './classes.authorization.js';
import { User } from './classes.user.js';
export interface IJwtData {
userId: string;
status: 'loggedIn' | 'loggedOut';
@ -13,7 +12,7 @@ export interface IJwtData {
}
export class CloudlyAuthManager {
cloudlyRef: Cloudly
cloudlyRef: Cloudly;
public get db() {
return this.cloudlyRef.mongodbConnector.smartdataDb;
}
@ -38,7 +37,9 @@ export class CloudlyAuthManager {
await this.smartjwtInstance.init();
const kvStore = await this.cloudlyRef.config.appData.getKvStore();
const existingJwtKeys: plugins.tsclass.network.IJwtKeypair = (await kvStore.readKey('jwtKeypair')) as plugins.tsclass.network.IJwtKeypair;
const existingJwtKeys: plugins.tsclass.network.IJwtKeypair = (await kvStore.readKey(
'jwtKeypair',
)) as plugins.tsclass.network.IJwtKeypair;
if (!existingJwtKeys) {
await this.smartjwtInstance.createNewKeyPair();
@ -76,40 +77,61 @@ export class CloudlyAuthManager {
type: user.data.type,
},
};
}
)
},
),
);
}
public async stop () {}
public async stop() {}
public validIdentityGuard = new plugins.smartguard.Guard<{identity: plugins.servezoneInterfaces.data.IIdentity}>(async (dataArg) => {
const jwt = dataArg.identity.jwt;
const jwtData: IJwtData = await this.smartjwtInstance.verifyJWTAndGetData(jwt);
const expired = jwtData.expiresAt < Date.now();
plugins.smartexpect.expect(jwtData.status).setFailMessage('user not logged in').toEqual('loggedIn');
plugins.smartexpect.expect(expired).setFailMessage(`jwt expired`).toBeFalse();
plugins.smartexpect.expect(dataArg.identity.expiresAt).setFailMessage(`expiresAt >>identity valid until:${dataArg.identity.expiresAt}, but jwt says: ${jwtData.expiresAt}<< has been tampered with`).toEqual(jwtData.expiresAt);
plugins.smartexpect.expect(dataArg.identity.userId).setFailMessage('userId has been tampered with').toEqual(jwtData.userId);
if (expired) {
throw new Error('identity is expired');
}
return true;
}, {
failedHint: 'identity is not valid.',
name: 'validIdentityGuard',
});
public validIdentityGuard = new plugins.smartguard.Guard<{
identity: plugins.servezoneInterfaces.data.IIdentity;
}>(
async (dataArg) => {
const jwt = dataArg.identity.jwt;
const jwtData: IJwtData = await this.smartjwtInstance.verifyJWTAndGetData(jwt);
const expired = jwtData.expiresAt < Date.now();
plugins.smartexpect
.expect(jwtData.status)
.setFailMessage('user not logged in')
.toEqual('loggedIn');
plugins.smartexpect.expect(expired).setFailMessage(`jwt expired`).toBeFalse();
plugins.smartexpect
.expect(dataArg.identity.expiresAt)
.setFailMessage(
`expiresAt >>identity valid until:${dataArg.identity.expiresAt}, but jwt says: ${jwtData.expiresAt}<< has been tampered with`,
)
.toEqual(jwtData.expiresAt);
plugins.smartexpect
.expect(dataArg.identity.userId)
.setFailMessage('userId has been tampered with')
.toEqual(jwtData.userId);
if (expired) {
throw new Error('identity is expired');
}
return true;
},
{
failedHint: 'identity is not valid.',
name: 'validIdentityGuard',
},
);
public adminIdentityGuard = new plugins.smartguard.Guard<{identity: plugins.servezoneInterfaces.data.IIdentity}>(async (dataArg) => {
await plugins.smartguard.passGuardsOrReject(dataArg, [this.validIdentityGuard]);
const jwt = dataArg.identity.jwt;
const jwtData: IJwtData = await this.smartjwtInstance.verifyJWTAndGetData(jwt);
const user = await this.CUser.getInstance({id: jwtData.userId});
const isAdminBool = user.data.role === 'admin';
console.log(`user is admin: ${isAdminBool}`);
return isAdminBool;
}, {
failedHint: 'user is not admin.',
name: 'adminIdentityGuard',
})
}
public adminIdentityGuard = new plugins.smartguard.Guard<{
identity: plugins.servezoneInterfaces.data.IIdentity;
}>(
async (dataArg) => {
await plugins.smartguard.passGuardsOrReject(dataArg, [this.validIdentityGuard]);
const jwt = dataArg.identity.jwt;
const jwtData: IJwtData = await this.smartjwtInstance.verifyJWTAndGetData(jwt);
const user = await this.CUser.getInstance({ id: jwtData.userId });
const isAdminBool = user.data.role === 'admin';
console.log(`user is admin: ${isAdminBool}`);
return isAdminBool;
},
{
failedHint: 'user is not admin.',
name: 'adminIdentityGuard',
},
);
}

@ -1,6 +1,4 @@
import * as plugins from '../plugins.js';
@plugins.smartdata.managed()
export class Authorization extends plugins.smartdata.SmartDataDbDoc<Authorization, Authorization> {
}
export class Authorization extends plugins.smartdata.SmartDataDbDoc<Authorization, Authorization> {}

@ -14,11 +14,13 @@ export class User extends plugins.smartdata.SmartDataDbDoc<
user.data = {
type: 'machine',
username: userNameArg,
tokens: [{
token: 'machineUser',
expiresAt: Date.now() + 3600 * 1000 * 24 * 365,
assignedRoles: ['admin'],
}],
tokens: [
{
token: 'machineUser',
expiresAt: Date.now() + 3600 * 1000 * 24 * 365,
assignedRoles: ['admin'],
},
],
role: 'api',
};
await user.save();

@ -1,5 +1,3 @@
import * as plugins from '../plugins.js';
export class Cert extends plugins.smartdata.SmartDataDbDoc<Cert, Cert> {
}
export class Cert extends plugins.smartdata.SmartDataDbDoc<Cert, Cert> {}

@ -11,4 +11,4 @@ export class CertManager {
constructor(cloudly: Cloudly) {
this.cloudlyRef = cloudly;
}
}
}

@ -4,11 +4,12 @@ import * as plugins from '../plugins.js';
* cluster defines a swarmkit cluster
*/
@plugins.smartdata.managed()
export class Cluster extends plugins.smartdata.SmartDataDbDoc<Cluster, plugins.servezoneInterfaces.data.ICluster> {
export class Cluster extends plugins.smartdata.SmartDataDbDoc<
Cluster,
plugins.servezoneInterfaces.data.ICluster
> {
// STATIC
public static async fromConfigObject(
configObjectArg: plugins.servezoneInterfaces.data.ICluster
) {
public static async fromConfigObject(configObjectArg: plugins.servezoneInterfaces.data.ICluster) {
const newCluster = new Cluster();
Object.assign(newCluster, configObjectArg);
return newCluster;

@ -40,7 +40,7 @@ export class ClusterManager {
return {
clusterConfig: await cluster.createSavableObject(),
};
})
}),
);
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.cluster.IRequest_GetAllClusters>(
@ -49,10 +49,10 @@ export class ClusterManager {
const clusters = await this.getAllClusters();
return {
clusters: await Promise.all(
clusters.map((clusterArg) => clusterArg.createSavableObject())
clusters.map((clusterArg) => clusterArg.createSavableObject()),
),
};
})
}),
);
// delete cluster
@ -63,7 +63,7 @@ export class ClusterManager {
return {
success: true,
};
})
}),
);
}

@ -18,17 +18,23 @@ export class CloudlyCoreflowManager {
new plugins.typedrequest.TypedHandler('getIdentityByToken', async (requestData) => {
const user = await this.cloudlyRef.authManager.CUser.getInstance({
data: {
tokens: [{
token: requestData.token,
}] // find the proper user here.
} as any
tokens: [
{
token: requestData.token,
},
], // find the proper user here.
} as any,
});
if (!user) {
throw new plugins.typedrequest.TypedResponseError('The supplied token is not valid. No matching user found.');
throw new plugins.typedrequest.TypedResponseError(
'The supplied token is not valid. No matching user found.',
);
}
if (user.data.type !== 'machine') {
throw new plugins.typedrequest.TypedResponseError('The supplied token is not valid. The user is not a machine.');
throw new plugins.typedrequest.TypedResponseError(
'The supplied token is not valid. The user is not a machine.',
);
}
let cluster: Cluster;
if (user.data.role === 'cluster') {
@ -42,18 +48,20 @@ export class CloudlyCoreflowManager {
type: 'machine', // if someone authenticates by token, they are a machine, no matter what.
userId: user.id,
expiresAt: expiryTimestamp,
...(cluster ? {
clusterId: cluster.id,
clusterName: cluster.data.name,
} : {}),
...(cluster
? {
clusterId: cluster.id,
clusterName: cluster.data.name,
}
: {}),
jwt: await this.cloudlyRef.authManager.smartjwtInstance.createJWT({
status: 'loggedIn',
userId: user.id,
expiresAt: expiryTimestamp,
})
}),
},
};
})
}),
);
// lets enable the getting of cluster configs
@ -64,17 +72,14 @@ export class CloudlyCoreflowManager {
const identity = dataArg.identity;
console.log('trying to get clusterConfigSet');
console.log(dataArg);
const cluster =
await this.cloudlyRef.clusterManager.getClusterBy_Identity(
identity
);
const cluster = await this.cloudlyRef.clusterManager.getClusterBy_Identity(identity);
console.log('got cluster config and sending it back to coreflow');
return {
configData: await cluster.createSavableObject(),
deploymentDirectives: [],
};
}
)
},
),
);
// lets enable getting of certificates
@ -84,14 +89,14 @@ export class CloudlyCoreflowManager {
async (dataArg) => {
console.log(`incoming API request for certificate ${dataArg.domainName}`);
const cert = await this.cloudlyRef.letsencryptConnector.getCertificateForDomain(
dataArg.domainName
dataArg.domainName,
);
console.log(`got certificate ready for reponse ${dataArg.domainName}`);
return {
certificate: await cert.createSavableObject(),
};
}
)
},
),
);
}
}

@ -2,8 +2,14 @@ import * as plugins from '../plugins.js';
import type { ImageManager } from './classes.imagemanager.js';
@plugins.smartdata.managed()
export class Image extends plugins.smartdata.SmartDataDbDoc<Image, plugins.servezoneInterfaces.data.IImage, ImageManager> {
public static async create(imageDataArg: Partial<plugins.servezoneInterfaces.data.IImage['data']>) {
export class Image extends plugins.smartdata.SmartDataDbDoc<
Image,
plugins.servezoneInterfaces.data.IImage,
ImageManager
> {
public static async create(
imageDataArg: Partial<plugins.servezoneInterfaces.data.IImage['data']>,
) {
const image = new Image();
image.id = await this.getNewId();
console.log(imageDataArg);
@ -14,7 +20,7 @@ export class Image extends plugins.smartdata.SmartDataDbDoc<Image, plugins.serve
versions: [],
},
});
console.log((Image as any).saveableProperties)
console.log((Image as any).saveableProperties);
await image.save();
return image;
}
@ -32,14 +38,10 @@ export class Image extends plugins.smartdata.SmartDataDbDoc<Image, plugins.serve
* note: this is relative to the storage method defined by the imageManager
*/
public async getStoragePath(versionStringArg: string) {
return `${this.data.name}:${versionStringArg}`.replace('/', '__')
return `${this.data.name}:${versionStringArg}`.replace('/', '__');
}
public async getWriteStream() {
}
public async getWriteStream() {}
public async getReadStream() {
}
}
public async getReadStream() {}
}

@ -35,8 +35,8 @@ export class ImageManager {
return {
image: await image.createSavableObject(),
};
}
)
},
),
);
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.image.IRequest_GetImage>(
@ -48,7 +48,7 @@ export class ImageManager {
return {
image: await image.createSavableObject(),
};
})
}),
);
this.typedrouter.addTypedHandler(
@ -61,8 +61,8 @@ export class ImageManager {
});
await image.delete();
return {};
}
)
},
),
);
this.typedrouter.addTypedHandler(
@ -75,11 +75,11 @@ export class ImageManager {
images: await Promise.all(
images.map((image) => {
return image.createSavableObject();
})
}),
),
};
}
)
},
),
);
this.typedrouter.addTypedHandler(
@ -97,7 +97,7 @@ export class ImageManager {
}
const imageVersion = reqArg.versionString;
console.log(
`got request to push image version ${imageVersion} for image ${refImage.data.name}`
`got request to push image version ${imageVersion} for image ${refImage.data.name}`,
);
const imagePushStream = reqArg.imageStream;
(async () => {
@ -111,13 +111,16 @@ export class ImageManager {
},
});
imagePushStream.writeToWebstream(smartWebDuplex.writable);
await this.dockerImageStore.storeImage(refImage.id, plugins.smartstream.SmartDuplex.fromWebReadableStream(smartWebDuplex.readable));
await this.dockerImageStore.storeImage(
refImage.id,
plugins.smartstream.SmartDuplex.fromWebReadableStream(smartWebDuplex.readable),
);
})();
return {
allowed: true,
};
}
)
},
),
);
this.typedrouter.addTypedHandler(
@ -128,20 +131,20 @@ export class ImageManager {
id: reqArg.imageId,
});
const imageVersion = image.data.versions.find(
(version) => version.versionString === reqArg.versionString
(version) => version.versionString === reqArg.versionString,
);
const readable = this.imageDir.fastGetStream(
{
path: await image.getStoragePath(reqArg.versionString),
},
'webstream'
'webstream',
);
const imageVirtualStream = new plugins.typedrequest.VirtualStream();
return {
imageStream: imageVirtualStream,
};
}
)
},
),
);
}
@ -151,7 +154,7 @@ export class ImageManager {
await this.cloudlyRef.config.appData.waitForAndGetKey('s3Descriptor');
console.log(this.cloudlyRef.config.data.s3Descriptor);
this.smartbucketInstance = new plugins.smartbucket.SmartBucket(
this.cloudlyRef.config.data.s3Descriptor
this.cloudlyRef.config.data.s3Descriptor,
);
const bucket = await this.smartbucketInstance.getBucketByName('cloudly-test');
await bucket.fastPut({ path: 'images/00init', contents: 'init' });

@ -12,4 +12,4 @@ export class LogManager {
this.cloudlyRef = cloudlyRefArg;
this.cloudlyRef.typedrouter.addTypedRouter(this.typedRouter);
}
}
}

@ -23,7 +23,7 @@ export class SecretBundle extends plugins.smartdata.SmartDataDbDoc<
secretGroups.push(
await SecretGroup.getInstance({
id: secretGroupId,
})
}),
);
}
return secretGroups;

@ -40,23 +40,23 @@ export class CloudlySecretManager {
'adminGetConfigBundlesAndSecretGroups',
async (dataArg, toolsArg) => {
await toolsArg.passGuards([this.cloudlyRef.authManager.adminIdentityGuard], dataArg);
dataArg.identity.jwt
dataArg.identity.jwt;
const secretBundles = await SecretBundle.getInstances({});
const secretGroups = await SecretGroup.getInstances({});
return {
secretBundles: [
...(await Promise.all(
secretBundles.map((configBundle) => configBundle.createSavableObject())
secretBundles.map((configBundle) => configBundle.createSavableObject()),
)),
],
secretGroups: [
...(await Promise.all(
secretGroups.map((secretGroup) => secretGroup.createSavableObject())
secretGroups.map((secretGroup) => secretGroup.createSavableObject()),
)),
],
};
}
)
},
),
);
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.secret.IReq_Admin_CreateConfigBundlesAndSecretGroups>(
@ -72,8 +72,8 @@ export class CloudlySecretManager {
return {
ok: true,
};
}
)
},
),
);
this.typedrouter.addTypedHandler(
@ -96,8 +96,8 @@ export class CloudlySecretManager {
return {
ok: true,
};
}
)
},
),
);
// lets add typedrouter routes for accessing the configvailt from apps
@ -116,19 +116,19 @@ export class CloudlySecretManager {
},
});
const authorization = await wantedBundle.getAuthorizationFromAuthKey(
dataArg.authorization
dataArg.authorization,
);
return {
envBundle: {
configKeyValueObject: await wantedBundle.getKeyValueObjectForEnvironment(
authorization.environment
authorization.environment,
),
environment: authorization.environment,
timeSensitive: false,
},
};
}
)
},
),
);
}

@ -5,7 +5,7 @@ import type { CloudlyServerManager } from './classes.servermanager.js';
export class CurlFresh {
public optionsArg = {
npmRegistry: 'https://registry.npmjs.org',
}
};
public scripts = {
'setup.sh': `#!/bin/bash
@ -50,7 +50,7 @@ bash -c "spark installdaemon"
public handler = new plugins.typedserver.servertools.Handler('ALL', async (req, res) => {
logger.log('info', 'curlfresh handler called. a server might be coming online soon :)');
const scriptname = req.params.scriptname;
switch(scriptname) {
switch (scriptname) {
case 'setup.sh':
logger.log('info', 'sending setup.sh');
res.type('application/x-sh');
@ -66,22 +66,25 @@ bash -c "spark installdaemon"
this.serverManagerRef = serverManagerRefArg;
}
public async getServerUserData(): Promise<string> {
const sslMode = await this.serverManagerRef.cloudlyRef.config.appData.waitForAndGetKey('sslMode');
const sslMode =
await this.serverManagerRef.cloudlyRef.config.appData.waitForAndGetKey('sslMode');
let protocol: 'http' | 'https';
if (sslMode === 'none') {
protocol = 'http';
} else {
protocol = 'https';
}
const domain = await this.serverManagerRef.cloudlyRef.config.appData.waitForAndGetKey('publicUrl');
const port = await this.serverManagerRef.cloudlyRef.config.appData.waitForAndGetKey('publicPort');
const domain =
await this.serverManagerRef.cloudlyRef.config.appData.waitForAndGetKey('publicUrl');
const port =
await this.serverManagerRef.cloudlyRef.config.appData.waitForAndGetKey('publicPort');
const serverUserData = `#cloud-config
runcmd:
- curl -o- ${protocol}://${domain}:${port}/curlfresh/setup.sh | sh
`
`;
console.log(serverUserData);
return serverUserData;
};
}
}

@ -4,10 +4,13 @@ import * as plugins from '../plugins.js';
* cluster defines a swarmkit cluster
*/
@plugins.smartdata.Manager()
export class Server extends plugins.smartdata.SmartDataDbDoc<Server, plugins.servezoneInterfaces.data.IServer> {
export class Server extends plugins.smartdata.SmartDataDbDoc<
Server,
plugins.servezoneInterfaces.data.IServer
> {
// STATIC
public static async createFromHetznerServer(
hetznerServerArg: plugins.hetznercloud.HetznerServer
hetznerServerArg: plugins.hetznercloud.HetznerServer,
) {
const newServer = new Server();
newServer.id = plugins.smartunique.shortId(8);
@ -16,7 +19,7 @@ export class Server extends plugins.smartdata.SmartDataDbDoc<Server, plugins.ser
requiredDebianPackages: [],
sshKeys: [],
type: 'hetzner',
}
};
Object.assign(newServer, { data });
await newServer.save();
return newServer;

@ -29,17 +29,19 @@ export class CloudlyServerManager {
const serverId = requestData.serverId;
const server = await this.CServer.getInstance({
id: serverId,
})
});
return {
configData: await server.createSavableObject(),
};
}
)
},
),
);
}
public async start() {
this.hetznerAccount = new plugins.hetznercloud.HetznerAccount(this.cloudlyRef.config.data.hetznerToken);
this.hetznerAccount = new plugins.hetznercloud.HetznerAccount(
this.cloudlyRef.config.data.hetznerToken,
);
}
public async stop() {}
@ -66,16 +68,18 @@ export class CloudlyServerManager {
clusterId: cluster.id,
priority: '1',
},
userData: await this.curlfreshInstance.getServerUserData()
userData: await this.curlfreshInstance.getServerUserData(),
});
const newServer = await Server.createFromHetznerServer(server);
console.log(`cluster created new server for cluster ${cluster.id}`);
} else {
console.log(`cluster ${cluster.id} already has servers. Making sure that they actually exist in the real world...`);
console.log(
`cluster ${cluster.id} already has servers. Making sure that they actually exist in the real world...`,
);
// if there is a server, make sure that it exists
for (const server of servers) {
const hetznerServer = await this.hetznerAccount.getServersByLabel({
'clusterId': cluster.id
clusterId: cluster.id,
});
if (!hetznerServer) {
console.log(`server ${server.id} does not exist in the real world. Creating it now...`);
@ -86,7 +90,7 @@ export class CloudlyServerManager {
labels: {
clusterId: cluster.id,
priority: '1',
}
},
});
const newServer = await Server.createFromHetznerServer(hetznerServer);
}
@ -99,7 +103,7 @@ export class CloudlyServerManager {
const results = await this.CServer.getInstances({
data: {
assignedClusterId: clusterArg.id,
}
},
});
return results;
}

@ -1,13 +1,14 @@
import * as plugins from '../plugins.js';
import { ServiceManager } from './classes.servicemanager.js';
export class Service extends plugins.smartdata.SmartDataDbDoc<Service, plugins.servezoneInterfaces.data.IService, ServiceManager> {
export class Service extends plugins.smartdata.SmartDataDbDoc<
Service,
plugins.servezoneInterfaces.data.IService,
ServiceManager
> {
@plugins.smartdata.svDb()
public id: string;
@plugins.smartdata.svDb()
public data: plugins.servezoneInterfaces.data.IService['data'];
}
}

@ -5,7 +5,7 @@ import { Service } from './classes.service.js';
export class ServiceManager {
public typedrouter = new plugins.typedrequest.TypedRouter();
public cloudlyRef: Cloudly;
get db() {
return this.cloudlyRef.mongodbConnector.smartdataDb;
}
@ -15,4 +15,4 @@ export class ServiceManager {
constructor(cloudlyRef: Cloudly) {
this.cloudlyRef = cloudlyRef;
}
}
}

@ -16,7 +16,7 @@ export class ExternalApiManager {
return {
networkNodes,
};
})
}),
);
}
}

@ -1,6 +1,9 @@
import * as plugins from './plugins.js';
export const packageDir = plugins.path.join(plugins.smartpath.get.dirnameFromImportMetaUrl(import.meta.url), '../');
export const packageDir = plugins.path.join(
plugins.smartpath.get.dirnameFromImportMetaUrl(import.meta.url),
'../',
);
export const nogitDir = plugins.path.join(packageDir, '.nogit/');
export const dockerImageStoreDir = plugins.path.join(nogitDir, './dockerimagestore/');
export const distServeDir = plugins.path.join(packageDir, './dist_serve');

@ -0,0 +1,8 @@
/**
* autocreated commitinfo by @push.rocks/commitinfo
*/
export const commitinfo = {
name: '@serve.zone/interfaces',
version: '1.1.2',
description: 'interfaces for working with containers'
}

@ -0,0 +1,16 @@
import * as plugins from '../plugins.js';
export interface ICloudlyConfig {
cfToken?: string;
hetznerToken?: string;
environment?: 'production' | 'integration';
letsEncryptEmail?: string;
letsEncryptPrivateKey?: string;
jwtKeypair?: plugins.tsclass.network.IJwtKeypair;
mongoDescriptor?: plugins.tsclass.database.IMongoDescriptor;
s3Descriptor?: plugins.tsclass.storage.IS3Descriptor;
publicUrl?: string;
publicPort?: string;
sslMode?: 'none' | 'letsencrypt' | 'external';
servezoneAdminaccount?: string;
}

@ -0,0 +1,36 @@
import * as plugins from '../plugins.js';
import { type IDockerRegistryInfo } from '../data/docker.js';
import type { IServer } from './server.js';
export interface ICluster {
id: string;
data: {
name: string;
/**
* a cluster has a machine user that governs access rights.
*/
userId: string;
/**
* how can the cluster reach cloudly
*/
cloudlyUrl?: string;
/**
* what servers are expected to be part of the cluster
*/
servers: IServer[];
/**
* ACME info. This is used to get SSL certificates.
*/
acmeInfo: {
serverAddress: string;
serverSecret: string;
};
sshKeys: plugins.tsclass.network.ISshKey[];
};
}

@ -0,0 +1 @@
export type TConfigType = 'server' | 'cluster' | 'coreflow' | 'service';

@ -0,0 +1,14 @@
import * as plugins from '../plugins.js';
/**
* results from a DeploymentDirective
* tracks the status of a deployment
*/
export interface IDeployment {
id: string;
deploymentDirectiveId: string;
affectedServiceIds: string[];
usedImageId: string;
deploymentLog: string[];
status: 'scheduled' | 'running' | 'deployed' | 'failed';
}

@ -0,0 +1,14 @@
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;
}

@ -0,0 +1,15 @@
import * as plugins from '../plugins.js';
export interface IDockerRegistryInfo {
serveraddress: string;
username: string;
password: string;
}
export interface IServiceRessources {
cpuLimit?: number;
cpuReservation?: number;
memorySizeLimitMB?: number;
memorySizeReservationMB?: number;
volumeMounts?: plugins.tsclass.container.IVolumeMount[];
}

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

@ -0,0 +1,11 @@
import * as plugins from '../plugins.js';
export interface IEvent_Cloudly_ContainerVersionNotification
extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedEvent<plugins.tsclass.container.IContainer>,
IEvent_Cloudly_ContainerVersionNotification
> {
name: 'newContainerVersion';
uniqueEventId: string;
payload: plugins.tsclass.container.IContainer;
}

@ -0,0 +1,15 @@
import * as plugins from '../plugins.js';
export interface IImage {
id: string;
data: {
name: string;
description: string;
versions: Array<{
versionString: string;
storagePath?: string;
size: number;
createdAt: number;
}>;
};
}

@ -0,0 +1,17 @@
export * from './cloudlyconfig.js';
export * from './cluster.js';
export * from './config.js';
export * from './deployment.js';
export * from './deploymentdirective.js';
export * from './docker.js';
export * from './env.js';
export * from './event.js';
export * from './image.js';
export * from './secretbundle.js';
export * from './secretgroup.js'
export * from './server.js';
export * from './service.js';
export * from './status.js';
export * from './traffic.js';
export * from './user.js';
export * from './version.js';

@ -0,0 +1,42 @@
export interface ISecretBundle {
id: string;
data: {
name: string;
description: string;
/**
* determines if the secret is a service or an external secret
* if external secret additional checks are put in place to protect the secret
*/
type: 'service' | 'npmci' | 'gitzone' | 'external';
/**
* You can add specific secret groups using this
*/
includedSecretGroupIds: string[];
/**
* You can add specific tags using this
*/
includedTags: {
key: string;
value?: string;
}[];
/**
* add images
*/
includedImages: {
imageId: string;
permissions: ('read' | 'write')[];
}[];
/**
* authrozations select a specific environment of a config bundle
*/
authorizations: Array<{
secretAccessKey: string;
environment: string;
}>;
};
}

@ -0,0 +1,54 @@
export interface ISecretGroup {
/**
* the insatnce id. This should be a random id, except for default
*/
id: string;
data: {
name: string;
description: string;
/**
* the key of the secretgroup like CI_RUNNER_TOKEN
*/
key: string;
/**
* the priority of the secretgroup
* will be used to determine which secretgroup will be used
* when there are multiple secretgroups with the same key
*/
priority?: number;
/**
* any tags that can be used to filter the secretgroup
* can be used for putting secrets into projects
*/
tags: {
key: string;
value: string;
}[];
/**
* the values for this secretGroup
*/
environments: {
[key: string]: {
value: string;
/**
* can be used to update the value
*/
updateToken?: string;
/**
* the linux timestamp of the last update
*/
lastUpdated: number;
history: {
timestamp: string;
value: string;
}[];
};
};
};
}

@ -0,0 +1,36 @@
import * as plugins from '../plugins.js';
import { type IDockerRegistryInfo } from './docker.js';
export interface IServerMetrics {
serverId: string;
cpuUsageInPercent: number;
memoryUsageinMB: number;
memoryAvailableInMB: number;
containerCount: number;
containerMetrics: Array<{
containerId: string;
containerName: string;
cpuUsageInPercent: number;
memoryUsageInMB: number;
}>;
}
export interface IServer {
id: string;
data: {
type: 'baremetal' | 'hetzner';
assignedClusterId: string;
/**
* a list of debian packages to be installed
*/
requiredDebianPackages: string[];
/**
* a list of SSH keys to deploy
*/
sshKeys: plugins.tsclass.network.ISshKey[];
};
}

@ -0,0 +1,26 @@
import type { IServiceRessources } from './docker.js';
export interface IService {
id: string;
data: {
name: 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';
}[];
deploymentIds: string[];
deploymentDirectiveIds: string[];
};
}

@ -0,0 +1,20 @@
import * as plugins from '../plugins.js';
export interface IClusterStatus {
name: string;
ip: string;
nodesCount: number;
containersUnderManagementCount: number;
nodeStatusId: string;
containerStatusArray: IContainerStatus[];
}
export interface INodeStatus {
nodeId: string;
}
export interface IContainerStatus {
serviceName: string;
dockerImageUrl: string;
dockerImageVersion: string;
}

@ -0,0 +1,5 @@
import * as plugins from '../plugins.js';
interface IReverseProxyConfig extends plugins.tsclass.network.IReverseProxyConfig {}
export { type IReverseProxyConfig };

@ -0,0 +1,30 @@
export interface IToken {
token: string;
expiresAt: number;
assignedRoles: string[];
}
/**
* an identity is assumed by authentication as a user
* an identity is ephemeral and has to be renewed regularly
*/
export interface IIdentity {
name: string;
userId: string;
type: 'machine' | 'human';
role: 'admin' | 'user' | 'api' | 'cluster';
expiresAt: number;
/** the jwt token should contain above data for verification */
jwt: string;
}
export interface IUser {
id: string;
data: {
type: 'machine' | 'human';
role: 'admin' | 'user' | 'api' | 'cluster';
username?: string;
password?: string;
tokens?: IToken[];
}
}

@ -0,0 +1,11 @@
export interface IContainerVersionData {
/**
* the docker image url
* example: registry.gitlab.com/hosttoday/ht-docker-node:latest
*/
dockerImageUrl: string;
/**
* the docker image version. Note: This is different from docker tags that are often used for versions.
*/
dockerImageVersion: string;
}

9
ts_interfaces/index.ts Normal file

@ -0,0 +1,9 @@
import * as data from './data/index.js';
import * as platformservice from './platformservice/index.js';
import * as requests from './requests/index.js';
export {
data,
platformservice,
requests
}

@ -0,0 +1 @@
The platform folder contains types that can be used for talking with the underlying platform by apps running on serve.zone.

@ -0,0 +1,23 @@
import * as plugins from '../plugins.js';
export interface IChat {
systemMessage: string;
messages: {
role: 'assistant' | 'user';
content: string;
}[];
}
export interface IReq_Chat extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IReq_Chat
> {
method: 'chat',
request: {
chat: IChat;
};
response: {
chat: IChat;
latestMessage: string;
}
}

@ -0,0 +1,13 @@
import * as aibridge from './aibridge.js';
import * as letter from './letter.js';
import * as mta from './mta.js';
import * as pushnotification from './pushnotification.js';
import * as sms from './sms.js';
export {
aibridge,
letter,
mta,
pushnotification,
sms,
}

@ -0,0 +1,34 @@
import * as plugins from '../plugins.js';
export interface IRequest_SendLetter extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_SendLetter
> {
method: 'sendLetter';
request: {
/**
* will be used in logs
*/
description: string;
/**
* if you send any PDF / invoice that you have not made sure to be letterxpress compliant
* we strongly recommend using a cover page
*/
needsCover: boolean;
title?: string;
from?: plugins.tsclass.business.IAddress;
to?: plugins.tsclass.business.IAddress;
coverBody?: string;
service: ('Einschreiben')[];
pdfAttachments?: Array<{
name: string;
binaryAttachmentString: string;
}>
};
response: {
/**
* this process id allows status retrieval of the letter
*/
processId: string;
};
}

@ -0,0 +1,39 @@
import * as plugins from '../plugins.js';
export type TTemplates = 'default' | 'linkaction' | 'notification';
export interface IRequest_SendEmail extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_SendEmail
> {
method: 'sendEmail';
request: {
title: string;
from: string;
to: string;
body: string;
attachments?: Array<{
name: string;
binaryAttachmentString: string;
}>
};
response: {
/**
* the response id allows for handling of responses to that email
*/
responseId: string;
};
}
export interface IRequestRegisterRecipient extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequestRegisterRecipient
> {
method: 'registerRecepient';
request: {
emailAddress: string;
};
response: {
status: 'ok' | 'not ok';
};
}

@ -0,0 +1,16 @@
import * as plugins from '../plugins.js';
export interface IRequest_SendPushNotification extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_SendPushNotification
> {
method: 'sendPushNotification';
request: {
deviceToken: string;
message: string;
}
response: {
ok: boolean;
status: string;
}
}

@ -0,0 +1,33 @@
import * as plugins from '../plugins.js';
export interface IRequest_SendSms
extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_SendSms
> {
method: 'sendSms';
request: {
toNumber: number;
fromName: string;
messageText: string;
};
response: {
status: 'ok' | 'not ok';
}
}
export interface IRequest_SendVerificationCode
extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_SendVerificationCode
> {
method: 'sendVerificationCode';
request: {
toNumber: number;
fromName: string;
};
response: {
status: 'ok' | 'not ok';
verificationCode: string;
}
}

20
ts_interfaces/plugins.ts Normal file

@ -0,0 +1,20 @@
// @apiglobal scope
import * as typedrequestInterfaces from '@api.global/typedrequest-interfaces';
export {
typedrequestInterfaces
}
// @push.rocks scope
import * as smartlogInterfaces from '@push.rocks/smartlog-interfaces';
export {
smartlogInterfaces,
}
// tsclass scope
import * as tsclass from '@tsclass/tsclass';
export {
tsclass
}

@ -0,0 +1,18 @@
import * as plugins from '../plugins.js';
import * as userInterfaces from '../data/user.js';
export interface IRequest_Any_Cloudly_GetCertificateForDomain
extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_Any_Cloudly_GetCertificateForDomain
> {
method: 'getCertificateForDomain';
request: {
identity: userInterfaces.IIdentity;
domainName: string;
type: 'ssl';
};
response: {
certificate: plugins.tsclass.network.ICert;
};
}

@ -0,0 +1,67 @@
import * as userInterfaces from '../data/user.js';
import * as clusterInterfaces from '../data/cluster.js';
import * as plugins from '../plugins.js';
/**
* get all clusters
*/
export interface IRequest_GetAllClusters extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_GetAllClusters
> {
method: 'getAllClusters';
request: {
identity: userInterfaces.IIdentity;
};
response: {
clusters: clusterInterfaces.ICluster[];
};
}
export interface IRequest_CreateCluster extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_CreateCluster
> {
method: 'createCluster';
request: {
identity: userInterfaces.IIdentity;
clusterName: string;
};
response: {
clusterConfig: clusterInterfaces.ICluster;
};
}
/**
* updates a cluster
*/
export interface IRequest_UpdateCluster extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_UpdateCluster
> {
method: 'updateCluster';
request: {
identity: userInterfaces.IIdentity;
clusterConfig: clusterInterfaces.ICluster;
};
response: {
clusterConfig: clusterInterfaces.ICluster;
};
}
/**
* deletes a cluster
*/
export interface IRequest_DeleteCluster extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_DeleteCluster
> {
method: 'deleteCluster';
request: {
identity: userInterfaces.IIdentity;
clusterId: string;
};
response: {
success: boolean;
};
}

@ -0,0 +1,49 @@
import * as plugins from '../plugins.js';
import * as clusterInterfaces from '../data/cluster.js';
import * as serverInterfaces from '../data/server.js';
import * as userInterfaces from '../data/user.js';
import type { IService } from '../data/service.js';
import type { IDeploymentDirective } from '../data/deploymentdirective.js';
export interface IRequest_Any_Cloudly_GetServerConfig
extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_Any_Cloudly_GetServerConfig
> {
method: 'getServerConfig';
request: {
identity: userInterfaces.IIdentity;
serverId: string;
};
response: {
configData: serverInterfaces.IServer;
};
}
export interface IRequest_Any_Cloudly_GetClusterConfig
extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_Any_Cloudly_GetClusterConfig
> {
method: 'getClusterConfig';
request: {
identity: userInterfaces.IIdentity;
};
response: {
configData: clusterInterfaces.ICluster;
deploymentDirectives: IDeploymentDirective[];
};
}
export interface IRequest_Cloudly_Coreflow_PushClusterConfig
extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_Cloudly_Coreflow_PushClusterConfig
> {
method: 'pushClusterConfig';
request: {
configData: clusterInterfaces.ICluster;
deploymentDirectives: IDeploymentDirective[];
};
response: {};
}

@ -0,0 +1,23 @@
import * as plugins from '../plugins.js';
import * as userInterfaces from '../data/user.js'
// ========
// IDENTITY
// ========
/**
* get the identity that then will be used to get the config
*/
export interface IRequest_Any_Cloudly_CoreflowManager_GetIdentityByToken
extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_Any_Cloudly_CoreflowManager_GetIdentityByToken
> {
method: 'getIdentityByToken';
request: {
token: string;
};
response: {
identity: userInterfaces.IIdentity;
};
}

@ -0,0 +1,94 @@
import * as plugins from '../plugins.js';
import * as userInterfaces from '../data/user.js';
import type { IImage } from '../data/index.js';
export interface IRequest_GetAllImages extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_GetAllImages
> {
method: 'getAllImages';
request: {
identity: userInterfaces.IIdentity;
};
response: {
images: IImage[];
};
}
/**
* gets a single image
*/
export interface IRequest_GetImage extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_GetImage
> {
method: 'getImage';
request: {
identity: userInterfaces.IIdentity;
imageId: string;
};
response: {
image: IImage;
};
}
export interface IRequest_CreateImage extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_CreateImage
> {
method: 'createImage';
request: {
identity: userInterfaces.IIdentity;
name: string;
description: string;
};
response: {
image: IImage;
};
}
export interface IRequest_PushImageVersion extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_PushImageVersion
> {
method: 'pushImageVersion';
request: {
identity: userInterfaces.IIdentity;
imageId: string;
versionString: string;
imageStream: plugins.typedrequestInterfaces.IVirtualStream;
};
response: {
allowed: boolean;
};
}
export interface IRequest_PullImageVersion extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_PullImageVersion
> {
method: 'pullImageVersion';
request: {
identity: userInterfaces.IIdentity;
imageId: string;
versionString: string;
};
response: {
imageStream: plugins.typedrequestInterfaces.IVirtualStream;
};
}
export interface IRequest_DeleteImage extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_DeleteImage
> {
method: 'deleteImage';
request: {
identity: userInterfaces.IIdentity;
imageId: string;
};
response: {
};
}

@ -0,0 +1,33 @@
import * as plugins from '../plugins.js';
import * as certificateRequests from './certificate.js';
import * as clusterRequests from './cluster.js';
import * as configRequests from './config.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 serverRequests from './server.js';
import * as statusRequests from './status.js';
import * as versionRequests from './version.js';
export {
certificateRequests as certificate,
clusterRequests as cluster,
configRequests as config,
identityRequests as identity,
imageRequests as image,
informRequests as inform,
logRequests as log,
networkRequests as network,
routingRequests as routing,
secretRequests as secret,
serverRequests as server,
statusRequests as status,
versionRequests as version,
};
export * from './inform.js';

@ -0,0 +1,12 @@
import * as plugins from '../plugins.js';
export interface IRequest_InformAboutNewContainerImage extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_InformAboutNewContainerImage
> {
method: 'servezonestandard_InformAboutNewContainerVersion';
request: {
containerImageInfo: plugins.tsclass.container.IContainer
};
response: {};
}

@ -0,0 +1,13 @@
import * as plugins from '../plugins.js';
export interface IRequest_Log extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_Log
> {
method: 'log';
request: {
authToken: string;
logPackages: plugins.smartlogInterfaces.ILogPackage[];
},
response: {};
}

@ -0,0 +1,9 @@
import * as plugins from '../plugins.js';
export interface IRequest_Any_Cloudly_GetNetworkNodes {
method: 'getNetworkNodes';
request: {};
response: {
networkNodes: plugins.tsclass.network.INetworkNode[];
};
}

@ -0,0 +1,12 @@
import { type IReverseProxyConfig } from '../data/traffic.js';
export interface IRequest_Coreflow_Coretraffic_RoutingUpdate {
method: 'updateRouting';
request: {
reverseConfigs: IReverseProxyConfig[];
};
response: {
status: 'ok' | 'error';
errorText: string;
};
}

@ -0,0 +1,94 @@
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;
};
}

@ -0,0 +1,47 @@
import type { IServerMetrics } from '../data/server.js';
import * as plugins from '../plugins.js';
/**
* This request can be used between any two players
* Examples:
* WebApp -> Cloudly (get metrics)
* Cloudly -> Webapp (send metrics)
* Cloudly -> Coreflow (get metrics)
* Coreflow -> Cloudly (send metrics)
*/
export interface IRequest_Any_Cloudly_ServerStatus
extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_Any_Cloudly_ServerStatus
> {
method: 'getOrSendServerMetrics',
request: {
getOrSend: 'get' | 'send';
serverMetrics?: IServerMetrics;
},
response: {
serverMetrics?: IServerMetrics;
},
}
/**
* this request can be used between any two players
* Examples:
* WebApp -> Cloudly
* Cloudly -> Coreflow
* Cloudly -> HostingProvider
*/
export interface IRequest_TriggerServerAction
extends plugins.typedrequestInterfaces.implementsTR<
plugins.typedrequestInterfaces.ITypedRequest,
IRequest_TriggerServerAction
> {
method: 'triggerServerAction';
request: {
actionName: 'reboot' | 'rebuild';
payload: any;
};
response: {
actionConfirmed: boolean;
};
}

@ -0,0 +1,12 @@
import * as userInterfaces from '../data/user.js';
/**
* a status update dashboard
*/
export interface IRequest_Coreflow_Cloudly_CoreflowManagerStatusupdate {
method: 'cloudlyStatus';
request: {
identity: userInterfaces.IIdentity;
};
response: {};
}

@ -0,0 +1,8 @@
import * as versionInterfaces from '../data/version.js';
// Containers
export interface IRequest_Any_Cloudly_VersionManager_InformCloudlyAboutNewContainerVersion {
method: 'informCloudlyAboutNewContainerVersion';
request: versionInterfaces.IContainerVersionData;
response: {};
}

@ -1,6 +1,8 @@
{
"name": "@serve.zone/interfaces",
"dependencies": [
"@api.global/typedrequest-interfaces",
"@push.rocks/smartlog-interfaces",
"@tsclass/tsclass"
],
"registries": [

@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@serve.zone/cloudly',
version: '1.2.3',
version: '1.2.4',
description: 'A comprehensive multi-cloud manager leveraging Docker Swarmkit to orchestrate containerized applications across various cloud services and provide robust configuration and API integration.'
}

@ -6,9 +6,21 @@
"module": "NodeNext",
"moduleResolution": "NodeNext",
"esModuleInterop": true,
"verbatimModuleSyntax": true
"verbatimModuleSyntax": true,
"baseUrl": ".",
"paths": {
"@serve.zone/api": [
"./ts_apiclient/index.ts"
],
"@serve.zone/cli": [
"./ts_cliclient/index.ts"
],
"@serve.zone/interfaces": [
"./ts_interfaces/index.ts"
]
}
},
"exclude": [
"dist_*/**/*.d.ts"
]
}
}