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

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

View File

@ -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.'
}

View File

@ -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';

View File

@ -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();

View File

@ -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();
}

View File

@ -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`);
});
}

View File

@ -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();
}

View File

@ -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 };

View File

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

View File

@ -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',
},
);
}

View File

@ -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> {}

View File

@ -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();

View File

@ -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> {}

View File

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

View File

@ -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;

View File

@ -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,
};
})
}),
);
}

View File

@ -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(),
};
}
)
},
),
);
}
}

View File

@ -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() {}
}

View File

@ -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' });

View File

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

View File

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

View File

@ -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,
},
};
}
)
},
),
);
}

View File

@ -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;
};
}
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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'];
}
}

View File

@ -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;
}
}
}

View File

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

View File

@ -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');