From 738f4299ca551d4149109fb89aba5741ed076845 Mon Sep 17 00:00:00 2001 From: nickyinluo Date: Wed, 18 Oct 2023 20:31:19 +0800 Subject: [PATCH 1/5] support login with AKSK input --- package.json | 13 +- package.nls.json | 13 +- src/commons/constants.ts | 1 - src/commons/index.ts | 4 +- src/commons/tencent/commands.ts | 12 +- src/commons/tencent/index.ts | 24 ++-- src/commons/tencent/user/auth/credentail.ts | 52 ++++++++ src/commons/tencent/user/auth/index.ts | 1 + src/commons/tencent/user/auth/qr.ts | 125 ++++++++++++++++++++ src/commons/tencent/user/index.ts | 67 +++++++++++ src/extension.ts | 24 ++-- 11 files changed, 294 insertions(+), 42 deletions(-) create mode 100644 src/commons/tencent/user/auth/credentail.ts create mode 100644 src/commons/tencent/user/auth/index.ts create mode 100644 src/commons/tencent/user/auth/qr.ts create mode 100644 src/commons/tencent/user/index.ts diff --git a/package.json b/package.json index ba5178f..4cee349 100644 --- a/package.json +++ b/package.json @@ -65,8 +65,8 @@ "views": { "tc-terraform-resources": [ { - "id": "tcTerraform.sessionExplorer", - "name": "%TcTerraform.view.session.explorer%", + "id": "tcTerraform.loginExplorer", + "name": "%TcTerraform.view.login.explorer%", "contextualTitle": "Session Explorer", "visibility": "collapsed" }, @@ -83,6 +83,12 @@ } ] }, + "viewsWelcome": [ + { + "view": "tcTerraform.loginExplorer", + "contents": "%TcTerraform.view.login.welcome%" + } + ], "languages": [ { "id": "terraform", @@ -101,8 +107,7 @@ "commands": [ { "command": "tcTerraform.login", - "title": "Login", - "category": "TencentCloud Terraform" + "title": "%TcTerraform.view.login.welcome%" }, { "command": "tcTerraform.init", diff --git a/package.nls.json b/package.nls.json index 21a8578..44622aa 100644 --- a/package.nls.json +++ b/package.nls.json @@ -1,6 +1,9 @@ { - "TcTerraform.title": "TencentCloud Terraofrm", - "TcTerraform.view.session.explorer": "Connect to TencentCloud", + "TcTerraform.title": "TencentCloud Terraform", + "TcTerraform.view.login.explorer": "Login TencentCloud", + "TcTerraform.view.login.welcome": "Please login the TencentCloud. If you don't have a account, please [Sign up](https://cloud.tencent.com/register) first.\n[Login TencentCloud](command:tcTerraform.login)", + "TcTerraform.view.welcome": "Welcome to use TencentCloud Terraform extension, please wait for the page loading...", + "TcTerraform.view.login": "登录腾讯云", "TcTerraform.view.template.explorer": "Tempaltes Management", "TcTerraform.view.resource.explorer": "Resources Explorer", "TcTerraform.view.resource.explorer.cvm": "Import Resouce: CVM", @@ -9,5 +12,9 @@ "TcTerraform.view.help.explorer.provider": "TencentCloud Terraform Provider", "TcTerraform.view.help.explorer.doc": "Documentation", "TcTerraform.view.help.explorer.repo": "GitHub Repository", + "TcTerraform.AKSK.title": "API AKSK Login", + "TcTerraform.QR.title": "Scan code Login", + "TcTerraform.AKSK.title.placeholder": "请输入腾讯云 API 密钥 {0}", + "TcTerraform.AKSK.title.verify.empty": "{0}不能为空", "TcTerraform.productName": "TcTerraform Toolkit" -} +} \ No newline at end of file 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/index.ts b/src/commons/index.ts index 4263d10..b7eceb8 100644 --- a/src/commons/index.ts +++ b/src/commons/index.ts @@ -1,11 +1,13 @@ import * as customerCmd from "./customCmdRegister"; +import { registerTencent } from "./tencent"; export { tencent } from "./tencent"; export * from "./container"; export * from "./context"; export { cmds } from "./customCmdRegister"; export function registerCommon() { - // registerTencent(); + registerTencent(); customerCmd.regHelpCommands(); customerCmd.regResourceRelatedCommands(); + } diff --git a/src/commons/tencent/commands.ts b/src/commons/tencent/commands.ts index f9bf6b4..3eb4bd8 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); + 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..e6af2e3 100644 --- a/src/commons/tencent/index.ts +++ b/src/commons/tencent/index.ts @@ -1,27 +1,25 @@ import { commands } from "vscode"; import { registerCommands, 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(); + registerCommands(); - await initialization(); + await initialization(); } async function initialization() { -// commands.executeCommand( -// "setContext", -// "tencent.login", -// !!(await _user.getInfo()) -// ); + commands.executeCommand( + "setContext", + "tencent.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/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/auth/qr.ts b/src/commons/tencent/user/auth/qr.ts new file mode 100644 index 0000000..548f227 --- /dev/null +++ b/src/commons/tencent/user/auth/qr.ts @@ -0,0 +1,125 @@ +import axios from "axios"; +import { window } from "vscode"; +import { join } from "path"; +import { Credential } from "tencentcloud-sdk-nodejs/tencentcloud/common/interface"; + +const LOGIN_SERVER = "https://test.ide.cloud.tencent.com"; + +const client = axios.create({ + baseURL: LOGIN_SERVER, + proxy: { + protocol: "http", + host: "9.135.97.58", + port: 8899, + }, +}); + +function getQrState() { + return client.get("/api/public/qcloud/oauth/qrcode").then((res) => { + return res.data.data; + }); +} + +function getQrUrl(state: string) { + return `${LOGIN_SERVER}/api/public/qcloud/oauth/scan?state=${state}`; +} + +type State = "WAITING" | "SCANNED" | "OK"; +function getState(state: string): Promise { + return client + .get("/api/public/qcloud/oauth/status", { + params: { + state, + }, + }) + .then((res) => res.data.data) + .catch((err) => { + return "WAITING"; + }); +} + +type TokenInfo = { + scope: string; + appId: string; + requestId: string; + userAccessToken: string; + userOpenId: string; + expiresAt: string; + userRefreshToken: string; + userUnionId: string; +}; + +function getTokenInfo(state: string): Promise { + return client + .get("/api/public/qcloud/oauth/token", { params: { state } }) + .then((res) => res.data.data); +} + +interface CredentialsType { + credentials: { + token: string; + tmpSecretId: string; + tmpSecretKey: string; + }; + expiredTime: string; +} + +function getSecret( + userAccessToken: string, + duration = 7200 * 24 +): Promise { + return client + .get("/api/public/qcloud/oauth/federationToken", { + params: { userAccessToken, duration }, + }) + .then((res) => res.data.data); +} + +function refreshToken(userRefreshToken: string, userOpenId: string) { + return client + .get("/api/public/qcloud/oauth/refreshToken", { + params: { userRefreshToken, userOpenId }, + }) + .then((res) => res.data.data); +} + +export async function getCredentailByQr() { + const stateCode = await getQrState(); + const qrUrl = getQrUrl(stateCode); + + const terminal = window.createTerminal({ + name: "登录腾讯云", + shellPath: join(__dirname, "bin/qrcode.js"), + shellArgs: [qrUrl], + isTransient: true, + }); + terminal.show(); + + let state: State = "WAITING"; + + while (state !== "OK") { + // await delay(500); + const newState = await getState(stateCode); + + if (state !== "SCANNED" && newState === "SCANNED") { + terminal.sendText("已扫码,等待授权... \n", true); + } + + state = newState; + } + + terminal.sendText("授权成功 \n", true); + terminal.dispose(); + + const u = await getTokenInfo(stateCode); + + const { + credentials: { token, tmpSecretId, tmpSecretKey }, + } = await getSecret(u.userAccessToken); + + return { + token, + secretId: tmpSecretId, + secretKey: tmpSecretKey, + }; +} diff --git a/src/commons/tencent/user/index.ts b/src/commons/tencent/user/index.ts new file mode 100644 index 0000000..63ee30d --- /dev/null +++ b/src/commons/tencent/user/index.ts @@ -0,0 +1,67 @@ +import { localize } from "vscode-nls-i18n"; +import { ExtensionContext, ProgressLocation, window } from "vscode"; +import { AbstractClient } from "tencentcloud-sdk-nodejs/tencentcloud/common/abstract_client"; +import { Credential } from "tencentcloud-sdk-nodejs/tencentcloud/common/interface"; + +import { container } from "../../container"; +import { Context } from "../../context"; +import { tree } from "../treeDataProvider"; +import { getCredentailByInput } from "./auth"; + +export namespace user { + interface UserInfo { + secretId: string; + secretKey: string; + token?: string; + uin: string; + } + + export const AKSK_TITLE = "TcTerraform.AKSK.title"; + export const AKSK_PLACEHOLD = "TcTerraform.AKSK.title.placeholder"; + export const AKSK_EMPTY = "TcTerraform.AKSK.title.verify.empty"; + + const USER_INFO = "USER_INFO"; + + export async function login() { + const api = localize(AKSK_TITLE); + const pick = await window.showQuickPick(["xxxxxxx", api]); + + if (pick) { + const credential = await getCredentailByInput(); + // api === pick ? await getCredentailByInput() : await getCredentailByQr(); + } + } + + 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/extension.ts b/src/extension.ts index e491c9f..8e77ae3 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -25,23 +25,17 @@ export async function activate(context: vscode.ExtensionContext) { 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; + // 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(); - // 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); - }); + // terraformShellManager.getShell().runNormalCmd("export TENCENTCLOUD_SECRET_ID=" + accessKey); + // terraformShellManager.getShell().runNormalCmd("export TENCENTCLOUD_SECRET_KEY=" + secretKey); + // }); - context.subscriptions.push(disposableLogin); + // context.subscriptions.push(disposableLogin); // terraform cmd context.subscriptions.push(vscode.commands.registerCommand('tcTerraform.init', () => { terraformShellManager.getShell().runTerraformCmd(TerraformCommand.Init); From 2ed455f42a3d44018f4295d212679bbb0e48311b Mon Sep 17 00:00:00 2001 From: nickyinluo Date: Thu, 19 Oct 2023 01:05:43 +0800 Subject: [PATCH 2/5] add aksk input --- package.json | 20 ++++- package.nls.json | 36 ++++---- src/commons/index.ts | 7 +- src/commons/tencent/commands.ts | 2 +- src/commons/tencent/index.ts | 9 +- src/commons/tencent/user/auth/qr.ts | 125 ---------------------------- src/commons/tencent/user/index.ts | 41 +++++++-- src/connectivity/client.ts | 11 ++- src/extension.ts | 4 +- src/views/help/helpExplorer.ts | 6 +- 10 files changed, 90 insertions(+), 171 deletions(-) delete mode 100644 src/commons/tencent/user/auth/qr.ts diff --git a/package.json b/package.json index 4cee349..a8634f2 100644 --- a/package.json +++ b/package.json @@ -66,19 +66,19 @@ "tc-terraform-resources": [ { "id": "tcTerraform.loginExplorer", - "name": "%TcTerraform.view.login.explorer%", + "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" } ] @@ -87,6 +87,10 @@ { "view": "tcTerraform.loginExplorer", "contents": "%TcTerraform.view.login.welcome%" + }, + { + "view": "tcTerraform.resourcesExplorer.cvm", + "contents": "%TcTerraform.view.login.welcome%" } ], "languages": [ @@ -174,6 +178,16 @@ "configuration": { "title": "TencentCloud Terraform", "properties": { + "tcTerraform.properties.secretId": { + "type": "string", + "default": "", + "description": "Tencent Cloud Secret ID" + }, + "tcTerraform.properties.secretKey": { + "type": "string", + "default": "", + "description": "Tencent Cloud Secret Key" + }, "tcTerraform.terminal": { "type": "string", "default": "integrated", diff --git a/package.nls.json b/package.nls.json index 44622aa..a9f85af 100644 --- a/package.nls.json +++ b/package.nls.json @@ -1,20 +1,20 @@ { - "TcTerraform.title": "TencentCloud Terraform", - "TcTerraform.view.login.explorer": "Login TencentCloud", - "TcTerraform.view.login.welcome": "Please login the TencentCloud. If you don't have a account, please [Sign up](https://cloud.tencent.com/register) first.\n[Login TencentCloud](command:tcTerraform.login)", - "TcTerraform.view.welcome": "Welcome to use TencentCloud Terraform extension, please wait for the page loading...", - "TcTerraform.view.login": "登录腾讯云", - "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.AKSK.title": "API AKSK Login", - "TcTerraform.QR.title": "Scan code Login", - "TcTerraform.AKSK.title.placeholder": "请输入腾讯云 API 密钥 {0}", - "TcTerraform.AKSK.title.verify.empty": "{0}不能为空", - "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.view.resource.cvm": "Import Resouce: CVM", + "TcTerraform.view.resource.tke": "Import Resouce: 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.logout": "Logout Tencent Cloud ({0})", + "TcTerraform.login": "Login Tencent Cloud..." } \ No newline at end of file diff --git a/src/commons/index.ts b/src/commons/index.ts index b7eceb8..c6d6680 100644 --- a/src/commons/index.ts +++ b/src/commons/index.ts @@ -1,13 +1,12 @@ import * as customerCmd from "./customCmdRegister"; -import { registerTencent } from "./tencent"; +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 3eb4bd8..293552c 100644 --- a/src/commons/tencent/commands.ts +++ b/src/commons/tencent/commands.ts @@ -1,7 +1,7 @@ import { commands } from "vscode"; import user from "./user"; -export function registerCommands() { +export function registerLoginCmds() { commands.registerCommand(command.TENCENT_LOGIN, user.login); // commands.registerCommand(command.TENCENT_LOGINOUT, user.loginOut); diff --git a/src/commons/tencent/index.ts b/src/commons/tencent/index.ts index e6af2e3..fcc8fad 100644 --- a/src/commons/tencent/index.ts +++ b/src/commons/tencent/index.ts @@ -1,19 +1,18 @@ import { commands } from "vscode"; -import { registerCommands, command as _command } from "./commands"; +import { registerLoginCmds, command as _command } from "./commands"; import _user from "./user"; import _tree from "./treeDataProvider"; -export async function registerTencent() { - registerCommands(); - +export async function regTencentCommands() { + registerLoginCmds(); await initialization(); } async function initialization() { commands.executeCommand( "setContext", - "tencent.login", + "TcTerraform.login", !!(await _user.getInfo()) ); } diff --git a/src/commons/tencent/user/auth/qr.ts b/src/commons/tencent/user/auth/qr.ts deleted file mode 100644 index 548f227..0000000 --- a/src/commons/tencent/user/auth/qr.ts +++ /dev/null @@ -1,125 +0,0 @@ -import axios from "axios"; -import { window } from "vscode"; -import { join } from "path"; -import { Credential } from "tencentcloud-sdk-nodejs/tencentcloud/common/interface"; - -const LOGIN_SERVER = "https://test.ide.cloud.tencent.com"; - -const client = axios.create({ - baseURL: LOGIN_SERVER, - proxy: { - protocol: "http", - host: "9.135.97.58", - port: 8899, - }, -}); - -function getQrState() { - return client.get("/api/public/qcloud/oauth/qrcode").then((res) => { - return res.data.data; - }); -} - -function getQrUrl(state: string) { - return `${LOGIN_SERVER}/api/public/qcloud/oauth/scan?state=${state}`; -} - -type State = "WAITING" | "SCANNED" | "OK"; -function getState(state: string): Promise { - return client - .get("/api/public/qcloud/oauth/status", { - params: { - state, - }, - }) - .then((res) => res.data.data) - .catch((err) => { - return "WAITING"; - }); -} - -type TokenInfo = { - scope: string; - appId: string; - requestId: string; - userAccessToken: string; - userOpenId: string; - expiresAt: string; - userRefreshToken: string; - userUnionId: string; -}; - -function getTokenInfo(state: string): Promise { - return client - .get("/api/public/qcloud/oauth/token", { params: { state } }) - .then((res) => res.data.data); -} - -interface CredentialsType { - credentials: { - token: string; - tmpSecretId: string; - tmpSecretKey: string; - }; - expiredTime: string; -} - -function getSecret( - userAccessToken: string, - duration = 7200 * 24 -): Promise { - return client - .get("/api/public/qcloud/oauth/federationToken", { - params: { userAccessToken, duration }, - }) - .then((res) => res.data.data); -} - -function refreshToken(userRefreshToken: string, userOpenId: string) { - return client - .get("/api/public/qcloud/oauth/refreshToken", { - params: { userRefreshToken, userOpenId }, - }) - .then((res) => res.data.data); -} - -export async function getCredentailByQr() { - const stateCode = await getQrState(); - const qrUrl = getQrUrl(stateCode); - - const terminal = window.createTerminal({ - name: "登录腾讯云", - shellPath: join(__dirname, "bin/qrcode.js"), - shellArgs: [qrUrl], - isTransient: true, - }); - terminal.show(); - - let state: State = "WAITING"; - - while (state !== "OK") { - // await delay(500); - const newState = await getState(stateCode); - - if (state !== "SCANNED" && newState === "SCANNED") { - terminal.sendText("已扫码,等待授权... \n", true); - } - - state = newState; - } - - terminal.sendText("授权成功 \n", true); - terminal.dispose(); - - const u = await getTokenInfo(stateCode); - - const { - credentials: { token, tmpSecretId, tmpSecretKey }, - } = await getSecret(u.userAccessToken); - - return { - token, - secretId: tmpSecretId, - secretKey: tmpSecretKey, - }; -} diff --git a/src/commons/tencent/user/index.ts b/src/commons/tencent/user/index.ts index 63ee30d..60df6f2 100644 --- a/src/commons/tencent/user/index.ts +++ b/src/commons/tencent/user/index.ts @@ -1,5 +1,6 @@ import { localize } from "vscode-nls-i18n"; -import { ExtensionContext, ProgressLocation, window } from "vscode"; +import { ExtensionContext, workspace, ConfigurationTarget, window } from "vscode"; +import { terraformShellManager } from "../../../client/terminal/terraformShellManager"; import { AbstractClient } from "tencentcloud-sdk-nodejs/tencentcloud/common/abstract_client"; import { Credential } from "tencentcloud-sdk-nodejs/tencentcloud/common/interface"; @@ -16,19 +17,43 @@ export namespace user { uin: string; } - export const AKSK_TITLE = "TcTerraform.AKSK.title"; - export const AKSK_PLACEHOLD = "TcTerraform.AKSK.title.placeholder"; - export const AKSK_EMPTY = "TcTerraform.AKSK.title.verify.empty"; + 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 api = localize(AKSK_TITLE); - const pick = await window.showQuickPick(["xxxxxxx", api]); + const aksk = localize(AKSK_TITLE); + const oauth = localize(OAUTH_TITLE); + const pick = await window.showQuickPick([aksk, oauth]); - if (pick) { + if (aksk === pick) { const credential = await getCredentailByInput(); - // api === pick ? await getCredentailByInput() : await getCredentailByQr(); + const accessKey = credential.secretId; + const secretKey = credential.secretKey; + + // 获取当前的配置对象 + const config = workspace.getConfiguration(); + + // 将 const 值设置到指定的环境变量中 + config.update('tcTerraform.properties.secretId', accessKey, ConfigurationTarget.Global) + .then(() => { + window.showInformationMessage('设置secretId成功'); + }, (error) => { + window.showErrorMessage('设置secretId失败: ' + error); + }); + config.update('tcTerraform.properties.secretKey', secretKey, ConfigurationTarget.Global) + .then(() => { + window.showInformationMessage('设置secretKey成功'); + }, (error) => { + window.showErrorMessage('设置secretKey失败: ' + error); + }); + + // terraformShellManager.getShell().runNormalCmd("export TENCENTCLOUD_SECRET_ID=" + accessKey); + // terraformShellManager.getShell().runNormalCmd("export TENCENTCLOUD_SECRET_KEY=" + secretKey); + // aksk === pick ? await getCredentailByInput() : await getCredentailByOAuth(); } } diff --git a/src/connectivity/client.ts b/src/connectivity/client.ts index 8dbdccb..d14079d 100644 --- a/src/connectivity/client.ts +++ b/src/connectivity/client.ts @@ -35,8 +35,15 @@ 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 config = vscode.workspace.getConfiguration(); + const secretId = String(config.get('tcTerraform.properties.secretId')); + const secretKey = String(config.get('tcTerraform.properties.secretKey')); + + vscode.window.showInformationMessage('Get Secret ID: ' + secretId); + vscode.window.showInformationMessage('Get Secret KEY: ' + secretKey); + + // const secretId = process.env.TENCENTCLOUD_SECRET_ID; + // const secretKey = process.env.TENCENTCLOUD_SECRET_KEY; 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!"); diff --git a/src/extension.ts b/src/extension.ts index 8e77ae3..07bd6f8 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -8,7 +8,7 @@ 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'; @@ -121,7 +121,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/views/help/helpExplorer.ts b/src/views/help/helpExplorer.ts index fa907f2..7b24b34 100644 --- a/src/views/help/helpExplorer.ts +++ b/src/views/help/helpExplorer.ts @@ -12,7 +12,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 +20,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 +28,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, From 1b185e3f6f0d2451e9696eb61bce4f0379e372dc Mon Sep 17 00:00:00 2001 From: nickyinluo Date: Thu, 19 Oct 2023 17:07:55 +0800 Subject: [PATCH 3/5] login with AKSK: 1.store aksk in process. 2.add refresh feature. 3.add icon pkg. --- .gitignore | 1 + package.json | 45 +++++++++++------------- package.nls.json | 10 ++++-- resources/dark/boolean.svg | 1 + resources/dark/dependency.svg | 1 + resources/dark/document.svg | 1 + resources/dark/edit.svg | 1 + resources/dark/folder.svg | 1 + resources/dark/number.svg | 1 + resources/dark/refresh.svg | 1 + resources/dark/string.svg | 1 + resources/light/boolean.svg | 1 + resources/light/dependency.svg | 1 + resources/light/document.svg | 1 + resources/light/edit.svg | 1 + resources/light/folder.svg | 1 + resources/light/number.svg | 1 + resources/light/refresh.svg | 1 + resources/light/string.svg | 1 + resources/package-explorer.png | Bin 0 -> 111518 bytes src/commons/customCmdRegister.ts | 11 ++++-- src/commons/tencent/treeDataProvider.ts | 3 ++ src/commons/tencent/user/index.ts | 14 ++++---- src/connectivity/client.ts | 19 +++++----- src/import/cvm.ts | 6 ++-- src/utils/settingUtils.ts | 12 +++++-- terraform.tfstate | 5 +-- 27 files changed, 90 insertions(+), 52 deletions(-) create mode 100644 resources/dark/boolean.svg create mode 100644 resources/dark/dependency.svg create mode 100644 resources/dark/document.svg create mode 100755 resources/dark/edit.svg create mode 100644 resources/dark/folder.svg create mode 100644 resources/dark/number.svg create mode 100644 resources/dark/refresh.svg create mode 100644 resources/dark/string.svg create mode 100644 resources/light/boolean.svg create mode 100644 resources/light/dependency.svg create mode 100644 resources/light/document.svg create mode 100755 resources/light/edit.svg create mode 100644 resources/light/folder.svg create mode 100644 resources/light/number.svg create mode 100644 resources/light/refresh.svg create mode 100644 resources/light/string.svg create mode 100644 resources/package-explorer.png 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 a8634f2..02f17cc 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,15 @@ "onLanguage:terraform" ], "contributes": { + "menus": { + "view/title": [ + { + "command": "tcTerraform.resourcesExplorer.refresh", + "when": "view == tcTerraform.resourcesExplorer.cvm", + "group": "navigation" + } + ] + }, "viewsContainers": { "activitybar": [ { @@ -113,6 +122,14 @@ "command": "tcTerraform.login", "title": "%TcTerraform.view.login.welcome%" }, + { + "command": "tcTerraform.resourcesExplorer.refresh", + "title": "%TcTerraform.refresh%", + "icon": { + "light": "resources/light/refresh.svg", + "dark": "resources/dark/refresh.svg" + } + }, { "command": "tcTerraform.init", "title": "Init", @@ -180,13 +197,13 @@ "properties": { "tcTerraform.properties.secretId": { "type": "string", - "default": "", - "description": "Tencent Cloud Secret ID" + "default": "your_secretid", + "description": "Input your Tencent Cloud secret Id." }, "tcTerraform.properties.secretKey": { "type": "string", - "default": "", - "description": "Tencent Cloud Secret Key" + "default": "your_secretkey", + "description": "Input your Tencent Cloud secret key." }, "tcTerraform.terminal": { "type": "string", @@ -212,26 +229,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 a9f85af..d41ed3a 100644 --- a/package.nls.json +++ b/package.nls.json @@ -4,8 +4,10 @@ "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.view.resource.cvm": "Import Resouce: CVM", - "TcTerraform.view.resource.tke": "Import Resouce: TKE", + "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", @@ -15,6 +17,8 @@ "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": "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 0000000000000000000000000000000000000000..31ef1ba28313f38c502e4935b8ad234b5a45642b GIT binary patch literal 111518 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 literal 0 HcmV?d00001 diff --git a/src/commons/customCmdRegister.ts b/src/commons/customCmdRegister.ts index 5cde677..31ffb19 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,21 @@ 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.plan", function (param: any) { - // terraformShellManager.getShell().runTerraformCmd(importObject); terraformShellManager.getIntegratedShell(TerraformRunner.getInstance()).plan(param); }); + + commands.registerCommand(cmds.resourceRefresh, function (param: any) { + tree.refreshTreeData(); + }); } export const cmds = { openURL, executeTfImport, - executeTferImport + executeTferImport, + resourceRefresh }; 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/index.ts b/src/commons/tencent/user/index.ts index 60df6f2..cd9a3eb 100644 --- a/src/commons/tencent/user/index.ts +++ b/src/commons/tencent/user/index.ts @@ -34,10 +34,9 @@ export namespace user { const accessKey = credential.secretId; const secretKey = credential.secretKey; - // 获取当前的配置对象 + // get configuration const config = workspace.getConfiguration(); - - // 将 const 值设置到指定的环境变量中 + // set in vscode configuration(setting.json) config.update('tcTerraform.properties.secretId', accessKey, ConfigurationTarget.Global) .then(() => { window.showInformationMessage('设置secretId成功'); @@ -51,9 +50,12 @@ export namespace user { window.showErrorMessage('设置secretKey失败: ' + error); }); - // terraformShellManager.getShell().runNormalCmd("export TENCENTCLOUD_SECRET_ID=" + accessKey); - // terraformShellManager.getShell().runNormalCmd("export TENCENTCLOUD_SECRET_KEY=" + secretKey); - // aksk === pick ? await getCredentailByInput() : await getCredentailByOAuth(); + // set in system environment + process.env.TENCENTCLOUD_SECRET_ID = accessKey; + process.env.TENCENTCLOUD_SECRET_KEY = secretKey; + + tree.refreshTreeData(); + window.showInformationMessage(localize("TcTerraform.login.success")); } } diff --git a/src/connectivity/client.ts b/src/connectivity/client.ts index d14079d..e29384c 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 utils from "../utils/settingUtils"; const tkeClient = TkeClient; const cvmClient = CvmClient; @@ -36,17 +37,17 @@ export async function getTkeClient(): Promise { export async function getCvmClient(region?: string): Promise { const config = vscode.workspace.getConfiguration(); - const secretId = String(config.get('tcTerraform.properties.secretId')); - const secretKey = String(config.get('tcTerraform.properties.secretKey')); + const secretIdConfig = utils.getSecretIdFromUI(); + const secretKeyConfig = utils.getSecretKeyFromUI(); + const secretIdEnv = utils.getSecretIdFromEnv(); + const secretKeyEnv = utils.getSecretKeyFromEnv(); - vscode.window.showInformationMessage('Get Secret ID: ' + secretId); - vscode.window.showInformationMessage('Get Secret KEY: ' + secretKey); - - // const secretId = process.env.TENCENTCLOUD_SECRET_ID; - // const secretKey = process.env.TENCENTCLOUD_SECRET_KEY; + const secretId = (secretIdEnv === undefined) ? secretIdConfig : secretIdEnv; + const secretKey = (secretKeyEnv === undefined) ? secretKeyConfig : secretKeyEnv; 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; } 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/utils/settingUtils.ts b/src/utils/settingUtils.ts index 5aff7b1..3f5103e 100644 --- a/src/utils/settingUtils.ts +++ b/src/utils/settingUtils.ts @@ -28,11 +28,19 @@ 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 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/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 } From 59b084994a2694adcabf52451470e2d7125ab3f6 Mon Sep 17 00:00:00 2001 From: nickyinluo Date: Thu, 19 Oct 2023 22:20:05 +0800 Subject: [PATCH 4/5] add aksk input --- package.json | 18 +++++----- src/commons/customCmdRegister.ts | 2 +- src/commons/tencent/user/index.ts | 10 +++--- src/connectivity/client.ts | 1 - src/extension.ts | 3 ++ src/test/runTest.ts | 23 ------------- src/test/suite/extension.test.ts | 15 --------- src/test/suite/index.ts | 40 ---------------------- src/views/help/helpExplorer.ts | 3 +- src/views/index.ts | 3 +- src/views/login/index.ts | 8 +++++ src/views/login/loginExplorer.ts | 55 +++++++++++++++++++++++++++++++ 12 files changed, 84 insertions(+), 97 deletions(-) delete mode 100644 src/test/runTest.ts delete mode 100644 src/test/suite/extension.test.ts delete mode 100644 src/test/suite/index.ts create mode 100644 src/views/login/index.ts create mode 100644 src/views/login/loginExplorer.ts diff --git a/package.json b/package.json index 02f17cc..a7c16ff 100644 --- a/package.json +++ b/package.json @@ -195,6 +195,15 @@ "configuration": { "title": "TencentCloud Terraform", "properties": { + "tcTerraform.terminal": { + "type": "string", + "default": "integrated", + "enum": [ + "integrated", + "cloudshell" + ], + "description": "Specifies terminal used to run Terraform commands. Valid settings are `cloudshell` or `integrated`." + }, "tcTerraform.properties.secretId": { "type": "string", "default": "your_secretid", @@ -205,15 +214,6 @@ "default": "your_secretkey", "description": "Input your Tencent Cloud secret key." }, - "tcTerraform.terminal": { - "type": "string", - "default": "integrated", - "enum": [ - "integrated", - "cloudshell" - ], - "description": "Specifies terminal used to run Terraform commands. Valid settings are `cloudshell` or `integrated`." - }, "tcTerraform.checkTerraformCmd": { "type": "boolean", "default": "true", diff --git a/src/commons/customCmdRegister.ts b/src/commons/customCmdRegister.ts index 31ffb19..ced6e1b 100644 --- a/src/commons/customCmdRegister.ts +++ b/src/commons/customCmdRegister.ts @@ -49,7 +49,7 @@ export function regResourceRelatedCommands() { terraformShellManager.getIntegratedShell(TerraformRunner.getInstance()).plan(param); }); - commands.registerCommand(cmds.resourceRefresh, function (param: any) { + commands.registerCommand(resourceRefresh, function (param: any) { tree.refreshTreeData(); }); } diff --git a/src/commons/tencent/user/index.ts b/src/commons/tencent/user/index.ts index cd9a3eb..4c7f919 100644 --- a/src/commons/tencent/user/index.ts +++ b/src/commons/tencent/user/index.ts @@ -1,13 +1,12 @@ import { localize } from "vscode-nls-i18n"; import { ExtensionContext, workspace, ConfigurationTarget, window } from "vscode"; -import { terraformShellManager } from "../../../client/terminal/terraformShellManager"; -import { AbstractClient } from "tencentcloud-sdk-nodejs/tencentcloud/common/abstract_client"; -import { Credential } from "tencentcloud-sdk-nodejs/tencentcloud/common/interface"; 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 { @@ -39,13 +38,11 @@ export namespace user { // set in vscode configuration(setting.json) config.update('tcTerraform.properties.secretId', accessKey, ConfigurationTarget.Global) .then(() => { - window.showInformationMessage('设置secretId成功'); }, (error) => { window.showErrorMessage('设置secretId失败: ' + error); }); config.update('tcTerraform.properties.secretKey', secretKey, ConfigurationTarget.Global) .then(() => { - window.showInformationMessage('设置secretKey成功'); }, (error) => { window.showErrorMessage('设置secretKey失败: ' + error); }); @@ -54,6 +51,9 @@ export namespace user { process.env.TENCENTCLOUD_SECRET_ID = accessKey; process.env.TENCENTCLOUD_SECRET_KEY = secretKey; + terraformShellManager.getShell().runNormalCmd("export TENCENTCLOUD_SECRET_ID=" + accessKey); + terraformShellManager.getShell().runNormalCmd("export TENCENTCLOUD_SECRET_KEY=" + secretKey); + tree.refreshTreeData(); window.showInformationMessage(localize("TcTerraform.login.success")); } diff --git a/src/connectivity/client.ts b/src/connectivity/client.ts index e29384c..cd2604d 100644 --- a/src/connectivity/client.ts +++ b/src/connectivity/client.ts @@ -36,7 +36,6 @@ export async function getTkeClient(): Promise { } export async function getCvmClient(region?: string): Promise { - const config = vscode.workspace.getConfiguration(); const secretIdConfig = utils.getSecretIdFromUI(); const secretKeyConfig = utils.getSecretKeyFromUI(); const secretIdEnv = utils.getSecretIdFromEnv(); diff --git a/src/extension.ts b/src/extension.ts index 07bd6f8..4e7b0de 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -13,6 +13,7 @@ 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,6 +22,7 @@ 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(); @@ -36,6 +38,7 @@ export async function activate(context: vscode.ExtensionContext) { // }); // context.subscriptions.push(disposableLogin); + // terraform cmd context.subscriptions.push(vscode.commands.registerCommand('tcTerraform.init', () => { terraformShellManager.getShell().runTerraformCmd(TerraformCommand.Init); 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/views/help/helpExplorer.ts b/src/views/help/helpExplorer.ts index 7b24b34..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; 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); From 0b4f4fe9bba680889ccaaff36edd8d315abd8c6a Mon Sep 17 00:00:00 2001 From: nickyinluo Date: Fri, 20 Oct 2023 18:47:00 +0800 Subject: [PATCH 5/5] support: set aksk and terraform init/plan/apply/destroy cmd --- package.json | 9 +--- src/client/runner/baseRunner.ts | 2 +- src/client/runner/terraformRunner.ts | 27 +++++++----- src/client/terminal/integratedShell.ts | 18 ++++++++ src/client/terminal/terraformShellManager.ts | 11 +++-- src/commons/customCmdRegister.ts | 4 ++ src/commons/tencent/user/index.ts | 3 -- src/connectivity/client.ts | 44 ++++++++++++++++---- src/extension.ts | 22 ---------- src/utils/settingUtils.ts | 9 ++++ 10 files changed, 93 insertions(+), 56 deletions(-) diff --git a/package.json b/package.json index a7c16ff..9679aae 100644 --- a/package.json +++ b/package.json @@ -39,15 +39,9 @@ "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" ], @@ -120,7 +114,8 @@ "commands": [ { "command": "tcTerraform.login", - "title": "%TcTerraform.view.login.welcome%" + "title": "Login: %TcTerraform.view.login.welcome%", + "category": "TencentCloud Terraform" }, { "command": "tcTerraform.resourcesExplorer.refresh", 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/customCmdRegister.ts b/src/commons/customCmdRegister.ts index ced6e1b..d4b11f6 100644 --- a/src/commons/customCmdRegister.ts +++ b/src/commons/customCmdRegister.ts @@ -45,6 +45,10 @@ export function regResourceRelatedCommands() { 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.getIntegratedShell(TerraformRunner.getInstance()).plan(param); }); diff --git a/src/commons/tencent/user/index.ts b/src/commons/tencent/user/index.ts index 4c7f919..cba44ac 100644 --- a/src/commons/tencent/user/index.ts +++ b/src/commons/tencent/user/index.ts @@ -51,9 +51,6 @@ export namespace user { process.env.TENCENTCLOUD_SECRET_ID = accessKey; process.env.TENCENTCLOUD_SECRET_KEY = secretKey; - terraformShellManager.getShell().runNormalCmd("export TENCENTCLOUD_SECRET_ID=" + accessKey); - terraformShellManager.getShell().runNormalCmd("export TENCENTCLOUD_SECRET_KEY=" + secretKey); - tree.refreshTreeData(); window.showInformationMessage(localize("TcTerraform.login.success")); } diff --git a/src/connectivity/client.ts b/src/connectivity/client.ts index cd2604d..4961709 100644 --- a/src/connectivity/client.ts +++ b/src/connectivity/client.ts @@ -4,7 +4,7 @@ import * as vscode from "vscode"; 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 utils from "../utils/settingUtils"; +import * as settingUtils from "../utils/settingUtils"; const tkeClient = TkeClient; const cvmClient = CvmClient; @@ -36,13 +36,43 @@ export async function getTkeClient(): Promise { } export async function getCvmClient(region?: string): Promise { - const secretIdConfig = utils.getSecretIdFromUI(); - const secretKeyConfig = utils.getSecretKeyFromUI(); - const secretIdEnv = utils.getSecretIdFromEnv(); - const secretKeyEnv = utils.getSecretKeyFromEnv(); + // 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 = (secretIdEnv === undefined) ? secretIdConfig : secretIdEnv; + // const secretKey = (secretKeyEnv === undefined) ? secretKeyConfig : secretKeyEnv; + 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; + } + + 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"); diff --git a/src/extension.ts b/src/extension.ts index 4e7b0de..7cabec3 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -27,29 +27,7 @@ export async function activate(context: vscode.ExtensionContext) { 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(); - - // 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); })); diff --git a/src/utils/settingUtils.ts b/src/utils/settingUtils.ts index 3f5103e..63f0c59 100644 --- a/src/utils/settingUtils.ts +++ b/src/utils/settingUtils.ts @@ -35,6 +35,15 @@ export function getSecretKeyFromUI(): string { 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; }