@facets-cloud/facetsctlv3
Version:
160 lines (159 loc) • 7.75 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const core_1 = require("@oclif/core");
const FacetsApi = __importStar(require("../../services/facets-api"));
const config_service_1 = require("../../services/config-service");
const errors_1 = require("@oclif/core/lib/errors");
class Wait extends core_1.Command {
static description = 'Wait for the sync status of the specified apps, and trigger sync if --sync is provided';
static flags = {
project: core_1.Flags.string({
char: 'p',
description: 'Project name',
required: true,
}),
environment: core_1.Flags.string({
char: 'e',
description: 'Environment name',
required: true,
}),
sync: core_1.Flags.boolean({
description: 'Trigger a sync if apps are out-of-sync',
default: false,
}),
debug: core_1.Flags.boolean({
description: 'To check API response for each resource',
default: false,
hidden: true
})
};
static args = {
apps: core_1.Args.string({
name: 'apps',
description: 'List of app names to wait for (comma-separated | example: ... sync app1,app2,app3 -p ...)',
required: true,
})
};
static usage = 'facetsctl release wait <apps> -p <value> -e <value> [--sync]';
async run() {
const { flags, args } = await this.parse(Wait);
const { project, environment, sync, debug } = flags;
const apps = args.apps ? args?.apps?.split(',')?.map(app => app.trim()) : [];
const allAppsSet = new Set(apps);
const failedAppsSet = new Set();
const redText = (text) => `\x1b[31m${text}\x1b[0m`;
const greenText = (text) => `\x1b[32m${text}\x1b[0m`;
const blueText = (text) => `\x1b[34m${text}\x1b[0m`;
const configFilePath = config_service_1.ConfigService.findConfigFile();
if (!configFilePath) {
throw new errors_1.CLIError('Configuration file not found. Please ensure you are logged in.', { exit: 2 });
}
const config = config_service_1.ConfigService.readConfig(configFilePath);
this.log(`Logged in to: ${config.ControlPlaneURL} with user: ${config.Username}`);
if (sync) {
core_1.ux.action.start('Initiating sync process before starting to wait');
try {
const syncResponse = await FacetsApi.syncApps(config.ControlPlaneURL, config.Username, config.AccessToken, project, environment, apps);
const alreadyInSyncResources = [];
syncResponse?.resourceStatuses?.forEach((resource) => {
if (resource?.syncStatus === 'IN_SYNC') {
alreadyInSyncResources.push(resource?.resourceName);
allAppsSet.delete(resource?.resourceName);
}
});
if (alreadyInSyncResources?.length) {
this.log(blueText(`Following resource(s) are already in sync: ${alreadyInSyncResources.join(', ')}.`));
}
if (allAppsSet?.size) {
this.log(`Starting syncing process for the following resource(s): ${(Array.from(allAppsSet))?.join(', ')}`);
}
}
catch (error) {
core_1.ux.action.stop('Failed');
if (error instanceof Error) {
throw new errors_1.CLIError(`Failed to trigger sync: ${error.message}`, { exit: 2 });
}
}
}
if (allAppsSet?.size)
core_1.ux.action.start('Waiting for apps to sync');
const timeout = 15 * 60 * 1000;
let elapsedTime = 0;
let releaseFailed = false;
while (elapsedTime < timeout) {
try {
const statusResponse = await FacetsApi.checkAppStatus(config.ControlPlaneURL, config.Username, config.AccessToken, project, environment, apps);
if (debug) {
console.log(`WAIT RSP (${elapsedTime})=> `, statusResponse);
}
statusResponse?.resourceStatuses?.forEach((resource) => {
if (resource.syncStatus === 'IN_SYNC' && allAppsSet?.has(resource.resourceName)) {
this.log(` - ${resource.resourceName} has synced successfully.`);
allAppsSet?.delete(resource.resourceName);
}
else if (resource.releaseStatus === 'FAILED') {
releaseFailed = true;
if (sync) {
allAppsSet?.clear();
}
else {
this.log(` - ${resource.resourceName} could not be synced due to release failure.`);
failedAppsSet.add(resource?.resourceName);
allAppsSet?.delete(resource.resourceName);
}
}
});
if (allAppsSet?.size === 0) {
core_1.ux.action.stop((releaseFailed && sync) ? redText('unsuccessful due to release failure.') : ((releaseFailed && !sync) ? redText('completed') : greenText('completed.')));
if (releaseFailed && sync) {
throw new errors_1.CLIError('All apps could not be synced', { exit: 2 });
}
else if (!sync && failedAppsSet?.size > 0 && failedAppsSet?.size < apps?.length) {
throw new errors_1.CLIError(`${Array.from(failedAppsSet)?.join(', ')} could not be synced`, { exit: 2 });
}
break;
}
if (failedAppsSet?.size == apps?.length) {
throw new errors_1.CLIError('All apps have reached FAILED release state', { exit: 2 });
}
await new Promise((resolve) => setTimeout(resolve, 5000));
elapsedTime += 5000;
}
catch (error) {
core_1.ux.action.stop('Failed');
if (error instanceof Error) {
throw new errors_1.CLIError(`Error while checking app status: ${error.message}`, { exit: 2 });
}
return;
}
}
if (allAppsSet?.size) {
this.log(`Timed out waiting for apps to become in-sync.`);
throw new errors_1.CLIError(`Apps which are still out of sync: ${Array.from(allAppsSet)?.join(', ')}`, { exit: 124 });
}
}
}
exports.default = Wait;