diff --git a/.gitignore b/.gitignore index 0b60dfa..a8fd202 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ dist node_modules .vscode-test/ *.vsix +terraform.log diff --git a/package.json b/package.json index ba5178f..9679aae 100644 --- a/package.json +++ b/package.json @@ -39,19 +39,22 @@ "onCommand:tcTerraform.init", "onCommand:tcTerraform.plan", "onCommand:tcTerraform.apply", - "onCommand:tcTerraform.import", - "onCommand:tcTerraform.validate", "onCommand:tcTerraform.refresh", "onCommand:tcTerraform.destroy", - "onCommand:tcTerraform.visualize", - "onCommand:tcTerraform.test", - "onCommand:tcTerraform.push", "onCommand:tcTerraformer.import", - "onCommand:tcTerraformer.plan", "workspaceContains:**/*.tf", "onLanguage:terraform" ], "contributes": { + "menus": { + "view/title": [ + { + "command": "tcTerraform.resourcesExplorer.refresh", + "when": "view == tcTerraform.resourcesExplorer.cvm", + "group": "navigation" + } + ] + }, "viewsContainers": { "activitybar": [ { @@ -65,24 +68,34 @@ "views": { "tc-terraform-resources": [ { - "id": "tcTerraform.sessionExplorer", - "name": "%TcTerraform.view.session.explorer%", + "id": "tcTerraform.loginExplorer", + "name": "%TcTerraform.view.login%", "contextualTitle": "Session Explorer", "visibility": "collapsed" }, { "id": "tcTerraform.resourcesExplorer.cvm", - "name": "%TcTerraform.view.resource.explorer.cvm%", + "name": "%TcTerraform.view.resource.cvm%", "contextualTitle": "Resources Explorer", "visibility": "collapsed" }, { "id": "tcTerraform.helpExplorer", - "name": "%TcTerraform.view.help.explorer%", + "name": "%TcTerraform.view.help%", "visibility": "collapsed" } ] }, + "viewsWelcome": [ + { + "view": "tcTerraform.loginExplorer", + "contents": "%TcTerraform.view.login.welcome%" + }, + { + "view": "tcTerraform.resourcesExplorer.cvm", + "contents": "%TcTerraform.view.login.welcome%" + } + ], "languages": [ { "id": "terraform", @@ -101,9 +114,17 @@ "commands": [ { "command": "tcTerraform.login", - "title": "Login", + "title": "Login: %TcTerraform.view.login.welcome%", "category": "TencentCloud Terraform" }, + { + "command": "tcTerraform.resourcesExplorer.refresh", + "title": "%TcTerraform.refresh%", + "icon": { + "light": "resources/light/refresh.svg", + "dark": "resources/dark/refresh.svg" + } + }, { "command": "tcTerraform.init", "title": "Init", @@ -178,6 +199,16 @@ ], "description": "Specifies terminal used to run Terraform commands. Valid settings are `cloudshell` or `integrated`." }, + "tcTerraform.properties.secretId": { + "type": "string", + "default": "your_secretid", + "description": "Input your Tencent Cloud secret Id." + }, + "tcTerraform.properties.secretKey": { + "type": "string", + "default": "your_secretkey", + "description": "Input your Tencent Cloud secret key." + }, "tcTerraform.checkTerraformCmd": { "type": "boolean", "default": "true", @@ -193,26 +224,6 @@ "default": "true", "description": "Specifies whether or not TCCLI installed in the PATH." }, - "tcTerraform.secretid.cmd": { - "type": "string", - "default": "tccli configure list | grep 'secretId'", - "description": "Indicates how to get the secretid." - }, - "tcTerraform.secretkey.cmd": { - "type": "string", - "default": "tccli configure list | grep 'secretKey'", - "description": "Indicates how to get the secretkey." - }, - "tcTerraform.secretid": { - "type": "string", - "default": "your_secretid", - "description": "Input your tencentcloud secret key id." - }, - "tcTerraform.secretkey": { - "type": "string", - "default": "your_secretkey", - "description": "Input your tencentcloud secret key." - }, "tcTerraform.test.path": { "type": "string", "default": "./", diff --git a/package.nls.json b/package.nls.json index 21a8578..d41ed3a 100644 --- a/package.nls.json +++ b/package.nls.json @@ -1,13 +1,24 @@ { - "TcTerraform.title": "TencentCloud Terraofrm", - "TcTerraform.view.session.explorer": "Connect to TencentCloud", - "TcTerraform.view.template.explorer": "Tempaltes Management", - "TcTerraform.view.resource.explorer": "Resources Explorer", - "TcTerraform.view.resource.explorer.cvm": "Import Resouce: CVM", - "TcTerraform.view.resource.explorer.tke": "Import Resouce: TKE", - "TcTerraform.view.help.explorer": "Help", - "TcTerraform.view.help.explorer.provider": "TencentCloud Terraform Provider", - "TcTerraform.view.help.explorer.doc": "Documentation", - "TcTerraform.view.help.explorer.repo": "GitHub Repository", - "TcTerraform.productName": "TcTerraform Toolkit" -} + "TcTerraform.title": "Tencent Cloud Terraform", + "TcTerraform.view.login": "Login Tencent Cloud", + "TcTerraform.view.login.welcome": "Please login the Tencent Cloud. [Sign up](https://cloud.tencent.com/register) for a Tencent Cloud account if you do not have one.\n[Sign in Tencent Cloud](command:tcTerraform.login)", + "TcTerraform.view.codesnippet": "Code Snippets and Examples", + "TcTerraform.view.resource": "Resources Explorer", + "TcTerraform.refresh": "Refresh", + "TcTerraform.refresh.success": "Resources refreshed.", + "TcTerraform.view.resource.cvm": "Resources: CVM", + "TcTerraform.view.resource.tke": "Resources: TKE", + "TcTerraform.view.help": "Help", + "TcTerraform.view.help.provider": "Tencent Cloud Terraform Provider", + "TcTerraform.view.help.doc": "Documentation", + "TcTerraform.view.help.repo": "GitHub Repository", + "TcTerraform.pickup.aksk": "Sign in with [Secret Id/Secret Key]", + "TcTerraform.pickup.oauth": "Sign in with [Tencent Cloud authoritication] (Coming Soon...)", + "TcTerraform.pickup.aksk.placeholder": "Please input your API {0}", + "TcTerraform.pickup.aksk.verify.empty": "{0} can not be empty", + "TcTerraform.welcome": "Welcome to use Tencent Cloud Terraform extension, please wait for the page loading...", + "TcTerraform.msg.aksk.notfound": "Cannot find TENCENTCLOUD_SECRET_ID and TENCENTCLOUD_SECRET_KEY, please sign in first!", + "TcTerraform.logout": "Logout Tencent Cloud ({0})", + "TcTerraform.login": "Login Tencent Cloud...", + "TcTerraform.login.success": "Logged into Tencent Cloud successfully." +} \ No newline at end of file diff --git a/resources/dark/boolean.svg b/resources/dark/boolean.svg new file mode 100644 index 0000000..d85957b --- /dev/null +++ b/resources/dark/boolean.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/dark/dependency.svg b/resources/dark/dependency.svg new file mode 100644 index 0000000..2bcd336 --- /dev/null +++ b/resources/dark/dependency.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/dark/document.svg b/resources/dark/document.svg new file mode 100644 index 0000000..46a9f38 --- /dev/null +++ b/resources/dark/document.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/dark/edit.svg b/resources/dark/edit.svg new file mode 100755 index 0000000..da956cb --- /dev/null +++ b/resources/dark/edit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/dark/folder.svg b/resources/dark/folder.svg new file mode 100644 index 0000000..13b18d1 --- /dev/null +++ b/resources/dark/folder.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/dark/number.svg b/resources/dark/number.svg new file mode 100644 index 0000000..421c491 --- /dev/null +++ b/resources/dark/number.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/dark/refresh.svg b/resources/dark/refresh.svg new file mode 100644 index 0000000..d79fdaa --- /dev/null +++ b/resources/dark/refresh.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/dark/string.svg b/resources/dark/string.svg new file mode 100644 index 0000000..e08a57f --- /dev/null +++ b/resources/dark/string.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/light/boolean.svg b/resources/light/boolean.svg new file mode 100644 index 0000000..b5b64b6 --- /dev/null +++ b/resources/light/boolean.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/light/dependency.svg b/resources/light/dependency.svg new file mode 100644 index 0000000..39bd11c --- /dev/null +++ b/resources/light/dependency.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/light/document.svg b/resources/light/document.svg new file mode 100644 index 0000000..949a376 --- /dev/null +++ b/resources/light/document.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/light/edit.svg b/resources/light/edit.svg new file mode 100755 index 0000000..ecde924 --- /dev/null +++ b/resources/light/edit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/light/folder.svg b/resources/light/folder.svg new file mode 100644 index 0000000..3d64ae7 --- /dev/null +++ b/resources/light/folder.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/light/number.svg b/resources/light/number.svg new file mode 100644 index 0000000..7b02665 --- /dev/null +++ b/resources/light/number.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/light/refresh.svg b/resources/light/refresh.svg new file mode 100644 index 0000000..e034574 --- /dev/null +++ b/resources/light/refresh.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/light/string.svg b/resources/light/string.svg new file mode 100644 index 0000000..943e69c --- /dev/null +++ b/resources/light/string.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/package-explorer.png b/resources/package-explorer.png new file mode 100644 index 0000000..31ef1ba Binary files /dev/null and b/resources/package-explorer.png differ diff --git a/src/client/runner/baseRunner.ts b/src/client/runner/baseRunner.ts index 3014e6d..aecadc6 100644 --- a/src/client/runner/baseRunner.ts +++ b/src/client/runner/baseRunner.ts @@ -9,7 +9,7 @@ export abstract class BaseRunner { public tfExecutor: any; constructor() { - this.init(); + // this.init(); } public abstract init(): void; diff --git a/src/client/runner/terraformRunner.ts b/src/client/runner/terraformRunner.ts index 33b3c79..6930baf 100644 --- a/src/client/runner/terraformRunner.ts +++ b/src/client/runner/terraformRunner.ts @@ -29,21 +29,24 @@ export class TerraformRunner extends BaseRunner { return TerraformRunner.ins; } - public init(): void { - // throw new Error("Method not implemented."); + public async init(): Promise { + console.debug("[DEBUG]#### TerraformRunner init begin."); + + this.setAKSK(); + + terraformShellManager.getShell().runTerraformCmd(TerraformCommand.Init); + + return "init success"; } public async executePlan(cwd: string, args: any): Promise { console.debug("[DEBUG]#### TerraformRunner executePlan begin."); - const resAddress = `${args.resource.type}.${args.resource.name}`; + // this.setAKSK(); - // reset state - await this.resetTFState(resAddress); + terraformShellManager.getShell().runTerraformCmd(TerraformCommand.Plan); - terraformShellManager.getIntegratedShell(TerraformRunner.getInstance()).runTerraformCmd(TerraformCommand.Plan); - - return ""; + return "plan success"; } public async executeShow(cwd: string, args?: any): Promise { @@ -125,6 +128,12 @@ export class TerraformRunner extends BaseRunner { await terraformShellManager.getIntegratedShell(TerraformRunner.getInstance()) .runTerraformCmd(TerraformCommand.State, ['rm', '-lock=false', resAddress]); } + + private setAKSK(runner?: any) { + const [ak, sk] = settingUtils.getAKSK(); + terraformShellManager.getIntegratedShell(runner).runNormalCmd("export TENCENTCLOUD_SECRET_ID=" + ak); + terraformShellManager.getIntegratedShell(runner).runNormalCmd("export TENCENTCLOUD_SECRET_KEY=" + sk); + } } export function getCheckTerraformCmd(): boolean { @@ -134,5 +143,3 @@ export function getCheckTerraformCmd(): boolean { export function setCheckTerraformCmd(checked: boolean): void { vscode.workspace.getConfiguration().update("tcTerraform.checkTerraformCmd", checked); } - - diff --git a/src/client/terminal/integratedShell.ts b/src/client/terminal/integratedShell.ts index 54b437d..00ece89 100644 --- a/src/client/terminal/integratedShell.ts +++ b/src/client/terminal/integratedShell.ts @@ -129,6 +129,24 @@ export class IntegratedShell extends BaseShell { await commands.executeCommand("vscode.open", Uri.file(tfFile), ViewColumn.Active || ViewColumn.One); } + // run terraform init command + public async init(params?: any): Promise { + console.debug("[DEBUG]#### IntegratedShell init begin. params:[%v]", params); + + await this.runner.checkInstalled(); + if (this.runner instanceof TerraformRunner) { + + const cwd: string = await selectWorkspaceFolder(); + if (!cwd) { + TelemetryWrapper.sendError(Error("noWorkspaceSelected")); + return; + } + + const result = await this.runner.init(); + console.debug("[DEBUG]#### Executed init. result:[%s]", result); + } + } + // run terraform plan command public async plan(params: any): Promise { console.debug("[DEBUG]#### IntegratedShell plan begin. params:[%v]", params); diff --git a/src/client/terminal/terraformShellManager.ts b/src/client/terminal/terraformShellManager.ts index 08db68c..662e6b5 100644 --- a/src/client/terminal/terraformShellManager.ts +++ b/src/client/terminal/terraformShellManager.ts @@ -28,9 +28,9 @@ class TerraformShellManager implements ITerraformShellManager { TelemetryWrapper.addContextProperty("isCloudShell", isCloudShell.toString()); if (isCloudShell) { - return TerraformShellManager.cloudShell; + return this.getCloudShell(); } - return TerraformShellManager.integratedShell; + return this.getIntegratedShell(); } public getCloudShell(): TencentCloudShell { @@ -39,14 +39,13 @@ class TerraformShellManager implements ITerraformShellManager { public getIntegratedShell(runner?: any): IntegratedShell { if (!TerraformShellManager.integratedShell) { + // default runner is Terraformer + TerraformShellManager.integratedShell = new IntegratedShell(TerraformerRunner.getInstance()); + // specify runner if (runner) { TerraformShellManager.integratedShell = new IntegratedShell(runner); - } else { - // default runner is Terraformer - TerraformShellManager.integratedShell = new IntegratedShell(TerraformerRunner.getInstance()); } } - return TerraformShellManager.integratedShell; } diff --git a/src/commons/constants.ts b/src/commons/constants.ts index 19cbd10..9abe975 100644 --- a/src/commons/constants.ts +++ b/src/commons/constants.ts @@ -8,5 +8,4 @@ export class Constants { // eslint-disable-next-line @typescript-eslint/naming-convention public static TerraformTerminalName = "TIAT-Terraform"; - } diff --git a/src/commons/customCmdRegister.ts b/src/commons/customCmdRegister.ts index 5cde677..d4b11f6 100644 --- a/src/commons/customCmdRegister.ts +++ b/src/commons/customCmdRegister.ts @@ -3,6 +3,7 @@ import { commands, env, Uri } from "vscode"; import { terraformShellManager } from "../client/terminal/terraformShellManager"; import { TerraformerRunner } from "../client/runner/terraformerRunner"; import { TerraformRunner } from "../client/runner/terraformRunner"; +import { tree } from "./tencent/treeDataProvider"; "use strict"; @@ -31,6 +32,7 @@ export enum TcCliCommand { const openURL = "tcTerraform.openurl"; const executeTfImport = TerraformCommand.Import; const executeTferImport = TerraformerCommand.Import; +const resourceRefresh = "tcTerraform.resourcesExplorer.refresh"; export function regHelpCommands() { commands.registerCommand(cmds.openURL, function (url: string) { @@ -40,18 +42,25 @@ export function regHelpCommands() { export function regResourceRelatedCommands() { commands.registerCommand(cmds.executeTferImport, function (param: any) { - // terraformShellManager.getShell().runTerraformCmd(importObject); terraformShellManager.getIntegratedShell(TerraformerRunner.getInstance()).import(param, param.fileName); }); + commands.registerCommand("tcTerraform.init", function (param: any) { + terraformShellManager.getIntegratedShell(TerraformRunner.getInstance()).init(); + }); + commands.registerCommand("tcTerraform.plan", function (param: any) { - // terraformShellManager.getShell().runTerraformCmd(importObject); terraformShellManager.getIntegratedShell(TerraformRunner.getInstance()).plan(param); }); + + commands.registerCommand(resourceRefresh, function (param: any) { + tree.refreshTreeData(); + }); } export const cmds = { openURL, executeTfImport, - executeTferImport + executeTferImport, + resourceRefresh }; diff --git a/src/commons/index.ts b/src/commons/index.ts index 4263d10..c6d6680 100644 --- a/src/commons/index.ts +++ b/src/commons/index.ts @@ -1,11 +1,12 @@ import * as customerCmd from "./customCmdRegister"; +import { regTencentCommands } from "./tencent"; export { tencent } from "./tencent"; export * from "./container"; export * from "./context"; export { cmds } from "./customCmdRegister"; -export function registerCommon() { - // registerTencent(); +export function registerExternelCommands() { + regTencentCommands(); customerCmd.regHelpCommands(); customerCmd.regResourceRelatedCommands(); } diff --git a/src/commons/tencent/commands.ts b/src/commons/tencent/commands.ts index f9bf6b4..293552c 100644 --- a/src/commons/tencent/commands.ts +++ b/src/commons/tencent/commands.ts @@ -1,13 +1,15 @@ import { commands } from "vscode"; +import user from "./user"; -export function registerCommands() { -// commands.registerCommand(command.TENCENT_LOGIN, user.login); +export function registerLoginCmds() { + commands.registerCommand(command.TENCENT_LOGIN, user.login); -// commands.registerCommand(command.TENCENT_LOGINOUT, user.loginOut); + // commands.registerCommand(command.TENCENT_LOGINOUT, user.loginOut); } export namespace command { - export const TENCENT_LOGIN = "toolkit.tencent.login"; - /** 退出登录 */ - export const TENCENT_LOGINOUT = "toolkit.tencent.loginout"; + // login command + export const TENCENT_LOGIN = "tcTerraform.login"; + // logout command + export const TENCENT_LOGINOUT = "tcTerraform.logout"; } diff --git a/src/commons/tencent/index.ts b/src/commons/tencent/index.ts index 02a8386..fcc8fad 100644 --- a/src/commons/tencent/index.ts +++ b/src/commons/tencent/index.ts @@ -1,27 +1,24 @@ import { commands } from "vscode"; -import { registerCommands, command as _command } from "./commands"; +import { registerLoginCmds, command as _command } from "./commands"; -// import "./api.localfile"; -// import './api'; -// import _user from "./user"; +import _user from "./user"; import _tree from "./treeDataProvider"; -export async function registerTencent() { - registerCommands(); - - await initialization(); +export async function regTencentCommands() { + registerLoginCmds(); + await initialization(); } async function initialization() { -// commands.executeCommand( -// "setContext", -// "tencent.login", -// !!(await _user.getInfo()) -// ); + commands.executeCommand( + "setContext", + "TcTerraform.login", + !!(await _user.getInfo()) + ); } export namespace tencent { -// export import user = _user; - export import tree = _tree; - export import command = _command; + export import user = _user; + export import tree = _tree; + export import command = _command; } diff --git a/src/commons/tencent/treeDataProvider.ts b/src/commons/tencent/treeDataProvider.ts index 26b4335..adf6c66 100644 --- a/src/commons/tencent/treeDataProvider.ts +++ b/src/commons/tencent/treeDataProvider.ts @@ -1,11 +1,13 @@ import { injectable } from "inversify"; import { + window, Event, EventEmitter, TreeDataProvider as BaseTreeDataProvider, TreeItem as BaseTreeItem, } from "vscode"; import { container } from "../container"; +import { localize } from "vscode-nls-i18n"; export namespace tree { export const TencentTreeProvider = Symbol("TencentTreeProvider"); @@ -15,6 +17,7 @@ export namespace tree { container.getAll(TencentTreeProvider); treeDataProvider.map((item) => item.refresh()); + window.showInformationMessage(localize("TcTerraform.refresh.success")); } // @ts-ignore diff --git a/src/commons/tencent/user/auth/credentail.ts b/src/commons/tencent/user/auth/credentail.ts new file mode 100644 index 0000000..98894cd --- /dev/null +++ b/src/commons/tencent/user/auth/credentail.ts @@ -0,0 +1,52 @@ +import MultiStepInput from "../../../multiStepInput"; +import { Credential } from "tencentcloud-sdk-nodejs/tencentcloud/common/interface"; +import { localize } from "vscode-nls-i18n"; +import constant from "../index"; + +export async function getCredentailByInput() { + const title = localize(constant.AKSK_TITLE); + async function collectInputs() { + const state = {} as Partial; + await MultiStepInput.run((input) => inputSecretId(input, state)); + return state as Required>; + } + + async function inputSecretId( + input: MultiStepInput, + state: Partial + ) { + state.secretId = await input.showInputBox({ + title, + step: 1, + totalSteps: 2, + value: state.secretId || "", + placeholder: localize(constant.AKSK_PLACEHOLD, "SecretId"), + validate: validateInput.bind({ key: "SecretId " }), + }); + return (input: MultiStepInput) => inpuSecretKey(input, state); + } + + async function inpuSecretKey( + input: MultiStepInput, + state: Partial + ) { + state.secretKey = await input.showInputBox({ + title, + step: 2, + totalSteps: 2, + value: state.secretKey || "", + placeholder: localize(constant.AKSK_PLACEHOLD, "SecretKey"), + validate: validateInput.bind({ key: "SecretKey " }), + }); + } + + async function validateInput(this: { key: string }, value: string) { + if (!value) { + return Promise.reject(localize(constant.AKSK_EMPTY, this.key)); + } + + return undefined; + } + + return collectInputs(); +} diff --git a/src/commons/tencent/user/auth/index.ts b/src/commons/tencent/user/auth/index.ts new file mode 100644 index 0000000..cbdafaf --- /dev/null +++ b/src/commons/tencent/user/auth/index.ts @@ -0,0 +1 @@ +export { getCredentailByInput } from "./credentail"; diff --git a/src/commons/tencent/user/index.ts b/src/commons/tencent/user/index.ts new file mode 100644 index 0000000..cba44ac --- /dev/null +++ b/src/commons/tencent/user/index.ts @@ -0,0 +1,91 @@ +import { localize } from "vscode-nls-i18n"; +import { ExtensionContext, workspace, ConfigurationTarget, window } from "vscode"; + +import { container } from "../../container"; +import { Context } from "../../context"; +import { tree } from "../treeDataProvider"; +import { getCredentailByInput } from "./auth"; +import { LoginProvider } from "../../../views/login/loginExplorer"; +import { terraformShellManager } from "../../../client/terminal/terraformShellManager"; + +export namespace user { + interface UserInfo { + secretId: string; + secretKey: string; + token?: string; + uin: string; + } + + export const AKSK_TITLE = "TcTerraform.pickup.aksk"; + export const OAUTH_TITLE = "TcTerraform.pickup.oauth"; + export const AKSK_PLACEHOLD = "TcTerraform.pickup.aksk.placeholder"; + export const AKSK_EMPTY = "TcTerraform.pickup.aksk.verify.empty"; + + const USER_INFO = "USER_INFO"; + + export async function login() { + const aksk = localize(AKSK_TITLE); + const oauth = localize(OAUTH_TITLE); + const pick = await window.showQuickPick([aksk, oauth]); + + if (aksk === pick) { + const credential = await getCredentailByInput(); + const accessKey = credential.secretId; + const secretKey = credential.secretKey; + + // get configuration + const config = workspace.getConfiguration(); + // set in vscode configuration(setting.json) + config.update('tcTerraform.properties.secretId', accessKey, ConfigurationTarget.Global) + .then(() => { + }, (error) => { + window.showErrorMessage('设置secretId失败: ' + error); + }); + config.update('tcTerraform.properties.secretKey', secretKey, ConfigurationTarget.Global) + .then(() => { + }, (error) => { + window.showErrorMessage('设置secretKey失败: ' + error); + }); + + // set in system environment + process.env.TENCENTCLOUD_SECRET_ID = accessKey; + process.env.TENCENTCLOUD_SECRET_KEY = secretKey; + + tree.refreshTreeData(); + window.showInformationMessage(localize("TcTerraform.login.success")); + } + } + + export async function getInfo(): Promise { + const { secrets } = container.get(Context); + const userinfo = await secrets.get(USER_INFO); + + if (userinfo) { + return JSON.parse(userinfo) as UserInfo; + } + + return undefined; + } + + export async function loginOut() { + const yes = localize("common.yes"); + const action = await window.showWarningMessage( + localize("tencent.loginout.title"), + { + modal: true, + detail: localize("tencent.loginout.detail"), + }, + yes + ); + if (action !== yes) { + return; + } + + const { secrets } = container.get(Context); + await secrets.delete(USER_INFO); + + tree.refreshTreeData(); + } +} + +export default user; diff --git a/src/connectivity/client.ts b/src/connectivity/client.ts index 8dbdccb..4961709 100644 --- a/src/connectivity/client.ts +++ b/src/connectivity/client.ts @@ -1,9 +1,10 @@ "use strict"; import * as vscode from "vscode"; -// import * as tencentcloud from "tencentcloud-sdk-nodejs-cvm"; import { Client as CvmClient } from "tencentcloud-sdk-nodejs-cvm/tencentcloud/services/cvm/v20170312/cvm_client"; import { Client as TkeClient } from "tencentcloud-sdk-nodejs-tke/tencentcloud/services/tke/v20180525/tke_client"; +import { localize } from "vscode-nls-i18n"; +import * as settingUtils from "../utils/settingUtils"; const tkeClient = TkeClient; const cvmClient = CvmClient; @@ -35,11 +36,47 @@ export async function getTkeClient(): Promise { } export async function getCvmClient(region?: string): Promise { - const secretId = process.env.TENCENTCLOUD_SECRET_ID; - const secretKey = process.env.TENCENTCLOUD_SECRET_KEY; + // const secretIdConfig = utils.getSecretIdFromUI(); + // const secretKeyConfig = utils.getSecretKeyFromUI(); + // const secretIdEnv = utils.getSecretIdFromEnv(); + // const secretKeyEnv = utils.getSecretKeyFromEnv(); + + // const secretId = (secretIdEnv === undefined) ? secretIdConfig : secretIdEnv; + // const secretKey = (secretKeyEnv === undefined) ? secretKeyConfig : secretKeyEnv; + const [secretId, secretKey] = settingUtils.getAKSK(); if (secretId === undefined || secretKey === undefined || secretId === null || secretKey === null) { - vscode.window.showErrorMessage("Cannot find TENCENTCLOUD_SECRET_ID and TENCENTCLOUD_SECRET_KEY, please set them first!"); + let msg = localize("TcTerraform.msg.aksk.notfound"); + vscode.window.showErrorMessage(msg); + return null; + } + + return new CvmClient({ + credential: { + secretId: secretId, + secretKey: secretKey, + }, + // 产品地域 + region: (process.env.TENCENTCLOUD_REGION === undefined) ? + "ap-guangzhou" : process.env.TENCENTCLOUD_REGION, + // 可选配置实例 + profile: { + // signMethod: "TC3-HMAC-SHA256", // 签名方法 + httpProfile: { + reqMethod: "POST", // 请求方法 + // reqTimeout: 60, // 请求超时时间,默认60s + endpoint: "cvm.tencentcloudapi.com", + }, + }, + }) +} + +export async function getStsClient(region?: string): Promise { + const [secretId, secretKey] = settingUtils.getAKSK(); + + if (secretId === undefined || secretKey === undefined || secretId === null || secretKey === null) { + let msg = localize("TcTerraform.msg.aksk.notfound"); + vscode.window.showErrorMessage(msg); return null; } diff --git a/src/extension.ts b/src/extension.ts index e491c9f..7cabec3 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -8,11 +8,12 @@ import { terraformShellManager } from "./client/terminal/terraformShellManager"; import { DialogOption } from "./utils/uiUtils"; import { TerraformCompletionProvider } from './autocomplete/TerraformCompletionProvider'; import { TerraformDefinitionProvider } from './autocomplete/TerraformDefinitionProvider'; -import { registerCommon } from './commons'; +import { registerExternelCommands } from './commons'; import { registerView } from './views'; import { TerraformRunner } from './client/runner/terraformRunner'; import { TerraformerRunner } from './client/runner/terraformerRunner'; import { GitUtils } from './utils/gitUtils'; +import { bindExtensionContext } from "./commons"; import _ from 'lodash'; const TF_MODE: vscode.DocumentFilter = { language: 'terraform', scheme: 'file' }; @@ -21,38 +22,12 @@ const TF_MODE: vscode.DocumentFilter = { language: 'terraform', scheme: 'file' } // Your extension is activated the very first time the command is executed export async function activate(context: vscode.ExtensionContext) { console.log('Congratulations, your extension "TencentCloud Terraform" is now active!'); + bindExtensionContext(context); await TerraformRunner.getInstance().checkInstalled(); await TerraformerRunner.getInstance().checkInstalled(); - let disposableLogin = vscode.commands.registerCommand('tcTerraform.login', async () => { - // to-do - // wait for cloudshell and tccli implement ready - let accessKey = settingUtils.getSecretIdFromUI(); - let secretKey = settingUtils.getSecretKeyFromUI(); - - // process.env.TENCENTCLOUD_SECRET_ID=accessKey; - // process.env.TENCENTCLOUD_SECRET_KEY=secretKey; - - // console.log("TENCENTCLOUD_SECRET_ID:", process.env.TENCENTCLOUD_SECRET_ID); - // console.log("TENCENTCLOUD_SECRET_KEY:", process.env.TENCENTCLOUD_SECRET_KEY); - - terraformShellManager.getShell().runNormalCmd("export TENCENTCLOUD_SECRET_ID=" + accessKey); - terraformShellManager.getShell().runNormalCmd("export TENCENTCLOUD_SECRET_KEY=" + secretKey); - }); - - context.subscriptions.push(disposableLogin); // terraform cmd - context.subscriptions.push(vscode.commands.registerCommand('tcTerraform.init', () => { - terraformShellManager.getShell().runTerraformCmd(TerraformCommand.Init); - })); - - // move plan to customCmdRegister - // context.subscriptions.push(vscode.commands.registerCommand('tcTerraform.plan', () => { - // await terraformShellManager.getIntegratedShell(TerraformRunner.getInstance()).plan(); - - // })); - context.subscriptions.push(vscode.commands.registerCommand('tcTerraform.apply', () => { terraformShellManager.getShell().runTerraformCmd(TerraformCommand.Apply); })); @@ -127,7 +102,7 @@ export async function activate(context: vscode.ExtensionContext) { // import-resource console.log('activate the import feature'); init(context.extensionPath); - registerCommon(); + registerExternelCommands(); registerView(); } diff --git a/src/import/cvm.ts b/src/import/cvm.ts index f5d09bc..1522a4e 100644 --- a/src/import/cvm.ts +++ b/src/import/cvm.ts @@ -1,10 +1,9 @@ "use strict"; -import * as vscode from "vscode"; import * as client from "../connectivity/client"; import { Instance } from "tencentcloud-sdk-nodejs-cvm/tencentcloud/services/cvm/v20170312/cvm_models"; import { ITencentCloudAPI } from "../commons/tencent/sdkApi"; -import { error } from "console"; +import { window } from "vscode"; export class CvmService implements ITencentCloudAPI { async getConfig(params?: any): Promise { @@ -32,7 +31,8 @@ export class CvmService implements ITencentCloudAPI { return result.InstanceSet; }, (err) => { - console.error('[Error] DescribeInstances got a error from SDK.', err.message); + console.error('[TencentCloudSDKError] DescribeInstances got a error from SDK.', err.message); + window.showErrorMessage('[TencentCloudSDKError] ' + err.message); return err; } ); diff --git a/src/test/runTest.ts b/src/test/runTest.ts deleted file mode 100644 index 93a4441..0000000 --- a/src/test/runTest.ts +++ /dev/null @@ -1,23 +0,0 @@ -import * as path from 'path'; - -import { runTests } from '@vscode/test-electron'; - -async function main() { - try { - // The folder containing the Extension Manifest package.json - // Passed to `--extensionDevelopmentPath` - const extensionDevelopmentPath = path.resolve(__dirname, '../../'); - - // The path to test runner - // Passed to --extensionTestsPath - const extensionTestsPath = path.resolve(__dirname, './suite/index'); - - // Download VS Code, unzip it and run the integration test - await runTests({ extensionDevelopmentPath, extensionTestsPath }); - } catch (err) { - console.error('Failed to run tests', err); - process.exit(1); - } -} - -main(); diff --git a/src/test/suite/extension.test.ts b/src/test/suite/extension.test.ts deleted file mode 100644 index 4ca0ab4..0000000 --- a/src/test/suite/extension.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import * as assert from 'assert'; - -// You can import and use all API from the 'vscode' module -// as well as import your extension to test it -import * as vscode from 'vscode'; -// import * as myExtension from '../../extension'; - -suite('Extension Test Suite', () => { - vscode.window.showInformationMessage('Start all tests.'); - - test('Sample test', () => { - assert.strictEqual(-1, [1, 2, 3].indexOf(5)); - assert.strictEqual(-1, [1, 2, 3].indexOf(0)); - }); -}); diff --git a/src/test/suite/index.ts b/src/test/suite/index.ts deleted file mode 100644 index 6671ba3..0000000 --- a/src/test/suite/index.ts +++ /dev/null @@ -1,40 +0,0 @@ -import * as path from 'path'; -// import * as Mocha from 'mocha'; -import mocha from "mocha"; -// import * as glob from 'glob'; -import glob from 'glob'; - -export function run(): Promise { - // Create the mocha test - const mocha = new Mocha({ - ui: 'tdd', - color: true - }); - - const testsRoot = path.resolve(__dirname, '..'); - - return new Promise((c, e) => { - glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { - if (err) { - return e(err); - } - - // Add files to the test suite - files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); - - try { - // Run the mocha test - mocha.run(failures => { - if (failures > 0) { - e(new Error(`${failures} tests failed.`)); - } else { - c(); - } - }); - } catch (err) { - console.error(err); - e(err); - } - }); - }); -} diff --git a/src/utils/settingUtils.ts b/src/utils/settingUtils.ts index 5aff7b1..63f0c59 100644 --- a/src/utils/settingUtils.ts +++ b/src/utils/settingUtils.ts @@ -28,11 +28,28 @@ export function getSecretKeyCmd(): string { } export function getSecretIdFromUI(): string { - return vscode.workspace.getConfiguration().get("tcTerraform.secretid"); + return vscode.workspace.getConfiguration().get("tcTerraform.properties.secretId"); } export function getSecretKeyFromUI(): string { - return vscode.workspace.getConfiguration().get("tcTerraform.secretkey"); + return vscode.workspace.getConfiguration().get("tcTerraform.properties.secretKey"); +} + +export function getAKSK(): [string, string] { + const secretIdConfig = getSecretIdFromUI(); + const secretKeyConfig = getSecretKeyFromUI(); + const secretIdEnv = getSecretIdFromEnv(); + const secretKeyEnv = getSecretKeyFromEnv(); + + return [secretIdEnv ?? secretIdConfig, secretKeyEnv ?? secretKeyConfig]; +} + +export function getSecretIdFromEnv(): string { + return process.env.TENCENTCLOUD_SECRET_ID; +} + +export function getSecretKeyFromEnv(): string { + return process.env.TENCENTCLOUD_SECRET_KEY; } export function getCheckTCCLI(): boolean { diff --git a/src/views/help/helpExplorer.ts b/src/views/help/helpExplorer.ts index fa907f2..3565c74 100644 --- a/src/views/help/helpExplorer.ts +++ b/src/views/help/helpExplorer.ts @@ -1,8 +1,7 @@ import { ThemeIcon } from "vscode"; import { localize } from "vscode-nls-i18n"; -import { container, tencent, cmds} from "../../commons"; -import { Icons } from "../../utils/icons"; +import { container, tencent, cmds } from "../../commons"; const { tree } = tencent; @@ -12,7 +11,7 @@ export class HelpProvider extends TreeDataProvider { async getChildren(element?: tencent.tree.TreeItem | undefined): Promise { if (!element) { const elements = [ - new TreeItem(localize("TcTerraform.view.help.explorer.provider"), { + new TreeItem(localize("TcTerraform.view.help.provider"), { // iconPath: Icons.getIcon("tools"), command: { command: cmds.openURL, @@ -20,7 +19,7 @@ export class HelpProvider extends TreeDataProvider { arguments: ["https://registry.terraform.io/providers/tencentcloudstack/tencentcloud/latest"], }, }), - new TreeItem(localize("TcTerraform.view.help.explorer.doc"), { + new TreeItem(localize("TcTerraform.view.help.doc"), { // iconPath: Icons.getIcon("book"), command: { command: cmds.openURL, @@ -28,7 +27,7 @@ export class HelpProvider extends TreeDataProvider { arguments: ["https://cloud.tencent.com/product/tiat"], }, }), - new TreeItem(localize("TcTerraform.view.help.explorer.repo"), { + new TreeItem(localize("TcTerraform.view.help.repo"), { // iconPath: Icons.getIcon("github"), command: { command: cmds.openURL, diff --git a/src/views/index.ts b/src/views/index.ts index 5216556..2e62530 100644 --- a/src/views/index.ts +++ b/src/views/index.ts @@ -1,8 +1,9 @@ import { registerHelp } from "./help"; +import { registerLogin } from "./login"; import { registerResources } from "./resources"; export function registerView() { registerHelp(); - registerResources(); + registerLogin(); } diff --git a/src/views/login/index.ts b/src/views/login/index.ts new file mode 100644 index 0000000..70f5af6 --- /dev/null +++ b/src/views/login/index.ts @@ -0,0 +1,8 @@ +import { window } from "vscode"; + +import { container } from "../../commons/container"; +import { LoginProvider } from "./loginExplorer"; + +export function registerLogin() { + window.registerTreeDataProvider("tcTerraform.loginExplorer", container.get(LoginProvider)); +} \ No newline at end of file diff --git a/src/views/login/loginExplorer.ts b/src/views/login/loginExplorer.ts new file mode 100644 index 0000000..0fbed55 --- /dev/null +++ b/src/views/login/loginExplorer.ts @@ -0,0 +1,55 @@ +import * as vscode from "vscode"; +import { localize } from "vscode-nls-i18n"; + +import { container, tencent, cmds } from "../../commons"; +import { getSecretIdFromEnv, getSecretKeyFromEnv } from "../../utils/settingUtils"; + +export class LoginProvider extends tencent.tree.TreeDataProvider { + private loggedIn = false; + + constructor() { + super(); + this.loggedIn = false; + } + + setLoggedIn(value: boolean) { + this.loggedIn = value; + } + + isLoggedIn(): boolean { + if (getSecretIdFromEnv() && getSecretKeyFromEnv()) { + return true; + } + return false; + } + + async getChildren(element?: tencent.tree.TreeItem | undefined): Promise { + if (!element) { + if (this.isLoggedIn()) { + return [new tencent.tree.TreeItem(localize("TcTerraform.login.success"))]; + } + + const welcome = [ + // new tencent.tree.TreeItem(localize("TcTerraform.view.login.welcome")) + ]; + + // const info = await user.getInfo(); + // if (info) { + // elements.push( + // new TreeItem(localize("tencent.loginout", info.uin), { + // iconPath: Icons.getIcon("account"), + // command: { command: tencent.command.TENCENT_LOGINOUT, title: "" }, + // }) + // ); + // } + + return welcome; + } + return []; + } + +} + +container.bind(LoginProvider).toSelf().inSingletonScope(); + +container.bind(tencent.tree.TencentTreeProvider).toService(LoginProvider); diff --git a/terraform.tfstate b/terraform.tfstate index f10eabb..c141228 100644 --- a/terraform.tfstate +++ b/terraform.tfstate @@ -1,8 +1,9 @@ { "version": 4, - "terraform_version": "1.2.9", + "terraform_version": "1.6.0", "serial": 1, "lineage": "1383ce09-0e23-874b-4a85-5e70c134da3b", "outputs": {}, - "resources": [] + "resources": [], + "check_results": null }