feat(cloudly): add service runtime and onboarding
This commit is contained in:
@@ -3,6 +3,30 @@ import { Cloudly } from '../classes.cloudly.js';
|
||||
import type { Cluster } from '../manager.cluster/classes.cluster.js';
|
||||
import { logger } from '../logger.js';
|
||||
|
||||
type TCoreflowDeploymentRequest =
|
||||
| plugins.servezoneInterfaces.requests.deployment.IReq_Cloudly_Coreflow_RestartDeployment
|
||||
| plugins.servezoneInterfaces.requests.deployment.IReq_Cloudly_Coreflow_KillDeployment
|
||||
| plugins.servezoneInterfaces.requests.deployment.IReq_Cloudly_Coreflow_DeploymentWorkspaceReadFile
|
||||
| plugins.servezoneInterfaces.requests.deployment.IReq_Cloudly_Coreflow_DeploymentWorkspaceWriteFile
|
||||
| plugins.servezoneInterfaces.requests.deployment.IReq_Cloudly_Coreflow_DeploymentWorkspaceReadDir
|
||||
| plugins.servezoneInterfaces.requests.deployment.IReq_Cloudly_Coreflow_DeploymentWorkspaceMkdir
|
||||
| plugins.servezoneInterfaces.requests.deployment.IReq_Cloudly_Coreflow_DeploymentWorkspaceRm
|
||||
| plugins.servezoneInterfaces.requests.deployment.IReq_Cloudly_Coreflow_DeploymentWorkspaceExists
|
||||
| plugins.servezoneInterfaces.requests.deployment.IReq_Cloudly_Coreflow_DeploymentWorkspaceExec;
|
||||
|
||||
type TCoreflowDeploymentActionMethod =
|
||||
| 'coreflowRestartDeployment'
|
||||
| 'coreflowKillDeployment';
|
||||
|
||||
type TCoreflowDeploymentActionRequest = Extract<TCoreflowDeploymentRequest, {
|
||||
method: TCoreflowDeploymentActionMethod;
|
||||
}>;
|
||||
|
||||
export type TCoreflowDeploymentWorkspaceMethod = Exclude<
|
||||
TCoreflowDeploymentRequest['method'],
|
||||
TCoreflowDeploymentActionMethod
|
||||
>;
|
||||
|
||||
/**
|
||||
* in charge of talking to coreflow services on clusters
|
||||
* coreflow runs on a server when ServerManager is done.
|
||||
@@ -159,4 +183,87 @@ export class CloudlyCoreflowManager {
|
||||
|
||||
return connections.length;
|
||||
}
|
||||
|
||||
public async getRuntimeDeploymentsForService(
|
||||
serviceArg: plugins.servezoneInterfaces.data.IService,
|
||||
): Promise<plugins.servezoneInterfaces.data.IDeployment[]> {
|
||||
const connections = await this.getConnectedCoreflowConnections();
|
||||
const deployments: plugins.servezoneInterfaces.data.IDeployment[] = [];
|
||||
for (const connection of connections) {
|
||||
try {
|
||||
const request = this.cloudlyRef.server.typedServer.typedsocket.createTypedRequest<plugins.servezoneInterfaces.requests.deployment.IReq_Cloudly_Coreflow_GetServiceDeployments>(
|
||||
'coreflowGetServiceDeployments',
|
||||
connection,
|
||||
);
|
||||
const response = await request.fire({ service: serviceArg });
|
||||
deployments.push(...(response.deployments || []));
|
||||
} catch (error) {
|
||||
logger.log('warn', `failed to query coreflow deployments: ${(error as Error).message}`);
|
||||
}
|
||||
}
|
||||
return deployments;
|
||||
}
|
||||
|
||||
public async fireDeploymentRuntimeAction(
|
||||
methodArg: TCoreflowDeploymentActionMethod,
|
||||
deploymentIdArg: string,
|
||||
): Promise<{ deployment: plugins.servezoneInterfaces.data.IDeployment }> {
|
||||
const response = await this.fireCoreflowRequestUntilFound<TCoreflowDeploymentActionRequest>(methodArg, {
|
||||
deploymentId: deploymentIdArg,
|
||||
});
|
||||
if (!response.deployment) {
|
||||
throw new plugins.typedrequest.TypedResponseError('Coreflow did not return deployment data');
|
||||
}
|
||||
return { deployment: response.deployment };
|
||||
}
|
||||
|
||||
public async fireDeploymentWorkspaceRequest(
|
||||
methodArg: TCoreflowDeploymentWorkspaceMethod,
|
||||
payloadArg: Extract<TCoreflowDeploymentRequest, { method: typeof methodArg }>['request'],
|
||||
) {
|
||||
return await this.fireCoreflowRequestUntilFound(methodArg, payloadArg);
|
||||
}
|
||||
|
||||
private async fireCoreflowRequestUntilFound<TRequest extends TCoreflowDeploymentRequest>(
|
||||
methodArg: TRequest['method'],
|
||||
payloadArg: TRequest['request'],
|
||||
): Promise<TRequest['response']> {
|
||||
const connections = await this.getConnectedCoreflowConnections();
|
||||
if (connections.length === 0) {
|
||||
throw new plugins.typedrequest.TypedResponseError('No connected coreflow');
|
||||
}
|
||||
|
||||
let lastError: Error | undefined;
|
||||
for (const connection of connections) {
|
||||
try {
|
||||
const request = this.cloudlyRef.server.typedServer.typedsocket.createTypedRequest<TRequest>(
|
||||
methodArg,
|
||||
connection,
|
||||
);
|
||||
const response = await request.fire(payloadArg);
|
||||
if (response?.found) {
|
||||
return response;
|
||||
}
|
||||
} catch (error) {
|
||||
lastError = error as Error;
|
||||
}
|
||||
}
|
||||
|
||||
throw new plugins.typedrequest.TypedResponseError(
|
||||
lastError?.message || 'No connected coreflow found the requested deployment',
|
||||
);
|
||||
}
|
||||
|
||||
private async getConnectedCoreflowConnections() {
|
||||
const typedsocket = this.cloudlyRef.server.typedServer?.typedsocket;
|
||||
if (!typedsocket) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return await typedsocket.findAllTargetConnections(async (connectionArg) => {
|
||||
const identityTag = await connectionArg.getTagById('identity');
|
||||
const identity = identityTag?.payload as plugins.servezoneInterfaces.data.IIdentity | undefined;
|
||||
return identity?.role === 'cluster' && !!identity.userId;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user