From dd43057de3a1d245f9f552bb2104e6198b0d9419 Mon Sep 17 00:00:00 2001 From: Denis Golovin Date: Mon, 3 May 2021 12:36:30 -0700 Subject: [PATCH] Provide fake kubeconfig for Components View to work without one This PR fixes #2044. Signed-off-by: Denis Golovin dgolovin@redhat.com --- config/kubeconfig | 15 ++++++++++ preference.yaml => config/preference.yaml | 0 src/componentTypesView.ts | 7 +++-- src/odo.ts | 35 +++++++++++++++++++---- src/odo/componentType.ts | 2 +- 5 files changed, 50 insertions(+), 9 deletions(-) create mode 100644 config/kubeconfig rename preference.yaml => config/preference.yaml (100%) diff --git a/config/kubeconfig b/config/kubeconfig new file mode 100644 index 000000000..5655ea9de --- /dev/null +++ b/config/kubeconfig @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Config +clusters: +- cluster: + server: https://api.crc.testing:6443 + name: api-crc-testing:6443 +contexts: +- context: + cluster: api-crc-testing:6443 + user: developer + name: no-config-workaround +current-context: no-config-workaround +preferences: {} +users: +- name: developer \ No newline at end of file diff --git a/preference.yaml b/config/preference.yaml similarity index 100% rename from preference.yaml rename to config/preference.yaml diff --git a/src/componentTypesView.ts b/src/componentTypesView.ts index 6deba25a7..4d60679fe 100644 --- a/src/componentTypesView.ts +++ b/src/componentTypesView.ts @@ -43,6 +43,7 @@ import { import { vsCommand, VsCommandError } from './vscommand'; import { Cluster } from '@kubernetes/client-node/dist/config_types'; import { KubeConfig } from '@kubernetes/client-node'; +import { Platform } from './util/platform'; type ExampleProject = SampleProject | StarterProject; type ComponentType = DevfileComponentType | ImageStreamTag | ExampleProject | Cluster | Registry; @@ -191,7 +192,7 @@ export class ComponentTypesView implements TreeDataProvider { // eslint-disable-next-line class-methods-use-this async getChildren(parent: ComponentType): Promise { let children: ComponentType[]; - + const addEnv = this.odo.getKubeconfigEnv(); if (!parent) { const config = new KubeConfig(); config.loadFromDefault(); @@ -211,7 +212,7 @@ export class ComponentTypesView implements TreeDataProvider { children = []; builders.forEach((builder: S2iComponentType) => children.splice(children.length,0, ...builder.spec.imageStreamTags)); } else if (isRegistry(parent) ) { - const result: CliExitData = await this.odo.execute(Command.listCatalogComponentsJson()); + const result = await this.odo.execute(Command.listCatalogComponentsJson(),Platform.getUserHomePath(), true, addEnv); children = this.loadItems(result, (data) => data.devfileItems); children = children.filter((element:DevfileComponentType) => element.Registry.Name === parent.Name); } else if (isS2iComponent(parent)) { @@ -220,7 +221,7 @@ export class ComponentTypesView implements TreeDataProvider { return tag; }); } else if (isDevfileComponent(parent)){ - const result: CliExitData = await this.odo.execute(Command.describeCatalogComponent(parent.Name)); + const result: CliExitData = await this.odo.execute(Command.describeCatalogComponent(parent.Name), Platform.getUserHomePath(), true, addEnv); children = this.loadItems(result, (data) => data.Data.starterProjects); children = children.map((starter:StarterProject) => { starter.typeName = parent.Name;; diff --git a/src/odo.ts b/src/odo.ts index 962596308..e57e47271 100644 --- a/src/odo.ts +++ b/src/odo.ts @@ -31,6 +31,9 @@ import { VsCommandError } from './vscommand'; import { Storage } from './odo/storage'; import bs = require('binary-search'); import { CliExitData } from './cli'; +import { KubeConfigUtils } from './util/kubeUtils'; +import { KubeConfig } from '@kubernetes/client-node'; +import { pathExistsSync } from 'fs-extra'; const {Collapsed} = TreeItemCollapsibleState; @@ -329,6 +332,7 @@ class OdoEventImpl implements OdoEvent { } export interface Odo { + getKubeconfigEnv(): {}; getClusters(): Promise; getProjects(): Promise; loadWorkspaceComponents(event: WorkspaceFoldersChangeEvent): Promise; @@ -344,7 +348,7 @@ export interface Odo { getServiceTemplates(): Promise; getServiceTemplatePlans(svc: string): Promise; getServices(application: OpenShiftObject): Promise; - execute(command: CommandText, cwd?: string, fail?: boolean): Promise; + execute(command: CommandText, cwd?: string, fail?: boolean, addEnv?: {}): Promise; spawn(command: string, cwd?: string): Promise; executeInTerminal(command: CommandText, cwd?: string, name?: string): Promise; requireLogin(): Promise; @@ -616,8 +620,29 @@ export class OdoImpl implements Odo { return deployedComponents; } + public getKubeconfigEnv(): {} { + const addEnv: {KUBECONFIG?: string} = {}; + let kc: KubeConfig; + // TODO: Remove when odo works without kubeconfig present + try { + kc = new KubeConfigUtils(); + } catch (err) { + // ignore error + } + + const configPath = path.join(Platform.getUserHomePath(), '.kube', 'config'); + + if (kc && !pathExistsSync(configPath)) { // config is loaded, yay! But there is still use case for missing config file + // use fake config to let odo get component types from registry + addEnv.KUBECONFIG = path.resolve(__dirname, '..', '..', 'config', 'kubeconfig'); + } + return addEnv; + } + public async getComponentTypes(): Promise { - const result: cliInstance.CliExitData = await this.execute(Command.listCatalogComponentsJson()); + // if kc is produced, KUBECONFIG env var is empty or pointing + + const result: cliInstance.CliExitData = await this.execute(Command.listCatalogComponentsJson(), undefined, true, this.getKubeconfigEnv()); const compTypesJson: ComponentTypesJson = this.loadJSON(result.stdout); const devfileItems: ComponentTypeAdapter[] = []; const s2iItems: ComponentTypeAdapter[] = []; @@ -738,7 +763,7 @@ export class OdoImpl implements Odo { public createEnv(): {} { const env = {...process.env }; - env.GLOBALODOCONFIG = path.resolve(__dirname,'..', '..', 'preference.yaml'); + env.GLOBALODOCONFIG = path.resolve(__dirname,'..', '..', 'config', 'preference.yaml'); return env; } @@ -750,7 +775,7 @@ export class OdoImpl implements Odo { terminal.show(); } - public async execute(command: CommandText, cwd?: string, fail = true): Promise { + public async execute(command: CommandText, cwd?: string, fail = true, addEnv = {}): Promise { const env = this.createEnv(); const commandActual = `${command}`; const commandPrivacy = `${command.privacyMode(true)}`; @@ -758,7 +783,7 @@ export class OdoImpl implements Odo { const toolLocation = await ToolsConfig.detect(cmd); const result: cliInstance.CliExitData = await OdoImpl.cli.execute( toolLocation ? commandActual.replace(cmd, `"${toolLocation}"`) : commandActual, - cwd ? {cwd, env} : { env } + cwd ? {cwd, env: {...env, ...addEnv}} : { env: {...env, ...addEnv} } ); if (result.error && fail) { throw new VsCommandError(`${result.error.message}`, `Error when running command: ${commandPrivacy}`, result.error); diff --git a/src/odo/componentType.ts b/src/odo/componentType.ts index 333d5d3ce..1810cef7d 100644 --- a/src/odo/componentType.ts +++ b/src/odo/componentType.ts @@ -57,7 +57,7 @@ export function isSampleProject(repo: any): repo is SampleProject { // eslint-disable-next-line @typescript-eslint/no-explicit-any export function isCluster(cluster: any): cluster is Cluster { - return cluster.name && cluster.server && cluster.skipTLSVerify !== undefined; + return cluster.name && cluster.server; } // eslint-disable-next-line @typescript-eslint/no-explicit-any