From 3a942ef7657085a3137b610f777c7556fe9e076e Mon Sep 17 00:00:00 2001 From: Thorarinn Sigurdsson Date: Tue, 14 Mar 2023 14:58:54 +0100 Subject: [PATCH] improvement(k8s): schedule runners w/o deploying This overcomes a limitation that had been temporarily introduced in 0.13, where the `helm` or `kubernetes` Deploy that a `kubernetes-pod` Run or Test targeted would have to be deployed before the Test/Run could be executed. This was essentially a semantic regression from 0.12. This was fixed/improved by simply providing manifests to `kubernetes-pod` Runs and Tests in an equivalent way to how `kubernetes` Deploys are configured. Helm Runs and Tests are now implemented with a new `helm-pod` action definition, which is conceptually similar to the new `kubernetes-pod` implementation, but which render the manifests from a Helm chart instead. Once the `kubernetes-exec` Run and Test action definitions have been implemented, those will be the generally recommended option unless the semantics of the `kubernetes-pod` or `helm-pod` action types are specifically required. --- core/src/constants.ts | 2 +- core/src/plugins/kubernetes/config.ts | 33 + core/src/plugins/kubernetes/helm/common.ts | 21 +- core/src/plugins/kubernetes/helm/config.ts | 190 ++-- core/src/plugins/kubernetes/helm/handlers.ts | 63 +- core/src/plugins/kubernetes/helm/helm-pod.ts | 186 ++++ .../kubernetes/kubernetes-type/common.ts | 24 +- .../kubernetes/kubernetes-type/config.ts | 18 +- .../kubernetes/kubernetes-type/handlers.ts | 11 +- .../plugins/kubernetes/kubernetes-type/run.ts | 84 +- .../kubernetes/kubernetes-type/test.ts | 14 +- core/src/plugins/kubernetes/kubernetes.ts | 5 +- core/src/plugins/kubernetes/run-results.ts | 5 +- core/src/plugins/kubernetes/test-results.ts | 5 +- core/src/plugins/kubernetes/types.ts | 6 +- .../helm/artifacts/templates/_helpers.tpl | 4 - .../src/plugins/kubernetes/container/run.ts | 8 +- .../integ/src/plugins/kubernetes/helm/run.ts | 8 +- .../integ/src/plugins/kubernetes/helm/test.ts | 2 +- .../kubernetes/kubernetes-module/run.ts | 8 +- .../kubernetes/kubernetes-module/test.ts | 2 +- docs/README.md | 2 + docs/reference/action-types/Deploy/helm.md | 16 +- docs/reference/action-types/README.md | 2 + docs/reference/action-types/Run/helm-pod.md | 952 ++++++++++++++++++ .../action-types/Run/kubernetes-pod.md | 101 +- docs/reference/action-types/Test/helm-pod.md | 952 ++++++++++++++++++ .../action-types/Test/kubernetes-pod.md | 101 +- docs/reference/module-types/helm.md | 12 +- 29 files changed, 2602 insertions(+), 235 deletions(-) create mode 100644 core/src/plugins/kubernetes/helm/helm-pod.ts create mode 100644 docs/reference/action-types/Run/helm-pod.md create mode 100644 docs/reference/action-types/Test/helm-pod.md diff --git a/core/src/constants.ts b/core/src/constants.ts index adc6374b6c..7337180e5c 100644 --- a/core/src/constants.ts +++ b/core/src/constants.ts @@ -29,7 +29,7 @@ export const DEFAULT_PORT_PROTOCOL = "TCP" export const DEFAULT_API_VERSION = "garden.io/v0" export const DEFAULT_TEST_TIMEOUT = 60 * 1000 -export const DEFAULT_TASK_TIMEOUT = 60 * 1000 +export const DEFAULT_RUN_TIMEOUT = 60 * 1000 export type SupportedPlatform = "linux" | "darwin" | "win32" export const SUPPORTED_PLATFORMS: SupportedPlatform[] = ["linux", "darwin", "win32"] diff --git a/core/src/plugins/kubernetes/config.ts b/core/src/plugins/kubernetes/config.ts index 6f0131b887..32b348949a 100644 --- a/core/src/plugins/kubernetes/config.ts +++ b/core/src/plugins/kubernetes/config.ts @@ -37,6 +37,9 @@ import { V1Toleration } from "@kubernetes/client-node" import { runPodSpecIncludeFields } from "./run" import { SyncDefaults, syncDefaultsSchema } from "./sync" import { KUBECTL_DEFAULT_TIMEOUT } from "./kubectl" +import { readFileSync } from "fs-extra" +import { join } from "path" +import { STATIC_DIR } from "../../constants" export const DEFAULT_KANIKO_IMAGE = "gcr.io/kaniko-project/executor:v1.8.1-debug" @@ -976,6 +979,36 @@ export const kubernetesCommonRunSchemaKeys = () => ({ namespace: namespaceNameSchema(), }) +export const runPodResourceSchema = (kind: string) => + targetResourceSpecSchema().description( + dedent` + Specify a Kubernetes resource to derive the Pod spec from for the ${kind}. + + This resource will be selected from the manifests provided in this ${kind}'s \`files\` or \`manifests\` config field. + + The following fields from the Pod will be used (if present) when executing the ${kind}: + ${runPodSpecWhitelistDescription()} + ` + ) + +// Need to use a sync read to avoid having to refactor createGardenPlugin() +// The `podspec-v1.json` file is copied from the handy +// kubernetes-json-schema repo (https://github.com/instrumenta/kubernetes-json-schema/tree/master/v1.18.1-standalone). +const jsonSchema = () => JSON.parse(readFileSync(join(STATIC_DIR, "kubernetes", "podspec-v1.json")).toString()) + +// TODO: allow reading the pod spec from a file +export const runPodSpecSchema = (kind: string) => joi + .object() + .jsonSchema({ ...jsonSchema(), type: "object" }) + .description( + dedent` + Supply a custom Pod specification. This should be a normal Kubernetes Pod manifest. Note that the spec will be modified for the ${kind}, including overriding with other fields you may set here (such as \`args\` and \`env\`), and removing certain fields that are not supported. + + The following Pod spec fields from the selected \`resource\` will be used (if present) when executing the ${kind}: + ${runPodSpecWhitelistDescription()} + ` + ) + export const kubernetesTaskSchema = () => baseTaskSpecSchema() .keys({ diff --git a/core/src/plugins/kubernetes/helm/common.ts b/core/src/plugins/kubernetes/helm/common.ts index 85185fd70b..94638546a1 100644 --- a/core/src/plugins/kubernetes/helm/common.ts +++ b/core/src/plugins/kubernetes/helm/common.ts @@ -15,7 +15,7 @@ import cryptoRandomString = require("crypto-random-string") import { PluginContext } from "../../../plugin-context" import { Log } from "../../../logger/log-entry" import { getActionNamespace } from "../namespace" -import { KubernetesResource } from "../types" +import { HelmRuntimeAction, KubernetesResource } from "../types" import { loadAll } from "js-yaml" import { helm } from "./helm-cli" import { HelmModule } from "./module-config" @@ -48,7 +48,7 @@ async function dependencyUpdate(ctx: KubernetesPluginContext, log: Log, namespac interface PrepareTemplatesParams { ctx: KubernetesPluginContext - action: Resolved + action: Resolved log: Log } @@ -156,7 +156,7 @@ type PrepareManifestsParams = GetChartResourcesParams & PrepareTemplatesOutput export async function prepareManifests(params: PrepareManifestsParams): Promise { const { ctx, action, log, namespace, releaseName, valuesPath, reference } = params - const timeout = action.getSpec("timeout") + const timeout = action.getSpec().timeout const res = await helm({ ctx, @@ -238,8 +238,8 @@ export function getBaseModule(module: HelmModule): HelmModule | undefined { /** * Get the full absolute path to the chart, within the action build path, if applicable. */ -export async function getChartPath(action: Resolved) { - const chartSpec = action.getSpec("chart") || {} +export async function getChartPath(action: Resolved) { + const chartSpec = action.getSpec().chart || {} const chartPath = chartSpec.path || "." const chartDir = resolve(action.getBuildPath(), chartPath) const yamlPath = resolve(chartDir, helmChartYamlFilename) @@ -271,11 +271,14 @@ export async function getChartPath(action: Resolved) { /** * Get the value files arguments that should be applied to any helm install/render command. */ -export async function getValueArgs({ action, valuesPath }: { action: Resolved; valuesPath: string }) { +export async function getValueArgs({ + action, + valuesPath +}: { action: Resolved; valuesPath: string }) { // The garden-values.yml file (which is created from the `values` field in the module config) takes precedence, // so it's added to the end of the list. const valueFiles = action - .getSpec("valueFiles") + .getSpec().valueFiles .map((f) => resolve(action.getBuildPath(), f)) .concat([valuesPath]) @@ -289,8 +292,8 @@ export async function getValueArgs({ action, valuesPath }: { action: Resolved) { - return action.getSpec("releaseName") || action.name +export function getReleaseName(action: Resolved) { + return action.getSpec().releaseName || action.name } /** diff --git a/core/src/plugins/kubernetes/helm/config.ts b/core/src/plugins/kubernetes/helm/config.ts index a67bceb2db..d68d781489 100644 --- a/core/src/plugins/kubernetes/helm/config.ts +++ b/core/src/plugins/kubernetes/helm/config.ts @@ -6,33 +6,42 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { DeepPrimitiveMap, joi, joiIdentifier, joiPrimitive, joiSparseArray } from "../../../config/common" +import { createSchema, DeepPrimitiveMap, joi, joiIdentifier, joiPrimitive, joiSparseArray } from "../../../config/common" import { + kubernetesCommonRunSchemaKeys, + KubernetesCommonRunSpec, KubernetesTargetResourceSpec, namespaceNameSchema, PortForwardSpec, portForwardsSchema, + runPodResourceSchema, targetResourceSpecSchema, } from "../config" import { kubernetesDeploySyncSchema, KubernetesDeploySyncSpec } from "../sync" import { DeployAction, DeployActionConfig } from "../../../actions/deploy" import { dedent, deline } from "../../../util/string" import { kubernetesLocalModeSchema, KubernetesLocalModeSpec } from "../local-mode" +import { RunActionConfig, RunAction } from "../../../actions/run" +import { KubernetesRunOutputs } from "../kubernetes-type/run" +import { TestAction, TestActionConfig } from "../../../actions/test" +import { ObjectSchema } from "@hapi/joi" // DEPLOY // export const defaultHelmTimeout = 300 export const defaultHelmRepo = "https://charts.helm.sh/stable" +interface HelmChartSpec { + name?: string // Formerly `chart` on Helm modules + path?: string // Formerly `chartPath` + repo?: string + url?: string + version?: string +} + interface HelmDeployActionSpec { atomicInstall: boolean - chart?: { - name?: string // Formerly `chart` on Helm modules - path?: string // Formerly `chartPath` - repo?: string // Formerly `repo` - url?: string - version?: string // Formerly `version` - } + chart?: HelmChartSpec defaultTarget?: KubernetesTargetResourceSpec sync?: KubernetesDeploySyncSpec localMode?: KubernetesLocalModeSpec @@ -53,6 +62,31 @@ const parameterValueSchema = () => ) .id("parameterValue") +const helmReleaseNameSchema = () => joiIdentifier().description( + "Optionally override the release name used when installing (defaults to the Deploy name)." + ) + +const helmValuesSchema = () => joi + .object() + .pattern(/.+/, parameterValueSchema()) + .default(() => ({})).description(deline` + Map of values to pass to Helm when rendering the templates. May include arrays and nested objects. + When specified, these take precedence over the values in the \`values.yaml\` file (or the files specified + in \`valueFiles\`). + `) + +const helmValueFilesSchema = () => joiSparseArray(joi.posixPath()).description(dedent` + Specify value files to use when rendering the Helm chart. These will take precedence over the \`values.yaml\` file + bundled in the Helm chart, and should be specified in ascending order of precedence. Meaning, the last file in + this list will have the highest precedence. + + If you _also_ specify keys under the \`values\` field, those will effectively be added as another file at the end + of this list, so they will take precedence over other files listed here. + + Note that the paths here should be relative to the _config_ root, and the files should be contained in + this action config's directory. + `) + export const helmCommonSchemaKeys = () => ({ atomicInstall: joi .boolean() @@ -62,9 +96,7 @@ export const helmCommonSchemaKeys = () => ({ ), namespace: namespaceNameSchema(), portForwards: portForwardsSchema(), - releaseName: joiIdentifier().description( - "Optionally override the release name used when installing (defaults to the module name)." - ), + releaseName: helmReleaseNameSchema(), timeout: joi .number() .integer() @@ -72,25 +104,8 @@ export const helmCommonSchemaKeys = () => ({ .description( "Time in seconds to wait for Helm to complete any individual Kubernetes operation (like Jobs for hooks)." ), - values: joi - .object() - .pattern(/.+/, parameterValueSchema()) - .default(() => ({})).description(deline` - Map of values to pass to Helm when rendering the templates. May include arrays and nested objects. - When specified, these take precedence over the values in the \`values.yaml\` file (or the files specified - in \`valueFiles\`). - `), - valueFiles: joiSparseArray(joi.posixPath()).description(dedent` - Specify value files to use when rendering the Helm chart. These will take precedence over the \`values.yaml\` file - bundled in the Helm chart, and should be specified in ascending order of precedence. Meaning, the last file in - this list will have the highest precedence. - - If you _also_ specify keys under the \`values\` field, those will effectively be added as another file at the end - of this list, so they will take precedence over other files listed here. - - Note that the paths here should be relative to the _module_ root, and the files should be contained in - your module directory. - `), + values: helmValuesSchema(), + valueFiles: helmValueFilesSchema(), }) export const helmChartNameSchema = () => @@ -120,42 +135,44 @@ export const defaultTargetSchema = () => ` ) +const helmChartSpecSchema = () => joi + .object() + .keys({ + name: helmChartNameSchema(), + path: joi + .posixPath() + .subPathOnly() + .description( + "The path, relative to the action path, to the chart sources (i.e. where the Chart.yaml file is, if any)." + ), + repo: helmChartRepoSchema(), + url: joi.string().uri().description("An absolute URL to a packaged URL."), + version: helmChartVersionSchema(), + }) + .with("name", ["version"]) + .without("path", ["name", "repo", "version", "url"]) + .without("url", ["name", "repo", "version", "path"]) + .xor("name", "path", "url") + .description( + dedent` + Specify the Helm chart to use. + + If the chart is defined in the same directory as the action, you can skip this, and the chart sources will be detected. If the chart is in the source tree but in a sub-directory, you should set \`chart.path\` to the directory path, relative to the action directory. + + If the chart is remote, you must specify \`chart.name\` and \`chart.version\, and optionally \`chart.repo\` (if the chart is not in the default "stable" repo). + + You may also specify an absolute URL to a packaged chart via \`chart.url\`. + + One of \`chart.name\`, \`chart.path\` or \`chart.url\` must be specified. + ` + ) + export const helmDeploySchema = () => joi .object() .keys({ ...helmCommonSchemaKeys(), - chart: joi - .object() - .keys({ - name: helmChartNameSchema(), - path: joi - .posixPath() - .subPathOnly() - .description( - "The path, relative to the action path, to the chart sources (i.e. where the Chart.yaml file is, if any)." - ), - repo: helmChartRepoSchema(), - url: joi.string().uri().description("An absolute URL to a packaged URL."), - version: helmChartVersionSchema(), - }) - .with("name", ["version"]) - .without("path", ["name", "repo", "version", "url"]) - .without("url", ["name", "repo", "version", "path"]) - .xor("name", "path", "url") - .description( - dedent` - Specify the Helm chart to deploy. - - If the chart is defined in the same directory as the action, you can skip this, and the chart sources will be detected. If the chart is in the source tree but in a sub-directory, you should set \`chart.path\` to the directory path, relative to the action directory. - - If the chart is remote, you must specify \`chart.name\` and \`chart.version\, and optionally \`chart.repo\` (if the chart is not in the default "stable" repo). - - You may also specify an absolute URL to a packaged chart via \`chart.url\`. - - One of \`chart.name\`, \`chart.path\` or \`chart.url\` must be specified. - ` - ), + chart: helmChartSpecSchema(), defaultTarget: defaultTargetSchema(), sync: kubernetesDeploySyncSchema(), localMode: kubernetesLocalModeSchema(), @@ -165,6 +182,53 @@ export const helmDeploySchema = () => export type HelmDeployConfig = DeployActionConfig<"helm", HelmDeployActionSpec> export type HelmDeployAction = DeployAction -// NOTE: Runs and Tests are handled as `kubernetes` Run and Test actions +// RUN & TEST // + +export interface HelmPodRunActionSpec extends KubernetesCommonRunSpec { + chart?: HelmChartSpec + namespace?: string + releaseName?: string + timeout: number + values: DeepPrimitiveMap + valueFiles: string[] + resource?: KubernetesTargetResourceSpec +} + +// Maintaining this cache to avoid errors when `kubernetesRunPodSchema` is called more than once with the same `kind`. +const runSchemas: { [name: string]: ObjectSchema } = {} + +export const helmPodRunSchema = (kind: string) => { + const name = `${kind}:helm-pod` + if (runSchemas[name]) { + return runSchemas[name] + } + const schema = createSchema({ + name: `${kind}:helm-pod`, + keys: () => ({ + ...kubernetesCommonRunSchemaKeys(), + releaseName: helmReleaseNameSchema() + .description(`Optionally override the release name used when rendering the templates (defaults to the ${kind} name).`), + chart: helmChartSpecSchema(), + values: helmValuesSchema(), + valueFiles: helmValueFilesSchema(), + resource: runPodResourceSchema("Run"), + timeout: joi + .number() + .integer() + .default(defaultHelmTimeout) + .description("Time in seconds to wait for Helm to render templates."), + }), + xor: ["resource", "podSpec"], + })() + runSchemas[name] = schema + return schema +} + +export type HelmPodRunConfig = RunActionConfig<"helm-pod", HelmPodRunActionSpec> +export type HelmPodRunAction = RunAction + +export interface HelmPodTestActionSpec extends HelmPodRunActionSpec {} +export type HelmPodTestConfig = TestActionConfig<"helm-pod", HelmPodTestActionSpec> +export type HelmPodTestAction = TestAction -export type HelmActionConfig = HelmDeployConfig +export type HelmActionConfig = HelmDeployConfig | HelmPodRunConfig | HelmPodTestConfig diff --git a/core/src/plugins/kubernetes/helm/handlers.ts b/core/src/plugins/kubernetes/helm/handlers.ts index e10a6e7ccc..7f8c34acf6 100644 --- a/core/src/plugins/kubernetes/helm/handlers.ts +++ b/core/src/plugins/kubernetes/helm/handlers.ts @@ -13,10 +13,9 @@ import { pathExists } from "fs-extra" import chalk = require("chalk") import { getBaseModule, helmChartYamlFilename } from "./common" import { ExecBuildConfig } from "../../exec/config" -import { KubernetesActionConfig } from "../kubernetes-type/config" -import { HelmActionConfig, HelmDeployConfig } from "./config" +import { HelmActionConfig, HelmDeployConfig, HelmPodTestConfig } from "./config" import { getServiceResourceSpec } from "../util" -import { isTruthy, jsonMerge } from "../../../util/util" +import { jsonMerge } from "../../../util/util" import { cloneDeep, omit } from "lodash" import { DeepPrimitiveMap } from "../../../config/common" import { convertServiceResource } from "../kubernetes-type/common" @@ -39,7 +38,7 @@ export const helmModuleHandlers: Partial> = { convertBuildDependency, prepareRuntimeDependencies, } = params - const actions: (ExecBuildConfig | KubernetesActionConfig | HelmActionConfig)[] = [] + const actions: (ExecBuildConfig | HelmActionConfig)[] = [] if (dummyBuild) { actions.push(dummyBuild) @@ -74,63 +73,75 @@ export const helmModuleHandlers: Partial> = { actions.push(deployAction) } - // Runs and Tests generated from helm modules all have the kubernetes-pod type, and don't use the podSpec field. - // Therefore, they include a runtime dependency on their parent module's Deploy. This means that the helm Deploy - // is executed first, and the pod spec for the Test/Run pod runner is read from the cluster. - // - // This behavior is different from 0.12, where the pod spec was read from the output of a dry-run deploy using the - // Helm CLI (and did thus not require the deployment to take place first). + const { + namespace, + releaseName, + timeout, + values, + valueFiles, + } = module.spec + const chart = { + name: module.spec.chart, + path: module.spec.chart ? undefined : module.spec.chartPath, + repo: module.spec.repo, + version: module.spec.version, + } for (const task of tasks) { - const resource = convertServiceResource(module, task.spec.resource) + const resource = convertServiceResource(module, task.spec.resource, task.name) if (!resource) { continue } - // We create a kubernetes Run action here, no need for a specific helm Run type. We add a dependency on this - // module's Deploy, since we'll read the pod spec for the Run from the deployed resources. actions.push({ kind: "Run", - type: "kubernetes-pod", + type: "helm-pod", name: task.name, ...params.baseFields, disabled: task.disabled, build: dummyBuild?.name, - dependencies: [deployDep, ...prepareRuntimeDependencies(task.config.dependencies, dummyBuild)].filter(isTruthy), + dependencies: prepareRuntimeDependencies(task.config.dependencies, dummyBuild), timeout: task.spec.timeout || undefined, spec: { ...omit(task.spec, ["name", "dependencies", "disabled", "timeout"]), resource, - namespace: module.spec.namespace + namespace, + releaseName, + timeout, + values, + valueFiles, + chart, }, }) } for (const test of tests) { - const resource = convertServiceResource(module, test.spec.resource) + const testName = module.name + "-" + test.name + const resource = convertServiceResource(module, test.spec.resource, testName) if (!resource) { continue } - // We create a kubernetes Test action here, no need for a specific helm Test type. We add a dependency on this - // module's Deploy, since we'll read the pod spec for the Test from the deployed resources. - const testAction: KubernetesActionConfig = { + const testAction: HelmPodTestConfig = { kind: "Test", - type: "kubernetes-pod", - name: module.name + "-" + test.name, + type: "helm-pod", + name: testName, ...params.baseFields, disabled: test.disabled, - build: dummyBuild?.name, - dependencies: [deployDep, ...prepareRuntimeDependencies(test.config.dependencies, dummyBuild)].filter(isTruthy), + dependencies: prepareRuntimeDependencies(test.config.dependencies, dummyBuild), timeout: test.spec.timeout || undefined, - spec: { ...omit(test.spec, ["name", "dependencies", "disabled", "timeout"]), resource, - namespace: module.spec.namespace + namespace, + releaseName, + timeout, + values, + valueFiles, + chart, }, } diff --git a/core/src/plugins/kubernetes/helm/helm-pod.ts b/core/src/plugins/kubernetes/helm/helm-pod.ts new file mode 100644 index 0000000000..69fb30df0e --- /dev/null +++ b/core/src/plugins/kubernetes/helm/helm-pod.ts @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2018-2022 Garden Technologies, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +import dedent from "dedent" +import { runResultToActionState } from "../../../actions/base" +import { Resolved } from "../../../actions/types" +import { DEFAULT_RUN_TIMEOUT } from "../../../constants" +import { ConfigurationError } from "../../../exceptions" +import { Log } from "../../../logger/log-entry" +import { RunActionDefinition, TestActionDefinition } from "../../../plugin/action-types" +import { CommonRunParams } from "../../../plugin/handlers/Run/run" +import { KubernetesPluginContext } from "../config" +import { kubernetesRunOutputsSchema } from "../kubernetes-type/run" +import { getActionNamespaceStatus } from "../namespace" +import { k8sGetRunResult, storeRunResult } from "../run-results" +import { getResourceContainer, getResourcePodSpec, getTargetResource, makePodName } from "../util" +import { HelmPodRunAction, helmPodRunSchema, HelmPodTestAction } from "./config" +import { runAndCopy } from "../run" +import { filterManifests, prepareManifests, prepareTemplates } from "./common" +import { storeTestResult } from "../test-results" + +const helmRunPodOutputsSchema = kubernetesRunOutputsSchema +const helmTestPodOutputsSchema = helmRunPodOutputsSchema + +export const helmPodRunDefinition = (): RunActionDefinition => ({ + name: "helm-pod", + docs: dedent` + Executes a Run in an ad-hoc instance of a Kubernetes Pod from a Helm chart and waits for it to complete. + + The \`resource\` field is used to find the Pod spec in the Kubernetes manifests generated by rendering the Helm chart. + `, + schema: helmPodRunSchema("Run"), + runtimeOutputsSchema: helmRunPodOutputsSchema(), + handlers: { + run: async (params) => { + const { ctx, log, action } = params + const k8sCtx = ctx + const namespaceStatus = await getActionNamespaceStatus({ + ctx: k8sCtx, + log, + action, + provider: k8sCtx.provider + }) + const namespace = namespaceStatus.namespaceName + + const res = await runOrTestWithChart({ ...params, ctx: k8sCtx, namespace }) + + const detail = { + ...res, + namespaceStatus, + taskName: action.name, + outputs: { + log: res.log || "", + }, + } + + if (action.getSpec("cacheResult")) { + await storeRunResult({ + ctx, + log, + action, + result: detail, + }) + } + + return { state: runResultToActionState(detail), detail, outputs: detail.outputs } + }, + + getResult: k8sGetRunResult, + }, +}) + +export const helmPodTestDefinition = (): TestActionDefinition => ({ + name: "helm-pod", + docs: dedent` + Executes a Test in an ad-hoc instance of a Kubernetes Pod from a Helm chart and waits for it to complete. + + The \`resource\` field is used to find the Pod spec in the Kubernetes manifests generated by rendering the Helm chart. + `, + schema: helmPodRunSchema("Test"), + runtimeOutputsSchema: helmTestPodOutputsSchema(), + handlers: { + run: async (params) => { + const { ctx, log, action } = params + const k8sCtx = ctx + const namespaceStatus = await getActionNamespaceStatus({ + ctx: k8sCtx, + log, + action, + provider: k8sCtx.provider + }) + const namespace = namespaceStatus.namespaceName + + const res = await runOrTestWithChart({ ...params, ctx: k8sCtx, namespace }) + + const detail = { + ...res, + namespaceStatus, + taskName: action.name, + outputs: { + log: res.log || "", + }, + } + + if (action.getSpec("cacheResult")) { + await storeTestResult({ + ctx, + log, + action, + result: detail, + }) + } + + return { state: runResultToActionState(detail), detail, outputs: detail.outputs } + }, + + getResult: k8sGetRunResult, + }, +}) + +export async function runOrTestWithChart( + params: CommonRunParams & { + ctx: KubernetesPluginContext + action: Resolved + log: Log + namespace: string + } +) { + const { ctx, action, log, namespace } = params + // Get the container spec to use for running + const spec = action.getSpec() + const version = action.versionString() + + const resourceSpec = spec.resource + + if (!resourceSpec) { + // Note: This will generally be caught in schema validation. + throw new ConfigurationError(`${action.longDescription()} specified neither podSpec nor resource.`, { spec }) + } + const k8sCtx = ctx + const preparedTemplates = await prepareTemplates({ + ctx: k8sCtx, + action, + log, + }) + let preparedManifests = await prepareManifests({ + ctx: k8sCtx, + log, + action, + ...preparedTemplates, + }) + const manifests = await filterManifests(preparedManifests) + const target = await getTargetResource({ + ctx, + log, + provider: k8sCtx.provider, + action, + manifests, + query: resourceSpec, + }) + const podSpec = getResourcePodSpec(target) + const container = getResourceContainer(target, resourceSpec.containerName) + + const { timeout } = action.getConfig() + + return runAndCopy({ + ...params, + container, + podSpec, + command: spec.command, + args: spec.args, + artifacts: spec.artifacts, + envVars: spec.env, + image: container.image!, + namespace, + podName: makePodName(action.kind.toLowerCase(), action.name), + timeout: timeout || DEFAULT_RUN_TIMEOUT, + version, + }) +} + diff --git a/core/src/plugins/kubernetes/kubernetes-type/common.ts b/core/src/plugins/kubernetes/kubernetes-type/common.ts index 10c48968c1..2c682213ed 100644 --- a/core/src/plugins/kubernetes/kubernetes-type/common.ts +++ b/core/src/plugins/kubernetes/kubernetes-type/common.ts @@ -22,7 +22,7 @@ import { ConfigurationError, PluginError } from "../../../exceptions" import { KubernetesPluginContext, KubernetesTargetResourceSpec, ServiceResourceSpec } from "../config" import { HelmModule } from "../helm/module-config" import { KubernetesDeployAction } from "./config" -import { DEFAULT_TASK_TIMEOUT } from "../../../constants" +import { DEFAULT_RUN_TIMEOUT } from "../../../constants" import { CommonRunParams } from "../../../plugin/handlers/Run/run" import { runAndCopy } from "../run" import { getTargetResource, getResourcePodSpec, getResourceContainer, makePodName } from "../util" @@ -45,7 +45,7 @@ export async function getManifests({ ctx: PluginContext api: KubeApi log: Log - action: Resolved + action: Resolved defaultNamespace: string readFromSrcDir?: boolean }): Promise { @@ -99,7 +99,7 @@ const disallowedKustomizeArgs = ["-o", "--output", "-h", "--help"] */ export async function readManifests( ctx: PluginContext, - action: Resolved, + action: Resolved, log: Log, readFromSrcDir = false ) { @@ -164,7 +164,8 @@ export function gardenNamespaceAnnotationValue(namespaceName: string) { export function convertServiceResource( module: KubernetesModule | HelmModule, - serviceResourceSpec?: ServiceResourceSpec + serviceResourceSpec?: ServiceResourceSpec, + defaultName?: string ): KubernetesTargetResourceSpec | null { const s = serviceResourceSpec || module.spec.serviceResource @@ -174,13 +175,13 @@ export function convertServiceResource( return { kind: s.kind, - name: s.name || module.name, + name: s.name || defaultName || module.name, podSelector: s.podSelector, containerName: s.containerName, } } -export async function runOrTest( +export async function runOrTestWithPod( params: CommonRunParams & { ctx: KubernetesPluginContext action: Resolved @@ -203,17 +204,18 @@ export async function runOrTest( // Note: This will generally be caught in schema validation. throw new ConfigurationError(`${action.longDescription()} specified neither podSpec nor resource.`, { spec }) } - // By this point, we can assume that the resource specified by `resourceSpec` has already been deployed by e.g. a - // `helm` or `kubernetes` Deployment. - + const k8sCtx = ctx + const provider = k8sCtx.provider + const api = await KubeApi.factory(log, ctx, provider) + const manifests = await getManifests({ ctx, api, log, action, defaultNamespace: namespace }) const target = await getTargetResource({ ctx, log, provider: ctx.provider, action, + manifests, query: resourceSpec, }) - podSpec = getResourcePodSpec(target) container = getResourceContainer(target, resourceSpec.containerName) } else if (!container) { @@ -236,7 +238,7 @@ export async function runOrTest( image: container.image!, namespace, podName: makePodName(action.kind.toLowerCase(), action.name), - timeout: timeout || DEFAULT_TASK_TIMEOUT, + timeout: timeout || DEFAULT_RUN_TIMEOUT, version, }) } diff --git a/core/src/plugins/kubernetes/kubernetes-type/config.ts b/core/src/plugins/kubernetes/kubernetes-type/config.ts index ca2dab8d9a..190ebe6c54 100644 --- a/core/src/plugins/kubernetes/kubernetes-type/config.ts +++ b/core/src/plugins/kubernetes/kubernetes-type/config.ts @@ -57,14 +57,20 @@ const kubernetesResourceSchema = () => }) .unknown(true) +export const kubernetesFilesSchema = () => + joiSparseArray(joi.posixPath().subPathOnly()).description( + "POSIX-style paths to YAML files to load manifests from. Each can contain multiple manifests, and can include any Garden template strings, which will be resolved before applying the manifests." + ) + +export const kubernetesManifestsSchema = () => + joiSparseArray(kubernetesResourceSchema()).description( + "List of Kubernetes resource manifests to deploy. If `files` is also specified, this is combined with the manifests read from the files." + ) + export const kubernetesCommonDeploySpecKeys = () => ({ - files: joiSparseArray(joi.posixPath().subPathOnly()).description( - "POSIX-style paths to YAML files to load manifests from. Each can contain multiple manifests, and can include any Garden template strings, which will be resolved before applying the manifests." - ), + files: kubernetesFilesSchema(), kustomize: kustomizeSpecSchema(), - manifests: joiSparseArray(kubernetesResourceSchema()).description( - "List of Kubernetes resource manifests to deploy. If `files` is also specified, this is combined with the manifests read from the files." - ), + manifests: kubernetesManifestsSchema(), namespace: namespaceNameSchema(), portForwards: portForwardsSchema(), timeout: k8sDeploymentTimeoutSchema(), diff --git a/core/src/plugins/kubernetes/kubernetes-type/handlers.ts b/core/src/plugins/kubernetes/kubernetes-type/handlers.ts index 2bacb490d0..0edbc3ee35 100644 --- a/core/src/plugins/kubernetes/kubernetes-type/handlers.ts +++ b/core/src/plugins/kubernetes/kubernetes-type/handlers.ts @@ -47,6 +47,9 @@ export const kubernetesHandlers: Partial> const service = services[0] // There is always exactly one service in kubernetes modules const serviceResource = module.spec.serviceResource + const files = module.spec.files || [] + const manifests = module.spec.manifests || [] + const deployAction: KubernetesDeployActionConfig = { kind: "Deploy", type: "kubernetes", @@ -60,8 +63,8 @@ export const kubernetesHandlers: Partial> spec: { ...omit(module.spec, ["name", "build", "dependencies", "serviceResource", "tasks", "tests", "sync", "devMode"]), - files: module.spec.files || [], - manifests: module.spec.manifests || [], + files, + manifests, sync: convertKubernetesModuleDevModeSpec(module, service, serviceResource), }, } @@ -96,6 +99,8 @@ export const kubernetesHandlers: Partial> spec: { ...omit(task.spec, ["name", "dependencies", "disabled", "timeout"]), resource, + files, + manifests, namespace: module.spec.namespace }, }) @@ -122,6 +127,8 @@ export const kubernetesHandlers: Partial> spec: { ...omit(test.spec, ["name", "dependencies", "disabled", "timeout"]), resource, + files, + manifests, namespace: module.spec.namespace }, }) diff --git a/core/src/plugins/kubernetes/kubernetes-type/run.ts b/core/src/plugins/kubernetes/kubernetes-type/run.ts index e8f6ce8ceb..9e73c78c59 100644 --- a/core/src/plugins/kubernetes/kubernetes-type/run.ts +++ b/core/src/plugins/kubernetes/kubernetes-type/run.ts @@ -11,22 +11,23 @@ import { KubernetesCommonRunSpec, KubernetesPluginContext, KubernetesTargetResourceSpec, - runPodSpecWhitelistDescription, - targetResourceSpecSchema, + runPodResourceSchema, + runPodSpecSchema, } from "../config" import { k8sGetRunResult, storeRunResult } from "../run-results" import { getActionNamespaceStatus } from "../namespace" -import { STATIC_DIR } from "../../../constants" import type { RunActionDefinition } from "../../../plugin/action-types" import { dedent } from "../../../util/string" import type { RunAction, RunActionConfig } from "../../../actions/run" -import { joi, createSchema } from "../../../config/common" +import { createSchema } from "../../../config/common" import { containerRunOutputSchema } from "../../container/config" import type { V1PodSpec } from "@kubernetes/client-node" -import { readFileSync } from "fs" -import { join } from "path" -import { runOrTest } from "./common" +import { runOrTestWithPod } from "./common" import { runResultToActionState } from "../../../actions/base" +import { kubernetesFilesSchema, kubernetesManifestsSchema } from "./config" +import { KubernetesResource } from "../types" +import { KubernetesKustomizeSpec } from "./kustomize" +import { ObjectSchema } from "@hapi/joi" export interface KubernetesRunOutputs { log: string @@ -34,55 +35,52 @@ export interface KubernetesRunOutputs { export const kubernetesRunOutputsSchema = () => containerRunOutputSchema() export interface KubernetesRunActionSpec extends KubernetesCommonRunSpec { + files: string[] + kustomize?: KubernetesKustomizeSpec + manifests: KubernetesResource[] resource?: KubernetesTargetResourceSpec podSpec?: V1PodSpec } export type KubernetesRunActionConfig = RunActionConfig<"kubernetes-pod", KubernetesRunActionSpec> export type KubernetesRunAction = RunAction -// Need to use a sync read to avoid having to refactor createGardenPlugin() -// The `podspec-v1.json` file is copied from the handy -// kubernetes-json-schema repo (https://github.com/instrumenta/kubernetes-json-schema/tree/master/v1.18.1-standalone). -const jsonSchema = () => JSON.parse(readFileSync(join(STATIC_DIR, "kubernetes", "podspec-v1.json")).toString()) +// Maintaining this cache to avoid errors when `kubernetesRunPodSchema` is called more than once with the same `kind`. +const runSchemas: { [name: string]: ObjectSchema } = {} -export const kubernetesRunSchema = createSchema({ - name: "Run:kubernetes-pod", - keys: () => ({ - ...kubernetesCommonRunSchemaKeys(), - resource: targetResourceSpecSchema().description( - dedent` - Specify a Kubernetes resource to derive the Pod spec from for the run. - - This resource will be fetched from the target namespace, so you'll need to make sure it's been deployed previously (say, by configuring a dependency on a \`helm\` or \`kubernetes\` Deploy). - - The following fields from the Pod will be used (if present) when executing the task: - ${runPodSpecWhitelistDescription()} - ` - ), - // TODO: allow reading the pod spec from a file - podSpec: joi - .object() - .jsonSchema({ ...jsonSchema(), type: "object" }) - .description( - dedent` - Supply a custom Pod specification. This should be a normal Kubernetes Pod manifest. Note that the spec will be modified for the run, including overriding with other fields you may set here (such as \`args\` and \`env\`), and removing certain fields that are not supported. - - The following Pod spec fields from the will be used (if present) when executing the task: - ${runPodSpecWhitelistDescription()} - ` +export const kubernetesRunPodSchema = (kind: string) => { + const name = `${kind}:kubernetes-pod` + if (runSchemas[name]) { + return runSchemas[name] + } + const schema = createSchema({ + name, + keys: () => ({ + ...kubernetesCommonRunSchemaKeys(), + manifests: kubernetesManifestsSchema() + .description( + `List of Kubernetes resource manifests to be searched (using \`resource\`e for the pod spec for the ${kind}. If \`files\` is also specified, this is combined with the manifests read from the files.` ), - }), - xor: ["resource", "podSpec"], -}) + files: kubernetesFilesSchema() + .description( + `POSIX-style paths to YAML files to load manifests from. Each can contain multiple manifests, and can include any Garden template strings, which will be resolved before searching the manifests for the resource that contains the Pod spec for the ${kind}.` + ), + resource: runPodResourceSchema(kind), + podSpec: runPodSpecSchema(kind), + }), + xor: ["resource", "podSpec"], + })() + runSchemas[name] = schema + return schema +} export const kubernetesRunDefinition = (): RunActionDefinition => ({ name: "kubernetes-pod", docs: dedent` - Run an ad-hoc instance of a Kubernetes Pod and wait for it to complete. + Executes a Run in an ad-hoc instance of a Kubernetes Pod and waits for it to complete. - TODO-G2 + The pod spec can be provided directly via the \`podSpec\` field, or the \`resource\` field can be used to find the pod spec in the Kubernetes manifests provided via the \`files\` and/or \`manifests\` fields. `, - schema: kubernetesRunSchema(), + schema: kubernetesRunPodSchema("Run"), runtimeOutputsSchema: kubernetesRunOutputsSchema(), handlers: { run: async (params) => { @@ -96,7 +94,7 @@ export const kubernetesRunDefinition = (): RunActionDefinition export type KubernetesTestAction = TestAction -const kubernetesTestSchema = () => kubernetesRunSchema() - export const kubernetesTestDefinition = (): TestActionDefinition => ({ name: "kubernetes-pod", docs: dedent` - Run a test in an ad-hoc instance of a Kubernetes Pod. + Executes a Test in an ad-hoc instance of a Kubernetes Pod and waits for it to complete. - TODO-G2 + The pod spec can be provided directly via the \`podSpec\` field, or the \`resource\` field can be used to find the pod spec in the Kubernetes manifests provided via the \`files\` and/or \`manifests\` fields. `, - schema: kubernetesTestSchema(), + schema: kubernetesRunPodSchema("Test"), runtimeOutputsSchema: kubernetesTestOutputsSchema(), handlers: { run: async (params) => { @@ -48,7 +46,7 @@ export const kubernetesTestDefinition = (): TestActionDefinition configmapDeployDefinition(), persistentvolumeclaimDeployDefinition(), ], - Run: [kubernetesRunDefinition()], - Test: [kubernetesTestDefinition()], + Run: [kubernetesRunDefinition(), helmPodRunDefinition()], + Test: [kubernetesTestDefinition(), helmPodTestDefinition()], }, extendActionTypes: { diff --git a/core/src/plugins/kubernetes/run-results.ts b/core/src/plugins/kubernetes/run-results.ts index cac7b5c497..b7f96aae53 100644 --- a/core/src/plugins/kubernetes/run-results.ts +++ b/core/src/plugins/kubernetes/run-results.ts @@ -23,6 +23,7 @@ import { Action } from "../../actions/types" import { RunResult } from "../../plugin/base" import { RunActionHandler } from "../../plugin/action-types" import { KubernetesRunAction } from "./kubernetes-type/run" +import { HelmPodRunAction } from "./helm/config" // TODO-G2: figure out how to get rid of the any cast here export const k8sGetRunResult: RunActionHandler<"getResult", any> = async (params) => { @@ -69,7 +70,7 @@ export function getRunResultKey(ctx: PluginContext, action: Action) { interface StoreTaskResultParams { ctx: PluginContext log: Log - action: ContainerRunAction | KubernetesRunAction + action: ContainerRunAction | KubernetesRunAction | HelmPodRunAction result: RunResult } @@ -108,7 +109,7 @@ export async function storeRunResult({ ctx, log, action, result }: StoreTaskResu /** * Clear the stored result for the given task. No-op if no result had been stored for it. */ -export async function clearTaskResult({ +export async function clearRunResult({ ctx, log, action, diff --git a/core/src/plugins/kubernetes/test-results.ts b/core/src/plugins/kubernetes/test-results.ts index 3f7e7bcdf1..eb9e16b0c3 100644 --- a/core/src/plugins/kubernetes/test-results.ts +++ b/core/src/plugins/kubernetes/test-results.ts @@ -22,6 +22,7 @@ import chalk from "chalk" import { TestActionHandler } from "../../plugin/action-types" import { KubernetesTestAction } from "./kubernetes-type/test" import { runResultToActionState } from "../../actions/base" +import { HelmPodTestAction } from "./helm/config" // TODO-G2: figure out how to get rid of the any case export const k8sGetTestResult: TestActionHandler<"getResult", any> = async (params) => { @@ -52,7 +53,7 @@ export const k8sGetTestResult: TestActionHandler<"getResult", any> = async (para } } -export function getTestResultKey(ctx: PluginContext, action: ContainerTestAction | KubernetesTestAction) { +export function getTestResultKey(ctx: PluginContext, action: StoreTestResultParams["action"]) { const key = `${ctx.projectName}--${action.name}--${action.versionString()}` const hash = hasha(key, { algorithm: "sha1" }) return `test-result--${hash.slice(0, 32)}` @@ -61,7 +62,7 @@ export function getTestResultKey(ctx: PluginContext, action: ContainerTestAction interface StoreTestResultParams { ctx: PluginContext log: Log - action: ContainerTestAction | KubernetesTestAction + action: ContainerTestAction | KubernetesTestAction | HelmPodTestAction result: TestResult } diff --git a/core/src/plugins/kubernetes/types.ts b/core/src/plugins/kubernetes/types.ts index 0f72cf5a92..772b02323a 100644 --- a/core/src/plugins/kubernetes/types.ts +++ b/core/src/plugins/kubernetes/types.ts @@ -25,7 +25,7 @@ import type { ContainerRunAction, ContainerTestAction, } from "../container/config" -import type { HelmDeployAction } from "./helm/config" +import type { HelmDeployAction, HelmPodRunAction, HelmPodTestAction } from "./helm/config" import type { KubernetesDeployAction } from "./kubernetes-type/config" import { KubernetesRunAction } from "./kubernetes-type/run" import { KubernetesTestAction } from "./kubernetes-type/test" @@ -98,12 +98,14 @@ export type SyncableResource = KubernetesWorkload | KubernetesPod export type SyncableKind = "Deployment" | "DaemonSet" | "StatefulSet" export const syncableKinds: string[] = ["Deployment", "DaemonSet", "StatefulSet"] +export type HelmRuntimeAction = HelmDeployAction | HelmPodRunAction | HelmPodTestAction + export type SupportedRuntimeActions = | ContainerBuildAction | ContainerDeployAction | ContainerTestAction | ContainerRunAction - | HelmDeployAction + | HelmRuntimeAction | KubernetesDeployAction | KubernetesRunAction | KubernetesTestAction diff --git a/core/test/data/test-projects/helm/artifacts/templates/_helpers.tpl b/core/test/data/test-projects/helm/artifacts/templates/_helpers.tpl index 54ca5c0215..7f2bc38416 100644 --- a/core/test/data/test-projects/helm/artifacts/templates/_helpers.tpl +++ b/core/test/data/test-projects/helm/artifacts/templates/_helpers.tpl @@ -16,11 +16,7 @@ If release name contains chart name it will be used as a full name. {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} {{- else -}} {{- $name := default .Chart.Name .Values.nameOverride -}} -{{- if contains $name .Release.Name -}} {{- .Release.Name | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} -{{- end -}} {{- end -}} {{- end -}} diff --git a/core/test/integ/src/plugins/kubernetes/container/run.ts b/core/test/integ/src/plugins/kubernetes/container/run.ts index 526e98b2fc..45b61e4924 100644 --- a/core/test/integ/src/plugins/kubernetes/container/run.ts +++ b/core/test/integ/src/plugins/kubernetes/container/run.ts @@ -14,7 +14,7 @@ import { RunTask } from "../../../../../../src/tasks/run" import { emptyDir, pathExists } from "fs-extra" import { join } from "path" import { getContainerTestGarden } from "./container" -import { clearTaskResult } from "../../../../../../src/plugins/kubernetes/run-results" +import { clearRunResult } from "../../../../../../src/plugins/kubernetes/run-results" import { KubernetesProvider } from "../../../../../../src/plugins/kubernetes/config" import { ContainerRunAction } from "../../../../../../src/plugins/container/config" @@ -51,7 +51,7 @@ describe("runContainerTask", () => { garden.events.eventLog = [] const ctx = await garden.getPluginContext({ provider, templateContext: undefined, events: undefined }) - await clearTaskResult({ ctx, log: garden.log, action }) + await clearRunResult({ ctx, log: garden.log, action }) const results = await garden.processTasks({ tasks: [testTask], throwOnError: true }) const result = results.results.getResult(testTask) @@ -90,7 +90,7 @@ describe("runContainerTask", () => { }) const ctx = await garden.getPluginContext({ provider, templateContext: undefined, events: undefined }) - await clearTaskResult({ ctx, log: garden.log, action }) + await clearRunResult({ ctx, log: garden.log, action }) await garden.processTasks({ tasks: [testTask], throwOnError: true }) @@ -120,7 +120,7 @@ describe("runContainerTask", () => { }) const ctx = await garden.getPluginContext({ provider, templateContext: undefined, events: undefined }) - await clearTaskResult({ ctx, log: garden.log, action }) + await clearRunResult({ ctx, log: garden.log, action }) await expectError( async () => await garden.processTasks({ tasks: [testTask], throwOnError: true }), diff --git a/core/test/integ/src/plugins/kubernetes/helm/run.ts b/core/test/integ/src/plugins/kubernetes/helm/run.ts index c0f5192ed3..07245570d4 100644 --- a/core/test/integ/src/plugins/kubernetes/helm/run.ts +++ b/core/test/integ/src/plugins/kubernetes/helm/run.ts @@ -14,9 +14,9 @@ import { getHelmTestGarden } from "./common" import { RunTask } from "../../../../../../src/tasks/run" import { emptyDir, pathExists } from "fs-extra" import { join } from "path" -import { clearTaskResult } from "../../../../../../src/plugins/kubernetes/run-results" +import { clearRunResult } from "../../../../../../src/plugins/kubernetes/run-results" -describe("runHelmTask", () => { +describe.only("Helm Pod Run", () => { let garden: TestGarden let graph: ConfigGraph @@ -43,7 +43,7 @@ describe("runHelmTask", () => { // Clear any existing task result const provider = await garden.resolveProvider(garden.log, "local-kubernetes") const ctx = await garden.getPluginContext({ provider, templateContext: undefined, events: undefined }) - await clearTaskResult({ ctx, log: garden.log, action }) + await clearRunResult({ ctx, log: garden.log, action }) const results = await garden.processTasks({ tasks: [testTask], throwOnError: true }) const result = results.results.getResult(testTask) @@ -81,7 +81,7 @@ describe("runHelmTask", () => { // Clear any existing task result const provider = await garden.resolveProvider(garden.log, "local-kubernetes") const ctx = await garden.getPluginContext({ provider, templateContext: undefined, events: undefined }) - await clearTaskResult({ ctx, log: garden.log, action }) + await clearRunResult({ ctx, log: garden.log, action }) await garden.processTasks({ tasks: [testTask], throwOnError: true }) diff --git a/core/test/integ/src/plugins/kubernetes/helm/test.ts b/core/test/integ/src/plugins/kubernetes/helm/test.ts index 7d27385926..cc7915aa30 100644 --- a/core/test/integ/src/plugins/kubernetes/helm/test.ts +++ b/core/test/integ/src/plugins/kubernetes/helm/test.ts @@ -15,7 +15,7 @@ import { TestTask } from "../../../../../../src/tasks/test" import { emptyDir, pathExists } from "fs-extra" import { join } from "path" -describe("testHelmModule", () => { +describe("Helm Pod Test", () => { let garden: TestGarden let graph: ConfigGraph diff --git a/core/test/integ/src/plugins/kubernetes/kubernetes-module/run.ts b/core/test/integ/src/plugins/kubernetes/kubernetes-module/run.ts index 70c9a67434..d21fd19ed2 100644 --- a/core/test/integ/src/plugins/kubernetes/kubernetes-module/run.ts +++ b/core/test/integ/src/plugins/kubernetes/kubernetes-module/run.ts @@ -14,10 +14,10 @@ import { getKubernetesTestGarden } from "./common" import { RunTask } from "../../../../../../src/tasks/run" import { emptyDir, pathExists } from "fs-extra" import { join } from "path" -import { clearTaskResult } from "../../../../../../src/plugins/kubernetes/run-results" +import { clearRunResult } from "../../../../../../src/plugins/kubernetes/run-results" import { KubernetesRunAction } from "../../../../../../src/plugins/kubernetes/kubernetes-type/run" -describe("runKubernetesTask", () => { +describe("kubernetes-type pod Run", () => { let garden: TestGarden let graph: ConfigGraph @@ -44,7 +44,7 @@ describe("runKubernetesTask", () => { // Clear any existing task result const provider = await garden.resolveProvider(garden.log, "local-kubernetes") const ctx = await garden.getPluginContext({ provider, templateContext: undefined, events: undefined }) - await clearTaskResult({ ctx, log: garden.log, action }) + await clearRunResult({ ctx, log: garden.log, action }) const results = await garden.processTasks({ tasks: [testTask], throwOnError: true }) const result = results.results.getResult(testTask) @@ -82,7 +82,7 @@ describe("runKubernetesTask", () => { // Clear any existing task result const provider = await garden.resolveProvider(garden.log, "local-kubernetes") const ctx = await garden.getPluginContext({ provider, templateContext: undefined, events: undefined }) - await clearTaskResult({ ctx, log: garden.log, action }) + await clearRunResult({ ctx, log: garden.log, action }) await garden.processTasks({ tasks: [testTask], throwOnError: true }) diff --git a/core/test/integ/src/plugins/kubernetes/kubernetes-module/test.ts b/core/test/integ/src/plugins/kubernetes/kubernetes-module/test.ts index 096870fd1f..5fc95b0d63 100644 --- a/core/test/integ/src/plugins/kubernetes/kubernetes-module/test.ts +++ b/core/test/integ/src/plugins/kubernetes/kubernetes-module/test.ts @@ -16,7 +16,7 @@ import { emptyDir, pathExists } from "fs-extra" import { join } from "path" import { KubernetesTestAction } from "../../../../../../src/plugins/kubernetes/kubernetes-type/test" -describe("testKubernetesModule", () => { +describe("kubernetes-type pod Test", () => { let garden: TestGarden let graph: ConfigGraph diff --git a/docs/README.md b/docs/README.md index 9fc226c22d..2374e3dc9a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -123,6 +123,7 @@ * [Run](./reference/action-types/Run/container.md) * [`container` Run](./reference/action-types/Run/container.md) * [`exec` Run](./reference/action-types/Run/exec.md) + * [`helm-pod` Run](./reference/action-types/Run/helm-pod.md) * [`kubernetes-pod` Run](./reference/action-types/Run/kubernetes-pod.md) * [Test](./reference/action-types/Test/conftest-helm.md) * [`conftest-helm` Test](./reference/action-types/Test/conftest-helm.md) @@ -130,6 +131,7 @@ * [`container` Test](./reference/action-types/Test/container.md) * [`exec` Test](./reference/action-types/Test/exec.md) * [`hadolint` Test](./reference/action-types/Test/hadolint.md) + * [`helm-pod` Test](./reference/action-types/Test/helm-pod.md) * [`kubernetes-pod` Test](./reference/action-types/Test/kubernetes-pod.md) * [Module Types](./reference/module-types/README.md) * [`configmap`](./reference/module-types/configmap.md) diff --git a/docs/reference/action-types/Deploy/helm.md b/docs/reference/action-types/Deploy/helm.md index 39b58f3e50..a1db775f39 100644 --- a/docs/reference/action-types/Deploy/helm.md +++ b/docs/reference/action-types/Deploy/helm.md @@ -181,7 +181,7 @@ spec: # not available, a warning is shown and a random port chosen instead. localPort: - # Optionally override the release name used when installing (defaults to the module name). + # Optionally override the release name used when installing (defaults to the Deploy name). releaseName: # Time in seconds to wait for Helm to complete any individual Kubernetes operation (like Jobs for hooks). @@ -198,11 +198,11 @@ spec: # If you _also_ specify keys under the `values` field, those will effectively be added as another file at the end # of this list, so they will take precedence over other files listed here. # - # Note that the paths here should be relative to the _module_ root, and the files should be contained in - # your module directory. + # Note that the paths here should be relative to the _config_ root, and the files should be contained in + # this action config's directory. valueFiles: [] - # Specify the Helm chart to deploy. + # Specify the Helm chart to use. # # If the chart is defined in the same directory as the action, you can skip this, and the chart sources will be # detected. If the chart is in the source tree but in a sub-directory, you should set `chart.path` to the directory @@ -741,7 +741,7 @@ The _preferred_ local port to forward from. If none is set, a random port is cho [spec](#spec) > releaseName -Optionally override the release name used when installing (defaults to the module name). +Optionally override the release name used when installing (defaults to the Deploy name). | Type | Required | | -------- | -------- | @@ -778,8 +778,8 @@ this list will have the highest precedence. If you _also_ specify keys under the `values` field, those will effectively be added as another file at the end of this list, so they will take precedence over other files listed here. -Note that the paths here should be relative to the _module_ root, and the files should be contained in -your module directory. +Note that the paths here should be relative to the _config_ root, and the files should be contained in +this action config's directory. | Type | Default | Required | | ------------------ | ------- | -------- | @@ -789,7 +789,7 @@ your module directory. [spec](#spec) > chart -Specify the Helm chart to deploy. +Specify the Helm chart to use. If the chart is defined in the same directory as the action, you can skip this, and the chart sources will be detected. If the chart is in the source tree but in a sub-directory, you should set `chart.path` to the directory path, relative to the action directory. diff --git a/docs/reference/action-types/README.md b/docs/reference/action-types/README.md index f6ba422086..6d089b6fbf 100644 --- a/docs/reference/action-types/README.md +++ b/docs/reference/action-types/README.md @@ -22,10 +22,12 @@ title: Action Types * [`exec`](./Run/exec.md) * [`container`](./Run/container.md) * [`kubernetes-pod`](./Run/kubernetes-pod.md) + * [`helm-pod`](./Run/helm-pod.md) * `kind` * [`exec`](./Test/exec.md) * [`container`](./Test/container.md) * [`hadolint`](./Test/hadolint.md) * [`kubernetes-pod`](./Test/kubernetes-pod.md) + * [`helm-pod`](./Test/helm-pod.md) * [`conftest`](./Test/conftest.md) * [`conftest-helm`](./Test/conftest-helm.md) \ No newline at end of file diff --git a/docs/reference/action-types/Run/helm-pod.md b/docs/reference/action-types/Run/helm-pod.md new file mode 100644 index 0000000000..b77a046175 --- /dev/null +++ b/docs/reference/action-types/Run/helm-pod.md @@ -0,0 +1,952 @@ +--- +title: "`helm-pod` Run" +tocTitle: "`helm-pod` Run" +--- + +# `helm-pod` Run + +## Description + +Executes a Run in an ad-hoc instance of a Kubernetes Pod from a Helm chart and waits for it to complete. + +The `resource` field is used to find the Pod spec in the Kubernetes manifests generated by rendering the Helm chart. + +Below is the full schema reference for the action. For an introduction to configuring Garden, please look at our [Configuration +guide](../../../using-garden/configuration-overview.md). + +The [first section](#complete-yaml-schema) contains the complete YAML schema, and the [second section](#configuration-keys) describes each schema key. + +`helm-pod` actions also export values that are available in template strings. See the [Outputs](#outputs) section below for details. + +## Complete YAML Schema + +The values in the schema below are the default values. + +```yaml +# The schema version of this config (currently not used). +apiVersion: garden.io/v0 + +# The type of action, e.g. `exec`, `container` or `kubernetes`. Some are built into Garden but mostly these will be +# defined by your configured providers. +type: + +# A valid name for the action. Must be unique across all actions of the same _kind_ in your project. +name: + +# A description of the action. +description: + +# By default, the directory where the action is defined is used as the source for the build context. +# +# You can override this by setting either `source.path` to another (POSIX-style) path relative to the action source +# directory, or `source.repository` to get the source from an external repository. +# +# If using `source.path`, you must make sure the target path is in a git repository. +# +# For `source.repository` behavior, please refer to the [Remote Sources +# guide](https://docs.garden.io/advanced/using-remote-sources). +source: + # A relative POSIX-style path to the source directory for this action. You must make sure this path exists and is + # ina git repository! + path: + + # When set, Garden will import the action source from this repository, but use this action configuration (and not + # scan for configs in the separate repository). + repository: + # A remote repository URL. Currently only supports git servers. Must contain a hash suffix pointing to a specific + # branch or tag, with the format: # + url: + +# A list of other actions that this action depends on, and should be built, deployed or run (depending on the action +# type) before processing this action. +# +# Each dependency should generally be expressed as a `"."` string, where __ is one of `build`, +# `deploy`, `run` or `test`, and __ is the name of the action to depend on. +# +# You may also optionally specify a dependency as an object, e.g. `{ kind: "Build", name: "some-image" }`. +# +# Any empty values (i.e. null or empty strings) are ignored, so that you can conditionally add in a dependency via +# template expressions. +dependencies: [] + +# Set this to `true` to disable the action. You can use this with conditional template strings to disable actions +# based on, for example, the current environment or other variables (e.g. `disabled: ${environment.name == "prod"}`). +# This can be handy when you only need certain actions for specific environments, e.g. only for development. +# +# For Build actions, this means the build is not performed _unless_ it is declared as a dependency by another enabled +# action (in which case the Build is assumed to be necessary for the dependant action to be run or built). +# +# For other action kinds, the action is skipped in all scenarios, and dependency declarations to it are ignored. Note +# however that template strings referencing outputs (i.e. runtime outputs) will fail to resolve when the action is +# disabled, so you need to make sure to provide alternate values for those if you're using them, using conditional +# expressions. +disabled: false + +# Specify a list of POSIX-style paths or globs that should be regarded as source files for this action, and thus will +# affect the computed _version_ of the action. +# +# For actions other than _Build_ actions, this is usually not necessary to specify, or is implicitly inferred. An +# exception would be e.g. an `exec` action without a `build` reference, where the relevant files cannot be inferred +# and you want to define which files should affect the version of the action, e.g. to make sure a Test action is run +# when certain files are modified. +# +# _Build_ actions have a different behavior, since they generally are based on some files in the source tree, so +# please reference the docs for more information on those. +# +# Note that you can also _exclude_ files using the `exclude` field or by placing `.gardenignore` files in your source +# tree, which use the same format as `.gitignore` files. See the [Configuration Files +# guide](https://docs.garden.io/using-garden/configuration-overview#including-excluding-files-and-directories) for +# details. +include: + +# Specify a list of POSIX-style paths or glob patterns that should be explicitly excluded from the action's version. +# +# For actions other than _Build_ actions, this is usually not necessary to specify, or is implicitly inferred. For +# _Deploy_, _Run_ and _Test_ actions, the exclusions specified here only applied on top of explicitly set `include` +# paths, or such paths inferred by providers. See the [Configuration Files +# guide](https://docs.garden.io/using-garden/configuration-overview#including-excluding-files-and-directories) for +# details. +# +# Unlike the `scan.exclude` field in the project config, the filters here have _no effect_ on which files and +# directories are watched for changes when watching is enabled. Use the project `scan.exclude` field to affect those, +# if you have large directories that should not be watched for changes. +exclude: + +# A map of variables scoped to this particular action. These are resolved before any other parts of the action +# configuration and take precedence over group-scoped variables (if applicable) and project-scoped variables, in that +# order. They may reference group-scoped and project-scoped variables, and generally can use any template strings +# normally allowed when resolving the action. +variables: + +# Specify a list of paths (relative to the directory where the action is defined) to a file containing variables, that +# we apply on top of the action-level `variables` field, and take precedence over group-level variables (if +# applicable) and project-level variables, in that order. +# +# If you specify multiple paths, they are merged in the order specified, i.e. the last one takes precedence over the +# previous ones. +# +# The format of the files is determined by the configured file's extension: +# +# * `.env` - Standard "dotenv" format, as defined by [dotenv](https://github.com/motdotla/dotenv#rules). +# * `.yaml`/`.yml` - YAML. The file must consist of a YAML document, which must be a map (dictionary). Keys may +# contain any value type. +# * `.json` - JSON. Must contain a single JSON _object_ (not an array). +# +# _NOTE: The default varfile format will change to YAML in Garden v0.13, since YAML allows for definition of nested +# objects and arrays._ +# +# To use different varfiles in different environments, you can template in the environment name to the varfile name, +# e.g. `varfile: "my-action.\$\{environment.name\}.env` (this assumes that the corresponding varfiles exist). +# +# If a listed varfile cannot be found, it is ignored. +varfiles: [] + +# Specify a _Build_ action, and resolve this action from the context of that Build. +# +# For example, you might create an `exec` Build which prepares some manifests, and then reference that in a +# `kubernetes` _Deploy_ action, and the resulting manifests from the Build. +# +# This would mean that instead of looking for manifest files relative to this action's location in your project +# structure, the output directory for the referenced `exec` Build would be the source. +build: + +kind: + +# Set a timeout for the run to complete, in seconds. +timeout: + +spec: + # Set to false if you don't want the task's result to be cached. Use this if the task needs to be run any time your + # project (or one or more of the task's dependants) is deployed. Otherwise the task is only re-run when its version + # changes (i.e. the module or one of its dependencies is modified), or when you run `garden run`. + cacheResult: true + + # The command/entrypoint used to run inside the container. + command: + + # The arguments to pass to the command/entypoint used for execution. + args: + + # Key/value map of environment variables. Keys must be valid POSIX environment variable names (must not start with + # `GARDEN`) and values must be primitives or references to secrets. + env: {} + + # Specify artifacts to copy out of the container after the run. The artifacts are stored locally under + # the `.garden/artifacts` directory. + artifacts: + - # A POSIX-style path or glob to copy. Must be an absolute path. May contain wildcards. + source: + + # A POSIX-style path to copy the artifacts to, relative to the project artifacts directory at + # `.garden/artifacts`. + target: . + + # A valid Kubernetes namespace name. Must be a valid RFC1035/RFC1123 (DNS) label (may contain lowercase letters, + # numbers and dashes, must start with a letter, and cannot end with a dash) and must not be longer than 63 + # characters. + namespace: + + # Optionally override the release name used when rendering the templates (defaults to the Run name). + releaseName: + + # Specify the Helm chart to use. + # + # If the chart is defined in the same directory as the action, you can skip this, and the chart sources will be + # detected. If the chart is in the source tree but in a sub-directory, you should set `chart.path` to the directory + # path, relative to the action directory. + # + # If the chart is remote, you must specify `chart.name` and `chart.version\, and optionally `chart.repo` (if the + # chart is not in the default "stable" repo). + # + # You may also specify an absolute URL to a packaged chart via `chart.url`. + # + # One of `chart.name`, `chart.path` or `chart.url` must be specified. + chart: + # A valid Helm chart name or URI (same as you'd input to `helm install`) Required if the module doesn't contain + # the Helm chart itself. + name: + + # The path, relative to the action path, to the chart sources (i.e. where the Chart.yaml file is, if any). + path: + + # The repository URL to fetch the chart from. Defaults to the "stable" helm repo (https://charts.helm.sh/stable). + repo: + + # An absolute URL to a packaged URL. + url: + + # The chart version to deploy. + version: + + # Map of values to pass to Helm when rendering the templates. May include arrays and nested objects. When specified, + # these take precedence over the values in the `values.yaml` file (or the files specified in `valueFiles`). + values: {} + + # Specify value files to use when rendering the Helm chart. These will take precedence over the `values.yaml` file + # bundled in the Helm chart, and should be specified in ascending order of precedence. Meaning, the last file in + # this list will have the highest precedence. + # + # If you _also_ specify keys under the `values` field, those will effectively be added as another file at the end + # of this list, so they will take precedence over other files listed here. + # + # Note that the paths here should be relative to the _config_ root, and the files should be contained in + # this action config's directory. + valueFiles: [] + + # Specify a Kubernetes resource to derive the Pod spec from for the Run. + # + # This resource will be selected from the manifests provided in this Run's `files` or `manifests` config field. + # + # The following fields from the Pod will be used (if present) when executing the Run: + # * `affinity` + # * `automountServiceAccountToken` + # * `containers` + # * `dnsConfig` + # * `dnsPolicy` + # * `enableServiceLinks` + # * `hostAliases` + # * `hostIPC` + # * `hostNetwork` + # * `hostPID` + # * `hostname` + # * `imagePullSecrets` + # * `nodeName` + # * `nodeSelector` + # * `overhead` + # * `preemptionPolicy` + # * `priority` + # * `priorityClassName` + # * `runtimeClassName` + # * `schedulerName` + # * `securityContext` + # * `serviceAccount` + # * `serviceAccountName` + # * `shareProcessNamespace` + # * `subdomain` + # * `tolerations` + # * `topologySpreadConstraints` + # * `volumes` + resource: + # The kind of Kubernetes resource to find. + kind: + + # The name of the resource, of the specified `kind`. If specified, you must also specify `kind`. + name: + + # A map of string key/value labels to match on any Pods in the namespace. When specified, a random ready Pod with + # matching labels will be picked as a target, so make sure the labels will always match a specific Pod type. + podSelector: + + # The name of a container in the target. Specify this if the target contains more than one container and the main + # container is not the first container in the spec. + containerName: + + # Time in seconds to wait for Helm to render templates. + timeout: 300 +``` + +## Configuration Keys + +### `apiVersion` + +The schema version of this config (currently not used). + +| Type | Allowed Values | Default | Required | +| -------- | -------------- | ---------------- | -------- | +| `string` | "garden.io/v0" | `"garden.io/v0"` | Yes | + +### `type` + +The type of action, e.g. `exec`, `container` or `kubernetes`. Some are built into Garden but mostly these will be defined by your configured providers. + +| Type | Required | +| -------- | -------- | +| `string` | Yes | + +### `name` + +A valid name for the action. Must be unique across all actions of the same _kind_ in your project. + +| Type | Required | +| -------- | -------- | +| `string` | Yes | + +### `description` + +A description of the action. + +| Type | Required | +| -------- | -------- | +| `string` | No | + +### `source` + +By default, the directory where the action is defined is used as the source for the build context. + +You can override this by setting either `source.path` to another (POSIX-style) path relative to the action source directory, or `source.repository` to get the source from an external repository. + +If using `source.path`, you must make sure the target path is in a git repository. + +For `source.repository` behavior, please refer to the [Remote Sources guide](https://docs.garden.io/advanced/using-remote-sources). + +| Type | Required | +| -------- | -------- | +| `object` | No | + +### `source.path` + +[source](#source) > path + +A relative POSIX-style path to the source directory for this action. You must make sure this path exists and is ina git repository! + +| Type | Required | +| ----------- | -------- | +| `posixPath` | No | + +### `source.repository` + +[source](#source) > repository + +When set, Garden will import the action source from this repository, but use this action configuration (and not scan for configs in the separate repository). + +| Type | Required | +| -------- | -------- | +| `object` | No | + +### `source.repository.url` + +[source](#source) > [repository](#sourcerepository) > url + +A remote repository URL. Currently only supports git servers. Must contain a hash suffix pointing to a specific branch or tag, with the format: # + +| Type | Required | +| ------------------ | -------- | +| `gitUrl \| string` | Yes | + +Example: + +```yaml +source: + ... + repository: + ... + url: "git+https://github.com/org/repo.git#v2.0" +``` + +### `dependencies[]` + +A list of other actions that this action depends on, and should be built, deployed or run (depending on the action type) before processing this action. + +Each dependency should generally be expressed as a `"."` string, where __ is one of `build`, `deploy`, `run` or `test`, and __ is the name of the action to depend on. + +You may also optionally specify a dependency as an object, e.g. `{ kind: "Build", name: "some-image" }`. + +Any empty values (i.e. null or empty strings) are ignored, so that you can conditionally add in a dependency via template expressions. + +| Type | Default | Required | +| ------------------------ | ------- | -------- | +| `array[actionReference]` | `[]` | No | + +Example: + +```yaml +dependencies: + - build.my-image + - deploy.api +``` + +### `disabled` + +Set this to `true` to disable the action. You can use this with conditional template strings to disable actions based on, for example, the current environment or other variables (e.g. `disabled: ${environment.name == "prod"}`). This can be handy when you only need certain actions for specific environments, e.g. only for development. + +For Build actions, this means the build is not performed _unless_ it is declared as a dependency by another enabled action (in which case the Build is assumed to be necessary for the dependant action to be run or built). + +For other action kinds, the action is skipped in all scenarios, and dependency declarations to it are ignored. Note however that template strings referencing outputs (i.e. runtime outputs) will fail to resolve when the action is disabled, so you need to make sure to provide alternate values for those if you're using them, using conditional expressions. + +| Type | Default | Required | +| --------- | ------- | -------- | +| `boolean` | `false` | No | + +### `include[]` + +Specify a list of POSIX-style paths or globs that should be regarded as source files for this action, and thus will affect the computed _version_ of the action. + +For actions other than _Build_ actions, this is usually not necessary to specify, or is implicitly inferred. An exception would be e.g. an `exec` action without a `build` reference, where the relevant files cannot be inferred and you want to define which files should affect the version of the action, e.g. to make sure a Test action is run when certain files are modified. + +_Build_ actions have a different behavior, since they generally are based on some files in the source tree, so please reference the docs for more information on those. + +Note that you can also _exclude_ files using the `exclude` field or by placing `.gardenignore` files in your source tree, which use the same format as `.gitignore` files. See the [Configuration Files guide](https://docs.garden.io/using-garden/configuration-overview#including-excluding-files-and-directories) for details. + +| Type | Required | +| ------------------ | -------- | +| `array[posixPath]` | No | + +Example: + +```yaml +include: + - my-app.js + - some-assets/**/* +``` + +### `exclude[]` + +Specify a list of POSIX-style paths or glob patterns that should be explicitly excluded from the action's version. + +For actions other than _Build_ actions, this is usually not necessary to specify, or is implicitly inferred. For _Deploy_, _Run_ and _Test_ actions, the exclusions specified here only applied on top of explicitly set `include` paths, or such paths inferred by providers. See the [Configuration Files guide](https://docs.garden.io/using-garden/configuration-overview#including-excluding-files-and-directories) for details. + +Unlike the `scan.exclude` field in the project config, the filters here have _no effect_ on which files and directories are watched for changes when watching is enabled. Use the project `scan.exclude` field to affect those, if you have large directories that should not be watched for changes. + +| Type | Required | +| ------------------ | -------- | +| `array[posixPath]` | No | + +Example: + +```yaml +exclude: + - tmp/**/* + - '*.log' +``` + +### `variables` + +A map of variables scoped to this particular action. These are resolved before any other parts of the action configuration and take precedence over group-scoped variables (if applicable) and project-scoped variables, in that order. They may reference group-scoped and project-scoped variables, and generally can use any template strings normally allowed when resolving the action. + +| Type | Required | +| -------- | -------- | +| `object` | No | + +### `varfiles[]` + +Specify a list of paths (relative to the directory where the action is defined) to a file containing variables, that we apply on top of the action-level `variables` field, and take precedence over group-level variables (if applicable) and project-level variables, in that order. + +If you specify multiple paths, they are merged in the order specified, i.e. the last one takes precedence over the previous ones. + +The format of the files is determined by the configured file's extension: + +* `.env` - Standard "dotenv" format, as defined by [dotenv](https://github.com/motdotla/dotenv#rules). +* `.yaml`/`.yml` - YAML. The file must consist of a YAML document, which must be a map (dictionary). Keys may contain any value type. +* `.json` - JSON. Must contain a single JSON _object_ (not an array). + +_NOTE: The default varfile format will change to YAML in Garden v0.13, since YAML allows for definition of nested objects and arrays._ + +To use different varfiles in different environments, you can template in the environment name to the varfile name, e.g. `varfile: "my-action.\$\{environment.name\}.env` (this assumes that the corresponding varfiles exist). + +If a listed varfile cannot be found, it is ignored. + +| Type | Default | Required | +| ------------------ | ------- | -------- | +| `array[posixPath]` | `[]` | No | + +Example: + +```yaml +varfiles: + "my-action.env" +``` + +### `build` + +Specify a _Build_ action, and resolve this action from the context of that Build. + +For example, you might create an `exec` Build which prepares some manifests, and then reference that in a `kubernetes` _Deploy_ action, and the resulting manifests from the Build. + +This would mean that instead of looking for manifest files relative to this action's location in your project structure, the output directory for the referenced `exec` Build would be the source. + +| Type | Required | +| -------- | -------- | +| `string` | No | + +### `kind` + +| Type | Allowed Values | Required | +| -------- | -------------- | -------- | +| `string` | "Run" | Yes | + +### `timeout` + +Set a timeout for the run to complete, in seconds. + +| Type | Required | +| -------- | -------- | +| `number` | No | + +### `spec` + +| Type | Required | +| -------- | -------- | +| `object` | No | + +### `spec.cacheResult` + +[spec](#spec) > cacheResult + +Set to false if you don't want the task's result to be cached. Use this if the task needs to be run any time your project (or one or more of the task's dependants) is deployed. Otherwise the task is only re-run when its version changes (i.e. the module or one of its dependencies is modified), or when you run `garden run`. + +| Type | Default | Required | +| --------- | ------- | -------- | +| `boolean` | `true` | No | + +### `spec.command[]` + +[spec](#spec) > command + +The command/entrypoint used to run inside the container. + +| Type | Required | +| --------------- | -------- | +| `array[string]` | No | + +Example: + +```yaml +spec: + ... + command: + - /bin/sh + - '-c' +``` + +### `spec.args[]` + +[spec](#spec) > args + +The arguments to pass to the command/entypoint used for execution. + +| Type | Required | +| --------------- | -------- | +| `array[string]` | No | + +Example: + +```yaml +spec: + ... + args: + - rake + - 'db:migrate' +``` + +### `spec.env` + +[spec](#spec) > env + +Key/value map of environment variables. Keys must be valid POSIX environment variable names (must not start with `GARDEN`) and values must be primitives or references to secrets. + +| Type | Default | Required | +| -------- | ------- | -------- | +| `object` | `{}` | No | + +Example: + +```yaml +spec: + ... + env: + - MY_VAR: some-value + MY_SECRET_VAR: + secretRef: + name: my-secret + key: some-key + - {} +``` + +### `spec.artifacts[]` + +[spec](#spec) > artifacts + +Specify artifacts to copy out of the container after the run. The artifacts are stored locally under +the `.garden/artifacts` directory. + +| Type | Default | Required | +| --------------- | ------- | -------- | +| `array[object]` | `[]` | No | + +### `spec.artifacts[].source` + +[spec](#spec) > [artifacts](#specartifacts) > source + +A POSIX-style path or glob to copy. Must be an absolute path. May contain wildcards. + +| Type | Required | +| ----------- | -------- | +| `posixPath` | Yes | + +Example: + +```yaml +spec: + ... + artifacts: + - source: "/output/**/*" +``` + +### `spec.artifacts[].target` + +[spec](#spec) > [artifacts](#specartifacts) > target + +A POSIX-style path to copy the artifacts to, relative to the project artifacts directory at `.garden/artifacts`. + +| Type | Default | Required | +| ----------- | ------- | -------- | +| `posixPath` | `"."` | No | + +Example: + +```yaml +spec: + ... + artifacts: + - target: "outputs/foo/" +``` + +### `spec.namespace` + +[spec](#spec) > namespace + +A valid Kubernetes namespace name. Must be a valid RFC1035/RFC1123 (DNS) label (may contain lowercase letters, numbers and dashes, must start with a letter, and cannot end with a dash) and must not be longer than 63 characters. + +| Type | Required | +| -------- | -------- | +| `string` | No | + +### `spec.releaseName` + +[spec](#spec) > releaseName + +Optionally override the release name used when rendering the templates (defaults to the Run name). + +| Type | Required | +| -------- | -------- | +| `string` | No | + +### `spec.chart` + +[spec](#spec) > chart + +Specify the Helm chart to use. + +If the chart is defined in the same directory as the action, you can skip this, and the chart sources will be detected. If the chart is in the source tree but in a sub-directory, you should set `chart.path` to the directory path, relative to the action directory. + +If the chart is remote, you must specify `chart.name` and `chart.version\, and optionally `chart.repo` (if the chart is not in the default "stable" repo). + +You may also specify an absolute URL to a packaged chart via `chart.url`. + +One of `chart.name`, `chart.path` or `chart.url` must be specified. + +| Type | Required | +| -------- | -------- | +| `object` | No | + +### `spec.chart.name` + +[spec](#spec) > [chart](#specchart) > name + +A valid Helm chart name or URI (same as you'd input to `helm install`) Required if the module doesn't contain the Helm chart itself. + +| Type | Required | +| -------- | -------- | +| `string` | No | + +Example: + +```yaml +spec: + ... + chart: + ... + name: "ingress-nginx" +``` + +### `spec.chart.path` + +[spec](#spec) > [chart](#specchart) > path + +The path, relative to the action path, to the chart sources (i.e. where the Chart.yaml file is, if any). + +| Type | Required | +| ----------- | -------- | +| `posixPath` | No | + +### `spec.chart.repo` + +[spec](#spec) > [chart](#specchart) > repo + +The repository URL to fetch the chart from. Defaults to the "stable" helm repo (https://charts.helm.sh/stable). + +| Type | Required | +| -------- | -------- | +| `string` | No | + +### `spec.chart.url` + +[spec](#spec) > [chart](#specchart) > url + +An absolute URL to a packaged URL. + +| Type | Required | +| -------- | -------- | +| `string` | No | + +### `spec.chart.version` + +[spec](#spec) > [chart](#specchart) > version + +The chart version to deploy. + +| Type | Required | +| -------- | -------- | +| `string` | No | + +### `spec.values` + +[spec](#spec) > values + +Map of values to pass to Helm when rendering the templates. May include arrays and nested objects. When specified, these take precedence over the values in the `values.yaml` file (or the files specified in `valueFiles`). + +| Type | Default | Required | +| -------- | ------- | -------- | +| `object` | `{}` | No | + +### `spec.valueFiles[]` + +[spec](#spec) > valueFiles + +Specify value files to use when rendering the Helm chart. These will take precedence over the `values.yaml` file +bundled in the Helm chart, and should be specified in ascending order of precedence. Meaning, the last file in +this list will have the highest precedence. + +If you _also_ specify keys under the `values` field, those will effectively be added as another file at the end +of this list, so they will take precedence over other files listed here. + +Note that the paths here should be relative to the _config_ root, and the files should be contained in +this action config's directory. + +| Type | Default | Required | +| ------------------ | ------- | -------- | +| `array[posixPath]` | `[]` | No | + +### `spec.resource` + +[spec](#spec) > resource + +Specify a Kubernetes resource to derive the Pod spec from for the Run. + +This resource will be selected from the manifests provided in this Run's `files` or `manifests` config field. + +The following fields from the Pod will be used (if present) when executing the Run: +* `affinity` +* `automountServiceAccountToken` +* `containers` +* `dnsConfig` +* `dnsPolicy` +* `enableServiceLinks` +* `hostAliases` +* `hostIPC` +* `hostNetwork` +* `hostPID` +* `hostname` +* `imagePullSecrets` +* `nodeName` +* `nodeSelector` +* `overhead` +* `preemptionPolicy` +* `priority` +* `priorityClassName` +* `runtimeClassName` +* `schedulerName` +* `securityContext` +* `serviceAccount` +* `serviceAccountName` +* `shareProcessNamespace` +* `subdomain` +* `tolerations` +* `topologySpreadConstraints` +* `volumes` + +| Type | Required | +| -------- | -------- | +| `object` | No | + +### `spec.resource.kind` + +[spec](#spec) > [resource](#specresource) > kind + +The kind of Kubernetes resource to find. + +| Type | Allowed Values | Required | +| -------- | ---------------------------------------- | -------- | +| `string` | "Deployment", "DaemonSet", "StatefulSet" | Yes | + +### `spec.resource.name` + +[spec](#spec) > [resource](#specresource) > name + +The name of the resource, of the specified `kind`. If specified, you must also specify `kind`. + +| Type | Required | +| -------- | -------- | +| `string` | No | + +### `spec.resource.podSelector` + +[spec](#spec) > [resource](#specresource) > podSelector + +A map of string key/value labels to match on any Pods in the namespace. When specified, a random ready Pod with matching labels will be picked as a target, so make sure the labels will always match a specific Pod type. + +| Type | Required | +| -------- | -------- | +| `object` | No | + +### `spec.resource.containerName` + +[spec](#spec) > [resource](#specresource) > containerName + +The name of a container in the target. Specify this if the target contains more than one container and the main container is not the first container in the spec. + +| Type | Required | +| -------- | -------- | +| `string` | No | + +### `spec.timeout` + +[spec](#spec) > timeout + +Time in seconds to wait for Helm to render templates. + +| Type | Default | Required | +| -------- | ------- | -------- | +| `number` | `300` | No | + + +## Outputs + +The following keys are available via the `${actions.run.}` template string key for `helm-pod` +modules. + +### `${actions.run..name}` + +The name of the action. + +| Type | +| -------- | +| `string` | + +### `${actions.run..disabled}` + +Whether the action is disabled. + +| Type | +| --------- | +| `boolean` | + +Example: + +```yaml +my-variable: ${actions.run.my-run.disabled} +``` + +### `${actions.run..buildPath}` + +The local path to the action build directory. + +| Type | +| -------- | +| `string` | + +Example: + +```yaml +my-variable: ${actions.run.my-run.buildPath} +``` + +### `${actions.run..sourcePath}` + +The local path to the action source directory. + +| Type | +| -------- | +| `string` | + +Example: + +```yaml +my-variable: ${actions.run.my-run.sourcePath} +``` + +### `${actions.run..mode}` + +The mode that the action should be executed in (e.g. 'sync' or 'local' for Deploy actions). Set to 'default' if no special mode is being used. + +| Type | Default | +| -------- | ----------- | +| `string` | `"default"` | + +Example: + +```yaml +my-variable: ${actions.run.my-run.mode} +``` + +### `${actions.run..var.*}` + +The variables configured on the action. + +| Type | Default | +| -------- | ------- | +| `object` | `{}` | + +### `${actions.run..var.}` + +| Type | +| ---------------------------------------------------- | +| `string \| number \| boolean \| link \| array[link]` | + +### `${actions.run..outputs.log}` + +The full log output from the executed action. (Pro-tip: Make it machine readable so it can be parsed by dependants) + +| Type | Default | +| -------- | ------- | +| `string` | `""` | diff --git a/docs/reference/action-types/Run/kubernetes-pod.md b/docs/reference/action-types/Run/kubernetes-pod.md index 40fffdad96..3c72afe089 100644 --- a/docs/reference/action-types/Run/kubernetes-pod.md +++ b/docs/reference/action-types/Run/kubernetes-pod.md @@ -7,9 +7,9 @@ tocTitle: "`kubernetes-pod` Run" ## Description -Run an ad-hoc instance of a Kubernetes Pod and wait for it to complete. +Executes a Run in an ad-hoc instance of a Kubernetes Pod and waits for it to complete. -TODO-G2 +The pod spec can be provided directly via the `podSpec` field, or the `resource` field can be used to find the pod spec in the Kubernetes manifests provided via the `files` and/or `manifests` fields. Below is the full schema reference for the action. For an introduction to configuring Garden, please look at our [Configuration guide](../../../using-garden/configuration-overview.md). @@ -186,12 +186,29 @@ spec: # characters. namespace: - # Specify a Kubernetes resource to derive the Pod spec from for the run. + # List of Kubernetes resource manifests to be searched (using `resource`e for the pod spec for the Run. If `files` + # is also specified, this is combined with the manifests read from the files. + manifests: + - # The API version of the resource. + apiVersion: + + # The kind of the resource. + kind: + + metadata: + # The name of the resource. + name: + + # POSIX-style paths to YAML files to load manifests from. Each can contain multiple manifests, and can include any + # Garden template strings, which will be resolved before searching the manifests for the resource that contains the + # Pod spec for the Run. + files: [] + + # Specify a Kubernetes resource to derive the Pod spec from for the Run. # - # This resource will be fetched from the target namespace, so you'll need to make sure it's been deployed previously - # (say, by configuring a dependency on a `helm` or `kubernetes` Deploy). + # This resource will be selected from the manifests provided in this Run's `files` or `manifests` config field. # - # The following fields from the Pod will be used (if present) when executing the task: + # The following fields from the Pod will be used (if present) when executing the Run: # * `affinity` # * `automountServiceAccountToken` # * `containers` @@ -236,10 +253,10 @@ spec: containerName: # Supply a custom Pod specification. This should be a normal Kubernetes Pod manifest. Note that the spec will be - # modified for the run, including overriding with other fields you may set here (such as `args` and `env`), and + # modified for the Run, including overriding with other fields you may set here (such as `args` and `env`), and # removing certain fields that are not supported. # - # The following Pod spec fields from the will be used (if present) when executing the task: + # The following Pod spec fields from the selected `resource` will be used (if present) when executing the Run: # * `affinity` # * `automountServiceAccountToken` # * `containers` @@ -923,15 +940,73 @@ A valid Kubernetes namespace name. Must be a valid RFC1035/RFC1123 (DNS) label ( | -------- | -------- | | `string` | No | +### `spec.manifests[]` + +[spec](#spec) > manifests + +List of Kubernetes resource manifests to be searched (using `resource`e for the pod spec for the Run. If `files` is also specified, this is combined with the manifests read from the files. + +| Type | Default | Required | +| --------------- | ------- | -------- | +| `array[object]` | `[]` | No | + +### `spec.manifests[].apiVersion` + +[spec](#spec) > [manifests](#specmanifests) > apiVersion + +The API version of the resource. + +| Type | Required | +| -------- | -------- | +| `string` | Yes | + +### `spec.manifests[].kind` + +[spec](#spec) > [manifests](#specmanifests) > kind + +The kind of the resource. + +| Type | Required | +| -------- | -------- | +| `string` | Yes | + +### `spec.manifests[].metadata` + +[spec](#spec) > [manifests](#specmanifests) > metadata + +| Type | Required | +| -------- | -------- | +| `object` | Yes | + +### `spec.manifests[].metadata.name` + +[spec](#spec) > [manifests](#specmanifests) > [metadata](#specmanifestsmetadata) > name + +The name of the resource. + +| Type | Required | +| -------- | -------- | +| `string` | Yes | + +### `spec.files[]` + +[spec](#spec) > files + +POSIX-style paths to YAML files to load manifests from. Each can contain multiple manifests, and can include any Garden template strings, which will be resolved before searching the manifests for the resource that contains the Pod spec for the Run. + +| Type | Default | Required | +| ------------------ | ------- | -------- | +| `array[posixPath]` | `[]` | No | + ### `spec.resource` [spec](#spec) > resource -Specify a Kubernetes resource to derive the Pod spec from for the run. +Specify a Kubernetes resource to derive the Pod spec from for the Run. -This resource will be fetched from the target namespace, so you'll need to make sure it's been deployed previously (say, by configuring a dependency on a `helm` or `kubernetes` Deploy). +This resource will be selected from the manifests provided in this Run's `files` or `manifests` config field. -The following fields from the Pod will be used (if present) when executing the task: +The following fields from the Pod will be used (if present) when executing the Run: * `affinity` * `automountServiceAccountToken` * `containers` @@ -1009,9 +1084,9 @@ The name of a container in the target. Specify this if the target contains more [spec](#spec) > podSpec -Supply a custom Pod specification. This should be a normal Kubernetes Pod manifest. Note that the spec will be modified for the run, including overriding with other fields you may set here (such as `args` and `env`), and removing certain fields that are not supported. +Supply a custom Pod specification. This should be a normal Kubernetes Pod manifest. Note that the spec will be modified for the Run, including overriding with other fields you may set here (such as `args` and `env`), and removing certain fields that are not supported. -The following Pod spec fields from the will be used (if present) when executing the task: +The following Pod spec fields from the selected `resource` will be used (if present) when executing the Run: * `affinity` * `automountServiceAccountToken` * `containers` diff --git a/docs/reference/action-types/Test/helm-pod.md b/docs/reference/action-types/Test/helm-pod.md new file mode 100644 index 0000000000..84e61cebe9 --- /dev/null +++ b/docs/reference/action-types/Test/helm-pod.md @@ -0,0 +1,952 @@ +--- +title: "`helm-pod` Test" +tocTitle: "`helm-pod` Test" +--- + +# `helm-pod` Test + +## Description + +Executes a Test in an ad-hoc instance of a Kubernetes Pod from a Helm chart and waits for it to complete. + +The `resource` field is used to find the Pod spec in the Kubernetes manifests generated by rendering the Helm chart. + +Below is the full schema reference for the action. For an introduction to configuring Garden, please look at our [Configuration +guide](../../../using-garden/configuration-overview.md). + +The [first section](#complete-yaml-schema) contains the complete YAML schema, and the [second section](#configuration-keys) describes each schema key. + +`helm-pod` actions also export values that are available in template strings. See the [Outputs](#outputs) section below for details. + +## Complete YAML Schema + +The values in the schema below are the default values. + +```yaml +# The schema version of this config (currently not used). +apiVersion: garden.io/v0 + +# The type of action, e.g. `exec`, `container` or `kubernetes`. Some are built into Garden but mostly these will be +# defined by your configured providers. +type: + +# A valid name for the action. Must be unique across all actions of the same _kind_ in your project. +name: + +# A description of the action. +description: + +# By default, the directory where the action is defined is used as the source for the build context. +# +# You can override this by setting either `source.path` to another (POSIX-style) path relative to the action source +# directory, or `source.repository` to get the source from an external repository. +# +# If using `source.path`, you must make sure the target path is in a git repository. +# +# For `source.repository` behavior, please refer to the [Remote Sources +# guide](https://docs.garden.io/advanced/using-remote-sources). +source: + # A relative POSIX-style path to the source directory for this action. You must make sure this path exists and is + # ina git repository! + path: + + # When set, Garden will import the action source from this repository, but use this action configuration (and not + # scan for configs in the separate repository). + repository: + # A remote repository URL. Currently only supports git servers. Must contain a hash suffix pointing to a specific + # branch or tag, with the format: # + url: + +# A list of other actions that this action depends on, and should be built, deployed or run (depending on the action +# type) before processing this action. +# +# Each dependency should generally be expressed as a `"."` string, where __ is one of `build`, +# `deploy`, `run` or `test`, and __ is the name of the action to depend on. +# +# You may also optionally specify a dependency as an object, e.g. `{ kind: "Build", name: "some-image" }`. +# +# Any empty values (i.e. null or empty strings) are ignored, so that you can conditionally add in a dependency via +# template expressions. +dependencies: [] + +# Set this to `true` to disable the action. You can use this with conditional template strings to disable actions +# based on, for example, the current environment or other variables (e.g. `disabled: ${environment.name == "prod"}`). +# This can be handy when you only need certain actions for specific environments, e.g. only for development. +# +# For Build actions, this means the build is not performed _unless_ it is declared as a dependency by another enabled +# action (in which case the Build is assumed to be necessary for the dependant action to be run or built). +# +# For other action kinds, the action is skipped in all scenarios, and dependency declarations to it are ignored. Note +# however that template strings referencing outputs (i.e. runtime outputs) will fail to resolve when the action is +# disabled, so you need to make sure to provide alternate values for those if you're using them, using conditional +# expressions. +disabled: false + +# Specify a list of POSIX-style paths or globs that should be regarded as source files for this action, and thus will +# affect the computed _version_ of the action. +# +# For actions other than _Build_ actions, this is usually not necessary to specify, or is implicitly inferred. An +# exception would be e.g. an `exec` action without a `build` reference, where the relevant files cannot be inferred +# and you want to define which files should affect the version of the action, e.g. to make sure a Test action is run +# when certain files are modified. +# +# _Build_ actions have a different behavior, since they generally are based on some files in the source tree, so +# please reference the docs for more information on those. +# +# Note that you can also _exclude_ files using the `exclude` field or by placing `.gardenignore` files in your source +# tree, which use the same format as `.gitignore` files. See the [Configuration Files +# guide](https://docs.garden.io/using-garden/configuration-overview#including-excluding-files-and-directories) for +# details. +include: + +# Specify a list of POSIX-style paths or glob patterns that should be explicitly excluded from the action's version. +# +# For actions other than _Build_ actions, this is usually not necessary to specify, or is implicitly inferred. For +# _Deploy_, _Run_ and _Test_ actions, the exclusions specified here only applied on top of explicitly set `include` +# paths, or such paths inferred by providers. See the [Configuration Files +# guide](https://docs.garden.io/using-garden/configuration-overview#including-excluding-files-and-directories) for +# details. +# +# Unlike the `scan.exclude` field in the project config, the filters here have _no effect_ on which files and +# directories are watched for changes when watching is enabled. Use the project `scan.exclude` field to affect those, +# if you have large directories that should not be watched for changes. +exclude: + +# A map of variables scoped to this particular action. These are resolved before any other parts of the action +# configuration and take precedence over group-scoped variables (if applicable) and project-scoped variables, in that +# order. They may reference group-scoped and project-scoped variables, and generally can use any template strings +# normally allowed when resolving the action. +variables: + +# Specify a list of paths (relative to the directory where the action is defined) to a file containing variables, that +# we apply on top of the action-level `variables` field, and take precedence over group-level variables (if +# applicable) and project-level variables, in that order. +# +# If you specify multiple paths, they are merged in the order specified, i.e. the last one takes precedence over the +# previous ones. +# +# The format of the files is determined by the configured file's extension: +# +# * `.env` - Standard "dotenv" format, as defined by [dotenv](https://github.com/motdotla/dotenv#rules). +# * `.yaml`/`.yml` - YAML. The file must consist of a YAML document, which must be a map (dictionary). Keys may +# contain any value type. +# * `.json` - JSON. Must contain a single JSON _object_ (not an array). +# +# _NOTE: The default varfile format will change to YAML in Garden v0.13, since YAML allows for definition of nested +# objects and arrays._ +# +# To use different varfiles in different environments, you can template in the environment name to the varfile name, +# e.g. `varfile: "my-action.\$\{environment.name\}.env` (this assumes that the corresponding varfiles exist). +# +# If a listed varfile cannot be found, it is ignored. +varfiles: [] + +# Specify a _Build_ action, and resolve this action from the context of that Build. +# +# For example, you might create an `exec` Build which prepares some manifests, and then reference that in a +# `kubernetes` _Deploy_ action, and the resulting manifests from the Build. +# +# This would mean that instead of looking for manifest files relative to this action's location in your project +# structure, the output directory for the referenced `exec` Build would be the source. +build: + +kind: + +# Set a timeout for the test to complete, in seconds. +timeout: + +spec: + # Set to false if you don't want the task's result to be cached. Use this if the task needs to be run any time your + # project (or one or more of the task's dependants) is deployed. Otherwise the task is only re-run when its version + # changes (i.e. the module or one of its dependencies is modified), or when you run `garden run`. + cacheResult: true + + # The command/entrypoint used to run inside the container. + command: + + # The arguments to pass to the command/entypoint used for execution. + args: + + # Key/value map of environment variables. Keys must be valid POSIX environment variable names (must not start with + # `GARDEN`) and values must be primitives or references to secrets. + env: {} + + # Specify artifacts to copy out of the container after the run. The artifacts are stored locally under + # the `.garden/artifacts` directory. + artifacts: + - # A POSIX-style path or glob to copy. Must be an absolute path. May contain wildcards. + source: + + # A POSIX-style path to copy the artifacts to, relative to the project artifacts directory at + # `.garden/artifacts`. + target: . + + # A valid Kubernetes namespace name. Must be a valid RFC1035/RFC1123 (DNS) label (may contain lowercase letters, + # numbers and dashes, must start with a letter, and cannot end with a dash) and must not be longer than 63 + # characters. + namespace: + + # Optionally override the release name used when rendering the templates (defaults to the Test name). + releaseName: + + # Specify the Helm chart to use. + # + # If the chart is defined in the same directory as the action, you can skip this, and the chart sources will be + # detected. If the chart is in the source tree but in a sub-directory, you should set `chart.path` to the directory + # path, relative to the action directory. + # + # If the chart is remote, you must specify `chart.name` and `chart.version\, and optionally `chart.repo` (if the + # chart is not in the default "stable" repo). + # + # You may also specify an absolute URL to a packaged chart via `chart.url`. + # + # One of `chart.name`, `chart.path` or `chart.url` must be specified. + chart: + # A valid Helm chart name or URI (same as you'd input to `helm install`) Required if the module doesn't contain + # the Helm chart itself. + name: + + # The path, relative to the action path, to the chart sources (i.e. where the Chart.yaml file is, if any). + path: + + # The repository URL to fetch the chart from. Defaults to the "stable" helm repo (https://charts.helm.sh/stable). + repo: + + # An absolute URL to a packaged URL. + url: + + # The chart version to deploy. + version: + + # Map of values to pass to Helm when rendering the templates. May include arrays and nested objects. When specified, + # these take precedence over the values in the `values.yaml` file (or the files specified in `valueFiles`). + values: {} + + # Specify value files to use when rendering the Helm chart. These will take precedence over the `values.yaml` file + # bundled in the Helm chart, and should be specified in ascending order of precedence. Meaning, the last file in + # this list will have the highest precedence. + # + # If you _also_ specify keys under the `values` field, those will effectively be added as another file at the end + # of this list, so they will take precedence over other files listed here. + # + # Note that the paths here should be relative to the _config_ root, and the files should be contained in + # this action config's directory. + valueFiles: [] + + # Specify a Kubernetes resource to derive the Pod spec from for the Run. + # + # This resource will be selected from the manifests provided in this Run's `files` or `manifests` config field. + # + # The following fields from the Pod will be used (if present) when executing the Run: + # * `affinity` + # * `automountServiceAccountToken` + # * `containers` + # * `dnsConfig` + # * `dnsPolicy` + # * `enableServiceLinks` + # * `hostAliases` + # * `hostIPC` + # * `hostNetwork` + # * `hostPID` + # * `hostname` + # * `imagePullSecrets` + # * `nodeName` + # * `nodeSelector` + # * `overhead` + # * `preemptionPolicy` + # * `priority` + # * `priorityClassName` + # * `runtimeClassName` + # * `schedulerName` + # * `securityContext` + # * `serviceAccount` + # * `serviceAccountName` + # * `shareProcessNamespace` + # * `subdomain` + # * `tolerations` + # * `topologySpreadConstraints` + # * `volumes` + resource: + # The kind of Kubernetes resource to find. + kind: + + # The name of the resource, of the specified `kind`. If specified, you must also specify `kind`. + name: + + # A map of string key/value labels to match on any Pods in the namespace. When specified, a random ready Pod with + # matching labels will be picked as a target, so make sure the labels will always match a specific Pod type. + podSelector: + + # The name of a container in the target. Specify this if the target contains more than one container and the main + # container is not the first container in the spec. + containerName: + + # Time in seconds to wait for Helm to render templates. + timeout: 300 +``` + +## Configuration Keys + +### `apiVersion` + +The schema version of this config (currently not used). + +| Type | Allowed Values | Default | Required | +| -------- | -------------- | ---------------- | -------- | +| `string` | "garden.io/v0" | `"garden.io/v0"` | Yes | + +### `type` + +The type of action, e.g. `exec`, `container` or `kubernetes`. Some are built into Garden but mostly these will be defined by your configured providers. + +| Type | Required | +| -------- | -------- | +| `string` | Yes | + +### `name` + +A valid name for the action. Must be unique across all actions of the same _kind_ in your project. + +| Type | Required | +| -------- | -------- | +| `string` | Yes | + +### `description` + +A description of the action. + +| Type | Required | +| -------- | -------- | +| `string` | No | + +### `source` + +By default, the directory where the action is defined is used as the source for the build context. + +You can override this by setting either `source.path` to another (POSIX-style) path relative to the action source directory, or `source.repository` to get the source from an external repository. + +If using `source.path`, you must make sure the target path is in a git repository. + +For `source.repository` behavior, please refer to the [Remote Sources guide](https://docs.garden.io/advanced/using-remote-sources). + +| Type | Required | +| -------- | -------- | +| `object` | No | + +### `source.path` + +[source](#source) > path + +A relative POSIX-style path to the source directory for this action. You must make sure this path exists and is ina git repository! + +| Type | Required | +| ----------- | -------- | +| `posixPath` | No | + +### `source.repository` + +[source](#source) > repository + +When set, Garden will import the action source from this repository, but use this action configuration (and not scan for configs in the separate repository). + +| Type | Required | +| -------- | -------- | +| `object` | No | + +### `source.repository.url` + +[source](#source) > [repository](#sourcerepository) > url + +A remote repository URL. Currently only supports git servers. Must contain a hash suffix pointing to a specific branch or tag, with the format: # + +| Type | Required | +| ------------------ | -------- | +| `gitUrl \| string` | Yes | + +Example: + +```yaml +source: + ... + repository: + ... + url: "git+https://github.com/org/repo.git#v2.0" +``` + +### `dependencies[]` + +A list of other actions that this action depends on, and should be built, deployed or run (depending on the action type) before processing this action. + +Each dependency should generally be expressed as a `"."` string, where __ is one of `build`, `deploy`, `run` or `test`, and __ is the name of the action to depend on. + +You may also optionally specify a dependency as an object, e.g. `{ kind: "Build", name: "some-image" }`. + +Any empty values (i.e. null or empty strings) are ignored, so that you can conditionally add in a dependency via template expressions. + +| Type | Default | Required | +| ------------------------ | ------- | -------- | +| `array[actionReference]` | `[]` | No | + +Example: + +```yaml +dependencies: + - build.my-image + - deploy.api +``` + +### `disabled` + +Set this to `true` to disable the action. You can use this with conditional template strings to disable actions based on, for example, the current environment or other variables (e.g. `disabled: ${environment.name == "prod"}`). This can be handy when you only need certain actions for specific environments, e.g. only for development. + +For Build actions, this means the build is not performed _unless_ it is declared as a dependency by another enabled action (in which case the Build is assumed to be necessary for the dependant action to be run or built). + +For other action kinds, the action is skipped in all scenarios, and dependency declarations to it are ignored. Note however that template strings referencing outputs (i.e. runtime outputs) will fail to resolve when the action is disabled, so you need to make sure to provide alternate values for those if you're using them, using conditional expressions. + +| Type | Default | Required | +| --------- | ------- | -------- | +| `boolean` | `false` | No | + +### `include[]` + +Specify a list of POSIX-style paths or globs that should be regarded as source files for this action, and thus will affect the computed _version_ of the action. + +For actions other than _Build_ actions, this is usually not necessary to specify, or is implicitly inferred. An exception would be e.g. an `exec` action without a `build` reference, where the relevant files cannot be inferred and you want to define which files should affect the version of the action, e.g. to make sure a Test action is run when certain files are modified. + +_Build_ actions have a different behavior, since they generally are based on some files in the source tree, so please reference the docs for more information on those. + +Note that you can also _exclude_ files using the `exclude` field or by placing `.gardenignore` files in your source tree, which use the same format as `.gitignore` files. See the [Configuration Files guide](https://docs.garden.io/using-garden/configuration-overview#including-excluding-files-and-directories) for details. + +| Type | Required | +| ------------------ | -------- | +| `array[posixPath]` | No | + +Example: + +```yaml +include: + - my-app.js + - some-assets/**/* +``` + +### `exclude[]` + +Specify a list of POSIX-style paths or glob patterns that should be explicitly excluded from the action's version. + +For actions other than _Build_ actions, this is usually not necessary to specify, or is implicitly inferred. For _Deploy_, _Run_ and _Test_ actions, the exclusions specified here only applied on top of explicitly set `include` paths, or such paths inferred by providers. See the [Configuration Files guide](https://docs.garden.io/using-garden/configuration-overview#including-excluding-files-and-directories) for details. + +Unlike the `scan.exclude` field in the project config, the filters here have _no effect_ on which files and directories are watched for changes when watching is enabled. Use the project `scan.exclude` field to affect those, if you have large directories that should not be watched for changes. + +| Type | Required | +| ------------------ | -------- | +| `array[posixPath]` | No | + +Example: + +```yaml +exclude: + - tmp/**/* + - '*.log' +``` + +### `variables` + +A map of variables scoped to this particular action. These are resolved before any other parts of the action configuration and take precedence over group-scoped variables (if applicable) and project-scoped variables, in that order. They may reference group-scoped and project-scoped variables, and generally can use any template strings normally allowed when resolving the action. + +| Type | Required | +| -------- | -------- | +| `object` | No | + +### `varfiles[]` + +Specify a list of paths (relative to the directory where the action is defined) to a file containing variables, that we apply on top of the action-level `variables` field, and take precedence over group-level variables (if applicable) and project-level variables, in that order. + +If you specify multiple paths, they are merged in the order specified, i.e. the last one takes precedence over the previous ones. + +The format of the files is determined by the configured file's extension: + +* `.env` - Standard "dotenv" format, as defined by [dotenv](https://github.com/motdotla/dotenv#rules). +* `.yaml`/`.yml` - YAML. The file must consist of a YAML document, which must be a map (dictionary). Keys may contain any value type. +* `.json` - JSON. Must contain a single JSON _object_ (not an array). + +_NOTE: The default varfile format will change to YAML in Garden v0.13, since YAML allows for definition of nested objects and arrays._ + +To use different varfiles in different environments, you can template in the environment name to the varfile name, e.g. `varfile: "my-action.\$\{environment.name\}.env` (this assumes that the corresponding varfiles exist). + +If a listed varfile cannot be found, it is ignored. + +| Type | Default | Required | +| ------------------ | ------- | -------- | +| `array[posixPath]` | `[]` | No | + +Example: + +```yaml +varfiles: + "my-action.env" +``` + +### `build` + +Specify a _Build_ action, and resolve this action from the context of that Build. + +For example, you might create an `exec` Build which prepares some manifests, and then reference that in a `kubernetes` _Deploy_ action, and the resulting manifests from the Build. + +This would mean that instead of looking for manifest files relative to this action's location in your project structure, the output directory for the referenced `exec` Build would be the source. + +| Type | Required | +| -------- | -------- | +| `string` | No | + +### `kind` + +| Type | Allowed Values | Required | +| -------- | -------------- | -------- | +| `string` | "Test" | Yes | + +### `timeout` + +Set a timeout for the test to complete, in seconds. + +| Type | Required | +| -------- | -------- | +| `number` | No | + +### `spec` + +| Type | Required | +| -------- | -------- | +| `object` | No | + +### `spec.cacheResult` + +[spec](#spec) > cacheResult + +Set to false if you don't want the task's result to be cached. Use this if the task needs to be run any time your project (or one or more of the task's dependants) is deployed. Otherwise the task is only re-run when its version changes (i.e. the module or one of its dependencies is modified), or when you run `garden run`. + +| Type | Default | Required | +| --------- | ------- | -------- | +| `boolean` | `true` | No | + +### `spec.command[]` + +[spec](#spec) > command + +The command/entrypoint used to run inside the container. + +| Type | Required | +| --------------- | -------- | +| `array[string]` | No | + +Example: + +```yaml +spec: + ... + command: + - /bin/sh + - '-c' +``` + +### `spec.args[]` + +[spec](#spec) > args + +The arguments to pass to the command/entypoint used for execution. + +| Type | Required | +| --------------- | -------- | +| `array[string]` | No | + +Example: + +```yaml +spec: + ... + args: + - rake + - 'db:migrate' +``` + +### `spec.env` + +[spec](#spec) > env + +Key/value map of environment variables. Keys must be valid POSIX environment variable names (must not start with `GARDEN`) and values must be primitives or references to secrets. + +| Type | Default | Required | +| -------- | ------- | -------- | +| `object` | `{}` | No | + +Example: + +```yaml +spec: + ... + env: + - MY_VAR: some-value + MY_SECRET_VAR: + secretRef: + name: my-secret + key: some-key + - {} +``` + +### `spec.artifacts[]` + +[spec](#spec) > artifacts + +Specify artifacts to copy out of the container after the run. The artifacts are stored locally under +the `.garden/artifacts` directory. + +| Type | Default | Required | +| --------------- | ------- | -------- | +| `array[object]` | `[]` | No | + +### `spec.artifacts[].source` + +[spec](#spec) > [artifacts](#specartifacts) > source + +A POSIX-style path or glob to copy. Must be an absolute path. May contain wildcards. + +| Type | Required | +| ----------- | -------- | +| `posixPath` | Yes | + +Example: + +```yaml +spec: + ... + artifacts: + - source: "/output/**/*" +``` + +### `spec.artifacts[].target` + +[spec](#spec) > [artifacts](#specartifacts) > target + +A POSIX-style path to copy the artifacts to, relative to the project artifacts directory at `.garden/artifacts`. + +| Type | Default | Required | +| ----------- | ------- | -------- | +| `posixPath` | `"."` | No | + +Example: + +```yaml +spec: + ... + artifacts: + - target: "outputs/foo/" +``` + +### `spec.namespace` + +[spec](#spec) > namespace + +A valid Kubernetes namespace name. Must be a valid RFC1035/RFC1123 (DNS) label (may contain lowercase letters, numbers and dashes, must start with a letter, and cannot end with a dash) and must not be longer than 63 characters. + +| Type | Required | +| -------- | -------- | +| `string` | No | + +### `spec.releaseName` + +[spec](#spec) > releaseName + +Optionally override the release name used when rendering the templates (defaults to the Test name). + +| Type | Required | +| -------- | -------- | +| `string` | No | + +### `spec.chart` + +[spec](#spec) > chart + +Specify the Helm chart to use. + +If the chart is defined in the same directory as the action, you can skip this, and the chart sources will be detected. If the chart is in the source tree but in a sub-directory, you should set `chart.path` to the directory path, relative to the action directory. + +If the chart is remote, you must specify `chart.name` and `chart.version\, and optionally `chart.repo` (if the chart is not in the default "stable" repo). + +You may also specify an absolute URL to a packaged chart via `chart.url`. + +One of `chart.name`, `chart.path` or `chart.url` must be specified. + +| Type | Required | +| -------- | -------- | +| `object` | No | + +### `spec.chart.name` + +[spec](#spec) > [chart](#specchart) > name + +A valid Helm chart name or URI (same as you'd input to `helm install`) Required if the module doesn't contain the Helm chart itself. + +| Type | Required | +| -------- | -------- | +| `string` | No | + +Example: + +```yaml +spec: + ... + chart: + ... + name: "ingress-nginx" +``` + +### `spec.chart.path` + +[spec](#spec) > [chart](#specchart) > path + +The path, relative to the action path, to the chart sources (i.e. where the Chart.yaml file is, if any). + +| Type | Required | +| ----------- | -------- | +| `posixPath` | No | + +### `spec.chart.repo` + +[spec](#spec) > [chart](#specchart) > repo + +The repository URL to fetch the chart from. Defaults to the "stable" helm repo (https://charts.helm.sh/stable). + +| Type | Required | +| -------- | -------- | +| `string` | No | + +### `spec.chart.url` + +[spec](#spec) > [chart](#specchart) > url + +An absolute URL to a packaged URL. + +| Type | Required | +| -------- | -------- | +| `string` | No | + +### `spec.chart.version` + +[spec](#spec) > [chart](#specchart) > version + +The chart version to deploy. + +| Type | Required | +| -------- | -------- | +| `string` | No | + +### `spec.values` + +[spec](#spec) > values + +Map of values to pass to Helm when rendering the templates. May include arrays and nested objects. When specified, these take precedence over the values in the `values.yaml` file (or the files specified in `valueFiles`). + +| Type | Default | Required | +| -------- | ------- | -------- | +| `object` | `{}` | No | + +### `spec.valueFiles[]` + +[spec](#spec) > valueFiles + +Specify value files to use when rendering the Helm chart. These will take precedence over the `values.yaml` file +bundled in the Helm chart, and should be specified in ascending order of precedence. Meaning, the last file in +this list will have the highest precedence. + +If you _also_ specify keys under the `values` field, those will effectively be added as another file at the end +of this list, so they will take precedence over other files listed here. + +Note that the paths here should be relative to the _config_ root, and the files should be contained in +this action config's directory. + +| Type | Default | Required | +| ------------------ | ------- | -------- | +| `array[posixPath]` | `[]` | No | + +### `spec.resource` + +[spec](#spec) > resource + +Specify a Kubernetes resource to derive the Pod spec from for the Run. + +This resource will be selected from the manifests provided in this Run's `files` or `manifests` config field. + +The following fields from the Pod will be used (if present) when executing the Run: +* `affinity` +* `automountServiceAccountToken` +* `containers` +* `dnsConfig` +* `dnsPolicy` +* `enableServiceLinks` +* `hostAliases` +* `hostIPC` +* `hostNetwork` +* `hostPID` +* `hostname` +* `imagePullSecrets` +* `nodeName` +* `nodeSelector` +* `overhead` +* `preemptionPolicy` +* `priority` +* `priorityClassName` +* `runtimeClassName` +* `schedulerName` +* `securityContext` +* `serviceAccount` +* `serviceAccountName` +* `shareProcessNamespace` +* `subdomain` +* `tolerations` +* `topologySpreadConstraints` +* `volumes` + +| Type | Required | +| -------- | -------- | +| `object` | No | + +### `spec.resource.kind` + +[spec](#spec) > [resource](#specresource) > kind + +The kind of Kubernetes resource to find. + +| Type | Allowed Values | Required | +| -------- | ---------------------------------------- | -------- | +| `string` | "Deployment", "DaemonSet", "StatefulSet" | Yes | + +### `spec.resource.name` + +[spec](#spec) > [resource](#specresource) > name + +The name of the resource, of the specified `kind`. If specified, you must also specify `kind`. + +| Type | Required | +| -------- | -------- | +| `string` | No | + +### `spec.resource.podSelector` + +[spec](#spec) > [resource](#specresource) > podSelector + +A map of string key/value labels to match on any Pods in the namespace. When specified, a random ready Pod with matching labels will be picked as a target, so make sure the labels will always match a specific Pod type. + +| Type | Required | +| -------- | -------- | +| `object` | No | + +### `spec.resource.containerName` + +[spec](#spec) > [resource](#specresource) > containerName + +The name of a container in the target. Specify this if the target contains more than one container and the main container is not the first container in the spec. + +| Type | Required | +| -------- | -------- | +| `string` | No | + +### `spec.timeout` + +[spec](#spec) > timeout + +Time in seconds to wait for Helm to render templates. + +| Type | Default | Required | +| -------- | ------- | -------- | +| `number` | `300` | No | + + +## Outputs + +The following keys are available via the `${actions.test.}` template string key for `helm-pod` +modules. + +### `${actions.test..name}` + +The name of the action. + +| Type | +| -------- | +| `string` | + +### `${actions.test..disabled}` + +Whether the action is disabled. + +| Type | +| --------- | +| `boolean` | + +Example: + +```yaml +my-variable: ${actions.test.my-test.disabled} +``` + +### `${actions.test..buildPath}` + +The local path to the action build directory. + +| Type | +| -------- | +| `string` | + +Example: + +```yaml +my-variable: ${actions.test.my-test.buildPath} +``` + +### `${actions.test..sourcePath}` + +The local path to the action source directory. + +| Type | +| -------- | +| `string` | + +Example: + +```yaml +my-variable: ${actions.test.my-test.sourcePath} +``` + +### `${actions.test..mode}` + +The mode that the action should be executed in (e.g. 'sync' or 'local' for Deploy actions). Set to 'default' if no special mode is being used. + +| Type | Default | +| -------- | ----------- | +| `string` | `"default"` | + +Example: + +```yaml +my-variable: ${actions.test.my-test.mode} +``` + +### `${actions.test..var.*}` + +The variables configured on the action. + +| Type | Default | +| -------- | ------- | +| `object` | `{}` | + +### `${actions.test..var.}` + +| Type | +| ---------------------------------------------------- | +| `string \| number \| boolean \| link \| array[link]` | + +### `${actions.test..outputs.log}` + +The full log output from the executed action. (Pro-tip: Make it machine readable so it can be parsed by dependants) + +| Type | Default | +| -------- | ------- | +| `string` | `""` | diff --git a/docs/reference/action-types/Test/kubernetes-pod.md b/docs/reference/action-types/Test/kubernetes-pod.md index 6771aa0008..8285689c8b 100644 --- a/docs/reference/action-types/Test/kubernetes-pod.md +++ b/docs/reference/action-types/Test/kubernetes-pod.md @@ -7,9 +7,9 @@ tocTitle: "`kubernetes-pod` Test" ## Description -Run a test in an ad-hoc instance of a Kubernetes Pod. +Executes a Test in an ad-hoc instance of a Kubernetes Pod and waits for it to complete. -TODO-G2 +The pod spec can be provided directly via the `podSpec` field, or the `resource` field can be used to find the pod spec in the Kubernetes manifests provided via the `files` and/or `manifests` fields. Below is the full schema reference for the action. For an introduction to configuring Garden, please look at our [Configuration guide](../../../using-garden/configuration-overview.md). @@ -186,12 +186,29 @@ spec: # characters. namespace: - # Specify a Kubernetes resource to derive the Pod spec from for the run. + # List of Kubernetes resource manifests to be searched (using `resource`e for the pod spec for the Test. If `files` + # is also specified, this is combined with the manifests read from the files. + manifests: + - # The API version of the resource. + apiVersion: + + # The kind of the resource. + kind: + + metadata: + # The name of the resource. + name: + + # POSIX-style paths to YAML files to load manifests from. Each can contain multiple manifests, and can include any + # Garden template strings, which will be resolved before searching the manifests for the resource that contains the + # Pod spec for the Test. + files: [] + + # Specify a Kubernetes resource to derive the Pod spec from for the Test. # - # This resource will be fetched from the target namespace, so you'll need to make sure it's been deployed previously - # (say, by configuring a dependency on a `helm` or `kubernetes` Deploy). + # This resource will be selected from the manifests provided in this Test's `files` or `manifests` config field. # - # The following fields from the Pod will be used (if present) when executing the task: + # The following fields from the Pod will be used (if present) when executing the Test: # * `affinity` # * `automountServiceAccountToken` # * `containers` @@ -236,10 +253,10 @@ spec: containerName: # Supply a custom Pod specification. This should be a normal Kubernetes Pod manifest. Note that the spec will be - # modified for the run, including overriding with other fields you may set here (such as `args` and `env`), and + # modified for the Test, including overriding with other fields you may set here (such as `args` and `env`), and # removing certain fields that are not supported. # - # The following Pod spec fields from the will be used (if present) when executing the task: + # The following Pod spec fields from the selected `resource` will be used (if present) when executing the Test: # * `affinity` # * `automountServiceAccountToken` # * `containers` @@ -923,15 +940,73 @@ A valid Kubernetes namespace name. Must be a valid RFC1035/RFC1123 (DNS) label ( | -------- | -------- | | `string` | No | +### `spec.manifests[]` + +[spec](#spec) > manifests + +List of Kubernetes resource manifests to be searched (using `resource`e for the pod spec for the Test. If `files` is also specified, this is combined with the manifests read from the files. + +| Type | Default | Required | +| --------------- | ------- | -------- | +| `array[object]` | `[]` | No | + +### `spec.manifests[].apiVersion` + +[spec](#spec) > [manifests](#specmanifests) > apiVersion + +The API version of the resource. + +| Type | Required | +| -------- | -------- | +| `string` | Yes | + +### `spec.manifests[].kind` + +[spec](#spec) > [manifests](#specmanifests) > kind + +The kind of the resource. + +| Type | Required | +| -------- | -------- | +| `string` | Yes | + +### `spec.manifests[].metadata` + +[spec](#spec) > [manifests](#specmanifests) > metadata + +| Type | Required | +| -------- | -------- | +| `object` | Yes | + +### `spec.manifests[].metadata.name` + +[spec](#spec) > [manifests](#specmanifests) > [metadata](#specmanifestsmetadata) > name + +The name of the resource. + +| Type | Required | +| -------- | -------- | +| `string` | Yes | + +### `spec.files[]` + +[spec](#spec) > files + +POSIX-style paths to YAML files to load manifests from. Each can contain multiple manifests, and can include any Garden template strings, which will be resolved before searching the manifests for the resource that contains the Pod spec for the Test. + +| Type | Default | Required | +| ------------------ | ------- | -------- | +| `array[posixPath]` | `[]` | No | + ### `spec.resource` [spec](#spec) > resource -Specify a Kubernetes resource to derive the Pod spec from for the run. +Specify a Kubernetes resource to derive the Pod spec from for the Test. -This resource will be fetched from the target namespace, so you'll need to make sure it's been deployed previously (say, by configuring a dependency on a `helm` or `kubernetes` Deploy). +This resource will be selected from the manifests provided in this Test's `files` or `manifests` config field. -The following fields from the Pod will be used (if present) when executing the task: +The following fields from the Pod will be used (if present) when executing the Test: * `affinity` * `automountServiceAccountToken` * `containers` @@ -1009,9 +1084,9 @@ The name of a container in the target. Specify this if the target contains more [spec](#spec) > podSpec -Supply a custom Pod specification. This should be a normal Kubernetes Pod manifest. Note that the spec will be modified for the run, including overriding with other fields you may set here (such as `args` and `env`), and removing certain fields that are not supported. +Supply a custom Pod specification. This should be a normal Kubernetes Pod manifest. Note that the spec will be modified for the Test, including overriding with other fields you may set here (such as `args` and `env`), and removing certain fields that are not supported. -The following Pod spec fields from the will be used (if present) when executing the task: +The following Pod spec fields from the selected `resource` will be used (if present) when executing the Test: * `affinity` * `automountServiceAccountToken` * `containers` diff --git a/docs/reference/module-types/helm.md b/docs/reference/module-types/helm.md index f056852c24..4232310e3e 100644 --- a/docs/reference/module-types/helm.md +++ b/docs/reference/module-types/helm.md @@ -186,7 +186,7 @@ portForwards: # not available, a warning is shown and a random port chosen instead. localPort: -# Optionally override the release name used when installing (defaults to the module name). +# Optionally override the release name used when installing (defaults to the Deploy name). releaseName: # Time in seconds to wait for Helm to complete any individual Kubernetes operation (like Jobs for hooks). @@ -203,8 +203,8 @@ values: {} # If you _also_ specify keys under the `values` field, those will effectively be added as another file at the end # of this list, so they will take precedence over other files listed here. # -# Note that the paths here should be relative to the _module_ root, and the files should be contained in -# your module directory. +# Note that the paths here should be relative to the _config_ root, and the files should be contained in +# this action config's directory. valueFiles: [] # The name of another `helm` module to use as a base for this one. Use this to re-use a Helm chart across multiple @@ -972,7 +972,7 @@ The _preferred_ local port to forward from. If none is set, a random port is cho ### `releaseName` -Optionally override the release name used when installing (defaults to the module name). +Optionally override the release name used when installing (defaults to the Deploy name). | Type | Required | | -------- | -------- | @@ -1003,8 +1003,8 @@ this list will have the highest precedence. If you _also_ specify keys under the `values` field, those will effectively be added as another file at the end of this list, so they will take precedence over other files listed here. -Note that the paths here should be relative to the _module_ root, and the files should be contained in -your module directory. +Note that the paths here should be relative to the _config_ root, and the files should be contained in +this action config's directory. | Type | Default | Required | | ------------------ | ------- | -------- |