Skip to content

Feat/enable reqcli with provider and extension version #16

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
May 15, 2024
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "vscode-tencentcloud-terraform",
"displayName": "Tencent Cloud Terraform",
"description": "VS Code extension for developing with Terraform on Tencent Cloud",
"version": "0.0.28",
"version": "0.0.29",
"license": "MIT",
"publisher": "Tencent-Cloud",
"icon": "images/tc-tf-logo.png",
Expand Down
2 changes: 1 addition & 1 deletion package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"TcTerraform.pickup.aksk.placeholder": "Tencent Cloud {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.msg.aksk.notfound": "Cannot find user info, please sign in first!",
"TcTerraform.login": "Login Tencent Cloud...",
"TcTerraform.login.msg.success": "Logged into Tencent Cloud successfully.",
"TcTerraform.login.msg.need.login": "Please log in Tencent Cloud first.",
Expand Down
28 changes: 3 additions & 25 deletions src/autocomplete/TerraformTipsProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,10 @@ import { CompletionItemProvider, TextDocument, Position, CancellationToken, Comp
// import resources from '../../config/tips/tiat-resources.json';
import * as _ from "lodash";
import * as vscode from 'vscode';
import { executeCommandByExec } from "@/utils/cpUtils";
import * as fs from "fs";
import * as path from "path";
import * as workspaceUtils from "@/utils/workspaceUtils";
import * as TelemetryWrapper from "vscode-extension-telemetry-wrapper";
import * as context from "@/commons/context";

const LATEST_VERSION = "latest";
const versionPattern = /^v\d+(\.\d+){2}\.json$/;
let topLevelTypes = ["output", "provider", "resource", "variable", "data"];
let topLevelRegexes = topLevelTypes.map(o => {
Expand Down Expand Up @@ -422,26 +419,7 @@ function compareVersions(a, b) {

// load resource config from json files based on the appropriate version
async function loadResource(extPath: string): Promise<Tips> {
let tfVersion: string;
const cwd = workspaceUtils.getActiveEditorPath();
if (!cwd) {
TelemetryWrapper.sendError(Error("noWorkspaceSelected"));
console.error(`can not get path from active editor`);
}

await executeCommandByExec("terraform version", cwd).then(output => {
let match = RegExp(/tencentcloudstack\/tencentcloud (v\d+\.\d+\.\d+)/).exec(output);

if (match) {
tfVersion = match[1];
} else {
// gives the latest JSON if not tf provider version found
tfVersion = LATEST_VERSION;
}
console.log(`tf provider version:[${tfVersion}], cwd:[${cwd}]`);
}).catch(error => {
console.error(`execute terraform version failed: ${error}`);
});
const tfVersion = await context.getTfVersion();

let result: Tips | null = null;
const tipsDir = path.join(extPath, 'config', 'tips');
Expand All @@ -461,4 +439,4 @@ async function loadResource(extPath: string): Promise<Tips> {
// vscode.window.showInformationMessage(`Loaded json. tf version:[${tfVersion}], json version:[${result.version}]`);

return result;
}
}
36 changes: 23 additions & 13 deletions src/client/runner/terraformRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { terraformShellManager } from "../terminal/terraformShellManager";
import { executeCommand } from "../../utils/cpUtils";
import * as settingUtils from "../../utils/settingUtils";
import { openUrlHintOrNotShowAgain } from "../../utils/uiUtils";
import { localize } from "vscode-nls-i18n";


export class TerraformRunner extends BaseRunner {
Expand All @@ -32,20 +33,24 @@ export class TerraformRunner extends BaseRunner {
public async init(): Promise<any> {
console.debug("[DEBUG]#### TerraformRunner init begin.");

this.setAKSK();
if (!checkAKSK()) {
return "plan abort";
}

terraformShellManager.getShell().runTerraformCmd(TerraformCommand.Version);
terraformShellManager.getShell().runTerraformCmd(TerraformCommand.Init);
(await terraformShellManager.getShell()).runTerraformCmd(TerraformCommand.Version);
(await terraformShellManager.getShell()).runTerraformCmd(TerraformCommand.Init);

return "init success";
}

public async executePlan(cwd: string, args: any): Promise<string> {
console.debug("[DEBUG]#### TerraformRunner executePlan begin.");

// this.setAKSK();
if (!checkAKSK()) {
return "plan abort";
}

terraformShellManager.getShell().runTerraformCmd(TerraformCommand.Plan);
(await terraformShellManager.getShell()).runTerraformCmd(TerraformCommand.Plan);

return "plan success";
}
Expand Down Expand Up @@ -112,7 +117,6 @@ export class TerraformRunner extends BaseRunner {
setCheckTerraformCmd(false);
});
}
return;
}

private async resetFileContent(tfFile: string, defaultContents: string) {
Expand All @@ -126,15 +130,9 @@ export class TerraformRunner extends BaseRunner {
public async resetTFState(resAddress: string) {
console.debug("[DEBUG]#### TerraformRunner resetTFState begin.");

await terraformShellManager.getIntegratedShell(TerraformRunner.getInstance())
await (await terraformShellManager.getIntegratedShell(TerraformRunner.getInstance()))
.runTerraformCmd(TerraformCommand.State, ['rm', '-lock=false', resAddress]);
}

private setAKSK(runner?: any) {
const [ak, sk, region] = settingUtils.getAKSKandRegion();
terraformShellManager.getIntegratedShell(runner).runNormalCmd("export TENCENTCLOUD_SECRET_ID=" + ak);
terraformShellManager.getIntegratedShell(runner).runNormalCmd("export TENCENTCLOUD_SECRET_KEY=" + sk);
}
}

export function getCheckTerraformCmd(): boolean {
Expand All @@ -144,3 +142,15 @@ export function getCheckTerraformCmd(): boolean {
export function setCheckTerraformCmd(checked: boolean): void {
vscode.workspace.getConfiguration().update("tcTerraform.checkTerraformCmd", checked);
}

export function checkAKSK(): boolean {
const [secretId, secretKey, _] = settingUtils.getAKSKandRegion();

if (secretId === undefined || secretKey === undefined || secretId === null || secretKey === null || secretId === '' || secretKey === '') {
let msg = localize("TcTerraform.msg.aksk.notfound");
console.error(msg);
vscode.window.showInformationMessage(msg);
return false;
}
return true;
}
21 changes: 15 additions & 6 deletions src/client/terminal/integratedShell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,22 @@ import { BaseRunner } from "../runner/baseRunner";
import { TerraformerRunner, CommandType, FlagType, FlagsMap, defaultProduct } from "../../client/runner/terraformerRunner";
import { TerraformRunner } from "../runner/terraformRunner";

// import stripAnsi from 'strip-ansi';

export class IntegratedShell extends BaseShell {
// eslint-disable-next-line @typescript-eslint/naming-convention
private static readonly GRAPH_FILE_NAME = "graph.png";
private readonly runner: BaseRunner;
private readonly env: { [key: string]: string | null | undefined };

constructor(rr: BaseRunner) {
constructor(rr: BaseRunner, ee: any) {
super();
// terraform or terraformer?
this.runner = rr;
this.env = ee;
}

public getEnv() {
return this.env;
}

// Creates a png of terraform resource graph to visualize the resources under management.
Expand Down Expand Up @@ -179,7 +184,7 @@ export class IntegratedShell extends BaseShell {
}

public async runTerraformCmd(tfCommand: string, args?: string[]) {
this.checkCreateTerminal();
this.createTerminal(Constants.TerraformTerminalName);
this.terminal.show();

// const cmd= [tfCommand, args.values].join(' ');
Expand All @@ -193,7 +198,7 @@ export class IntegratedShell extends BaseShell {
}

public async runNormalCmd(tfCommand: string, newLine = true) {
this.checkCreateTerminal();
this.createTerminal(Constants.TerraformTerminalName);
this.terminal.show();
this.terminal.sendText(tfCommand, newLine);
}
Expand All @@ -220,9 +225,13 @@ export class IntegratedShell extends BaseShell {
}
}

private checkCreateTerminal(): void {
private createTerminal(name: string): void {
if (!this.terminal) {
this.terminal = vscode.window.createTerminal(Constants.TerraformTerminalName);
const options: vscode.TerminalOptions = {
name: name,
env: this.env,
};
this.terminal = vscode.window.createTerminal(options);
}
}
}
39 changes: 30 additions & 9 deletions src/client/terminal/terraformShellManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,22 @@ import { TencentCloudShell } from "./cloudShell";
import { IntegratedShell } from "./integratedShell";
import { isTerminalSetToCloudShell } from "../../utils/settingUtils";
import { TerraformerRunner } from "../runner/terraformerRunner";
import * as context from "../../commons/context";
import * as settingUtils from "../../utils/settingUtils";
import { Constants } from "../../commons/constants";

export interface ITerraformShellManager {
getShell(): BaseShell;
getShell(): Promise<BaseShell>;
// getCloudShell(): TCCloudShell;
getIntegratedShell(runner?: any): IntegratedShell;
getIntegratedShell(runner?: any): Promise<IntegratedShell>;
dispose(): void;
}

class TerraformShellManager implements ITerraformShellManager {
private static cloudShell = new TencentCloudShell();
private static integratedShell: IntegratedShell;

public getShell(): BaseShell {
public async getShell(): Promise<BaseShell> {
const isCloudShell: boolean = isTerminalSetToCloudShell();

TelemetryWrapper.addContextProperty("isCloudShell", isCloudShell.toString());
Expand All @@ -37,18 +40,36 @@ class TerraformShellManager implements ITerraformShellManager {
return TerraformShellManager.cloudShell;
}

public getIntegratedShell(runner?: any): IntegratedShell {
public async getIntegratedShell(runner?: any): Promise<IntegratedShell> {
if (!TerraformShellManager.integratedShell) {
// default runner is Terraformer
TerraformShellManager.integratedShell = new IntegratedShell(TerraformerRunner.getInstance());
// specify runner
if (runner) {
TerraformShellManager.integratedShell = new IntegratedShell(runner);
// set TencentCloud AKSK, Region and Client info
await this.initIntegratedShell(runner);
} else {
const curEnv = TerraformShellManager.integratedShell.getEnv();
// need to be reset if the current AKSK is undefined
if (!curEnv[Constants.TENCENTCLOUD_SECRET_ID] || !curEnv[Constants.TENCENTCLOUD_SECRET_KEY]) {
await this.initIntegratedShell(runner);
}
}
return TerraformShellManager.integratedShell;
}

private async initIntegratedShell(runner: any) {
const [ak, sk, region] = settingUtils.getAKSKandRegion();
const reqCli = await context.genRequestClient();
const tfEnv = {
[Constants.REQUEST_CLIENT]: reqCli, // set ReqCli for TIC Terminal
[Constants.TENCENTCLOUD_SECRET_ID]: ak,
[Constants.TENCENTCLOUD_SECRET_KEY]: sk,
[Constants.TENCENTCLOUD_REGION]: region,
};
// default runner is Terraformer
TerraformShellManager.integratedShell = new IntegratedShell(TerraformerRunner.getInstance(), tfEnv);
if (runner) {
TerraformShellManager.integratedShell = new IntegratedShell(runner, tfEnv);
}
}

public dispose(): void {
TerraformShellManager.cloudShell.dispose();
TerraformShellManager.integratedShell.dispose();
Expand Down
8 changes: 6 additions & 2 deletions src/commons/constants.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/naming-convention */
/*---------------------------------------------------------------------------------------------
* Copyright (c) Tencent Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
Expand All @@ -6,6 +7,9 @@
"use strict";

export class Constants {
// eslint-disable-next-line @typescript-eslint/naming-convention
public static TerraformTerminalName = "TIAT-Terraform";
public static TerraformTerminalName = "TIC-Terraform";
public static REQUEST_CLIENT = "TENCENTCLOUD_API_REQUEST_CLIENT";
public static TENCENTCLOUD_SECRET_ID = "TENCENTCLOUD_SECRET_ID";
public static TENCENTCLOUD_SECRET_KEY = "TENCENTCLOUD_SECRET_KEY";
public static TENCENTCLOUD_REGION = "TENCENTCLOUD_REGION";
}
43 changes: 43 additions & 0 deletions src/commons/context.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,51 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { container } from './container';
import * as vscode from 'vscode';
import * as workspaceUtils from "@/utils/workspaceUtils";
import * as cpUtils from "@/utils/cpUtils";
import * as TelemetryWrapper from "vscode-extension-telemetry-wrapper";

export const Context = Symbol('ExtensionContext');
export const REQUEST_CLIENT_PREFIX = "Terraform-";//Terraform-1.81.61@vscode";
const LATEST_VERSION = "latest";

export function bindExtensionContext(ctx: vscode.ExtensionContext) {
container.bind(Context).toConstantValue(ctx);
}

export function getExtensionVersion(): string {
let extension = vscode.extensions.getExtension('Tencent-Cloud.vscode-tencentcloud-terraform');
let currentVersion = extension.packageJSON.version;
return currentVersion;
}

export async function genRequestClient(): Promise<string> {
const extVersion = getExtensionVersion();
const tfVersion = await getTfVersion() || LATEST_VERSION;
const reqCli = `${REQUEST_CLIENT_PREFIX}${tfVersion}@vscode-v${extVersion}`;
return reqCli;
}

export async function getTfVersion(): Promise<string> {
let tfVersion = '';
const cwd = workspaceUtils.getActiveEditorPath();
if (!cwd) {
TelemetryWrapper.sendError(Error("noWorkspaceSelected"));
console.error(`can not get path from active editor`);
}

await cpUtils.executeCommandByExec("terraform version", cwd).then(output => {
let match = RegExp(/tencentcloudstack\/tencentcloud (v\d+\.\d+\.\d+)/).exec(output);

if (match) {
tfVersion = match[1];
} else {
// gives the latest JSON if not tf provider version found
tfVersion = LATEST_VERSION;
}
console.log(`[DEBUG]getTfVersion tf provider version:[${tfVersion}], cwd:[${cwd}]`);
}).catch(error => {
console.error(`execute terraform version failed: ${error}`);
});
return tfVersion;
}
12 changes: 6 additions & 6 deletions src/commons/customCmdRegister.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,16 @@ export function regHelpCommands() {
}

export function regResourceRelatedCommands() {
commands.registerCommand(cmds.executeTferImport, function (param: any) {
terraformShellManager.getIntegratedShell(TerraformerRunner.getInstance()).import(param, param.fileName);
commands.registerCommand(cmds.executeTferImport, async function (param: any) {
(await terraformShellManager.getIntegratedShell(TerraformerRunner.getInstance())).import(param, param.fileName);
});

commands.registerCommand("tcTerraform.init", function (param: any) {
terraformShellManager.getIntegratedShell(TerraformRunner.getInstance()).init();
commands.registerCommand("tcTerraform.init", async function (param: any) {
(await terraformShellManager.getIntegratedShell(TerraformRunner.getInstance())).init();
});

commands.registerCommand("tcTerraform.plan", function (param: any) {
terraformShellManager.getIntegratedShell(TerraformRunner.getInstance()).plan(param);
commands.registerCommand("tcTerraform.plan", async function (param: any) {
(await terraformShellManager.getIntegratedShell(TerraformRunner.getInstance())).plan(param);
});

commands.registerCommand(resourceRefresh, function (param: any) {
Expand Down
1 change: 0 additions & 1 deletion src/commons/tencent/user/auth/credentail.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import MultiStepInput from "../../../multiStepInput";
import { Credential } from "tencentcloud-sdk-nodejs/tencentcloud/common/interface";
import { localize } from "vscode-nls-i18n";
import constant from "../index";
import * as vscode from "vscode";

export async function getCredentailByInput() {
const defaultRegion = "ap-guangzhou";
Expand Down
Loading