Migrating Vue components to React and stores refactoring (#585)

Signed-off-by: Roman <ixrock@gmail.com>

Co-authored-by: Sebastian Malton <sebastian@malton.name>
Co-authored-by: Sebastian Malton <smalton@mirantis.com>
Co-authored-by: Lauri Nevala <lauri.nevala@gmail.com>
Co-authored-by: Alex Andreev <alex.andreev.email@gmail.com>
This commit is contained in:
authored and GitHub committed 2020-08-20 08:53:07 +03:00
1 parent 905bbe9d3f
commit 5670312c47
297 files changed
+8186 -9103

No files matched your search

+74
View File
@@ -0,0 +1,74 @@
import fs from "fs";
import * as yaml from "js-yaml";
import { HelmRepo, HelmRepoManager } from "./helm-repo-manager"
import logger from "../logger";
import { promiseExec } from "../promise-exec"
import { helmCli } from "./helm-cli"
type CachedYaml = {
entries: any; // todo: types
}
export class HelmChartManager {
protected cache: any = {}
protected repo: HelmRepo
constructor(repo: HelmRepo){
this.cache = HelmRepoManager.cache
this.repo = repo
}
public async chart(name: string) {
const charts = await this.charts()
return charts[name]
}
public async charts(): Promise<any> {
try {
const cachedYaml = await this.cachedYaml()
return cachedYaml["entries"]
} catch(error) {
logger.error(error)
return []
}
}
public async getReadme(name: string, version = "") {
const helm = await helmCli.binaryPath()
if(version && version != "") {
const { stdout, stderr} = await promiseExec(`"${helm}" show readme ${this.repo.name}/${name} --version ${version}`).catch((error) => { throw(error.stderr)})
return stdout
} else {
const { stdout, stderr} = await promiseExec(`"${helm}" show readme ${this.repo.name}/${name}`).catch((error) => { throw(error.stderr)})
return stdout
}
}
public async getValues(name: string, version = "") {
const helm = await helmCli.binaryPath()
if(version && version != "") {
const { stdout, stderr} = await promiseExec(`"${helm}" show values ${this.repo.name}/${name} --version ${version}`).catch((error) => { throw(error.stderr)})
return stdout
} else {
const { stdout, stderr} = await promiseExec(`"${helm}" show values ${this.repo.name}/${name}`).catch((error) => { throw(error.stderr)})
return stdout
}
}
protected async cachedYaml(): Promise<CachedYaml> {
if (!(this.repo.name in this.cache)) {
const cacheFile = await fs.promises.readFile(this.repo.cacheFilePath, 'utf-8')
const data = yaml.safeLoad(cacheFile)
for(const key in data["entries"]) {
data["entries"][key].forEach((version: any) => {
version['repo'] = this.repo.name
version['created'] = Date.parse(version.created).toString()
})
}
this.cache[this.repo.name] = Buffer.from(JSON.stringify(data))
}
return JSON.parse(this.cache[this.repo.name].toString())
}
}
+43
View File
@@ -0,0 +1,43 @@
import packageInfo from "../../../package.json"
import path from "path"
import { LensBinary, LensBinaryOpts } from "../lens-binary"
import { isProduction } from "../../common/vars";
export class HelmCli extends LensBinary {
public constructor(baseDir: string, version: string) {
const opts: LensBinaryOpts = {
version,
baseDir: baseDir,
originalBinaryName: "helm",
newBinaryName: "helm3"
}
super(opts)
}
protected getTarName(): string | null {
return `${this.binaryName}-v${this.binaryVersion}-${this.platformName}-${this.arch}.tar.gz`
}
protected getUrl() {
return `https://get.helm.sh/helm-v${this.binaryVersion}-${this.platformName}-${this.arch}.tar.gz`
}
protected getBinaryPath() {
return path.join(this.dirname, this.binaryName)
}
protected getOriginalBinaryPath() {
return path.join(this.dirname, this.platformName + "-" + this.arch, this.originalBinaryName)
}
}
const helmVersion = packageInfo.config.bundledHelmVersion;
let baseDir = process.resourcesPath;
if (!isProduction) {
baseDir = path.join(process.cwd(), "binaries", "client");
}
export const helmCli = new HelmCli(baseDir, helmVersion);
+111
View File
@@ -0,0 +1,111 @@
import * as tempy from "tempy";
import fs from "fs";
import * as yaml from "js-yaml";
import { promiseExec} from "../promise-exec"
import { helmCli } from "./helm-cli";
import { Cluster } from "../cluster";
import { toCamelCase } from "../../common/utils/camelCase";
export class HelmReleaseManager {
public async listReleases(pathToKubeconfig: string, namespace?: string) {
const helm = await helmCli.binaryPath()
const namespaceFlag = namespace ? `-n ${namespace}` : "--all-namespaces"
const { stdout } = await promiseExec(`"${helm}" ls --output json ${namespaceFlag} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr)})
const output = JSON.parse(stdout)
if (output.length == 0) {
return output
}
output.forEach((release: any, index: number) => {
output[index] = toCamelCase(release)
});
return output
}
public async installChart(chart: string, values: any, name: string, namespace: string, version: string, pathToKubeconfig: string){
const helm = await helmCli.binaryPath()
const fileName = tempy.file({name: "values.yaml"})
await fs.promises.writeFile(fileName, yaml.safeDump(values))
try {
let generateName = ""
if (!name) {
generateName = "--generate-name"
name = ""
}
const { stdout, stderr } = await promiseExec(`"${helm}" install ${name} ${chart} --version ${version} -f ${fileName} --namespace ${namespace} --kubeconfig ${pathToKubeconfig} ${generateName}`).catch((error) => { throw(error.stderr)})
const releaseName = stdout.split("\n")[0].split(' ')[1].trim()
return {
log: stdout,
release: {
name: releaseName,
namespace: namespace
}
}
} finally {
await fs.promises.unlink(fileName)
}
}
public async upgradeRelease(name: string, chart: string, values: any, namespace: string, version: string, cluster: Cluster){
const helm = await helmCli.binaryPath()
const fileName = tempy.file({name: "values.yaml"})
await fs.promises.writeFile(fileName, yaml.safeDump(values))
try {
const { stdout, stderr } = await promiseExec(`"${helm}" upgrade ${name} ${chart} --version ${version} -f ${fileName} --namespace ${namespace} --kubeconfig ${cluster.getProxyKubeconfigPath()}`).catch((error) => { throw(error.stderr)})
return {
log: stdout,
release: this.getRelease(name, namespace, cluster)
}
} finally {
await fs.promises.unlink(fileName)
}
}
public async getRelease(name: string, namespace: string, cluster: Cluster) {
const helm = await helmCli.binaryPath()
const {stdout, stderr} = await promiseExec(`"${helm}" status ${name} --output json --namespace ${namespace} --kubeconfig ${cluster.getProxyKubeconfigPath()}`).catch((error) => { throw(error.stderr)})
const release = JSON.parse(stdout)
release.resources = await this.getResources(name, namespace, cluster)
return release
}
public async deleteRelease(name: string, namespace: string, pathToKubeconfig: string) {
const helm = await helmCli.binaryPath()
const { stdout, stderr } = await promiseExec(`"${helm}" delete ${name} --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr)})
return stdout
}
public async getValues(name: string, namespace: string, pathToKubeconfig: string) {
const helm = await helmCli.binaryPath()
const { stdout, stderr } = await promiseExec(`"${helm}" get values ${name} --all --output yaml --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr)})
return stdout
}
public async getHistory(name: string, namespace: string, pathToKubeconfig: string) {
const helm = await helmCli.binaryPath()
const {stdout, stderr} = await promiseExec(`"${helm}" history ${name} --output json --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr)})
return JSON.parse(stdout)
}
public async rollback(name: string, namespace: string, revision: number, pathToKubeconfig: string) {
const helm = await helmCli.binaryPath()
const {stdout, stderr} = await promiseExec(`"${helm}" rollback ${name} ${revision} --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr)})
return stdout
}
protected async getResources(name: string, namespace: string, cluster: Cluster) {
const helm = await helmCli.binaryPath()
const kubectl = await cluster.kubeCtl.getPath()
const pathToKubeconfig = cluster.getProxyKubeconfigPath()
const { stdout } = await promiseExec(`"${helm}" get manifest ${name} --namespace ${namespace} --kubeconfig ${pathToKubeconfig} | "${kubectl}" get -n ${namespace} --kubeconfig ${pathToKubeconfig} -f - -o=json`).catch((error) => {
return { stdout: JSON.stringify({items: []})}
})
return stdout
}
}
export const releaseManager = new HelmReleaseManager()
+130
View File
@@ -0,0 +1,130 @@
import yaml from "js-yaml";
import { readFile } from "fs-extra";
import { promiseExec } from "../promise-exec";
import { helmCli } from "./helm-cli";
import { Singleton } from "../../common/utils/singleton";
import { customRequestPromise } from "../../common/request";
import orderBy from "lodash/orderBy";
import logger from "../logger";
export type HelmEnv = Record<string, string> & {
HELM_REPOSITORY_CACHE?: string;
HELM_REPOSITORY_CONFIG?: string;
}
export interface HelmRepoConfig {
repositories: HelmRepo[]
}
export interface HelmRepo {
name: string;
url: string;
cacheFilePath?: string
caFile?: string,
certFile?: string,
insecure_skip_tls_verify?: boolean,
keyFile?: string,
username?: string,
password?: string,
}
export class HelmRepoManager extends Singleton {
static cache = {} // todo: remove implicit updates in helm-chart-manager.ts
protected repos: HelmRepo[];
protected helmEnv: HelmEnv
protected initialized: boolean
async loadAvailableRepos(): Promise<HelmRepo[]> {
const res = await customRequestPromise({
uri: "https://hub.helm.sh/assets/js/repos.json",
json: true,
resolveWithFullResponse: true,
timeout: 10000,
});
return orderBy<HelmRepo>(res.body.data, repo => repo.name);
}
async init() {
await helmCli.ensureBinary();
if (!this.initialized) {
this.helmEnv = await this.parseHelmEnv()
await this.update()
this.initialized = true
}
}
protected async parseHelmEnv() {
const helm = await helmCli.binaryPath()
const { stdout } = await promiseExec(`"${helm}" env`).catch((error) => {
throw(error.stderr)
})
const lines = stdout.split(/\r?\n/) // split by new line feed
const env: HelmEnv = {}
lines.forEach((line: string) => {
const [key, value] = line.split("=")
if (key && value) {
env[key] = value.replace(/"/g, "") // strip quotas
}
})
return env
}
public async repositories(): Promise<HelmRepo[]> {
if (!this.initialized) {
await this.init()
}
try {
const repoConfigFile = this.helmEnv.HELM_REPOSITORY_CONFIG;
const { repositories }: HelmRepoConfig = await readFile(repoConfigFile, 'utf8')
.then((yamlContent: string) => yaml.safeLoad(yamlContent))
.catch(() => ({
repositories: []
}));
if (!repositories.length) {
await this.addRepo({ name: "stable", url: "https://kubernetes-charts.storage.googleapis.com/" });
return await this.repositories();
}
return repositories.map(repo => ({
...repo,
cacheFilePath: `${this.helmEnv.HELM_REPOSITORY_CACHE}/${repo.name}-index.yaml`
}));
} catch (error) {
logger.error(`[HELM]: repositories listing error "${error}"`)
return []
}
}
public async repository(name: string) {
const repositories = await this.repositories()
return repositories.find(repo => repo.name == name);
}
public async update() {
const helm = await helmCli.binaryPath()
const { stdout } = await promiseExec(`"${helm}" repo update`).catch((error) => {
return { stdout: error.stdout }
})
return stdout
}
public async addRepo({ name, url }: HelmRepo) {
logger.info(`[HELM]: adding repo "${name}" from ${url}`);
const helm = await helmCli.binaryPath()
const { stdout } = await promiseExec(`"${helm}" repo add ${name} ${url}`).catch((error) => {
throw(error.stderr)
})
return stdout
}
public async removeRepo({ name, url }: HelmRepo): Promise<string> {
logger.info(`[HELM]: removing repo "${name}" from ${url}`);
const helm = await helmCli.binaryPath()
const { stdout, stderr } = await promiseExec(`"${helm}" repo remove ${name}`).catch((error) => {
throw(error.stderr)
})
return stdout
}
}
export const repoManager = HelmRepoManager.getInstance<HelmRepoManager>()
+98
View File
@@ -0,0 +1,98 @@
import { Cluster } from "../cluster";
import logger from "../logger";
import { repoManager } from "./helm-repo-manager";
import { HelmChartManager } from "./helm-chart-manager";
import { releaseManager } from "./helm-release-manager";
class HelmService {
public async installChart(cluster: Cluster, data: { chart: string; values: {}; name: string; namespace: string; version: string }) {
return await releaseManager.installChart(data.chart, data.values, data.name, data.namespace, data.version, cluster.getProxyKubeconfigPath())
}
public async listCharts() {
const charts: any = {}
await repoManager.init()
const repositories = await repoManager.repositories()
for (const repo of repositories) {
charts[repo.name] = {}
const manager = new HelmChartManager(repo)
let entries = await manager.charts()
entries = this.excludeDeprecated(entries)
for (const key in entries) {
entries[key] = entries[key][0]
}
charts[repo.name] = entries
}
return charts
}
public async getChart(repoName: string, chartName: string, version = "") {
const result = {
readme: "",
versions: {}
}
const repo = await repoManager.repository(repoName)
const chartManager = new HelmChartManager(repo)
const chart = await chartManager.chart(chartName)
result.readme = await chartManager.getReadme(chartName, version)
result.versions = chart
return result
}
public async getChartValues(repoName: string, chartName: string, version = "") {
const repo = await repoManager.repository(repoName)
const chartManager = new HelmChartManager(repo)
return chartManager.getValues(chartName, version)
}
public async listReleases(cluster: Cluster, namespace: string = null) {
await repoManager.init()
return await releaseManager.listReleases(cluster.getProxyKubeconfigPath(), namespace)
}
public async getRelease(cluster: Cluster, releaseName: string, namespace: string) {
logger.debug("Fetch release")
return await releaseManager.getRelease(releaseName, namespace, cluster)
}
public async getReleaseValues(cluster: Cluster, releaseName: string, namespace: string) {
logger.debug("Fetch release values")
return await releaseManager.getValues(releaseName, namespace, cluster.getProxyKubeconfigPath())
}
public async getReleaseHistory(cluster: Cluster, releaseName: string, namespace: string) {
logger.debug("Fetch release history")
return await releaseManager.getHistory(releaseName, namespace, cluster.getProxyKubeconfigPath())
}
public async deleteRelease(cluster: Cluster, releaseName: string, namespace: string) {
logger.debug("Delete release")
return await releaseManager.deleteRelease(releaseName, namespace, cluster.getProxyKubeconfigPath())
}
public async updateRelease(cluster: Cluster, releaseName: string, namespace: string, data: { chart: string; values: {}; version: string }) {
logger.debug("Upgrade release")
return await releaseManager.upgradeRelease(releaseName, data.chart, data.values, namespace, data.version, cluster)
}
public async rollback(cluster: Cluster, releaseName: string, namespace: string, revision: number) {
logger.debug("Rollback release")
const output = await releaseManager.rollback(releaseName, namespace, revision, cluster.getProxyKubeconfigPath())
return { message: output }
}
protected excludeDeprecated(entries: any) {
for (const key in entries) {
entries[key] = entries[key].filter((entry: any) => {
if (Array.isArray(entry)) {
return entry[0]['deprecated'] != true
}
return entry["deprecated"] != true
})
}
return entries
}
}
export const helmService = new HelmService()