preferences page -- part 2

Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
Roman committed 2020-07-23 16:01:32 +03:00
1 parent 24f754697b
commit 6fd9b7cf76
14 files changed
+452 -535

No files matched your search

+3 -2
View File
@@ -6,12 +6,13 @@ import { promiseExec } from "../promise-exec"
import { helmCli } from "./helm-cli"
type CachedYaml = {
entries: any;
entries: any; // todo: types
}
export class HelmChartManager {
protected cache: any
protected cache: any = {}
protected repo: HelmRepo
constructor(repo: HelmRepo){
this.cache = HelmRepoManager.cache
this.repo = repo
+57 -37
View File
@@ -1,28 +1,51 @@
import fs from "fs";
import logger from "../logger";
import * as yaml from "js-yaml";
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 type HelmRepo = {
export interface HelmRepoConfig {
repositories: HelmRepo[]
}
export interface HelmRepo {
name: string;
url: string;
cacheFilePath?: 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 = {}
static cache = {} // todo: remove implicit updates in helm-chart-manager.ts
protected repos: HelmRepo[];
protected helmEnv: HelmEnv
protected initialized: boolean
public async init() {
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()
@@ -47,60 +70,57 @@ export class HelmRepoManager extends Singleton {
return env
}
public async repositories(): Promise<Array<HelmRepo>> {
public async repositories(): Promise<HelmRepo[]> {
if (!this.initialized) {
await this.init()
}
const repositoryFilePath = this.helmEnv.HELM_REPOSITORY_CONFIG
const repoFile = await fs.promises.readFile(repositoryFilePath, 'utf8').catch(async (error) => {
return null
})
if (!repoFile) {
await this.addRepo({ name: "stable", url: "https://kubernetes-charts.storage.googleapis.com/" })
return await this.repositories()
}
try {
const repositories = yaml.safeLoad(repoFile)
const result = repositories['repositories'].map((repository: HelmRepo) => {
return {
name: repository.name,
url: repository.url,
cacheFilePath: `${this.helmEnv.HELM_REPOSITORY_CACHE}/${repository['name']}-index.yaml`
}
});
if (result.length == 0) {
await this.addRepo({ name: "stable", url: "https://kubernetes-charts.storage.googleapis.com/" })
return await this.repositories()
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 result
return repositories.map(repo => ({
...repo,
cacheFilePath: `${this.helmEnv.HELM_REPOSITORY_CACHE}/${repo.name}-index.yaml`
}));
} catch (error) {
logger.debug(error)
logger.error(`[HELM]: repositories listing error "${error}"`)
return []
}
}
public async repository(name: string) {
const repositories = await this.repositories()
return repositories.find((repo: HelmRepo) => {
return repo.name == name
})
return repositories.find(repo => repo.name == name);
}
public async update() {
const helm = await helmCli.binaryPath()
logger.debug(`${helm} repo update`)
const { stdout } = await promiseExec(`"${helm}" repo update`).catch((error) => {
return { stdout: error.stdout }
})
return stdout
}
public async addRepo(repository: HelmRepo) {
public async addRepo({ name, url }: HelmRepo) {
logger.info(`[HELM]: adding repo "${name}" from ${url}`);
const helm = await helmCli.binaryPath()
logger.debug(`${helm} repo add ${repository.name} ${repository.url}`)
const { stdout } = await promiseExec(`"${helm}" repo add ${name} ${url}`).catch((error) => {
throw(error.stderr)
})
return stdout
}
const { stdout } = await promiseExec(`"${helm}" repo add ${repository.name} ${repository.url}`).catch((error) => {
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
+35 -37
View File
@@ -1,15 +1,15 @@
import { app, remote } from "electron"
import path from "path"
import fs from "fs"
import request from "request"
import { promiseExec} from "./promise-exec"
import { promiseExec } from "./promise-exec"
import logger from "./logger"
import { ensureDir, pathExists } from "fs-extra"
import { globalRequestOpts } from "../common/request"
import * as lockFile from "proper-lockfile"
import { helmCli } from "./helm/helm-cli"
import { userStore } from "../common/user-store"
import { getBundledKubectlVersion} from "../common/utils/app-version"
import { customRequest } from "../common/request";
import { getBundledKubectlVersion } from "../common/utils/app-version"
import { isDevelopment, isWindows } from "../common/vars";
const bundledVersion = getBundledKubectlVersion()
const kubectlMap: Map<string, string> = new Map([
@@ -32,18 +32,18 @@ const packageMirrors: Map<string, string> = new Map([
["china", "https://mirror.azure.cn/kubernetes/kubectl"]
])
let bundledPath: string
const initScriptVersionString = "# lens-initscript v3\n"
const isDevelopment = process.env.NODE_ENV !== "production"
let bundledPath: string = null
if(isDevelopment) {
if (isDevelopment) {
bundledPath = path.join(process.cwd(), "binaries", "client", process.platform, process.arch, "kubectl")
} else {
bundledPath = path.join(process.resourcesPath, process.arch, "kubectl")
}
if(process.platform === "win32") bundledPath = `${bundledPath}.exe`
if (isWindows) {
bundledPath = `${bundledPath}.exe`
}
export class Kubectl {
public kubectlVersion: string
@@ -52,7 +52,7 @@ export class Kubectl {
protected path: string
protected dirname: string
static get kubectlDir(){
static get kubectlDir() {
return path.join((app || remote.app).getPath("userData"), "binaries", "kubectl")
}
@@ -62,7 +62,7 @@ export class Kubectl {
// Returns the single bundled Kubectl instance
public static bundled() {
if(!Kubectl.bundledInstance) Kubectl.bundledInstance = new Kubectl(Kubectl.bundledKubectlVersion)
if (!Kubectl.bundledInstance) Kubectl.bundledInstance = new Kubectl(Kubectl.bundledKubectlVersion)
return Kubectl.bundledInstance
}
@@ -71,7 +71,7 @@ export class Kubectl {
const minorVersion = versionParts[1]
/* minorVersion is the first two digits of kube server version
if the version map includes that, use that version, if not, fallback to the exact x.y.z of kube version */
if(kubectlMap.has(minorVersion)) {
if (kubectlMap.has(minorVersion)) {
this.kubectlVersion = kubectlMap.get(minorVersion)
logger.debug("Set kubectl version " + this.kubectlVersion + " for cluster version " + clusterVersion + " using version map")
} else {
@@ -81,16 +81,16 @@ export class Kubectl {
let arch = null
if(process.arch == "x64") {
if (process.arch == "x64") {
arch = "amd64"
} else if(process.arch == "x86" || process.arch == "ia32") {
} else if (process.arch == "x86" || process.arch == "ia32") {
arch = "386"
} else {
arch = process.arch
}
const platformName = process.platform === "win32" ? "windows" : process.platform
const binaryName = process.platform === "win32" ? "kubectl.exe" : "kubectl"
const platformName = isWindows ? "windows" : process.platform
const binaryName = isWindows ? "kubectl.exe" : "kubectl"
this.url = `${this.getDownloadMirror()}/v${this.kubectlVersion}/bin/${platformName}/${arch}/${binaryName}`
@@ -102,7 +102,7 @@ export class Kubectl {
try {
await this.ensureKubectl()
return this.path
} catch(err) {
} catch (err) {
logger.error("Failed to ensure kubectl, fallback to the bundled version")
logger.error(err)
return Kubectl.bundledKubectlPath
@@ -113,7 +113,7 @@ export class Kubectl {
try {
await this.ensureKubectl()
return this.dirname
} catch(err) {
} catch (err) {
logger.error(err)
return ""
}
@@ -138,8 +138,7 @@ export class Kubectl {
return true
}
logger.error(`Local kubectl is version ${version}, expected ${this.kubectlVersion}, unlinking`)
}
catch(err) {
} catch (err) {
logger.error(`Local kubectl failed to run properly (${err.message}), unlinking`)
}
await fs.promises.unlink(this.path)
@@ -148,7 +147,7 @@ export class Kubectl {
}
protected async checkBundled(): Promise<boolean> {
if(this.kubectlVersion === Kubectl.bundledKubectlVersion) {
if (this.kubectlVersion === Kubectl.bundledKubectlVersion) {
try {
const exist = await pathExists(this.path)
if (!exist) {
@@ -156,7 +155,7 @@ export class Kubectl {
await fs.promises.chmod(this.path, 0o755)
}
return true
} catch(err) {
} catch (err) {
logger.error("Could not copy the bundled kubectl to app-data: " + err)
return false
}
@@ -171,10 +170,15 @@ export class Kubectl {
logger.debug(`Acquired a lock for ${this.kubectlVersion}`)
const bundled = await this.checkBundled()
const isValid = await this.checkBinary(!bundled)
if(!isValid) {
await this.downloadKubectl().catch((error) => { logger.error(error) });
if (!isValid) {
await this.downloadKubectl().catch((error) => {
logger.error(error)
});
}
await this.writeInitScripts().catch((error) => { logger.error("Failed to write init scripts"); logger.error(error) })
await this.writeInitScripts().catch((error) => {
logger.error("Failed to write init scripts");
logger.error(error)
})
logger.debug(`Releasing lock for ${this.kubectlVersion}`)
release()
return true
@@ -190,10 +194,10 @@ export class Kubectl {
logger.info(`Downloading kubectl ${this.kubectlVersion} from ${this.url} to ${this.path}`)
return new Promise((resolve, reject) => {
const stream = request({
const stream = customRequest({
url: this.url,
gzip: true,
...this.getRequestOpts()
})
});
const file = fs.createWriteStream(this.path)
stream.on("complete", () => {
logger.debug("kubectl binary download finished")
@@ -215,7 +219,7 @@ export class Kubectl {
protected async scriptIsLatest(scriptPath: string) {
const scriptExists = await pathExists(scriptPath)
if(!scriptExists) return false
if (!scriptExists) return false
try {
const filehandle = await fs.promises.open(scriptPath, 'r')
@@ -234,7 +238,7 @@ export class Kubectl {
const fsPromises = fs.promises;
const bashScriptPath = path.join(this.dirname, '.bash_set_path')
const bashScriptIsLatest = await this.scriptIsLatest(bashScriptPath)
if(!bashScriptIsLatest) {
if (!bashScriptIsLatest) {
let bashScript = "" + initScriptVersionString
bashScript += "tempkubeconfig=\"$KUBECONFIG\"\n"
bashScript += "test -f \"/etc/profile\" && . \"/etc/profile\"\n"
@@ -253,7 +257,7 @@ export class Kubectl {
const zshScriptPath = path.join(this.dirname, '.zlogin')
const zshScriptIsLatest = await this.scriptIsLatest(zshScriptPath)
if(!zshScriptIsLatest) {
if (!zshScriptIsLatest) {
let zshScript = "" + initScriptVersionString
zshScript += "tempkubeconfig=\"$KUBECONFIG\"\n"
@@ -280,12 +284,6 @@ export class Kubectl {
}
}
protected getRequestOpts() {
return globalRequestOpts({
url: this.url
})
}
protected getDownloadMirror() {
const mirror = packageMirrors.get(userStore.preferences.downloadMirror)
if (mirror) {