@controlplane/cli
Version:
Control Plane Corporation CLI
185 lines • 8.35 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.HelmReleaseMigrator = void 0;
const constants_1 = require("./constants");
const resolver_1 = require("../commands/resolver");
const helm_base_1 = require("./helm-base");
const functions_1 = require("./functions");
class HelmReleaseMigrator extends helm_base_1.HelmBase {
constructor(client, session, args, ensureDeletion, secret) {
super(client, session, args, ensureDeletion);
// Required Parameters
this.secret = secret;
// Parameters dependant
this.secretSelfLink = (0, resolver_1.resolveToLink)('secret', secret.name, this.session.context);
}
// Public Methods //
async migrate() {
// Check if the secret is already at the latest version
if (this.secret.tags && this.secret.tags[constants_1.CPLN_HELM_SCHEMA_LATEST_VERSION_TAG_KEY] === constants_1.CPLN_HELM_SCHEMA_LATEST_VERSION) {
// No need to migrate
return;
}
// Handle the migration safely
try {
// Parse the data of the secret into a IHasSchemaVersion, no need to worry about parsing issues because
// we are sure that the schema version could either be '1' or '2' for now.
let releaseHasSchemaVersion;
// Handle secret data differently for legacy versions >= 3
if (this.secret.tags.hasOwnProperty(constants_1.CPLN_HELM_SCHEMA_LATEST_VERSION_TAG_KEY)) {
releaseHasSchemaVersion = (0, functions_1.decodeReleaseFromSecret)(this.secret);
}
else {
releaseHasSchemaVersion = JSON.parse(this.secret.data.payload);
}
// Migrate based on the schema version
switch (releaseHasSchemaVersion.schemaVersion) {
case '1':
// Migrate from version 1 to version 2
const legacyReleaseV2 = await this.migrateFromVersion1ToVersion2(releaseHasSchemaVersion);
// Migrate from version 2 straight to version 4
await this.migrateFromVersion2ToVersion4(legacyReleaseV2);
break;
case '2':
// Migrate from version 2 straight to version 4
await this.migrateFromVersion2ToVersion4(releaseHasSchemaVersion);
break;
case '3':
// Migrate from version 3 to version 4
await this.migrateFromVersion3ToVersion4(releaseHasSchemaVersion);
break;
}
}
catch (e) {
this.session.err(`ERROR: Failed to migrate release '${this.releaseName}'.`);
this.session.abort({ error: e });
}
}
// Private Methods //
async migrateFromVersion1ToVersion2(legacyReleaseV1) {
var _a;
const resources = [];
for (const resource of legacyReleaseV1.resources) {
try {
resources.push({
...resource,
template: await this.fetchResource(resource.kind, resource.link),
});
}
catch (e) {
// Ignore 404
if (((_a = e.response) === null || _a === void 0 ? void 0 : _a.status) !== 404) {
throw e;
}
}
}
return {
schemaVersion: '2',
release: legacyReleaseV1.release,
deployments: [
{
gvc: '',
revision: 1,
updated: new Date().toISOString(),
status: 'deployed',
chart: '',
appVersion: '',
description: legacyReleaseV1.description,
config: {},
values: {},
valuesFiles: [],
resources,
},
],
};
}
async migrateFromVersion2ToVersion4(legacyReleaseV2) {
// A variable to hold all secret creation promises so we can await for the creation asynchronously
const promises = [];
// Iterate over each release deployment and create a new secret with the revision number
for (const deployment of legacyReleaseV2.deployments) {
// Construct the release object for schema version 3
const release = {
schemaVersion: '4',
name: legacyReleaseV2.release,
info: {
firstDeployed: new Date(this.secret.created).toISOString(),
lastDeployed: deployment.updated,
description: deployment.description,
status: deployment.status,
notes: '',
resources: deployment.resources,
},
chart: {
metadata: {
name: deployment.chart,
appVersion: deployment.appVersion,
},
values: deployment.values,
},
config: deployment.config,
manifest: '',
version: deployment.revision,
gvc: deployment.gvc,
labels: {},
// Custom Properties
valuesFiles: deployment.valuesFiles,
};
// Create a new secret with the release object
promises.push(this.createReleaseSecret(release, this.secret.tags));
}
// Wait for all secrets to be created
await Promise.all(promises);
// Delete the original secret after successful migration
await this.client.delete(this.secretSelfLink);
}
async migrateFromVersion3ToVersion4(legacyReleaseV3) {
// Update the schema version tag in the secret
this.secret.tags[constants_1.CPLN_HELM_SCHEMA_LATEST_VERSION_TAG_KEY] = '4';
// Initialize the release object with the latest schema version
const release = {
...legacyReleaseV3,
schemaVersion: constants_1.CPLN_HELM_SCHEMA_LATEST_VERSION,
labels: {},
};
// Attempt to fetch the first available resource from the legacy release resources
const firstResource = await this.fetchFirstAvailableResource(legacyReleaseV3.info.resources);
// If a resource was found, we can extract the injected tags
if (firstResource !== null) {
// Extract the injected tags from the resource by finding common tags between the resource and the secret
const injectedTags = Object.fromEntries(Object.entries(this.secret.tags)
// 1) Drop secret core keys from the secret tags
.filter(([key, _]) => !constants_1.CPLN_HELM_SECRET_CORE_KEYS.has(key))
// 2) Only keep ones that match on the resource
.filter(([key, value]) => firstResource.tags[key] === value));
// Update the release labels with the injected tags (could be empty if no tags matched)
release.labels = injectedTags;
}
// Update the secret payload with the new release object
this.secret.data.payload = await (0, functions_1.encodeRelease)(release);
// Update the secret and return
await this.client.put(this.secretSelfLink, this.secret);
}
async fetchFirstAvailableResource(helmResources) {
var _a;
// Iterate over the resources and attempt to find at least one that exists
for (const helmResource of helmResources) {
try {
// Fetch the resource using its link and return it
return await this.client.get(helmResource.link);
}
catch (err) {
// Ignore 404 errors and try the next resource
if (((_a = err.response) === null || _a === void 0 ? void 0 : _a.status) === 404) {
continue;
}
// If the error is not a 404, rethrow it
throw err;
}
}
// If no resource was found, return null
return null;
}
}
exports.HelmReleaseMigrator = HelmReleaseMigrator;
//# sourceMappingURL=helm-release-migrator.js.map