mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Renable Strict TSLint (#5018)
* removes more builder references * remove builder from profiler * formatting * fix profiler dailog * remove builder from oatuhdialog * remove the rest of builder references * formatting * add more strict null checks to base * enable strict tslint rules * fix formatting * fix compile error * fix the rest of the hygeny issues and add pipeline step * fix pipeline files
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vscode-nls';
|
||||
import * as nls from 'vscode-nls';
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
import { Shell } from '../utility/shell';
|
||||
@@ -11,111 +11,111 @@ import { Host } from './host';
|
||||
import { FS } from '../utility/fs';
|
||||
|
||||
export interface BinCheckContext {
|
||||
readonly host: Host;
|
||||
readonly fs: FS;
|
||||
readonly shell: Shell;
|
||||
readonly installDependenciesCallback: () => void;
|
||||
binFound: boolean;
|
||||
binPath: string;
|
||||
readonly host: Host;
|
||||
readonly fs: FS;
|
||||
readonly shell: Shell;
|
||||
readonly installDependenciesCallback: () => void;
|
||||
binFound: boolean;
|
||||
binPath: string;
|
||||
}
|
||||
|
||||
interface FindBinaryResult {
|
||||
err: number | null;
|
||||
output: string;
|
||||
err: number | null;
|
||||
output: string;
|
||||
}
|
||||
|
||||
async function findBinary(shell: Shell, binName: string): Promise<FindBinaryResult> {
|
||||
let cmd = `which ${binName}`;
|
||||
let cmd = `which ${binName}`;
|
||||
|
||||
if (shell.isWindows()) {
|
||||
cmd = `where.exe ${binName}.exe`;
|
||||
}
|
||||
if (shell.isWindows()) {
|
||||
cmd = `where.exe ${binName}.exe`;
|
||||
}
|
||||
|
||||
const opts = {
|
||||
async: true,
|
||||
env: {
|
||||
HOME: process.env.HOME,
|
||||
PATH: process.env.PATH
|
||||
}
|
||||
};
|
||||
const opts = {
|
||||
async: true,
|
||||
env: {
|
||||
HOME: process.env.HOME,
|
||||
PATH: process.env.PATH
|
||||
}
|
||||
};
|
||||
|
||||
const execResult = await shell.execCore(cmd, opts);
|
||||
if (execResult.code) {
|
||||
return { err: execResult.code, output: execResult.stderr };
|
||||
}
|
||||
const execResult = await shell.execCore(cmd, opts);
|
||||
if (execResult.code) {
|
||||
return { err: execResult.code, output: execResult.stderr };
|
||||
}
|
||||
|
||||
return { err: null, output: execResult.stdout };
|
||||
return { err: null, output: execResult.stdout };
|
||||
}
|
||||
|
||||
export function execPath(shell: Shell, basePath: string): string {
|
||||
let bin = basePath;
|
||||
if (shell.isWindows() && bin && !(bin.endsWith('.exe'))) {
|
||||
bin = bin + '.exe';
|
||||
}
|
||||
return bin;
|
||||
let bin = basePath;
|
||||
if (shell.isWindows() && bin && !(bin.endsWith('.exe'))) {
|
||||
bin = bin + '.exe';
|
||||
}
|
||||
return bin;
|
||||
}
|
||||
|
||||
type CheckPresentFailureReason = 'inferFailed' | 'configuredFileMissing';
|
||||
const installDependenciesAction = localize('installDependenciesAction','Install dependencies');
|
||||
const learnMoreAction = localize('learnMoreAction','Learn more');
|
||||
const installDependenciesAction = localize('installDependenciesAction', 'Install dependencies');
|
||||
const learnMoreAction = localize('learnMoreAction', 'Learn more');
|
||||
function alertNoBin(host: Host, binName: string, failureReason: CheckPresentFailureReason, message: string, installDependencies: () => void): void {
|
||||
switch (failureReason) {
|
||||
case 'inferFailed':
|
||||
host.showErrorMessage(message, installDependenciesAction, learnMoreAction).then(
|
||||
(str) => {
|
||||
switch (str) {
|
||||
case learnMoreAction:
|
||||
host.showInformationMessage(localize('moreInfoMsg', 'Add {0} directory to path, or set "mssql-bdc.{0}-path" config to {0} binary.', binName));
|
||||
break;
|
||||
case installDependenciesAction:
|
||||
installDependencies();
|
||||
break;
|
||||
}
|
||||
switch (failureReason) {
|
||||
case 'inferFailed':
|
||||
host.showErrorMessage(message, installDependenciesAction, learnMoreAction).then(
|
||||
(str) => {
|
||||
switch (str) {
|
||||
case learnMoreAction:
|
||||
host.showInformationMessage(localize('moreInfoMsg', 'Add {0} directory to path, or set "mssql-bdc.{0}-path" config to {0} binary.', binName));
|
||||
break;
|
||||
case installDependenciesAction:
|
||||
installDependencies();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
);
|
||||
break;
|
||||
case 'configuredFileMissing':
|
||||
host.showErrorMessage(message, installDependenciesAction).then(
|
||||
(str) => {
|
||||
if (str === installDependenciesAction) {
|
||||
installDependencies();
|
||||
}
|
||||
}
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
);
|
||||
break;
|
||||
case 'configuredFileMissing':
|
||||
host.showErrorMessage(message, installDependenciesAction).then(
|
||||
(str) => {
|
||||
if (str === installDependenciesAction) {
|
||||
installDependencies();
|
||||
}
|
||||
}
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
export async function checkForBinary(context: BinCheckContext, bin: string | undefined, binName: string, inferFailedMessage: string, configuredFileMissingMessage: string, alertOnFail: boolean): Promise<boolean> {
|
||||
if (!bin) {
|
||||
const fb = await findBinary(context.shell, binName);
|
||||
if (!bin) {
|
||||
const fb = await findBinary(context.shell, binName);
|
||||
|
||||
if (fb.err || fb.output.length === 0) {
|
||||
if (alertOnFail) {
|
||||
alertNoBin(context.host, binName, 'inferFailed', inferFailedMessage, context.installDependenciesCallback);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (fb.err || fb.output.length === 0) {
|
||||
if (alertOnFail) {
|
||||
alertNoBin(context.host, binName, 'inferFailed', inferFailedMessage, context.installDependenciesCallback);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
context.binFound = true;
|
||||
context.binFound = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (context.shell.isWindows) {
|
||||
context.binFound = context.fs.existsSync(bin);
|
||||
} else {
|
||||
const sr = await context.shell.exec(`ls ${bin}`);
|
||||
context.binFound = (!!sr && sr.code === 0);
|
||||
}
|
||||
if (context.binFound) {
|
||||
context.binPath = bin;
|
||||
} else {
|
||||
if (alertOnFail) {
|
||||
alertNoBin(context.host, binName, 'configuredFileMissing', configuredFileMissingMessage, context.installDependenciesCallback);
|
||||
}
|
||||
}
|
||||
if (context.shell.isWindows) {
|
||||
context.binFound = context.fs.existsSync(bin);
|
||||
} else {
|
||||
const sr = await context.shell.exec(`ls ${bin}`);
|
||||
context.binFound = (!!sr && sr.code === 0);
|
||||
}
|
||||
if (context.binFound) {
|
||||
context.binPath = bin;
|
||||
} else {
|
||||
if (alertOnFail) {
|
||||
alertNoBin(context.host, binName, 'configuredFileMissing', configuredFileMissingMessage, context.installDependenciesCallback);
|
||||
}
|
||||
}
|
||||
|
||||
return context.binFound;
|
||||
return context.binFound;
|
||||
}
|
||||
|
||||
@@ -6,61 +6,61 @@
|
||||
import { Errorable, failed } from '../interfaces';
|
||||
|
||||
interface CompatibilityGuaranteed {
|
||||
readonly guaranteed: true;
|
||||
readonly guaranteed: true;
|
||||
}
|
||||
|
||||
interface CompatibilityNotGuaranteed {
|
||||
readonly guaranteed: false;
|
||||
readonly didCheck: boolean;
|
||||
readonly clientVersion: string;
|
||||
readonly serverVersion: string;
|
||||
readonly guaranteed: false;
|
||||
readonly didCheck: boolean;
|
||||
readonly clientVersion: string;
|
||||
readonly serverVersion: string;
|
||||
}
|
||||
|
||||
export type Compatibility = CompatibilityGuaranteed | CompatibilityNotGuaranteed;
|
||||
|
||||
export function isGuaranteedCompatible(c: Compatibility): c is CompatibilityGuaranteed {
|
||||
return c.guaranteed;
|
||||
return c.guaranteed;
|
||||
}
|
||||
|
||||
export interface Version {
|
||||
readonly major: string;
|
||||
readonly minor: string;
|
||||
readonly gitVersion: string;
|
||||
readonly major: string;
|
||||
readonly minor: string;
|
||||
readonly gitVersion: string;
|
||||
}
|
||||
|
||||
export async function check(kubectlLoadJSON: (cmd: string) => Promise<Errorable<any>>): Promise<Compatibility> {
|
||||
const version = await kubectlLoadJSON('version -o json');
|
||||
if (failed(version)) {
|
||||
return {
|
||||
guaranteed: false,
|
||||
didCheck: false,
|
||||
clientVersion: '',
|
||||
serverVersion: ''
|
||||
};
|
||||
}
|
||||
const version = await kubectlLoadJSON('version -o json');
|
||||
if (failed(version)) {
|
||||
return {
|
||||
guaranteed: false,
|
||||
didCheck: false,
|
||||
clientVersion: '',
|
||||
serverVersion: ''
|
||||
};
|
||||
}
|
||||
|
||||
const clientVersion: Version = version.result.clientVersion;
|
||||
const serverVersion: Version = version.result.serverVersion;
|
||||
const clientVersion: Version = version.result.clientVersion;
|
||||
const serverVersion: Version = version.result.serverVersion;
|
||||
|
||||
if (isCompatible(clientVersion, serverVersion)) {
|
||||
return { guaranteed: true };
|
||||
}
|
||||
if (isCompatible(clientVersion, serverVersion)) {
|
||||
return { guaranteed: true };
|
||||
}
|
||||
|
||||
return {
|
||||
guaranteed: false,
|
||||
didCheck: true,
|
||||
clientVersion: clientVersion.gitVersion,
|
||||
serverVersion: serverVersion.gitVersion
|
||||
};
|
||||
return {
|
||||
guaranteed: false,
|
||||
didCheck: true,
|
||||
clientVersion: clientVersion.gitVersion,
|
||||
serverVersion: serverVersion.gitVersion
|
||||
};
|
||||
}
|
||||
|
||||
function isCompatible(clientVersion: Version, serverVersion: Version): boolean {
|
||||
if (clientVersion.major === serverVersion.major) {
|
||||
const clientMinor = Number.parseInt(clientVersion.minor);
|
||||
const serverMinor = Number.parseInt(serverVersion.minor);
|
||||
if (Number.isInteger(clientMinor) && Number.isInteger(serverMinor) && Math.abs(clientMinor - serverMinor) <= 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
if (clientVersion.major === serverVersion.major) {
|
||||
const clientMinor = Number.parseInt(clientVersion.minor);
|
||||
const serverMinor = Number.parseInt(serverVersion.minor);
|
||||
if (Number.isInteger(clientMinor) && Number.isInteger(serverMinor) && Math.abs(clientMinor - serverMinor) <= 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -6,37 +6,37 @@
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
export interface Host {
|
||||
showErrorMessage(message: string, ...items: string[]): Thenable<string | undefined>;
|
||||
showWarningMessage(message: string, ...items: string[]): Thenable<string | undefined>;
|
||||
showInformationMessage(message: string, ...items: string[]): Thenable<string | undefined>;
|
||||
getConfiguration(key: string): any;
|
||||
onDidChangeConfiguration(listener: (ch: vscode.ConfigurationChangeEvent) => any): vscode.Disposable;
|
||||
showErrorMessage(message: string, ...items: string[]): Thenable<string | undefined>;
|
||||
showWarningMessage(message: string, ...items: string[]): Thenable<string | undefined>;
|
||||
showInformationMessage(message: string, ...items: string[]): Thenable<string | undefined>;
|
||||
getConfiguration(key: string): any;
|
||||
onDidChangeConfiguration(listener: (ch: vscode.ConfigurationChangeEvent) => any): vscode.Disposable;
|
||||
}
|
||||
|
||||
export const host: Host = {
|
||||
showErrorMessage : showErrorMessage,
|
||||
showWarningMessage : showWarningMessage,
|
||||
showInformationMessage : showInformationMessage,
|
||||
getConfiguration : getConfiguration,
|
||||
onDidChangeConfiguration : onDidChangeConfiguration,
|
||||
showErrorMessage: showErrorMessage,
|
||||
showWarningMessage: showWarningMessage,
|
||||
showInformationMessage: showInformationMessage,
|
||||
getConfiguration: getConfiguration,
|
||||
onDidChangeConfiguration: onDidChangeConfiguration,
|
||||
};
|
||||
|
||||
function showErrorMessage(message: string, ...items: string[]): Thenable<string | undefined> {
|
||||
return vscode.window.showErrorMessage(message, ...items);
|
||||
return vscode.window.showErrorMessage(message, ...items);
|
||||
}
|
||||
|
||||
function showWarningMessage(message: string, ...items: string[]): Thenable<string | undefined> {
|
||||
return vscode.window.showWarningMessage(message, ...items);
|
||||
return vscode.window.showWarningMessage(message, ...items);
|
||||
}
|
||||
|
||||
function showInformationMessage(message: string, ...items: string[]): Thenable<string | undefined> {
|
||||
return vscode.window.showInformationMessage(message, ...items);
|
||||
return vscode.window.showInformationMessage(message, ...items);
|
||||
}
|
||||
|
||||
function getConfiguration(key: string): any {
|
||||
return vscode.workspace.getConfiguration(key);
|
||||
return vscode.workspace.getConfiguration(key);
|
||||
}
|
||||
|
||||
function onDidChangeConfiguration(listener: (e: vscode.ConfigurationChangeEvent) => any): vscode.Disposable {
|
||||
return vscode.workspace.onDidChangeConfiguration(listener);
|
||||
return vscode.workspace.onDidChangeConfiguration(listener);
|
||||
}
|
||||
|
||||
@@ -15,128 +15,128 @@ import * as compatibility from './compatibility';
|
||||
import { getToolPath } from '../config/config';
|
||||
|
||||
export interface Kubectl {
|
||||
checkPresent(errorMessageMode: CheckPresentMessageMode): Promise<boolean>;
|
||||
asJson<T>(command: string): Promise<Errorable<T>>;
|
||||
invokeAsync(command: string, stdin?: string): Promise<ShellResult | undefined>;
|
||||
getContext(): Context;
|
||||
checkPresent(errorMessageMode: CheckPresentMessageMode): Promise<boolean>;
|
||||
asJson<T>(command: string): Promise<Errorable<T>>;
|
||||
invokeAsync(command: string, stdin?: string): Promise<ShellResult | undefined>;
|
||||
getContext(): Context;
|
||||
}
|
||||
|
||||
interface Context {
|
||||
readonly host: Host;
|
||||
readonly fs: FS;
|
||||
readonly shell: Shell;
|
||||
readonly installDependenciesCallback: () => void;
|
||||
binFound: boolean;
|
||||
binPath: string;
|
||||
readonly host: Host;
|
||||
readonly fs: FS;
|
||||
readonly shell: Shell;
|
||||
readonly installDependenciesCallback: () => void;
|
||||
binFound: boolean;
|
||||
binPath: string;
|
||||
}
|
||||
|
||||
class KubectlImpl implements Kubectl {
|
||||
constructor(host: Host, fs: FS, shell: Shell, installDependenciesCallback: () => void, kubectlFound: boolean) {
|
||||
this.context = { host : host, fs : fs, shell : shell, installDependenciesCallback : installDependenciesCallback, binFound : kubectlFound, binPath : 'kubectl' };
|
||||
}
|
||||
constructor(host: Host, fs: FS, shell: Shell, installDependenciesCallback: () => void, kubectlFound: boolean) {
|
||||
this.context = { host: host, fs: fs, shell: shell, installDependenciesCallback: installDependenciesCallback, binFound: kubectlFound, binPath: 'kubectl' };
|
||||
}
|
||||
|
||||
readonly context: Context;
|
||||
readonly context: Context;
|
||||
|
||||
checkPresent(errorMessageMode: CheckPresentMessageMode): Promise<boolean> {
|
||||
return checkPresent(this.context, errorMessageMode);
|
||||
}
|
||||
asJson<T>(command: string): Promise<Errorable<T>> {
|
||||
return asJson(this.context, command);
|
||||
}
|
||||
invokeAsync(command: string, stdin?: string): Promise<ShellResult | undefined> {
|
||||
return invokeAsync(this.context, command, stdin);
|
||||
}
|
||||
checkPresent(errorMessageMode: CheckPresentMessageMode): Promise<boolean> {
|
||||
return checkPresent(this.context, errorMessageMode);
|
||||
}
|
||||
asJson<T>(command: string): Promise<Errorable<T>> {
|
||||
return asJson(this.context, command);
|
||||
}
|
||||
invokeAsync(command: string, stdin?: string): Promise<ShellResult | undefined> {
|
||||
return invokeAsync(this.context, command, stdin);
|
||||
}
|
||||
|
||||
getContext(): Context {
|
||||
return this.context;
|
||||
}
|
||||
getContext(): Context {
|
||||
return this.context;
|
||||
}
|
||||
}
|
||||
|
||||
export function create(host: Host, fs: FS, shell: Shell, installDependenciesCallback: () => void): Kubectl {
|
||||
return new KubectlImpl(host, fs, shell, installDependenciesCallback, false);
|
||||
return new KubectlImpl(host, fs, shell, installDependenciesCallback, false);
|
||||
}
|
||||
|
||||
export enum CheckPresentMessageMode {
|
||||
Command,
|
||||
Activation,
|
||||
Silent,
|
||||
Command,
|
||||
Activation,
|
||||
Silent,
|
||||
}
|
||||
|
||||
async function checkPresent(context: Context, errorMessageMode: CheckPresentMessageMode): Promise<boolean> {
|
||||
if (context.binFound) {
|
||||
return true;
|
||||
}
|
||||
if (context.binFound) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return await checkForKubectlInternal(context, errorMessageMode);
|
||||
return await checkForKubectlInternal(context, errorMessageMode);
|
||||
}
|
||||
|
||||
async function checkForKubectlInternal(context: Context, errorMessageMode: CheckPresentMessageMode): Promise<boolean> {
|
||||
const binName = 'kubectl';
|
||||
const bin = getToolPath(context.host, context.shell, binName);
|
||||
const binName = 'kubectl';
|
||||
const bin = getToolPath(context.host, context.shell, binName);
|
||||
|
||||
const contextMessage = getCheckKubectlContextMessage(errorMessageMode);
|
||||
const inferFailedMessage = localize('binaryNotFound', 'Could not find {0} binary. {1}', binName, contextMessage);
|
||||
const configuredFileMissingMessage = localize('binaryNotInstalled', '{0} is not installed. {1}', bin, contextMessage);
|
||||
const contextMessage = getCheckKubectlContextMessage(errorMessageMode);
|
||||
const inferFailedMessage = localize('binaryNotFound', 'Could not find {0} binary. {1}', binName, contextMessage);
|
||||
const configuredFileMissingMessage = localize('binaryNotInstalled', '{0} is not installed. {1}', bin, contextMessage);
|
||||
|
||||
return await binutil.checkForBinary(context, bin, binName, inferFailedMessage, configuredFileMissingMessage, errorMessageMode !== CheckPresentMessageMode.Silent);
|
||||
return await binutil.checkForBinary(context, bin, binName, inferFailedMessage, configuredFileMissingMessage, errorMessageMode !== CheckPresentMessageMode.Silent);
|
||||
}
|
||||
|
||||
function getCheckKubectlContextMessage(errorMessageMode: CheckPresentMessageMode): string {
|
||||
if (errorMessageMode === CheckPresentMessageMode.Activation) {
|
||||
return localize('kubernetesRequired',' SQL Server Big data cluster requires kubernetes.');
|
||||
} else if (errorMessageMode === CheckPresentMessageMode.Command) {
|
||||
return localize('cannotExecuteCmd', ' Cannot execute command.');
|
||||
}
|
||||
return '';
|
||||
if (errorMessageMode === CheckPresentMessageMode.Activation) {
|
||||
return localize('kubernetesRequired', ' SQL Server Big data cluster requires kubernetes.');
|
||||
} else if (errorMessageMode === CheckPresentMessageMode.Command) {
|
||||
return localize('cannotExecuteCmd', ' Cannot execute command.');
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
async function invokeAsync(context: Context, command: string, stdin?: string): Promise<ShellResult | undefined> {
|
||||
if (await checkPresent(context, CheckPresentMessageMode.Command)) {
|
||||
const bin = baseKubectlPath(context);
|
||||
const cmd = `${bin} ${command}`;
|
||||
const sr = await context.shell.exec(cmd, stdin);
|
||||
if (sr && sr.code !== 0) {
|
||||
checkPossibleIncompatibility(context);
|
||||
}
|
||||
return sr;
|
||||
} else {
|
||||
return { code: -1, stdout: '', stderr: '' };
|
||||
}
|
||||
if (await checkPresent(context, CheckPresentMessageMode.Command)) {
|
||||
const bin = baseKubectlPath(context);
|
||||
const cmd = `${bin} ${command}`;
|
||||
const sr = await context.shell.exec(cmd, stdin);
|
||||
if (sr && sr.code !== 0) {
|
||||
checkPossibleIncompatibility(context);
|
||||
}
|
||||
return sr;
|
||||
} else {
|
||||
return { code: -1, stdout: '', stderr: '' };
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: invalidate this when the context changes or if we know kubectl has changed (e.g. config)
|
||||
let checkedCompatibility = false; // We don't want to spam the user (or CPU!) repeatedly running the version check
|
||||
|
||||
async function checkPossibleIncompatibility(context: Context): Promise<void> {
|
||||
if (checkedCompatibility) {
|
||||
return;
|
||||
}
|
||||
checkedCompatibility = true;
|
||||
const compat = await compatibility.check((cmd) => asJson<compatibility.Version>(context, cmd));
|
||||
if (!compatibility.isGuaranteedCompatible(compat) && compat.didCheck) {
|
||||
const versionAlert = localize('kubectlVersionIncompatible', 'kubectl version ${0} may be incompatible with cluster Kubernetes version {1}', compat.clientVersion, compat.serverVersion);
|
||||
context.host.showWarningMessage(versionAlert);
|
||||
}
|
||||
if (checkedCompatibility) {
|
||||
return;
|
||||
}
|
||||
checkedCompatibility = true;
|
||||
const compat = await compatibility.check((cmd) => asJson<compatibility.Version>(context, cmd));
|
||||
if (!compatibility.isGuaranteedCompatible(compat) && compat.didCheck) {
|
||||
const versionAlert = localize('kubectlVersionIncompatible', 'kubectl version ${0} may be incompatible with cluster Kubernetes version {1}', compat.clientVersion, compat.serverVersion);
|
||||
context.host.showWarningMessage(versionAlert);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function baseKubectlPath(context: Context): string {
|
||||
let bin = getToolPath(context.host, context.shell, 'kubectl');
|
||||
if (!bin) {
|
||||
bin = 'kubectl';
|
||||
}
|
||||
return bin;
|
||||
let bin = getToolPath(context.host, context.shell, 'kubectl');
|
||||
if (!bin) {
|
||||
bin = 'kubectl';
|
||||
}
|
||||
return bin;
|
||||
}
|
||||
|
||||
async function asJson<T>(context: Context, command: string): Promise<Errorable<T>> {
|
||||
const shellResult = await invokeAsync(context, command);
|
||||
if (!shellResult) {
|
||||
return { succeeded: false, error: [localize('cannotRunCommand', 'Unable to run command ({0})', command)] };
|
||||
}
|
||||
const shellResult = await invokeAsync(context, command);
|
||||
if (!shellResult) {
|
||||
return { succeeded: false, error: [localize('cannotRunCommand', 'Unable to run command ({0})', command)] };
|
||||
}
|
||||
|
||||
if (shellResult.code === 0) {
|
||||
return { succeeded: true, result: JSON.parse(shellResult.stdout.trim()) as T };
|
||||
if (shellResult.code === 0) {
|
||||
return { succeeded: true, result: JSON.parse(shellResult.stdout.trim()) as T };
|
||||
|
||||
}
|
||||
return { succeeded: false, error: [ shellResult.stderr ] };
|
||||
}
|
||||
return { succeeded: false, error: [shellResult.stderr] };
|
||||
}
|
||||
@@ -11,126 +11,126 @@ import { Kubectl } from './kubectl';
|
||||
import { failed, ClusterType } from '../interfaces';
|
||||
|
||||
export interface KubectlContext {
|
||||
readonly clusterName: string;
|
||||
readonly contextName: string;
|
||||
readonly userName: string;
|
||||
readonly active: boolean;
|
||||
readonly clusterName: string;
|
||||
readonly contextName: string;
|
||||
readonly userName: string;
|
||||
readonly active: boolean;
|
||||
}
|
||||
|
||||
interface Kubeconfig {
|
||||
readonly apiVersion: string;
|
||||
readonly 'current-context': string;
|
||||
readonly clusters: {
|
||||
readonly name: string;
|
||||
readonly cluster: {
|
||||
readonly server: string;
|
||||
readonly 'certificate-authority'?: string;
|
||||
readonly 'certificate-authority-data'?: string;
|
||||
};
|
||||
}[] | undefined;
|
||||
readonly contexts: {
|
||||
readonly name: string;
|
||||
readonly context: {
|
||||
readonly cluster: string;
|
||||
readonly user: string;
|
||||
readonly namespace?: string;
|
||||
};
|
||||
}[] | undefined;
|
||||
readonly users: {
|
||||
readonly name: string;
|
||||
readonly user: {};
|
||||
}[] | undefined;
|
||||
readonly apiVersion: string;
|
||||
readonly 'current-context': string;
|
||||
readonly clusters: {
|
||||
readonly name: string;
|
||||
readonly cluster: {
|
||||
readonly server: string;
|
||||
readonly 'certificate-authority'?: string;
|
||||
readonly 'certificate-authority-data'?: string;
|
||||
};
|
||||
}[] | undefined;
|
||||
readonly contexts: {
|
||||
readonly name: string;
|
||||
readonly context: {
|
||||
readonly cluster: string;
|
||||
readonly user: string;
|
||||
readonly namespace?: string;
|
||||
};
|
||||
}[] | undefined;
|
||||
readonly users: {
|
||||
readonly name: string;
|
||||
readonly user: {};
|
||||
}[] | undefined;
|
||||
}
|
||||
|
||||
export interface ClusterConfig {
|
||||
readonly server: string;
|
||||
readonly certificateAuthority: string | undefined;
|
||||
readonly server: string;
|
||||
readonly certificateAuthority: string | undefined;
|
||||
}
|
||||
|
||||
|
||||
|
||||
async function getKubeconfig(kubectl: Kubectl): Promise<Kubeconfig | null> {
|
||||
const shellResult = await kubectl.asJson<any>('config view -o json');
|
||||
if (failed(shellResult)) {
|
||||
vscode.window.showErrorMessage(shellResult.error[0]);
|
||||
return null;
|
||||
}
|
||||
return shellResult.result;
|
||||
const shellResult = await kubectl.asJson<any>('config view -o json');
|
||||
if (failed(shellResult)) {
|
||||
vscode.window.showErrorMessage(shellResult.error[0]);
|
||||
return null;
|
||||
}
|
||||
return shellResult.result;
|
||||
}
|
||||
|
||||
export async function getCurrentClusterConfig(kubectl: Kubectl): Promise<ClusterConfig | undefined> {
|
||||
const kubeConfig = await getKubeconfig(kubectl);
|
||||
if (!kubeConfig || !kubeConfig.clusters || !kubeConfig.contexts) {
|
||||
return undefined;
|
||||
}
|
||||
const contextConfig = kubeConfig.contexts.find((context) => context.name === kubeConfig['current-context'])!;
|
||||
const clusterConfig = kubeConfig.clusters.find((cluster) => cluster.name === contextConfig.context.cluster)!;
|
||||
return {
|
||||
server: clusterConfig.cluster.server,
|
||||
certificateAuthority: clusterConfig.cluster['certificate-authority']
|
||||
};
|
||||
const kubeConfig = await getKubeconfig(kubectl);
|
||||
if (!kubeConfig || !kubeConfig.clusters || !kubeConfig.contexts) {
|
||||
return undefined;
|
||||
}
|
||||
const contextConfig = kubeConfig.contexts.find((context) => context.name === kubeConfig['current-context'])!;
|
||||
const clusterConfig = kubeConfig.clusters.find((cluster) => cluster.name === contextConfig.context.cluster)!;
|
||||
return {
|
||||
server: clusterConfig.cluster.server,
|
||||
certificateAuthority: clusterConfig.cluster['certificate-authority']
|
||||
};
|
||||
}
|
||||
|
||||
export async function getContexts(kubectl: Kubectl): Promise<KubectlContext[]> {
|
||||
const kubectlConfig = await getKubeconfig(kubectl);
|
||||
if (!kubectlConfig) {
|
||||
return [];
|
||||
}
|
||||
const currentContext = kubectlConfig['current-context'];
|
||||
const contexts = kubectlConfig.contexts || [];
|
||||
return contexts.map((c) => {
|
||||
return {
|
||||
clusterName: c.context.cluster,
|
||||
contextName: c.name,
|
||||
userName: c.context.user,
|
||||
active: c.name === currentContext
|
||||
};
|
||||
});
|
||||
const kubectlConfig = await getKubeconfig(kubectl);
|
||||
if (!kubectlConfig) {
|
||||
return [];
|
||||
}
|
||||
const currentContext = kubectlConfig['current-context'];
|
||||
const contexts = kubectlConfig.contexts || [];
|
||||
return contexts.map((c) => {
|
||||
return {
|
||||
clusterName: c.context.cluster,
|
||||
contextName: c.name,
|
||||
userName: c.context.user,
|
||||
active: c.name === currentContext
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export async function setContext(kubectl: Kubectl, targetContext: string): Promise<void> {
|
||||
const shellResult = await kubectl.invokeAsync(`config use-context ${targetContext}`);
|
||||
if (!shellResult || shellResult.code !== 0) {
|
||||
// TODO: Update error handling for now.
|
||||
let errMsg = shellResult ? shellResult.stderr : localize('runKubectlFailed', 'Unable to run kubectl');
|
||||
vscode.window.showErrorMessage(localize('setClusterFailed', 'Failed to set \'{0}\' as current cluster: {1}', targetContext, errMsg));
|
||||
}
|
||||
const shellResult = await kubectl.invokeAsync(`config use-context ${targetContext}`);
|
||||
if (!shellResult || shellResult.code !== 0) {
|
||||
// TODO: Update error handling for now.
|
||||
let errMsg = shellResult ? shellResult.stderr : localize('runKubectlFailed', 'Unable to run kubectl');
|
||||
vscode.window.showErrorMessage(localize('setClusterFailed', 'Failed to set \'{0}\' as current cluster: {1}', targetContext, errMsg));
|
||||
}
|
||||
}
|
||||
|
||||
export async function inferCurrentClusterType(kubectl: Kubectl): Promise<ClusterType> {
|
||||
let latestContextName = '';
|
||||
let latestContextName = '';
|
||||
|
||||
const ctxsr = await kubectl.invokeAsync('config current-context');
|
||||
if (ctxsr && ctxsr.code === 0) {
|
||||
latestContextName = ctxsr.stdout.trim();
|
||||
} else {
|
||||
return ClusterType.Other;
|
||||
}
|
||||
const ctxsr = await kubectl.invokeAsync('config current-context');
|
||||
if (ctxsr && ctxsr.code === 0) {
|
||||
latestContextName = ctxsr.stdout.trim();
|
||||
} else {
|
||||
return ClusterType.Other;
|
||||
}
|
||||
|
||||
const cisr = await kubectl.invokeAsync('cluster-info');
|
||||
if (!cisr || cisr.code !== 0) {
|
||||
return ClusterType.Unknown;
|
||||
}
|
||||
const masterInfos = cisr.stdout.split('\n')
|
||||
.filter((s) => s.indexOf('master is running at') >= 0);
|
||||
const cisr = await kubectl.invokeAsync('cluster-info');
|
||||
if (!cisr || cisr.code !== 0) {
|
||||
return ClusterType.Unknown;
|
||||
}
|
||||
const masterInfos = cisr.stdout.split('\n')
|
||||
.filter((s) => s.indexOf('master is running at') >= 0);
|
||||
|
||||
if (masterInfos.length === 0) {
|
||||
return ClusterType.Other;
|
||||
}
|
||||
if (masterInfos.length === 0) {
|
||||
return ClusterType.Other;
|
||||
}
|
||||
|
||||
const masterInfo = masterInfos[0];
|
||||
if (masterInfo.indexOf('azmk8s.io') >= 0 || masterInfo.indexOf('azure.com') >= 0) {
|
||||
return ClusterType.AKS;
|
||||
}
|
||||
const masterInfo = masterInfos[0];
|
||||
if (masterInfo.indexOf('azmk8s.io') >= 0 || masterInfo.indexOf('azure.com') >= 0) {
|
||||
return ClusterType.AKS;
|
||||
}
|
||||
|
||||
if (latestContextName) {
|
||||
const gcsr = await kubectl.invokeAsync(`config get-contexts ${latestContextName}`);
|
||||
if (gcsr && gcsr.code === 0) {
|
||||
if (gcsr.stdout.indexOf('minikube') >= 0) {
|
||||
return ClusterType.Minikube;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (latestContextName) {
|
||||
const gcsr = await kubectl.invokeAsync(`config get-contexts ${latestContextName}`);
|
||||
if (gcsr && gcsr.code === 0) {
|
||||
if (gcsr.stdout.indexOf('minikube') >= 0) {
|
||||
return ClusterType.Minikube;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ClusterType.Other;
|
||||
return ClusterType.Other;
|
||||
}
|
||||
@@ -8,22 +8,22 @@ import * as nls from 'vscode-nls';
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export interface ISqlServerBigDataClusterChannel {
|
||||
showOutput(message: any, title?: string): void;
|
||||
showOutput(message: any, title?: string): void;
|
||||
}
|
||||
|
||||
const outputChannelName = localize('bigDataClusterOutputChannel', 'SQL Server big data cluster');
|
||||
class SqlServerBigDataCluster implements ISqlServerBigDataClusterChannel {
|
||||
private readonly channel: vscode.OutputChannel = vscode.window.createOutputChannel(outputChannelName);
|
||||
private readonly channel: vscode.OutputChannel = vscode.window.createOutputChannel(outputChannelName);
|
||||
|
||||
showOutput(message: any, title?: string): void {
|
||||
if (title) {
|
||||
const simplifiedTime = (new Date()).toISOString().replace(/z|t/gi, ' ').trim(); // YYYY-MM-DD HH:mm:ss.sss
|
||||
const hightlightingTitle = `[${title} ${simplifiedTime}]`;
|
||||
this.channel.appendLine(hightlightingTitle);
|
||||
}
|
||||
this.channel.appendLine(message);
|
||||
this.channel.show();
|
||||
}
|
||||
showOutput(message: any, title?: string): void {
|
||||
if (title) {
|
||||
const simplifiedTime = (new Date()).toISOString().replace(/z|t/gi, ' ').trim(); // YYYY-MM-DD HH:mm:ss.sss
|
||||
const hightlightingTitle = `[${title} ${simplifiedTime}]`;
|
||||
this.channel.appendLine(hightlightingTitle);
|
||||
}
|
||||
this.channel.appendLine(message);
|
||||
this.channel.show();
|
||||
}
|
||||
}
|
||||
|
||||
export const sqlserverbigdataclusterchannel: ISqlServerBigDataClusterChannel = new SqlServerBigDataCluster();
|
||||
Reference in New Issue
Block a user