@hashgraph/solo
Version:
An opinionated CLI tool to deploy and manage private Hedera Networks.
195 lines • 9.43 kB
JavaScript
// SPDX-License-Identifier: Apache-2.0
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
import * as constants from './constants.js';
import chalk from 'chalk';
import { SoloError } from './errors/solo-error.js';
import { inject, injectable } from 'tsyringe-neo';
import { patchInject } from './dependency-injection/container-helper.js';
import { InjectTokens } from './dependency-injection/inject-tokens.js';
import { Repository } from '../integration/helm/model/repository.js';
import { UpgradeChartOptions } from '../integration/helm/model/upgrade/upgrade-chart-options.js';
import { Chart } from '../integration/helm/model/chart.js';
import { InstallChartOptionsBuilder } from '../integration/helm/model/install/install-chart-options-builder.js';
import { UnInstallChartOptionsBuilder } from '../integration/helm/model/install/un-install-chart-options-builder.js';
import { AddRepoOptionsBuilder } from '../integration/helm/model/add/add-repo-options-builder.js';
let ChartManager = class ChartManager {
helm;
logger;
constructor(helm, logger) {
this.helm = helm;
this.logger = logger;
this.helm = patchInject(helm, InjectTokens.Helm, this.constructor.name);
this.logger = patchInject(logger, InjectTokens.SoloLogger, this.constructor.name);
}
/**
* Setup chart repositories
*
* This must be invoked before calling other methods
*
* @param repoURLs - a map of name and chart repository URLs
* @param force - whether or not to update the repo
* @returns the urls
*/
async setup(repoURLs = constants.DEFAULT_CHART_REPO, force = true) {
try {
const promises = [];
for (const [name, url] of repoURLs.entries()) {
this.logger.debug(`pushing promise for: add repo ${name} -> ${url}`);
promises.push(this.addRepo(name, url, force));
}
const urls = await Promise.all(promises); // urls
await this.helm.updateRepositories();
return urls;
}
catch (error) {
throw new SoloError(`failed to setup chart repositories: ${error.message}`, error);
}
}
/**
* Check if the required chart repositories are set up
*
* @param repoURLs - a map of name and chart repository URLs
* @returns true if all repos are set up, false otherwise
*/
async isSetup(repoURLs = constants.DEFAULT_CHART_REPO) {
try {
const existingRepos = await this.helm.listRepositories();
for (const [name, url] of repoURLs.entries()) {
const found = existingRepos.find((repo) => repo.name === name && repo.url === url);
if (!found) {
this.logger.debug(`Repo not found: ${name} -> ${url}`);
return false;
}
}
return true;
}
catch (error) {
throw new SoloError(`failed to check chart repositories: ${error.message}`, error);
}
}
async addRepo(name, url, force) {
// detect if repo already exists for name provided and the url matches, if so, exit, otherwise force update
const repositories = await this.helm.listRepositories();
const existingRepo = repositories.find((repo) => repo.name === name);
if (existingRepo) {
if (existingRepo.url === url) {
this.logger.debug(`Repo already exists: ${name} -> ${url}`);
return url;
}
this.logger.debug(`Repo URL mismatch for ${name}: existing URL is ${existingRepo.url}, new URL is ${url}`);
}
this.logger.debug(`Adding repo ${name} -> ${url}`, { repoName: name, repoURL: url });
const options = new AddRepoOptionsBuilder().forceUpdate(force).build();
await this.helm.addRepository(new Repository(name, url), options);
return url;
}
/** List available clusters
*
* @param namespaceName - the namespace name
* @param kubeContext - the kube context
*/
async getInstalledCharts(namespaceName, kubeContext) {
try {
const result = await this.helm.listReleases(!namespaceName, namespaceName?.name, kubeContext);
// convert to string[]
return result.map((release) => `${release.name} [${release.chart}]`);
}
catch (error) {
this.logger.showUserError(error);
throw new SoloError(`failed to list installed charts: ${error.message}`, error);
}
}
async install(namespaceName, chartReleaseName, chartName, repoName, version, valuesArgument = '', kubeContext, atomic = false, waitFor = false) {
try {
const isInstalled = await this.isChartInstalled(namespaceName, chartReleaseName, kubeContext);
if (isInstalled) {
this.logger.debug(`OK: chart is already installed:${chartReleaseName} (${chartName}) (${repoName})`);
}
else {
this.logger.debug(`> installing chart:${chartName}`);
const builder = InstallChartOptionsBuilder.builder()
.version(version)
.kubeContext(kubeContext)
.atomic(atomic)
.waitFor(waitFor)
.extraArgs(valuesArgument);
if (namespaceName) {
builder.createNamespace(true);
builder.namespace(namespaceName.name);
}
const options = builder.build();
await this.helm.installChart(chartReleaseName, new Chart(chartName, repoName), options);
this.logger.debug(`OK: chart is installed: ${chartReleaseName} (${chartName}) (${repoName})`);
}
}
catch (error) {
throw new SoloError(`failed to install chart ${chartReleaseName}: ${error.message}`, error);
}
return true;
}
async isChartInstalled(namespaceName, chartReleaseName, kubeContext) {
this.logger.debug(`> checking if chart is installed [ chart: ${chartReleaseName}, namespace: ${namespaceName}, kubeContext: ${kubeContext} ]`);
const charts = await this.getInstalledCharts(namespaceName, kubeContext);
let match = false;
for (const chart of charts) {
if (chart.split(' ')[0] === chartReleaseName) {
match = true;
break;
}
}
return match;
}
async uninstall(namespaceName, chartReleaseName, kubeContext) {
try {
const isInstalled = await this.isChartInstalled(namespaceName, chartReleaseName, kubeContext);
if (isInstalled) {
this.logger.debug(`uninstalling chart release: ${chartReleaseName}`);
const options = UnInstallChartOptionsBuilder.builder()
.namespace(namespaceName.name)
.kubeContext(kubeContext)
.build();
await this.helm.uninstallChart(chartReleaseName, options);
this.logger.debug(`OK: chart release is uninstalled: ${chartReleaseName}`);
}
else {
this.logger.debug(`OK: chart release is already uninstalled: ${chartReleaseName}`);
}
}
catch (error) {
throw new SoloError(`failed to uninstall chart ${chartReleaseName}: ${error.message}`, error);
}
return true;
}
async upgrade(namespaceName, chartReleaseName, chartName, repoName, version = '', valuesArgument = '', kubeContext, reuseValues) {
try {
this.logger.debug(chalk.cyan('> upgrading chart:'), chalk.yellow(`${chartReleaseName}`));
const options = new UpgradeChartOptions(namespaceName?.name, kubeContext, reuseValues ?? true, valuesArgument, version);
const chart = new Chart(chartName, repoName);
await this.helm.upgradeChart(chartReleaseName, chart, options);
this.logger.debug(chalk.green('OK'), `chart '${chartReleaseName}' is upgraded`);
}
catch (error) {
throw new SoloError(`failed to upgrade chart ${chartReleaseName}: ${error.message}`, error);
}
return true;
}
};
ChartManager = __decorate([
injectable(),
__param(0, inject(InjectTokens.Helm)),
__param(1, inject(InjectTokens.SoloLogger)),
__metadata("design:paramtypes", [Object, Object])
], ChartManager);
export { ChartManager };
//# sourceMappingURL=chart-manager.js.map