feat: provision corestore bindings
This commit is contained in:
@@ -9,6 +9,18 @@ type TPlatformDesiredState = {
|
||||
services?: plugins.servezoneInterfaces.data.IService[];
|
||||
};
|
||||
|
||||
type TCoreStoreProvisionResponse = {
|
||||
serviceId: string;
|
||||
serviceName?: string;
|
||||
resources: Array<{
|
||||
capability: 'database' | 'objectstorage';
|
||||
provider: 'smartdb' | 'smartstorage';
|
||||
resourceName: string;
|
||||
env: Record<string, string>;
|
||||
}>;
|
||||
env: Record<string, string>;
|
||||
};
|
||||
|
||||
export class PlatformManager {
|
||||
public coreflowRef: Coreflow;
|
||||
private configSubscription?: { unsubscribe: () => void };
|
||||
@@ -52,6 +64,28 @@ export class PlatformManager {
|
||||
logger.log('info', `Platform service reconciliation completed for ${desiredState.bindings.length} bindings`);
|
||||
}
|
||||
|
||||
public async provisionBindingsForService(
|
||||
serviceArg: plugins.servezoneInterfaces.data.IService,
|
||||
): Promise<Record<string, string>> {
|
||||
const desiredState = this.currentDesiredState || (await this.getDesiredState());
|
||||
this.currentDesiredState = desiredState;
|
||||
const bindings = desiredState.bindings.filter((bindingArg) => {
|
||||
return (
|
||||
bindingArg.desiredState !== 'disabled' &&
|
||||
this.bindingMatchesService(bindingArg, serviceArg) &&
|
||||
this.isCoreStoreCapability(bindingArg.capability)
|
||||
);
|
||||
});
|
||||
|
||||
const env: Record<string, string> = {};
|
||||
for (const binding of bindings) {
|
||||
const providerConfig = this.getProviderConfig(binding, desiredState.providerConfigs);
|
||||
const provisionedEnv = await this.provisionCoreStoreBinding(binding, serviceArg, providerConfig);
|
||||
Object.assign(env, provisionedEnv);
|
||||
}
|
||||
return env;
|
||||
}
|
||||
|
||||
private async getDesiredState(
|
||||
desiredStateArg: Partial<TPlatformDesiredState> = {},
|
||||
): Promise<TPlatformDesiredState> {
|
||||
@@ -107,6 +141,15 @@ export class PlatformManager {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isCoreStoreCapability(bindingArg.capability)) {
|
||||
try {
|
||||
await this.provisionCoreStoreBinding(bindingArg, service, providerConfig);
|
||||
} catch (error) {
|
||||
await this.failBinding(bindingArg, `CoreStore provisioning failed: ${(error as Error).message}`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!providerConfig) {
|
||||
await this.failBinding(bindingArg, `No enabled provider config found for ${bindingArg.capability}`);
|
||||
return;
|
||||
@@ -138,6 +181,109 @@ export class PlatformManager {
|
||||
);
|
||||
}
|
||||
|
||||
private bindingMatchesService(
|
||||
bindingArg: plugins.servezoneInterfaces.platform.IPlatformBinding,
|
||||
serviceArg: plugins.servezoneInterfaces.data.IService,
|
||||
) {
|
||||
return bindingArg.serviceId === serviceArg.id || bindingArg.serviceId === serviceArg.data.name;
|
||||
}
|
||||
|
||||
private isCoreStoreCapability(
|
||||
capabilityArg: plugins.servezoneInterfaces.platform.TPlatformCapability,
|
||||
): capabilityArg is 'database' | 'objectstorage' {
|
||||
return capabilityArg === 'database' || capabilityArg === 'objectstorage';
|
||||
}
|
||||
|
||||
private getCoreStoreControlUrl(
|
||||
providerConfigArg?: plugins.servezoneInterfaces.platform.IPlatformProviderConfig,
|
||||
) {
|
||||
const configuredUrl = this.getStringConfigValue(providerConfigArg?.config || {}, 'controlUrl');
|
||||
return configuredUrl || process.env.CORESTORE_CONTROL_URL || 'http://corestore:3000';
|
||||
}
|
||||
|
||||
private getCoreStoreApiToken(
|
||||
providerConfigArg?: plugins.servezoneInterfaces.platform.IPlatformProviderConfig,
|
||||
) {
|
||||
return this.getStringConfigValue(providerConfigArg?.config || {}, 'apiToken') || process.env.CORESTORE_API_TOKEN;
|
||||
}
|
||||
|
||||
private async provisionCoreStoreBinding(
|
||||
bindingArg: plugins.servezoneInterfaces.platform.IPlatformBinding,
|
||||
serviceArg: plugins.servezoneInterfaces.data.IService,
|
||||
providerConfigArg?: plugins.servezoneInterfaces.platform.IPlatformProviderConfig,
|
||||
): Promise<Record<string, string>> {
|
||||
if (!this.isCoreStoreCapability(bindingArg.capability)) {
|
||||
throw new Error(`CoreStore cannot provision ${bindingArg.capability}`);
|
||||
}
|
||||
const capability = bindingArg.capability;
|
||||
const controlUrl = this.getCoreStoreControlUrl(providerConfigArg);
|
||||
const response = await this.postCoreStore<TCoreStoreProvisionResponse>(
|
||||
`${controlUrl.replace(/\/+$/, '')}/resources/provision`,
|
||||
{
|
||||
serviceId: serviceArg.id,
|
||||
serviceName: serviceArg.data.name,
|
||||
capabilities: [capability],
|
||||
},
|
||||
providerConfigArg,
|
||||
);
|
||||
const resource = response.resources.find((resourceArg) => resourceArg.capability === capability);
|
||||
if (!resource) {
|
||||
throw new Error(`CoreStore did not return a ${capability} resource`);
|
||||
}
|
||||
await this.updateBindingStatus(bindingArg, {
|
||||
status: 'ready',
|
||||
endpoints: [this.getCoreStoreEndpoint(capability, resource.env)],
|
||||
credentials: [{ env: resource.env }],
|
||||
errorText: '',
|
||||
});
|
||||
return resource.env;
|
||||
}
|
||||
|
||||
private getCoreStoreEndpoint(
|
||||
capabilityArg: 'database' | 'objectstorage',
|
||||
envArg: Record<string, string>,
|
||||
): plugins.servezoneInterfaces.platform.IPlatformServiceEndpoint {
|
||||
if (capabilityArg === 'database') {
|
||||
return {
|
||||
name: 'corestore-smartdb',
|
||||
capability: 'database',
|
||||
protocol: 'mongodb',
|
||||
internalUrl: envArg.MONGODB_URI,
|
||||
networkAlias: envArg.MONGODB_HOST || 'corestore',
|
||||
port: Number(envArg.MONGODB_PORT || '27017'),
|
||||
};
|
||||
}
|
||||
return {
|
||||
name: 'corestore-smartstorage',
|
||||
capability: 'objectstorage',
|
||||
protocol: 's3',
|
||||
internalUrl: envArg.AWS_ENDPOINT_URL || envArg.S3_ENDPOINT,
|
||||
networkAlias: envArg.S3_ENDPOINT_HOST || 'corestore',
|
||||
port: Number(envArg.S3_PORT || '9000'),
|
||||
};
|
||||
}
|
||||
|
||||
private async postCoreStore<T>(
|
||||
urlArg: string,
|
||||
bodyArg: unknown,
|
||||
providerConfigArg?: plugins.servezoneInterfaces.platform.IPlatformProviderConfig,
|
||||
): Promise<T> {
|
||||
const token = this.getCoreStoreApiToken(providerConfigArg);
|
||||
const response = await fetch(urlArg, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
...(token ? { authorization: `Bearer ${token}` } : {}),
|
||||
},
|
||||
body: JSON.stringify(bodyArg),
|
||||
});
|
||||
const responseText = await response.text();
|
||||
if (!response.ok) {
|
||||
throw new Error(`CoreStore request failed ${response.status}: ${responseText}`);
|
||||
}
|
||||
return responseText ? JSON.parse(responseText) as T : ({} as T);
|
||||
}
|
||||
|
||||
private getEndpointsForBinding(
|
||||
bindingArg: plugins.servezoneInterfaces.platform.IPlatformBinding,
|
||||
providerConfigArg: plugins.servezoneInterfaces.platform.IPlatformProviderConfig,
|
||||
|
||||
Reference in New Issue
Block a user