diff --git a/docs/reference/commands.md b/docs/reference/commands.md index 91d143ba63..5df214a56b 100644 --- a/docs/reference/commands.md +++ b/docs/reference/commands.md @@ -152,9 +152,8 @@ deployments: # Latest error status message of the service (if any). lastError: - # A map of primitive values, output from the service. + # A map of values output from the service. outputs: - # Number, string or boolean : # How many replicas of the service are currently running. @@ -490,9 +489,8 @@ serviceStatuses: # Latest error status message of the service (if any). lastError: - # A map of primitive values, output from the service. + # A map of values output from the service. outputs: - # Number, string or boolean : # How many replicas of the service are currently running. @@ -589,9 +587,8 @@ Examples: # Latest error status message of the service (if any). lastError: - # A map of primitive values, output from the service. + # A map of values output from the service. outputs: - # Number, string or boolean : # How many replicas of the service are currently running. @@ -737,9 +734,8 @@ deployments: # Latest error status message of the service (if any). lastError: - # A map of primitive values, output from the service. + # A map of values output from the service. outputs: - # Number, string or boolean : # How many replicas of the service are currently running. @@ -1438,9 +1434,8 @@ services: # Latest error status message of the service (if any). lastError: - # A map of primitive values, output from the service. + # A map of values output from the service. outputs: - # Number, string or boolean : # How many replicas of the service are currently running. @@ -1965,9 +1960,8 @@ deployments: # Latest error status message of the service (if any). lastError: - # A map of primitive values, output from the service. + # A map of values output from the service. outputs: - # Number, string or boolean : # How many replicas of the service are currently running. @@ -2482,9 +2476,8 @@ deployments: # Latest error status message of the service (if any). lastError: - # A map of primitive values, output from the service. + # A map of values output from the service. outputs: - # Number, string or boolean : # How many replicas of the service are currently running. diff --git a/docs/reference/module-types/terraform.md b/docs/reference/module-types/terraform.md index 028bccd48f..87056d6567 100644 --- a/docs/reference/module-types/terraform.md +++ b/docs/reference/module-types/terraform.md @@ -442,13 +442,13 @@ Note that these are only resolved when deploying/running dependants of the servi A map of all the outputs defined in the Terraform stack. -| Type | -| -------- | -| `object` | +| Type | Default | +| -------- | ------- | +| `object` | `{}` | ### `${runtime.services..outputs.}` -| Type | -| ----- | -| `any` | +| Type | +| ------------------------------------------------ | +| `number | string | boolean | link | array[link]` | 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 775942680c..6a41cdface 100644 --- a/garden-service/src/types/service.ts +++ b/garden-service/src/types/service.ts @@ -8,7 +8,7 @@ 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, joiVariables } from "../config/common" import { Module } from "./module" import { ServiceConfig, serviceConfigSchema } from "../config/service" import dedent = require("dedent") @@ -229,10 +229,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/actions.ts b/garden-service/test/unit/src/actions.ts index 3437628974..e6cd7ce79f 100644 --- a/garden-service/test/unit/src/actions.ts +++ b/garden-service/test/unit/src/actions.ts @@ -548,7 +548,7 @@ describe("ActionRouter", () => { describe("deleteService", () => { it("should correctly call the corresponding plugin handler", async () => { const result = await actions.deleteService({ log, service, runtimeContext }) - expect(result).to.eql({ forwardablePorts: [], state: "ready", detail: {} }) + expect(result).to.eql({ forwardablePorts: [], state: "ready", detail: {}, outputs: {} }) }) }) diff --git a/garden-service/test/unit/src/commands/delete.ts b/garden-service/test/unit/src/commands/delete.ts index 43e1e9ab97..fd91b5d03d 100644 --- a/garden-service/test/unit/src/commands/delete.ts +++ b/garden-service/test/unit/src/commands/delete.ts @@ -142,10 +142,10 @@ describe("DeleteEnvironmentCommand", () => { expect(result!.providerStatuses["test-plugin"]["ready"]).to.be.false expect(result!.serviceStatuses).to.eql({ - "service-a": { forwardablePorts: [], state: "missing", detail: {} }, - "service-b": { forwardablePorts: [], state: "missing", detail: {} }, - "service-c": { forwardablePorts: [], state: "missing", detail: {} }, - "service-d": { forwardablePorts: [], state: "missing", detail: {} }, + "service-a": { forwardablePorts: [], state: "missing", detail: {}, outputs: {} }, + "service-b": { forwardablePorts: [], state: "missing", detail: {}, outputs: {} }, + "service-c": { forwardablePorts: [], state: "missing", detail: {}, outputs: {} }, + "service-d": { forwardablePorts: [], state: "missing", detail: {}, outputs: {} }, }) expect(deletedServices.sort()).to.eql(["service-a", "service-b", "service-c", "service-d"]) }) @@ -212,7 +212,7 @@ describe("DeleteServiceCommand", () => { expect(command.outputsSchema().validate(result).error).to.be.undefined expect(result).to.eql({ - "service-a": { forwardablePorts: [], state: "unknown", ingresses: [], detail: {} }, + "service-a": { forwardablePorts: [], state: "unknown", ingresses: [], detail: {}, outputs: {} }, }) }) @@ -229,8 +229,8 @@ describe("DeleteServiceCommand", () => { opts: withDefaultGlobalOpts({}), }) expect(result).to.eql({ - "service-a": { forwardablePorts: [], state: "unknown", ingresses: [], detail: {} }, - "service-b": { forwardablePorts: [], state: "unknown", ingresses: [], detail: {} }, + "service-a": { forwardablePorts: [], state: "unknown", ingresses: [], detail: {}, outputs: {} }, + "service-b": { forwardablePorts: [], state: "unknown", ingresses: [], detail: {}, outputs: {} }, }) }) diff --git a/garden-service/test/unit/src/commands/deploy.ts b/garden-service/test/unit/src/commands/deploy.ts index 1fe86be9d6..0a2859046d 100644 --- a/garden-service/test/unit/src/commands/deploy.ts +++ b/garden-service/test/unit/src/commands/deploy.ts @@ -173,6 +173,7 @@ describe("DeployCommand", () => { durationMsec: 0, error: undefined, success: true, + outputs: {}, }, "service-d": { version: "1", @@ -183,6 +184,7 @@ describe("DeployCommand", () => { durationMsec: 0, error: undefined, success: true, + outputs: {}, }, "service-a": { version: "1", @@ -193,6 +195,7 @@ describe("DeployCommand", () => { durationMsec: 0, error: undefined, success: true, + outputs: {}, }, "service-b": { version: "1", @@ -203,6 +206,7 @@ describe("DeployCommand", () => { durationMsec: 0, error: undefined, success: true, + outputs: {}, }, }) 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", () => {