fix(deps): Update dependencies to latest versions
This commit is contained in:
parent
acc642adf9
commit
0ec665516d
62
changelog.md
Normal file
62
changelog.md
Normal file
@ -0,0 +1,62 @@
|
||||
# Changelog
|
||||
|
||||
## 2024-08-25 - 1.1.7 - fix(deps)
|
||||
Update dependencies to latest versions
|
||||
|
||||
- Updated @git.zone/tsbuild from ^2.1.80 to ^2.1.84
|
||||
- Updated @push.rocks/tapbundle from ^5.0.23 to ^5.0.24
|
||||
- Updated @types/node from ^20.14.6 to ^22.5.0
|
||||
- Updated @apiclient.xyz/docker from ^1.2.2 to ^1.2.3
|
||||
- Updated @design.estate/dees-catalog from ^1.0.289 to ^1.1.6
|
||||
- Updated @design.estate/dees-element from ^2.0.34 to ^2.0.36
|
||||
- Updated @git.zone/tsrun from ^1.2.37 to ^1.2.49
|
||||
- Updated @push.rocks/smartbucket from ^3.0.20 to ^3.0.22
|
||||
- Updated @push.rocks/smartpromise from ^4.0.3 to ^4.0.4
|
||||
- Updated @serve.zone/interfaces from ^1.0.74 to ^1.0.78
|
||||
- Updated @tsclass/tsclass from ^4.0.60 to ^4.1.2
|
||||
|
||||
## 2024-06-20 - 1.1.6 - Updates
|
||||
Routine updates and fixes.
|
||||
|
||||
- (fix) core: update
|
||||
|
||||
## 2024-06-13 - 1.1.4 - Service Management Preparation
|
||||
Incorporated updates and service management preparations.
|
||||
|
||||
- (fix) core: update
|
||||
- (feat) prepare service management
|
||||
|
||||
## 2024-06-05 - 1.1.3 - CI Integration Improvement
|
||||
Structural improvements and better CI integration preparation.
|
||||
|
||||
- (fix) structure: improve structure, prepare better CI integration
|
||||
|
||||
## 2024-06-02 - 1.1.2 - Image Manager Update
|
||||
Prepared proper storage and retrieval of container images.
|
||||
|
||||
- (fix) imagemanager: prepare proper storage and retrieval of container images
|
||||
|
||||
## 2024-06-01 - 1.1.0 - Image Registry Work
|
||||
Initiated work on image registry.
|
||||
|
||||
- (fix) image registry: start work on image registry
|
||||
|
||||
## 2024-05-30 - 1.0.216 - Enhanced Smartguards
|
||||
Enhanced smartguards to verify action authorization.
|
||||
|
||||
- (feat) guards: use better smartguards to verify action authorization
|
||||
|
||||
## 2024-05-28 - 1.0.215 - Unified Package Update
|
||||
Updated package unification for cloudly + API + CLI.
|
||||
|
||||
- (fix) switch to unified package for cloudly + API + CLI: update
|
||||
|
||||
## 2024-05-05 - 1.0.214 - Core Updates
|
||||
Routine core updates.
|
||||
|
||||
- (fix) core: update
|
||||
|
||||
## 2024-04-20 - 1.0.213 - Core Update
|
||||
Routine core updates.
|
||||
|
||||
- (fix) core: update
|
25
package.json
25
package.json
@ -21,44 +21,45 @@
|
||||
"localPublish": "gitzone commit"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@git.zone/tsbuild": "^2.1.80",
|
||||
"@git.zone/tsbuild": "^2.1.84",
|
||||
"@git.zone/tsbundle": "^2.0.15",
|
||||
"@git.zone/tstest": "^1.0.90",
|
||||
"@git.zone/tswatch": "^2.0.23",
|
||||
"@push.rocks/tapbundle": "^5.0.23",
|
||||
"@types/node": "^20.14.6"
|
||||
"@push.rocks/tapbundle": "^5.0.24",
|
||||
"@types/node": "^22.5.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@api.global/typedrequest": "3.0.30",
|
||||
"@api.global/typedserver": "^3.0.50",
|
||||
"@api.global/typedsocket": "^3.0.1",
|
||||
"@apiclient.xyz/cloudflare": "^6.0.1",
|
||||
"@apiclient.xyz/docker": "^1.2.2",
|
||||
"@apiclient.xyz/docker": "^1.2.3",
|
||||
"@apiclient.xyz/hetznercloud": "^1.2.0",
|
||||
"@apiclient.xyz/slack": "^3.0.9",
|
||||
"@design.estate/dees-catalog": "^1.0.289",
|
||||
"@design.estate/dees-catalog": "^1.1.6",
|
||||
"@design.estate/dees-domtools": "^2.0.57",
|
||||
"@design.estate/dees-element": "^2.0.34",
|
||||
"@git.zone/tsrun": "^1.2.37",
|
||||
"@design.estate/dees-element": "^2.0.36",
|
||||
"@git.zone/tsrun": "^1.2.49",
|
||||
"@push.rocks/early": "^4.0.3",
|
||||
"@push.rocks/npmextra": "^5.0.23",
|
||||
"@push.rocks/projectinfo": "^5.0.1",
|
||||
"@push.rocks/qenv": "^6.0.5",
|
||||
"@push.rocks/smartacme": "^5.0.0",
|
||||
"@push.rocks/smartbucket": "^3.0.20",
|
||||
"@push.rocks/smartbucket": "^3.0.22",
|
||||
"@push.rocks/smartcli": "^4.0.11",
|
||||
"@push.rocks/smartclickhouse": "^2.0.17",
|
||||
"@push.rocks/smartdata": "^5.2.6",
|
||||
"@push.rocks/smartdelay": "^3.0.5",
|
||||
"@push.rocks/smartexit": "^1.0.23",
|
||||
"@push.rocks/smartfile": "^11.0.20",
|
||||
"@push.rocks/smartexpect": "^1.2.1",
|
||||
"@push.rocks/smartfile": "^11.0.21",
|
||||
"@push.rocks/smartguard": "^3.0.2",
|
||||
"@push.rocks/smartjson": "^5.0.19",
|
||||
"@push.rocks/smartjwt": "^2.0.4",
|
||||
"@push.rocks/smartlog": "^3.0.7",
|
||||
"@push.rocks/smartlog-destination-clickhouse": "^1.0.13",
|
||||
"@push.rocks/smartpath": "^5.0.18",
|
||||
"@push.rocks/smartpromise": "^4.0.3",
|
||||
"@push.rocks/smartpromise": "^4.0.4",
|
||||
"@push.rocks/smartrequest": "^2.0.22",
|
||||
"@push.rocks/smartrx": "^3.0.7",
|
||||
"@push.rocks/smartssh": "^2.0.1",
|
||||
@ -68,8 +69,8 @@
|
||||
"@push.rocks/smartunique": "^3.0.9",
|
||||
"@push.rocks/taskbuffer": "^3.0.2",
|
||||
"@push.rocks/webjwt": "^1.0.9",
|
||||
"@serve.zone/interfaces": "^1.0.74",
|
||||
"@tsclass/tsclass": "^4.0.60"
|
||||
"@serve.zone/interfaces": "^1.0.78",
|
||||
"@tsclass/tsclass": "^4.1.2"
|
||||
},
|
||||
"files": [
|
||||
"ts/**/*",
|
||||
|
2637
pnpm-lock.yaml
generated
2637
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -8,4 +8,4 @@
|
||||
`code.foss.global/serve.zone/cloudly:latest`
|
||||
|
||||
- Note: the exports are defined in the package.json.
|
||||
- For know, cloud wise only the setup with cloudron and hetzner cloud is supported.
|
||||
- For now, cloud wise only the setup with cloudron and hetzner cloud is supported.
|
23
test/helpers/cloudlyfactory.ts
Normal file
23
test/helpers/cloudlyfactory.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { Qenv } from '@push.rocks/qenv';
|
||||
const testQenv = new Qenv('./', './.nogit/');
|
||||
|
||||
import * as cloudly from '../../ts/index.js';
|
||||
|
||||
export const createCloudly = async () => {
|
||||
const cloudlyConfig: cloudly.ICloudlyConfig = {
|
||||
cfToken: await testQenv.getEnvVarOnDemand('CF_TOKEN'),
|
||||
environment: 'integration',
|
||||
letsEncryptEmail: await testQenv.getEnvVarOnDemand('LETSENCRYPT_EMAIL'),
|
||||
publicUrl: await testQenv.getEnvVarOnDemand('SERVEZONE_URL'),
|
||||
publicPort: await testQenv.getEnvVarOnDemand('SERVEZONE_PORT'),
|
||||
mongoDescriptor: {
|
||||
mongoDbName: await testQenv.getEnvVarOnDemand('MONGODB_DATABASE'),
|
||||
mongoDbUser: await testQenv.getEnvVarOnDemand('MONGODB_USER'),
|
||||
mongoDbPass: await testQenv.getEnvVarOnDemand('MONGODB_PASSWORD'),
|
||||
mongoDbUrl: await testQenv.getEnvVarOnDemand('MONGODB_URL'),
|
||||
},
|
||||
};
|
||||
const cloudlyInstance = new cloudly.Cloudly();
|
||||
return cloudlyInstance;
|
||||
}
|
||||
|
1
test/helpers/index.ts
Normal file
1
test/helpers/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './cloudlyfactory.js';
|
@ -9,15 +9,21 @@ tap.test('should create a new cloudlyApiClient', async () => {
|
||||
registerAs: 'api',
|
||||
cloudlyUrl: 'http://localhost:3000',
|
||||
});
|
||||
await testClient.start();
|
||||
// await testClient.start();
|
||||
expect(testClient).toBeTruthy();
|
||||
});
|
||||
|
||||
tap.test('should get an identity', async () => {
|
||||
const identity = await testClient.getIdentityByJumpCode('test');
|
||||
expect(identity).toBeTruthy();
|
||||
});
|
||||
|
||||
tap.test('should trigger a server action', async () => {
|
||||
|
||||
})
|
||||
|
||||
tap.test('should stop the apiclient', async () => {
|
||||
tap.test('should stop the apiclient', async (toolsArg) => {
|
||||
await toolsArg.delayFor(1000);
|
||||
await testClient.stop();
|
||||
})
|
||||
|
||||
|
21
test/test.ts
21
test/test.ts
@ -1,28 +1,11 @@
|
||||
import { expect, tap } from '@push.rocks/tapbundle';
|
||||
import { Qenv } from '@push.rocks/qenv';
|
||||
const testQenv = new Qenv('./', './.nogit/');
|
||||
process.env.TESTING_CLOUDLY = 'true';
|
||||
|
||||
delete process.env.CLI_CALL;
|
||||
import * as helpers from './helpers/index.js';
|
||||
|
||||
import * as cloudly from '../ts/index.js';
|
||||
|
||||
let testCloudly: cloudly.Cloudly;
|
||||
tap.test('first test', async () => {
|
||||
const cloudlyConfig: cloudly.ICloudlyConfig = {
|
||||
cfToken: await testQenv.getEnvVarOnDemand('CF_TOKEN'),
|
||||
environment: 'integration',
|
||||
letsEncryptEmail: await testQenv.getEnvVarOnDemand('LETSENCRYPT_EMAIL'),
|
||||
publicUrl: await testQenv.getEnvVarOnDemand('SERVEZONE_URL'),
|
||||
publicPort: await testQenv.getEnvVarOnDemand('SERVEZONE_PORT'),
|
||||
mongoDescriptor: {
|
||||
mongoDbName: await testQenv.getEnvVarOnDemand('MONGODB_DATABASE'),
|
||||
mongoDbUser: await testQenv.getEnvVarOnDemand('MONGODB_USER'),
|
||||
mongoDbPass: await testQenv.getEnvVarOnDemand('MONGODB_PASSWORD'),
|
||||
mongoDbUrl: await testQenv.getEnvVarOnDemand('MONGODB_URL'),
|
||||
},
|
||||
};
|
||||
testCloudly = new cloudly.Cloudly();
|
||||
testCloudly = await helpers.createCloudly();
|
||||
expect(testCloudly).toBeInstanceOf(cloudly.Cloudly);
|
||||
});
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
/**
|
||||
* autocreated commitinfo by @pushrocks/commitinfo
|
||||
* autocreated commitinfo by @push.rocks/commitinfo
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@serve.zone/cloudly',
|
||||
version: '1.1.6',
|
||||
version: '1.1.7',
|
||||
description: 'A comprehensive multi-cloud manager leveraging Docker Swarmkit to orchestrate containerized applications across various cloud services and provide robust configuration and API integration.'
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ export const getUsers = async (cloudlyRef: Cloudly) => {
|
||||
users.push({
|
||||
id: 'envadmin',
|
||||
data: {
|
||||
type: 'human',
|
||||
username: envAdminUser.split(':')[0],
|
||||
password: envAdminUser.split(':')[1],
|
||||
role: 'admin',
|
||||
|
@ -34,7 +34,7 @@ export class LetsencryptConnector {
|
||||
},
|
||||
mongoDescriptor: this.cloudlyRef.config.data.mongoDescriptor,
|
||||
});
|
||||
await this.smartacme.init().catch(err => {
|
||||
await this.smartacme.start().catch(err => {
|
||||
console.error('error in init', err);
|
||||
console.log(`trying again in a few minutes`)
|
||||
});
|
||||
|
@ -9,6 +9,7 @@ import { User } from './classes.user.js';
|
||||
export interface IJwtData {
|
||||
userId: string;
|
||||
status: 'loggedIn' | 'loggedOut';
|
||||
expiresAt: number;
|
||||
}
|
||||
|
||||
export class CloudlyAuthManager {
|
||||
@ -33,12 +34,12 @@ export class CloudlyAuthManager {
|
||||
await this.smartjwtInstance.init();
|
||||
const kvStore = await this.cloudlyRef.config.appData.getKvStore();
|
||||
|
||||
const existingJwtKeys: plugins.tsclass.network.IJwtKeypair = await kvStore.readKey('jwtKeys');
|
||||
const existingJwtKeys: plugins.tsclass.network.IJwtKeypair = (await kvStore.readKey('jwtKeypair')) as plugins.tsclass.network.IJwtKeypair;
|
||||
|
||||
if (!existingJwtKeys) {
|
||||
await this.smartjwtInstance.createNewKeyPair();
|
||||
const newJwtKeys = this.smartjwtInstance.getKeyPairAsJson();
|
||||
await kvStore.writeKey('jwtKeys', newJwtKeys);
|
||||
await kvStore.writeKey('jwtKeypair', newJwtKeys);
|
||||
} else {
|
||||
this.smartjwtInstance.setKeyPairAsJson(existingJwtKeys);
|
||||
}
|
||||
@ -48,6 +49,7 @@ export class CloudlyAuthManager {
|
||||
'adminLoginWithUsernameAndPassword',
|
||||
async (dataArg) => {
|
||||
let jwt: string;
|
||||
let expiresAtTimestamp: number = Date.now() + 3600 * 1000 * 24 * 7;
|
||||
const user = await User.findUserByUsernameAndPassword(dataArg.username, dataArg.password);
|
||||
if (!user) {
|
||||
logger.log('warn', 'login failed');
|
||||
@ -55,11 +57,19 @@ export class CloudlyAuthManager {
|
||||
jwt = await this.smartjwtInstance.createJWT({
|
||||
userId: user.id,
|
||||
status: 'loggedIn',
|
||||
expiresAt: expiresAtTimestamp,
|
||||
});
|
||||
logger.log('success', 'login successful');
|
||||
}
|
||||
return {
|
||||
identity: {
|
||||
jwt,
|
||||
userId: user.id,
|
||||
name: user.data.username,
|
||||
expiresAt: expiresAtTimestamp,
|
||||
role: user.data.role,
|
||||
type: user.data.type,
|
||||
},
|
||||
};
|
||||
}
|
||||
)
|
||||
@ -68,14 +78,33 @@ export class CloudlyAuthManager {
|
||||
|
||||
public async stop () {}
|
||||
|
||||
public adminJwtGuard = new plugins.smartguard.Guard<{jwt: string}>(async (dataArg) => {
|
||||
const jwt = dataArg.jwt;
|
||||
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.smartexpect.expectAsync(this.validIdentityGuard.exec(dataArg)).toBeTrue();
|
||||
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.'
|
||||
failedHint: 'user is not admin.',
|
||||
name: 'adminIdentityGuard',
|
||||
})
|
||||
}
|
@ -19,9 +19,5 @@ export class User extends plugins.smartdata.SmartDataDbDoc<
|
||||
public id: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public data: {
|
||||
role: 'admin' | 'user';
|
||||
username: string;
|
||||
password: string;
|
||||
};
|
||||
public data: plugins.servezoneInterfaces.data.IUser['data'];
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
|
||||
export class Cert extends plugins.smartdata.SmartDataDbDoc<> {
|
||||
export class Cert extends plugins.smartdata.SmartDataDbDoc<Cert, Cert> {
|
||||
|
||||
}
|
@ -22,12 +22,14 @@ export class ClusterManager {
|
||||
|
||||
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.cluster.IRequest_CreateCluster>(
|
||||
new plugins.typedrequest.TypedHandler('createCluster', async (dataArg) => {
|
||||
const cluster = await this.storeCluster({
|
||||
// TODO: guards
|
||||
const cluster = await this.createCluster({
|
||||
id: plugins.smartunique.uniSimple('cluster'),
|
||||
data: {
|
||||
userId: null,
|
||||
name: dataArg.clusterName,
|
||||
jumpCode: plugins.smartunique.uniSimple('cluster'),
|
||||
jumpCodeUsedAt: null,
|
||||
initialJumpToken: plugins.smartunique.uniSimple('initialJumpToken'),
|
||||
initialJumpTokenUsedAt: null,
|
||||
acmeInfo: null,
|
||||
cloudlyUrl: `https://${this.cloudlyRef.config.data.publicUrl}:${this.cloudlyRef.config.data.publicPort}/`,
|
||||
servers: [],
|
||||
@ -57,7 +59,7 @@ export class ClusterManager {
|
||||
// delete cluster
|
||||
this.typedrouter.addTypedHandler<plugins.servezoneInterfaces.requests.cluster.IRequest_DeleteCluster>(
|
||||
new plugins.typedrequest.TypedHandler('deleteCluster', async (reqDataArg, toolsArg) => {
|
||||
await toolsArg.passGuards([this.cloudlyRef.authManager.adminJwtGuard], reqDataArg);
|
||||
await toolsArg.passGuards([this.cloudlyRef.authManager.adminIdentityGuard], reqDataArg);
|
||||
await this.deleteCluster(reqDataArg.clusterId);
|
||||
return {
|
||||
success: true,
|
||||
@ -80,25 +82,24 @@ export class ClusterManager {
|
||||
// TODO: implement getclusterConfigByServerIp
|
||||
}
|
||||
|
||||
public async getClusterConfigBy_JumpCode(jumpCodeArg: string) {
|
||||
public async getClusterBy_JumpCode(initialJumpTokenArg: string) {
|
||||
await this.ready.promise;
|
||||
|
||||
return await Cluster.getInstance({
|
||||
data: {
|
||||
jumpCode: jumpCodeArg,
|
||||
initialJumpToken: initialJumpTokenArg,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public async getClusterConfigBy_ClusterIdentifier(
|
||||
clusterIdentifier: plugins.servezoneInterfaces.data.IClusterIdentifier
|
||||
public async getClusterBy_Identity(
|
||||
clusterIdentity: plugins.servezoneInterfaces.data.IIdentity
|
||||
) {
|
||||
await this.ready.promise;
|
||||
|
||||
return await Cluster.getInstance({
|
||||
id: clusterIdentifier.clusterId,
|
||||
data: {
|
||||
name: clusterIdentifier.clusterName,
|
||||
userId: clusterIdentity.userId,
|
||||
},
|
||||
});
|
||||
}
|
||||
@ -128,13 +129,20 @@ export class ClusterManager {
|
||||
* @param configName
|
||||
* @param configObjectArg
|
||||
*/
|
||||
public async storeCluster(configObjectArg: plugins.servezoneInterfaces.data.ICluster) {
|
||||
let clusterInstance = await Cluster.getInstance({ id: configObjectArg.id });
|
||||
if (!clusterInstance) {
|
||||
clusterInstance = await Cluster.fromConfigObject(configObjectArg);
|
||||
} else {
|
||||
Object.assign(clusterInstance, configObjectArg);
|
||||
public async createCluster(configObjectArg: plugins.servezoneInterfaces.data.ICluster) {
|
||||
// TODO: guards
|
||||
// lets create the cluster user
|
||||
const clusterUser = new this.cloudlyRef.authManager.CUser();
|
||||
clusterUser.id = await this.cloudlyRef.authManager.CUser.getNewId();
|
||||
clusterUser.data = {
|
||||
role: 'cluster',
|
||||
type: 'machine',
|
||||
}
|
||||
await clusterUser.save();
|
||||
Object.assign(configObjectArg, {
|
||||
userId: clusterUser.id,
|
||||
});
|
||||
const clusterInstance = await Cluster.fromConfigObject(configObjectArg);
|
||||
await clusterInstance.save();
|
||||
return clusterInstance;
|
||||
}
|
||||
|
@ -15,22 +15,37 @@ export class CloudlyCoreflowManager {
|
||||
|
||||
this.typedRouter.addTypedHandler<plugins.servezoneInterfaces.requests.identity.IRequest_Any_Cloudly_CoreflowManager_GetIdentityByJumpCode>(
|
||||
new plugins.typedrequest.TypedHandler('getIdentityByJumpCode', async (requestData) => {
|
||||
const clusterConfig =
|
||||
await this.cloudlyRef.clusterManager.getClusterConfigBy_JumpCode(
|
||||
const cluster =
|
||||
await this.cloudlyRef.clusterManager.getClusterBy_JumpCode(
|
||||
requestData.jumpCode
|
||||
);
|
||||
|
||||
if (!clusterConfig) {
|
||||
throw new plugins.typedrequest.TypedResponseError('The supplied jumpCode is not valid.');
|
||||
if (!cluster) {
|
||||
throw new plugins.typedrequest.TypedResponseError('The supplied jumpCode is not valid. No cluster found.');
|
||||
}
|
||||
|
||||
const user = await this.cloudlyRef.authManager.CUser.getInstance({
|
||||
id: cluster.data.userId,
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
throw new plugins.typedrequest.TypedResponseError('The supplied jumpCode is not valid. No user found.');
|
||||
}
|
||||
|
||||
const expiryTimestamp = Date.now() + 3600 * 1000 * 24 * 365;
|
||||
return {
|
||||
clusterIdentifier: {
|
||||
clusterId: clusterConfig.id,
|
||||
clusterName: clusterConfig.data.name,
|
||||
identity: {
|
||||
name: cluster.data.name,
|
||||
role: 'cluster',
|
||||
type: 'machine',
|
||||
userId: cluster.data.userId,
|
||||
expiresAt: expiryTimestamp,
|
||||
clusterId: cluster.id,
|
||||
clusterName: cluster.data.name,
|
||||
jwt: await this.cloudlyRef.authManager.smartjwtInstance.createJWT({
|
||||
status: 'loggedIn',
|
||||
userId: 'cluster:' + clusterConfig.id, // TODO: create real users for clusters
|
||||
userId: cluster.data.userId,
|
||||
expiresAt: expiryTimestamp,
|
||||
})
|
||||
},
|
||||
};
|
||||
@ -42,16 +57,16 @@ export class CloudlyCoreflowManager {
|
||||
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.config.IRequest_Any_Cloudly_GetClusterConfig>(
|
||||
'getClusterConfig',
|
||||
async (dataArg) => {
|
||||
const clusterIdentifier = dataArg.clusterIdentifier;
|
||||
const identity = dataArg.identity;
|
||||
console.log('trying to get clusterConfigSet');
|
||||
console.log(dataArg);
|
||||
const clusterConfigSet =
|
||||
await this.cloudlyRef.clusterManager.getClusterConfigBy_ClusterIdentifier(
|
||||
clusterIdentifier
|
||||
const cluster =
|
||||
await this.cloudlyRef.clusterManager.getClusterBy_Identity(
|
||||
identity
|
||||
);
|
||||
console.log('got cluster config and sending it back to coreflow');
|
||||
return {
|
||||
configData: await clusterConfigSet.createSavableObject(),
|
||||
configData: await cluster.createSavableObject(),
|
||||
deploymentDirectives: [],
|
||||
};
|
||||
}
|
||||
@ -60,14 +75,14 @@ export class CloudlyCoreflowManager {
|
||||
|
||||
// lets enable getting of certificates
|
||||
this.typedRouter.addTypedHandler(
|
||||
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.certificate.IRequest_Any_Cloudly_GetSslCertificate>(
|
||||
'getSslCertificate',
|
||||
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.certificate.IRequest_Any_Cloudly_GetCertificateForDomain>(
|
||||
'getCertificateForDomain',
|
||||
async (dataArg) => {
|
||||
console.log(`got request for certificate ${dataArg.requiredCertName}`);
|
||||
console.log(`incoming API request for certificate ${dataArg.domainName}`);
|
||||
const cert = await this.cloudlyRef.letsencryptConnector.getCertificateForDomain(
|
||||
dataArg.requiredCertName
|
||||
dataArg.domainName
|
||||
);
|
||||
console.log(`got certificate ready for reponse ${dataArg.requiredCertName}`);
|
||||
console.log(`got certificate ready for reponse ${dataArg.domainName}`);
|
||||
return {
|
||||
certificate: await cert.createSavableObject(),
|
||||
};
|
||||
|
@ -26,7 +26,7 @@ export class ImageManager {
|
||||
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.image.IRequest_CreateImage>(
|
||||
'createImage',
|
||||
async (reqArg, toolsArg) => {
|
||||
await toolsArg.passGuards([this.cloudlyRef.authManager.adminJwtGuard], reqArg);
|
||||
await toolsArg.passGuards([this.cloudlyRef.authManager.adminIdentityGuard], reqArg);
|
||||
const image = await this.CImage.create({
|
||||
name: reqArg.name,
|
||||
description: reqArg.description,
|
||||
@ -43,7 +43,7 @@ export class ImageManager {
|
||||
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.image.IRequest_DeleteImage>(
|
||||
'deleteImage',
|
||||
async (reqArg, toolsArg) => {
|
||||
await toolsArg.passGuards([this.cloudlyRef.authManager.adminJwtGuard], reqArg);
|
||||
await toolsArg.passGuards([this.cloudlyRef.authManager.adminIdentityGuard], reqArg);
|
||||
const image = await this.CImage.getInstance({
|
||||
id: reqArg.imageId,
|
||||
});
|
||||
@ -57,7 +57,7 @@ export class ImageManager {
|
||||
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.image.IRequest_GetAllImages>(
|
||||
'getAllImages',
|
||||
async (requestArg, toolsArg) => {
|
||||
await toolsArg.passGuards([this.cloudlyRef.authManager.adminJwtGuard], requestArg);
|
||||
await toolsArg.passGuards([this.cloudlyRef.authManager.adminIdentityGuard], requestArg);
|
||||
const images = await this.CImage.getInstances({});
|
||||
return {
|
||||
images: await Promise.all(
|
||||
|
@ -39,8 +39,8 @@ export class CloudlySecretManager {
|
||||
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.secret.IReq_Admin_GetConfigBundlesAndSecretGroups>(
|
||||
'adminGetConfigBundlesAndSecretGroups',
|
||||
async (dataArg, toolsArg) => {
|
||||
await toolsArg.passGuards([this.cloudlyRef.authManager.adminJwtGuard], dataArg);
|
||||
dataArg.jwt
|
||||
await toolsArg.passGuards([this.cloudlyRef.authManager.adminIdentityGuard], dataArg);
|
||||
dataArg.identity.jwt
|
||||
const secretBundles = await SecretBundle.getInstances({});
|
||||
const secretGroups = await SecretGroup.getInstances({});
|
||||
return {
|
||||
|
@ -1,4 +1,5 @@
|
||||
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> {
|
||||
|
||||
|
@ -33,6 +33,7 @@ import * as smartclickhouse from '@push.rocks/smartclickhouse';
|
||||
import * as smartdata from '@push.rocks/smartdata';
|
||||
import * as smartdelay from '@push.rocks/smartdelay';
|
||||
import * as smartexit from '@push.rocks/smartexit';
|
||||
import * as smartexpect from '@push.rocks/smartexpect';
|
||||
import * as smartfile from '@push.rocks/smartfile';
|
||||
import * as smartguard from '@push.rocks/smartguard';
|
||||
import * as smartjson from '@push.rocks/smartjson';
|
||||
@ -57,6 +58,7 @@ export {
|
||||
smartclickhouse,
|
||||
smartdata,
|
||||
smartexit,
|
||||
smartexpect,
|
||||
smartdelay,
|
||||
smartfile,
|
||||
smartguard,
|
||||
|
@ -63,12 +63,19 @@ export class CloudlyApiClient {
|
||||
await this.typedsocketClient.stop();
|
||||
}
|
||||
|
||||
public identity: plugins.servezoneInterfaces.data.IClusterIdentifier;
|
||||
public identity: plugins.servezoneInterfaces.data.IIdentity;
|
||||
public async getIdentityByJumpCode(
|
||||
jumpCodeArg: string,
|
||||
tagConnection = false,
|
||||
statefullIdentity = true
|
||||
): Promise<plugins.servezoneInterfaces.data.IClusterIdentifier> {
|
||||
optionsArg?: {
|
||||
tagConnection?: boolean;
|
||||
statefullIdentity?: boolean;
|
||||
}
|
||||
): Promise<plugins.servezoneInterfaces.data.IIdentity> {
|
||||
optionsArg = Object.assign({}, {
|
||||
tagConnection: false,
|
||||
statefullIdentity: true,
|
||||
}, optionsArg);
|
||||
|
||||
const identityRequest =
|
||||
this.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.identity.IRequest_Any_Cloudly_CoreflowManager_GetIdentityByJumpCode>(
|
||||
'getIdentityByJumpCode'
|
||||
@ -78,42 +85,47 @@ export class CloudlyApiClient {
|
||||
jumpCode: jumpCodeArg,
|
||||
});
|
||||
console.log('got identity response');
|
||||
const identity = response.clusterIdentifier;
|
||||
const identity = response.identity;
|
||||
|
||||
if (tagConnection) {
|
||||
if (optionsArg.tagConnection) {
|
||||
this.typedsocketClient.addTag('identity', identity);
|
||||
}
|
||||
|
||||
if (statefullIdentity) {
|
||||
if (optionsArg.statefullIdentity) {
|
||||
this.identity = identity;
|
||||
}
|
||||
|
||||
return identity;
|
||||
}
|
||||
|
||||
/**
|
||||
* will use statefull identity by default
|
||||
*/
|
||||
public async getClusterConfigFromCloudlyByIdentity(
|
||||
identityArg: plugins.servezoneInterfaces.data.IClusterIdentifier
|
||||
identityArg: plugins.servezoneInterfaces.data.IIdentity = this.identity
|
||||
): Promise<plugins.servezoneInterfaces.data.ICluster> {
|
||||
const clusterConfigRequest =
|
||||
this.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.config.IRequest_Any_Cloudly_GetClusterConfig>(
|
||||
'getClusterConfig'
|
||||
);
|
||||
const response = await clusterConfigRequest.fire({
|
||||
jwt: '',
|
||||
clusterIdentifier: identityArg,
|
||||
identity: identityArg,
|
||||
});
|
||||
return response.configData;
|
||||
}
|
||||
|
||||
/**
|
||||
* will use statefull identity by default
|
||||
*/
|
||||
public async getServerConfigFromCloudlyByIdentity(
|
||||
identityArg: plugins.servezoneInterfaces.data.IClusterIdentifier
|
||||
identityArg: plugins.servezoneInterfaces.data.IIdentity = this.identity
|
||||
): Promise<plugins.servezoneInterfaces.data.IServer> {
|
||||
const serverConfigRequest =
|
||||
this.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.config.IRequest_Any_Cloudly_GetServerConfig>(
|
||||
'getServerConfig'
|
||||
);
|
||||
const response = await serverConfigRequest.fire({
|
||||
jwt: '', // TODO: do proper auth here
|
||||
identity: identityArg,
|
||||
serverId: '', // TODO: get server id here
|
||||
});
|
||||
return response.configData;
|
||||
@ -121,19 +133,24 @@ export class CloudlyApiClient {
|
||||
|
||||
/**
|
||||
* gets a certificate for a domain used by a service
|
||||
* @param serviceNameArg
|
||||
* @param domainNameArg
|
||||
*/
|
||||
public async getCertificateForDomainOverHttps(
|
||||
domainNameArg: string
|
||||
): Promise<plugins.tsclass.network.ICert> {
|
||||
public async getCertificateForDomain(optionsArg: {
|
||||
domainName: string;
|
||||
type: plugins.servezoneInterfaces.requests.certificate.IRequest_Any_Cloudly_GetCertificateForDomain['request']['type'];
|
||||
identity?: plugins.servezoneInterfaces.data.IIdentity;
|
||||
}): Promise<plugins.tsclass.network.ICert> {
|
||||
optionsArg.identity = optionsArg.identity || this.identity;
|
||||
if (!optionsArg.identity) {
|
||||
throw new Error('identity is required. Either provide one or login first.');
|
||||
}
|
||||
const typedCertificateRequest =
|
||||
this.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.certificate.IRequest_Any_Cloudly_GetSslCertificate>(
|
||||
'getSslCertificate'
|
||||
this.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.certificate.IRequest_Any_Cloudly_GetCertificateForDomain>(
|
||||
'getCertificateForDomain'
|
||||
);
|
||||
const typedResponse = await typedCertificateRequest.fire({
|
||||
authToken: '', // do proper auth here
|
||||
requiredCertName: domainNameArg,
|
||||
identity: this.identity, // do proper auth here
|
||||
domainName: optionsArg.domainName,
|
||||
type: optionsArg.type,
|
||||
});
|
||||
return typedResponse.certificate;
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ export class Image implements plugins.servezoneInterfaces.data.IImage {
|
||||
'getAllImages'
|
||||
);
|
||||
const response = await getAllImagesTR.fire({
|
||||
jwt: cloudlyClientRef.identity.jwt,
|
||||
identity: cloudlyClientRef.identity,
|
||||
});
|
||||
const resultImages: Image[] = [];
|
||||
for (const image of response.images) {
|
||||
@ -18,6 +18,23 @@ export class Image implements plugins.servezoneInterfaces.data.IImage {
|
||||
return resultImages;
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a new image
|
||||
*/
|
||||
public static async createImage(cloudlyClientRef: CloudlyApiClient, imageDataArg: Partial<plugins.servezoneInterfaces.data.IImage['data']>) {
|
||||
const createImageTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.image.IRequest_CreateImage>(
|
||||
'createImage'
|
||||
);
|
||||
const response = await createImageTR.fire({
|
||||
identity: cloudlyClientRef.identity,
|
||||
name: imageDataArg.name,
|
||||
description: imageDataArg.description,
|
||||
});
|
||||
const newImage = new Image(cloudlyClientRef);
|
||||
Object.assign(newImage, response.image);
|
||||
return newImage;
|
||||
}
|
||||
|
||||
// INSTANCE
|
||||
cloudlyClientRef: CloudlyApiClient;
|
||||
|
||||
@ -36,7 +53,7 @@ export class Image implements plugins.servezoneInterfaces.data.IImage {
|
||||
'getImageMetadata'
|
||||
);
|
||||
const response = await getVersionsTR.fire({
|
||||
jwt: this.cloudlyClientRef.identity.jwt,
|
||||
identity: this.cloudlyClientRef.identity,
|
||||
imageId: this.id,
|
||||
});
|
||||
Object.assign(this, response.image);
|
||||
@ -54,7 +71,7 @@ export class Image implements plugins.servezoneInterfaces.data.IImage {
|
||||
);
|
||||
const virtualStream = new plugins.typedrequest.VirtualStream();
|
||||
const response = await pullImageTR.fire({
|
||||
jwt: this.cloudlyClientRef.identity.jwt,
|
||||
identity: this.cloudlyClientRef.identity,
|
||||
imageId: this.id,
|
||||
versionString: '',
|
||||
imageStream: virtualStream,
|
||||
@ -72,7 +89,7 @@ export class Image implements plugins.servezoneInterfaces.data.IImage {
|
||||
'pullImageVersion'
|
||||
);
|
||||
const response = await pullImageTR.fire({
|
||||
jwt: this.cloudlyClientRef.identity.jwt,
|
||||
identity: this.cloudlyClientRef.identity,
|
||||
imageId: this.id,
|
||||
versionString: versionStringArg,
|
||||
});
|
||||
|
@ -1,8 +1,8 @@
|
||||
/**
|
||||
* autocreated commitinfo by @pushrocks/commitinfo
|
||||
* autocreated commitinfo by @push.rocks/commitinfo
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@serve.zone/cloudly',
|
||||
version: '1.1.6',
|
||||
version: '1.1.7',
|
||||
description: 'A comprehensive multi-cloud manager leveraging Docker Swarmkit to orchestrate containerized applications across various cloud services and provide robust configuration and API integration.'
|
||||
}
|
||||
|
@ -3,11 +3,11 @@ import * as domtools from '@design.estate/dees-domtools';
|
||||
|
||||
const appstate = new plugins.deesDomtools.plugins.smartstate.Smartstate();
|
||||
export interface ILoginState {
|
||||
jwt: string;
|
||||
identity: plugins.interfaces.data.IIdentity;
|
||||
}
|
||||
export const loginStatePart: plugins.smartstate.StatePart<unknown, ILoginState> = await appstate.getStatePart<ILoginState>(
|
||||
'login',
|
||||
{ jwt: null },
|
||||
{ identity: null },
|
||||
'persistent'
|
||||
);
|
||||
|
||||
@ -25,7 +25,7 @@ export const loginAction = loginStatePart.createAction<{ username: string; passw
|
||||
});
|
||||
return {
|
||||
...currentState,
|
||||
...(response.jwt ? { jwt: response.jwt } : {}),
|
||||
...(response.identity ? { identity: response.identity } : {}),
|
||||
};
|
||||
}
|
||||
);
|
||||
@ -34,7 +34,7 @@ export const logoutAction = loginStatePart.createAction(async (statePartArg) =>
|
||||
const currentState = statePartArg.getState();
|
||||
return {
|
||||
...currentState,
|
||||
jwt: null,
|
||||
identity: null,
|
||||
};
|
||||
});
|
||||
|
||||
@ -81,7 +81,7 @@ export const getAllDataAction = dataState.createAction(async (statePartArg, part
|
||||
'adminGetConfigBundlesAndSecretGroups'
|
||||
);
|
||||
const response = await trGetSecrets.fire({
|
||||
jwt: loginStatePart.getState().jwt,
|
||||
identity: loginStatePart.getState().identity,
|
||||
});
|
||||
currentState = {
|
||||
...currentState,
|
||||
@ -95,7 +95,7 @@ export const getAllDataAction = dataState.createAction(async (statePartArg, part
|
||||
'getAllImages'
|
||||
);
|
||||
const responseImages = await trGetImages.fire({
|
||||
jwt: loginStatePart.getState().jwt,
|
||||
identity: loginStatePart.getState().identity,
|
||||
});
|
||||
currentState = {
|
||||
...currentState,
|
||||
@ -109,7 +109,7 @@ export const getAllDataAction = dataState.createAction(async (statePartArg, part
|
||||
'getAllClusters'
|
||||
);
|
||||
const responseClusters = await trGetClusters.fire({
|
||||
jwt: loginStatePart.getState().jwt,
|
||||
identity: loginStatePart.getState().identity,
|
||||
});
|
||||
|
||||
currentState = {
|
||||
@ -130,7 +130,7 @@ export const createSecretGroupAction = dataState.createAction(
|
||||
'adminCreateConfigBundlesAndSecretGroups'
|
||||
);
|
||||
const response = await trCreateSecretGroup.fire({
|
||||
jwt: loginStatePart.getState().jwt,
|
||||
identity: loginStatePart.getState().identity,
|
||||
secretBundles: [],
|
||||
secretGroups: [payloadArg],
|
||||
});
|
||||
@ -149,7 +149,7 @@ export const deleteSecretGroupAction = dataState.createAction(
|
||||
'adminDeleteConfigBundlesAndSecretGroups'
|
||||
);
|
||||
const response = await trDeleteSecretGroup.fire({
|
||||
jwt: loginStatePart.getState().jwt,
|
||||
identity: loginStatePart.getState().identity,
|
||||
secretBundleIds: [],
|
||||
secretGroupIds: [payloadArg.secretGroupId],
|
||||
});
|
||||
@ -168,7 +168,7 @@ export const deleteSecretBundleAction = dataState.createAction(
|
||||
'adminDeleteConfigBundlesAndSecretGroups'
|
||||
);
|
||||
const response = await trDeleteConfigBundle.fire({
|
||||
jwt: loginStatePart.getState().jwt,
|
||||
identity: loginStatePart.getState().identity,
|
||||
secretBundleIds: [payloadArg.configBundleId],
|
||||
secretGroupIds: [],
|
||||
});
|
||||
@ -187,7 +187,7 @@ export const createImageAction = dataState.createAction(
|
||||
'createImage'
|
||||
);
|
||||
const response = await trCreateImage.fire({
|
||||
jwt: loginStatePart.getState().jwt,
|
||||
identity: loginStatePart.getState().identity,
|
||||
name: payloadArg.imageName,
|
||||
description: payloadArg.description,
|
||||
});
|
||||
@ -210,7 +210,7 @@ export const deleteImageAction = dataState.createAction(
|
||||
'deleteImage'
|
||||
);
|
||||
const response = await trDeleteImage.fire({
|
||||
jwt: loginStatePart.getState().jwt,
|
||||
identity: loginStatePart.getState().identity,
|
||||
imageId: payloadArg.imageId,
|
||||
});
|
||||
currentState = {
|
||||
@ -238,7 +238,7 @@ export const addClusterAction = dataState.createAction(
|
||||
'createCluster'
|
||||
);
|
||||
const response = await trAddCluster.fire({
|
||||
jwt: loginStatePart.getState().jwt,
|
||||
identity: loginStatePart.getState().identity,
|
||||
...payloadArg,
|
||||
});
|
||||
currentState = {
|
||||
|
@ -33,7 +33,7 @@ declare global {
|
||||
|
||||
@customElement('cloudly-dashboard')
|
||||
export class CloudlyDashboard extends DeesElement {
|
||||
@state() private jwt: string;
|
||||
@state() private identity: plugins.interfaces.data.IIdentity;
|
||||
@state() private data: appstate.IDataState = {
|
||||
secretGroups: [],
|
||||
secretBundles: [],
|
||||
@ -169,8 +169,8 @@ export class CloudlyDashboard extends DeesElement {
|
||||
const domtools = await this.domtoolsPromise;
|
||||
const loginState = appstate.loginStatePart.getState();
|
||||
console.log(loginState);
|
||||
if (loginState.jwt) {
|
||||
this.jwt = loginState.jwt;
|
||||
if (loginState.identity) {
|
||||
this.identity = loginState.identity;
|
||||
await simpleLogin.switchToSlottedContent();
|
||||
await appstate.dataState.dispatchAction(appstate.getAllDataAction, null);
|
||||
}
|
||||
@ -186,9 +186,9 @@ export class CloudlyDashboard extends DeesElement {
|
||||
username,
|
||||
password,
|
||||
});
|
||||
if (state.jwt) {
|
||||
if (state.identity) {
|
||||
console.log('got jwt');
|
||||
this.jwt = state.jwt;
|
||||
this.identity = state.identity;
|
||||
form.setStatus('success', 'Logged in!');
|
||||
await simpleLogin.switchToSlottedContent();
|
||||
await appstate.dataState.dispatchAction(appstate.getAllDataAction, null);
|
||||
|
Loading…
Reference in New Issue
Block a user