From 4dcb70a1ae1c8453efd44aa3397721d3b6485504 Mon Sep 17 00:00:00 2001 From: Jon Edvald Date: Mon, 3 Aug 2020 21:25:07 +0200 Subject: [PATCH] fix(terraform): allow map outputs from modules Fixes #1947 --- garden-service/src/config/common.ts | 2 +- .../src/plugins/terraform/terraform.ts | 7 ++--- garden-service/src/types/service.ts | 15 ++++++---- .../test-projects/terraform-module/tf/foo.tf | 6 +++- .../unit/src/plugins/terraform/terraform.ts | 29 +++++++++++++++++++ 5 files changed, 47 insertions(+), 12 deletions(-) diff --git a/garden-service/src/config/common.ts b/garden-service/src/config/common.ts index 11a7f86af9..0351bc6be1 100644 --- a/garden-service/src/config/common.ts +++ b/garden-service/src/config/common.ts @@ -435,7 +435,7 @@ export const joiVariables = () => .object() .pattern(variableNameRegex, joi.alternatives(joiPrimitive(), joi.link("..."), joi.array().items(joi.link("...")))) .default(() => ({})) - .unknown(false) + .unknown(true) .description("Key/value map. " + joiVariablesDescription) export const joiEnvVars = () => diff --git a/garden-service/src/plugins/terraform/terraform.ts b/garden-service/src/plugins/terraform/terraform.ts index d7d2789a3e..bca7383f7e 100644 --- a/garden-service/src/plugins/terraform/terraform.ts +++ b/garden-service/src/plugins/terraform/terraform.ts @@ -11,7 +11,7 @@ import { pathExists } from "fs-extra" import { createGardenPlugin } from "../../types/plugin/plugin" import { getEnvironmentStatus, prepareEnvironment } from "./init" import { providerConfigBaseSchema, ProviderConfig, Provider } from "../../config/provider" -import { joi } from "../../config/common" +import { joi, joiVariables } from "../../config/common" import { dedent } from "../../util/string" import { supportedVersions, defaultTerraformVersion, terraformCliSpecs } from "./cli" import { ConfigureProviderParams, ConfigureProviderResult } from "../../types/plugin/provider/configureProvider" @@ -88,10 +88,7 @@ export const gardenPlugin = createGardenPlugin({ See the [Terraform guide](${DOCS_BASE_URL}/advanced/terraform) for a high-level introduction to the \`terraform\` provider. `, - serviceOutputsSchema: joi - .object() - .pattern(/.+/, joi.any()) - .description("A map of all the outputs defined in the Terraform stack."), + serviceOutputsSchema: joiVariables().description("A map of all the outputs defined in the Terraform stack."), schema, handlers: { suggestModules: async ({ name, path }: SuggestModulesParams): Promise => { diff --git a/garden-service/src/types/service.ts b/garden-service/src/types/service.ts index 2c542b3a8c..aaba629ba8 100644 --- a/garden-service/src/types/service.ts +++ b/garden-service/src/types/service.ts @@ -8,7 +8,15 @@ import normalizeUrl from "normalize-url" import { format } from "url" -import { joiUserIdentifier, joi, joiIdentifier, joiArray, PrimitiveMap, joiPrimitive } from "../config/common" +import { + joiUserIdentifier, + joi, + joiIdentifier, + joiArray, + PrimitiveMap, + joiPrimitive, + joiVariables, +} from "../config/common" import { Module } from "./module" import { ServiceConfig, serviceConfigSchema } from "../config/service" import dedent = require("dedent") @@ -231,10 +239,7 @@ export const serviceStatusSchema = () => .allow("") .description("Latest status message of the service (if any)."), lastError: joi.string().description("Latest error status message of the service (if any)."), - outputs: joi - .object() - .pattern(/.+/, joiPrimitive()) - .description("A map of primitive values, output from the service."), + outputs: joiVariables().description("A map of values output from the service."), runningReplicas: joi.number().description("How many replicas of the service are currently running."), state: joi .string() diff --git a/garden-service/test/data/test-projects/terraform-module/tf/foo.tf b/garden-service/test/data/test-projects/terraform-module/tf/foo.tf index 2ca82e762a..c16e23b177 100644 --- a/garden-service/test/data/test-projects/terraform-module/tf/foo.tf +++ b/garden-service/test/data/test-projects/terraform-module/tf/foo.tf @@ -13,4 +13,8 @@ output "test-file-path" { output "my-output" { value = "input: ${var.my-variable}" -} \ No newline at end of file +} + +output "map-output" { + value = map("first", "second") +} diff --git a/garden-service/test/unit/src/plugins/terraform/terraform.ts b/garden-service/test/unit/src/plugins/terraform/terraform.ts index 59793efa55..0795073505 100644 --- a/garden-service/test/unit/src/plugins/terraform/terraform.ts +++ b/garden-service/test/unit/src/plugins/terraform/terraform.ts @@ -20,6 +20,7 @@ import { LogLevel } from "../../../../../src/logger/log-node" import { ConfigGraph } from "../../../../../src/config-graph" import { TerraformProvider } from "../../../../../src/plugins/terraform/terraform" import { DeployTask } from "../../../../../src/tasks/deploy" +import { emptyRuntimeContext } from "../../../../../src/runtime-context" describe("Terraform provider", () => { const testRoot = getDataDir("test-projects", "terraform-provider") @@ -257,6 +258,34 @@ describe("Terraform module type", () => { expect(result["task.test-task"]!.output.log).to.equal("input: foo") expect(result["task.test-task"]!.output.outputs.log).to.equal("input: foo") }) + + it("should should return outputs with the service status", async () => { + const provider = await garden.resolveProvider(garden.log, "terraform") + const ctx = garden.getPluginContext(provider) + const applyCommand = findByName(terraformCommands, "apply-module")! + await applyCommand.handler({ + ctx, + args: ["tf", "-auto-approve", "-input=false"], + log: garden.log, + modules: graph.getModules(), + }) + + const actions = await garden.getActionRouter() + const status = await actions.getServiceStatus({ + service: graph.getService("tf"), + hotReload: false, + log: garden.log, + runtimeContext: emptyRuntimeContext, + }) + + expect(status.outputs).to.eql({ + "map-output": { + first: "second", + }, + "my-output": "input: foo", + "test-file-path": "./test.log", + }) + }) }) context("autoApply=true", () => {