Skip to content

Commit

Permalink
print errors array from response of any error that happens with Terra…
Browse files Browse the repository at this point in the history
…form Cloud

it seems that the structure of an error returned from the api differs between endpoints (e.g. a POST to workspaces returns an error object with four properties while a GET at a different request only returns two properties in the object of an error), hence we just print the whole error object for the time being
  • Loading branch information
ansgarm committed Apr 12, 2021
1 parent 9203f6c commit bb5a697
Showing 1 changed file with 33 additions and 0 deletions.
33 changes: 33 additions & 0 deletions packages/cdktf-cli/bin/cmds/ui/models/terraform-cloud.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,29 @@ const wait = (ms = 1000) => {
});
}

function BeaufifyErrors(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const isMethod = descriptor && descriptor.value instanceof Function;
if (!isMethod)
return;

const originalMethod = descriptor!.value;
descriptor!.value = async function (...args: any[]) {
try {
return await originalMethod.apply(this, args);
} catch (e) {
if (e.response && e.response.status >= 400 && e.response.status <= 599){
const errors = e.response.data?.errors as (object[] | undefined);
if (errors) {
throw new Error(`Request to Terraform Cloud failed with status ${e.response.status}: ${errors.map(e => JSON.stringify(e)).join(', ')}`);
}
}
throw e;
}
};

Object.defineProperty(target, propertyKey, descriptor!);
}

export class TerraformCloud implements Terraform {
private readonly terraformConfigFilePath = path.join(os.homedir(), '.terraform.d', 'credentials.tfrc.json')
private readonly token: string;
Expand Down Expand Up @@ -96,11 +119,13 @@ export class TerraformCloud implements Terraform {
this.client = new TerraformCloudClient.TerraformCloud(this.token)
}

@BeaufifyErrors
public async isRemoteWorkspace(): Promise<boolean> {
const workspace = await this.workspace()
return workspace.attributes.executionMode !== 'local'
}

@BeaufifyErrors
public async init(): Promise<void> {
if (fs.existsSync(path.join(process.cwd(), 'terraform.tfstate'))) throw new Error('Found a "terraform.tfstate" file in your current working directory. Please migrate the state manually to Terraform Cloud and delete the file afterwards. https://cdk.tf/migrate-state')
const workspace = await this.workspace()
Expand All @@ -122,6 +147,7 @@ export class TerraformCloud implements Terraform {
await this.client.ConfigurationVersion.upload(version.attributes.uploadUrl, zipBuffer)
}

@BeaufifyErrors
public async plan(destroy = false): Promise<TerraformPlan> {
if (!this.configurationVersionId) throw new Error("Please create a ConfigurationVersion before planning");
const workspace = await this.workspace()
Expand Down Expand Up @@ -165,6 +191,7 @@ export class TerraformCloud implements Terraform {
return new TerraformCloudPlan('terraform-cloud', plan as unknown as any, url)
}

@BeaufifyErrors
public async deploy(_planFile: string, stdout: (chunk: Buffer) => any): Promise<void> {
if (!this.run) throw new Error("Please create a ConfigurationVersion / Plan before deploying");

Expand All @@ -190,6 +217,7 @@ export class TerraformCloud implements Terraform {
}
}

@BeaufifyErrors
public async destroy(stdout: (chunk: Buffer) => any): Promise<void> {
if (!this.run) throw new Error("Please create a ConfigurationVersion / Plan before destroying");

Expand All @@ -215,10 +243,12 @@ export class TerraformCloud implements Terraform {
}
}

@BeaufifyErrors
public async version(): Promise<string> {
return (await this.workspace()).attributes.terraformVersion
}

@BeaufifyErrors
public async output(): Promise<{ [key: string]: TerraformOutput }> {
const stateVersion = await this.client.StateVersions.current((await this.workspace()).id, true)
if (!stateVersion.included) return {}
Expand All @@ -236,11 +266,14 @@ export class TerraformCloud implements Terraform {
return outputs
}

@BeaufifyErrors
private async workspace() {
try {
return await this.client.Workspaces.showByName(this.organizationName, this.workspaceName)
} catch (e) {
if (e.response?.status === 404) {
// return a more descriptive error message as http response is not descriptive enough
// will not be touched by BeautifyErrors decorator
throw new Error(`TerraformCloud returned an HTTP 404 error. Please make sure the configured organization (${this.organizationName}) and workspace (${this.workspaceName}) exist and you have the correct access rights.`);
}
throw e;
Expand Down

0 comments on commit bb5a697

Please sign in to comment.