diff --git a/core/src/plugins/kubernetes/config.ts b/core/src/plugins/kubernetes/config.ts index ce09f943c6..068155de94 100644 --- a/core/src/plugins/kubernetes/config.ts +++ b/core/src/plugins/kubernetes/config.ts @@ -27,6 +27,7 @@ import { baseTaskSpecSchema, BaseTaskSpec, cacheResultSchema } from "../../confi import { baseTestSpecSchema, BaseTestSpec } from "../../config/test" import { ArtifactSpec } from "../../config/validation" import { V1Toleration } from "@kubernetes/client-node" +import { runPodSpecWhitelist } from "./run" export const DEFAULT_KANIKO_IMAGE = "gcr.io/kaniko-project/executor:debug-v1.2.0" export interface ProviderSecretRef { @@ -642,13 +643,18 @@ export const hotReloadArgsSchema = () => .description("If specified, overrides the arguments for the main container when running in hot-reload mode.") .example(["nodemon", "my-server.js"]) +const runPodSpecWhitelistDescription = runPodSpecWhitelist.map((f) => `* \`${f}\``).join("\n") + export const kubernetesTaskSchema = () => baseTaskSpecSchema() .keys({ resource: serviceResourceSchema().description( - deline`The Deployment, DaemonSet or StatefulSet that Garden should use to execute this task. + dedent`The Deployment, DaemonSet or StatefulSet that Garden should use to execute this task. If not specified, the \`serviceResource\` configured on the module will be used. If neither is specified, - an error will be thrown.` + an error will be thrown. + + The following pod spec fields from the service resource will be used (if present) when executing the task: + ${runPodSpecWhitelistDescription}` ), cacheResult: cacheResultSchema(), command: joi @@ -670,9 +676,12 @@ export const kubernetesTestSchema = () => baseTestSpecSchema() .keys({ resource: serviceResourceSchema().description( - deline`The Deployment, DaemonSet or StatefulSet that Garden should use to execute this test suite. + dedent`The Deployment, DaemonSet or StatefulSet that Garden should use to execute this test suite. If not specified, the \`serviceResource\` configured on the module will be used. If neither is specified, - an error will be thrown.` + an error will be thrown. + + The following pod spec fields from the service resource will be used (if present) when executing the test suite: + ${runPodSpecWhitelistDescription}` ), command: joi .array() diff --git a/core/src/plugins/kubernetes/helm/config.ts b/core/src/plugins/kubernetes/helm/config.ts index 8db6af2a3c..83c32b0fd8 100644 --- a/core/src/plugins/kubernetes/helm/config.ts +++ b/core/src/plugins/kubernetes/helm/config.ts @@ -35,6 +35,7 @@ import { hotReloadArgsSchema, } from "../config" import { posix } from "path" +import { runPodSpecWhitelist } from "../run" export const defaultHelmTimeout = 300 @@ -82,7 +83,7 @@ export const helmModuleOutputsSchema = () => const helmServiceResourceSchema = () => serviceResourceSchema().keys({ name: joi.string().description( - deline`The name of the resource to sync to. If the chart contains a single resource of the specified Kind, + dedent`The name of the resource to sync to. If the chart contains a single resource of the specified Kind, this can be omitted. This can include a Helm template string, e.g. '{{ template "my-chart.fullname" . }}'. @@ -94,21 +95,29 @@ const helmServiceResourceSchema = () => hotReloadArgs: hotReloadArgsSchema(), }) +const runPodSpecWhitelistDescription = runPodSpecWhitelist.map((f) => `* \`${f}\``).join("\n") + const helmTaskSchema = () => kubernetesTaskSchema().keys({ resource: helmServiceResourceSchema().description( - deline`The Deployment, DaemonSet or StatefulSet that Garden should use to execute this task. + dedent`The Deployment, DaemonSet or StatefulSet that Garden should use to execute this task. If not specified, the \`serviceResource\` configured on the module will be used. If neither is specified, - an error will be thrown.` + an error will be thrown. + + The following pod spec fields from the service resource will be used (if present) when executing the task: + ${runPodSpecWhitelistDescription}` ), }) const helmTestSchema = () => kubernetesTestSchema().keys({ resource: helmServiceResourceSchema().description( - deline`The Deployment, DaemonSet or StatefulSet that Garden should use to execute this test suite. + dedent`The Deployment, DaemonSet or StatefulSet that Garden should use to execute this test suite. If not specified, the \`serviceResource\` configured on the module will be used. If neither is specified, - an error will be thrown.` + an error will be thrown. + + The following pod spec fields from the service resource will be used (if present) when executing the test suite: + ${runPodSpecWhitelistDescription}` ), }) diff --git a/core/src/plugins/kubernetes/helm/run.ts b/core/src/plugins/kubernetes/helm/run.ts index 66d9c8d406..be929db9c9 100644 --- a/core/src/plugins/kubernetes/helm/run.ts +++ b/core/src/plugins/kubernetes/helm/run.ts @@ -9,7 +9,13 @@ import { HelmModule } from "./config" import { PodRunner, runAndCopy } from "../run" import { getChartResources, getBaseModule } from "./common" -import { findServiceResource, getResourceContainer, getServiceResourceSpec, makePodName } from "../util" +import { + findServiceResource, + getResourceContainer, + getResourcePodSpec, + getServiceResourceSpec, + makePodName, +} from "../util" import { ConfigurationError } from "../../../exceptions" import { KubernetesPluginContext } from "../config" import { storeTaskResult } from "../task-results" @@ -137,6 +143,7 @@ export async function runHelmTask(params: RunTaskParams): Promise): Promise { @@ -42,6 +48,7 @@ export async function testHelmModule(params: TestModuleParams): Prom const result = await runAndCopy({ ...params, container, + podSpec: getResourcePodSpec(target), command, args, artifacts: testConfig.spec.artifacts, diff --git a/core/src/plugins/kubernetes/kubernetes-module/run.ts b/core/src/plugins/kubernetes/kubernetes-module/run.ts index a95c0fa558..5092db0e72 100644 --- a/core/src/plugins/kubernetes/kubernetes-module/run.ts +++ b/core/src/plugins/kubernetes/kubernetes-module/run.ts @@ -8,7 +8,13 @@ import { KubernetesModule } from "./config" import { runAndCopy } from "../run" -import { findServiceResource, getResourceContainer, getServiceResourceSpec, makePodName } from "../util" +import { + findServiceResource, + getResourceContainer, + getResourcePodSpec, + getServiceResourceSpec, + makePodName, +} from "../util" import { KubernetesPluginContext } from "../config" import { storeTaskResult } from "../task-results" import { RunTaskParams, RunTaskResult } from "../../../types/plugin/task/runTask" @@ -45,6 +51,7 @@ export async function runKubernetesTask(params: RunTaskParams) const res = await runAndCopy({ ...params, container, + podSpec: getResourcePodSpec(target), command, args, artifacts: task.spec.artifacts, diff --git a/core/src/plugins/kubernetes/kubernetes-module/test.ts b/core/src/plugins/kubernetes/kubernetes-module/test.ts index a08a249672..c7d1c67065 100644 --- a/core/src/plugins/kubernetes/kubernetes-module/test.ts +++ b/core/src/plugins/kubernetes/kubernetes-module/test.ts @@ -16,7 +16,13 @@ import { TestResult } from "../../../types/plugin/module/getTestResult" import { getModuleNamespace } from "../namespace" import { KubeApi } from "../api" import { getManifests } from "./common" -import { getServiceResourceSpec, findServiceResource, getResourceContainer, makePodName } from "../util" +import { + getServiceResourceSpec, + findServiceResource, + getResourceContainer, + makePodName, + getResourcePodSpec, +} from "../util" export async function testKubernetesModule(params: TestModuleParams): Promise { const { ctx, log, module, testConfig, testVersion } = params @@ -43,6 +49,7 @@ export async function testKubernetesModule(params: TestModuleParamsctx.provider const api = await KubeApi.factory(log, ctx, provider) - // Prepare environment variables - envVars = { ...runtimeContext.envVars, ...envVars } - const env = uniqByName([ - ...prepareEnvVars(envVars), - // If `container` is specified, include its variables as well - ...(container && container.env ? container.env : []), - ]) - - const getArtifacts = !interactive && artifacts && artifacts.length > 0 && artifactsPath + const getArtifacts = !!(!interactive && artifacts && artifacts.length > 0 && artifactsPath) const mainContainerName = "main" - const podSpec: V1PodSpec = { - containers: [ - { - ...(container || {}), - // We always override the following attributes - name: mainContainerName, - image, - env, - // TODO: consider supporting volume mounts in ad-hoc runs (would need specific logic and testing) - volumeMounts: [], - }, - ], - imagePullSecrets: await prepareImagePullSecrets({ api, provider, namespace, log }), - } - - if (volumes) { - configureVolumes(module, podSpec, volumes) - } - if (!description) { description = `Container module '${module.name}'` } const errorMetadata: any = { moduleName: module.name, description, args, artifacts } + podSpec = await prepareRunPodSpec({ + podSpec, + getArtifacts, + log, + module, + args, + command, + api, + provider, + runtimeContext, + envVars, + description, + errorMetadata, + mainContainerName, + image, + container, + namespace, + volumes, + }) + if (!podName) { podName = makePodName("run", module.name) } @@ -150,6 +189,104 @@ export async function runAndCopy({ } } +// This helper was created to facilitate testing the pod spec generation in `runAndCopy`. +export async function prepareRunPodSpec({ + podSpec, + getArtifacts, + api, + provider, + log, + module, + args, + command, + runtimeContext, + envVars, + description, + errorMetadata, + mainContainerName, + image, + container, + namespace, + volumes, +}: { + podSpec?: V1PodSpec + getArtifacts: boolean + log: LogEntry + module: GardenModule + args: string[] + command: string[] | undefined + api: KubeApi + provider: KubernetesProvider + runtimeContext: RuntimeContext + envVars: ContainerEnvVars + description: string + errorMetadata: any + mainContainerName: string + image: string + container?: V1Container + namespace: string + volumes?: ContainerVolumeSpec[] +}): Promise { + // Prepare environment variables + envVars = { ...runtimeContext.envVars, ...envVars } + const env = uniqByName([ + ...prepareEnvVars(envVars), + // If `container` is specified, include its variables as well + ...(container && container.env ? container.env : []), + ]) + + const containers: V1Container[] = [ + { + ...(container || {}), + // We always override the following attributes + name: mainContainerName, + image, + env, + // TODO: consider supporting volume mounts in ad-hoc runs (would need specific logic and testing) + volumeMounts: [], + }, + ] + + const imagePullSecrets = await prepareImagePullSecrets({ api, provider, namespace, log }) + + podSpec = { + ...pick(podSpec || {}, runPodSpecWhitelist), + containers, + imagePullSecrets, + } + + if (volumes) { + configureVolumes(module, podSpec, volumes) + } + + if (getArtifacts) { + if (!command) { + throw new ConfigurationError( + deline` + ${description} specifies artifacts to export, but doesn't + explicitly set a \`command\`. The kubernetes provider currently requires an explicit command to be set for + tests and tasks that export artifacts, because the image's entrypoint cannot be inferred in that execution + mode. Please set the \`command\` field and try again. + `, + errorMetadata + ) + } + + // We start the container with a named pipe and tail that, to get the logs from the actual command + // we plan on running. Then we sleep, so that we can copy files out of the container. + podSpec.containers[0].command = ["sh", "-c", "mkfifo /tmp/output && cat /tmp/output && sleep 86400"] + } else { + if (args) { + podSpec.containers[0].args = args + } + if (command) { + podSpec.containers[0].command = command + } + } + + return podSpec +} + async function runWithoutArtifacts({ ctx, api, @@ -170,13 +307,6 @@ async function runWithoutArtifacts({ podName: string namespace: string }): Promise { - if (args) { - podSpec.containers[0].args = args - } - if (command) { - podSpec.containers[0].command = command - } - const pod: KubernetesResource = { apiVersion: "v1", kind: "Pod", @@ -277,22 +407,6 @@ async function runWithArtifacts({ stderr?: Writable namespace: string }): Promise { - if (!command) { - throw new ConfigurationError( - deline` - ${description} specifies artifacts to export, but doesn't - explicitly set a \`command\`. The kubernetes provider currently requires an explicit command to be set for - tests and tasks that export artifacts, because the image's entrypoint cannot be inferred in that execution - mode. Please set the \`command\` field and try again. - `, - errorMetadata - ) - } - - // We start the container with a named pipe and tail that, to get the logs from the actual command - // we plan on running. Then we sleep, so that we can copy files out of the container. - podSpec.containers[0].command = ["sh", "-c", "mkfifo /tmp/output && cat /tmp/output && sleep 86400"] - const pod: KubernetesResource = { apiVersion: "v1", kind: "Pod", diff --git a/core/src/plugins/kubernetes/util.ts b/core/src/plugins/kubernetes/util.ts index e80278995b..246b0cf8be 100644 --- a/core/src/plugins/kubernetes/util.ts +++ b/core/src/plugins/kubernetes/util.ts @@ -8,7 +8,7 @@ import Bluebird from "bluebird" import { get, flatten, uniqBy, sortBy, omit, chain, sample, isEmpty, find } from "lodash" -import { V1Pod, V1EnvVar } from "@kubernetes/client-node" +import { V1Pod, V1EnvVar, V1Container, V1PodSpec } from "@kubernetes/client-node" import { apply as jsonMerge } from "json-merge-patch" import chalk from "chalk" import hasha from "hasha" @@ -477,7 +477,7 @@ interface GetServiceResourceParams { } /** - * Finds and returns the configured service resource from the specified chart resources, that we can use for + * Finds and returns the configured service resource from the specified manifests, that we can use for * hot-reloading and other service-specific functionality. * * Optionally provide a `resourceSpec`, which is then used instead of the default `module.serviceResource` spec. @@ -554,11 +554,11 @@ export async function findServiceResource({ * From the given Deployment, DaemonSet or StatefulSet resource, get either the first container spec, * or if `containerName` is specified, the one matching that name. */ -export function getResourceContainer(resource: HotReloadableResource, containerName?: string) { +export function getResourceContainer(resource: HotReloadableResource, containerName?: string): V1Container { const kind = resource.kind const name = resource.metadata.name - const containers = resource.spec.template.spec?.containers || [] + const containers = getResourcePodSpec(resource)?.containers || [] if (containers.length === 0) { throw new ConfigurationError(`${kind} ${resource.metadata.name} has no containers configured.`, { resource }) @@ -576,6 +576,10 @@ export function getResourceContainer(resource: HotReloadableResource, containerN return container } +export function getResourcePodSpec(resource: HotReloadableResource): V1PodSpec | undefined { + return resource.spec.template.spec +} + const maxPodNameLength = 63 const podNameHashLength = 6 const maxPodNamePrefixLength = maxPodNameLength - podNameHashLength - 1 diff --git a/core/test/data/test-projects/helm/artifacts/templates/deployment.yaml b/core/test/data/test-projects/helm/artifacts/templates/deployment.yaml index 93a8e6ecee..c5ea5063c1 100644 --- a/core/test/data/test-projects/helm/artifacts/templates/deployment.yaml +++ b/core/test/data/test-projects/helm/artifacts/templates/deployment.yaml @@ -19,6 +19,7 @@ spec: app.kubernetes.io/name: {{ include "api.name" . }} app.kubernetes.io/instance: {{ .Release.Name }} spec: + terminationGracePeriodSeconds: 60 containers: - name: {{ .Chart.Name }} image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" @@ -30,10 +31,7 @@ spec: protocol: TCP resources: {{- toYaml .Values.resources | nindent 12 }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} + shareProcessNamespace: {{ .Values.shareProcessNamespace }} {{- with .Values.affinity }} affinity: {{- toYaml . | nindent 8 }} diff --git a/core/test/data/test-projects/helm/artifacts/values.yaml b/core/test/data/test-projects/helm/artifacts/values.yaml index 7bbb6c9188..cf2f515605 100644 --- a/core/test/data/test-projects/helm/artifacts/values.yaml +++ b/core/test/data/test-projects/helm/artifacts/values.yaml @@ -41,7 +41,8 @@ resources: {} # cpu: 100m # memory: 128Mi -nodeSelector: {} +# This field is whitelisted in `runPodSpecWhitelist`, so it should be included when running tests/tasks +shareProcessNamespace: true tolerations: [] diff --git a/core/test/integ/src/plugins/kubernetes/helm/common.ts b/core/test/integ/src/plugins/kubernetes/helm/common.ts index 5ae237f254..e9a35739b0 100644 --- a/core/test/integ/src/plugins/kubernetes/helm/common.ts +++ b/core/test/integ/src/plugins/kubernetes/helm/common.ts @@ -28,6 +28,7 @@ import { deline, dedent } from "../../../../../../src/util/string" import { ConfigGraph } from "../../../../../../src/config-graph" import { KubernetesPluginContext } from "../../../../../../src/plugins/kubernetes/config" import { safeLoadAll } from "js-yaml" +import { Garden } from "../../../../../../src" let helmTestGarden: TestGarden @@ -44,7 +45,7 @@ export async function getHelmTestGarden() { return garden } -export async function buildHelmModules(garden: TestGarden, graph: ConfigGraph) { +export async function buildHelmModules(garden: Garden | TestGarden, graph: ConfigGraph) { const modules = graph.getModules() const tasks = modules.map( (module) => diff --git a/core/test/integ/src/plugins/kubernetes/run.ts b/core/test/integ/src/plugins/kubernetes/run.ts index 3c8355ce9a..ec77e3d835 100644 --- a/core/test/integ/src/plugins/kubernetes/run.ts +++ b/core/test/integ/src/plugins/kubernetes/run.ts @@ -14,16 +14,31 @@ import { join } from "path" import { Garden } from "../../../../../src/garden" import { ConfigGraph } from "../../../../../src/config-graph" import { deline, randomString, dedent } from "../../../../../src/util/string" -import { runAndCopy, PodRunner } from "../../../../../src/plugins/kubernetes/run" +import { runAndCopy, PodRunner, prepareRunPodSpec } from "../../../../../src/plugins/kubernetes/run" import { containerHelpers } from "../../../../../src/plugins/container/helpers" import { KubeApi } from "../../../../../src/plugins/kubernetes/api" -import { KubernetesProvider } from "../../../../../src/plugins/kubernetes/config" -import { makePodName } from "../../../../../src/plugins/kubernetes/util" +import { + KubernetesPluginContext, + KubernetesProvider, + ServiceResourceSpec, +} from "../../../../../src/plugins/kubernetes/config" +import { + findServiceResource, + getResourceContainer, + getServiceResourceSpec, + getResourcePodSpec, + makePodName, +} from "../../../../../src/plugins/kubernetes/util" import { getContainerTestGarden } from "./container/container" -import { KubernetesPod } from "../../../../../src/plugins/kubernetes/types" +import { KubernetesPod, KubernetesResource } from "../../../../../src/plugins/kubernetes/types" import { PluginContext } from "../../../../../src/plugin-context" import { LogEntry } from "../../../../../src/logger/log-entry" import { sleep, StringCollector } from "../../../../../src/util/util" +import { buildHelmModules, getHelmTestGarden } from "./helm/common" +import { getBaseModule, getChartResources } from "../../../../../src/plugins/kubernetes/helm/common" +import { getModuleNamespace } from "../../../../../src/plugins/kubernetes/namespace" +import { GardenModule } from "../../../../../src/types/module" +import { V1Container, V1DaemonSet, V1Deployment, V1StatefulSet } from "@kubernetes/client-node" describe("kubernetes Pod runner functions", () => { let garden: Garden @@ -396,6 +411,174 @@ describe("kubernetes Pod runner functions", () => { }) }) + describe("prepareRunPodSpec", () => { + let helmGarden: Garden + let helmProvider: KubernetesProvider + let helmCtx: KubernetesPluginContext + let helmApi: KubeApi + let helmLog: LogEntry + let helmGraph: ConfigGraph + let helmModule: GardenModule + let helmManifests: any[] + let helmBaseModule: GardenModule | undefined + let helmResourceSpec: ServiceResourceSpec + let helmTarget: KubernetesResource + let helmContainer: V1Container + let helmNamespace: string + + before(async () => { + helmGarden = await getHelmTestGarden() + helmProvider = await helmGarden.resolveProvider(helmGarden.log, "local-kubernetes") + helmCtx = await helmGarden.getPluginContext(helmProvider) + helmApi = await KubeApi.factory(helmGarden.log, helmCtx, helmProvider) + helmLog = helmGarden.log + helmGraph = await helmGarden.getConfigGraph(helmLog) + await buildHelmModules(helmGarden, helmGraph) + helmModule = helmGraph.getModule("artifacts") + + helmManifests = await getChartResources(helmCtx, helmModule, false, helmLog) + helmBaseModule = getBaseModule(helmModule) + helmResourceSpec = getServiceResourceSpec(helmModule, helmBaseModule) + helmTarget = await findServiceResource({ + ctx: helmCtx, + log: helmLog, + manifests: helmManifests, + module: helmModule, + baseModule: helmBaseModule, + resourceSpec: helmResourceSpec, + }) + helmContainer = getResourceContainer(helmTarget, helmResourceSpec.containerName) + helmNamespace = await getModuleNamespace({ + ctx: helmCtx, + log: helmLog, + module: helmModule, + provider: helmCtx.provider, + }) + }) + + // These test cases should cover the `kubernetes` module type as well, since these helpers operate on manifests + // (it shouldn't matter whether they come from a rendered Helm chart or directly from manifests) + it("should generate a default pod spec when none is provided", async () => { + const generatedPodSpec = await prepareRunPodSpec({ + podSpec: undefined, // <------ + getArtifacts: false, + api: helmApi, + provider: helmProvider, + log: helmLog, + module: helmModule, + args: ["sh", "-c"], + command: ["echo", "foo"], + runtimeContext: { envVars: {}, dependencies: [] }, + envVars: {}, + description: "Helm module", + errorMetadata: {}, + mainContainerName: "main", + image: "foo", + container: helmContainer, + namespace: helmNamespace, + volumes: [], + }) + + expect(generatedPodSpec).to.eql({ + containers: [ + { + name: "main", + image: "foo", + imagePullPolicy: "IfNotPresent", + args: ["sh", "-c"], + ports: [ + { + name: "http", + containerPort: 80, + protocol: "TCP", + }, + ], + resources: {}, + env: [], + volumeMounts: [], + command: ["echo", "foo"], + }, + ], + imagePullSecrets: [], + volumes: [], + }) + }) + + it("should include only whitelisted pod spec fields in the generated pod spec", async () => { + const podSpec = getResourcePodSpec(helmTarget) + expect(podSpec).to.eql({ + // This field is *not* whitelisted in `runPodSpecWhitelist`, so it shouldn't appear in the + // generated pod spec below. + terminationGracePeriodSeconds: 60, + containers: [ + { + name: "api", + image: "busybox:latest", + imagePullPolicy: "IfNotPresent", + args: ["python", "app.py"], + ports: [ + { + name: "http", + containerPort: 80, + protocol: "TCP", + }, + ], + resources: {}, + }, + ], + // This field is whitelisted in `runPodSpecWhitelist`, so it *should* appear in the generated + // pod spec below. + shareProcessNamespace: true, + }) + const generatedPodSpec = await prepareRunPodSpec({ + podSpec, // <------ + getArtifacts: false, + api: helmApi, + provider: helmProvider, + log: helmLog, + module: helmModule, + args: ["sh", "-c"], + command: ["echo", "foo"], + runtimeContext: { envVars: {}, dependencies: [] }, + envVars: {}, + description: "Helm module", + errorMetadata: {}, + mainContainerName: "main", + image: "foo", + container: helmContainer, + namespace: helmNamespace, + volumes: [], + }) + + expect(generatedPodSpec).to.eql({ + // `shareProcessNamespace` is not blacklisted, so it should be propagated to here. + shareProcessNamespace: true, + // `terminationGracePeriodSeconds` *is* blacklisted, so it should not appear here. + containers: [ + { + name: "main", + image: "foo", + imagePullPolicy: "IfNotPresent", + args: ["sh", "-c"], + ports: [ + { + name: "http", + containerPort: 80, + protocol: "TCP", + }, + ], + resources: {}, + env: [], + volumeMounts: [], + command: ["echo", "foo"], + }, + ], + imagePullSecrets: [], + volumes: [], + }) + }) + }) + describe("runAndCopy", () => { let tmpDir: tmp.DirectoryResult diff --git a/docs/reference/module-types/helm.md b/docs/reference/module-types/helm.md index f4b9c729ad..f8fa6924f9 100644 --- a/docs/reference/module-types/helm.md +++ b/docs/reference/module-types/helm.md @@ -165,12 +165,13 @@ serviceResource: # container is not the first container in the spec. containerName: - # The name of the resource to sync to. If the chart contains a single resource of the specified Kind, this can be - # omitted. - # This can include a Helm template string, e.g. '{{ template "my-chart.fullname" . }}'. This allows you to easily - # match the dynamic names given by Helm. In most cases you should copy this directly from the template in question - # in order to match it. Note that you may need to add single quotes around the string for the YAML to be parsed - # correctly. + # The name of the resource to sync to. If the chart contains a single resource of the specified Kind, + # this can be omitted. + # + # This can include a Helm template string, e.g. '{{ template "my-chart.fullname" . }}'. + # This allows you to easily match the dynamic names given by Helm. In most cases you should copy this + # directly from the template in question in order to match it. Note that you may need to add single quotes around + # the string for the YAML to be parsed correctly. name: # The Garden module that contains the sources for the container. This needs to be specified under `serviceResource` @@ -240,8 +241,39 @@ tasks: # `.garden/artifacts`. target: . - # The Deployment, DaemonSet or StatefulSet that Garden should use to execute this task. If not specified, the - # `serviceResource` configured on the module will be used. If neither is specified, an error will be thrown. + # The Deployment, DaemonSet or StatefulSet that Garden should use to execute this task. + # If not specified, the `serviceResource` configured on the module will be used. If neither is specified, + # an error will be thrown. + # + # The following pod spec fields from the service resource will be used (if present) when executing the task: + # * `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 type of Kubernetes resource to sync files to. kind: Deployment @@ -250,12 +282,14 @@ tasks: # main container is not the first container in the spec. containerName: - # The name of the resource to sync to. If the chart contains a single resource of the specified Kind, this can - # be omitted. - # This can include a Helm template string, e.g. '{{ template "my-chart.fullname" . }}'. This allows you to - # easily match the dynamic names given by Helm. In most cases you should copy this directly from the template in - # question in order to match it. Note that you may need to add single quotes around the string for the YAML to - # be parsed correctly. + # The name of the resource to sync to. If the chart contains a single resource of the specified Kind, + # this can be omitted. + # + # This can include a Helm template string, e.g. '{{ template "my-chart.fullname" . }}'. + # This allows you to easily match the dynamic names given by Helm. In most cases you should copy this + # directly from the template in question in order to match it. Note that you may need to add single quotes + # around + # the string for the YAML to be parsed correctly. name: # The Garden module that contains the sources for the container. This needs to be specified under @@ -306,8 +340,39 @@ tests: # `.garden/artifacts`. target: . - # The Deployment, DaemonSet or StatefulSet that Garden should use to execute this test suite. If not specified, - # the `serviceResource` configured on the module will be used. If neither is specified, an error will be thrown. + # The Deployment, DaemonSet or StatefulSet that Garden should use to execute this test suite. + # If not specified, the `serviceResource` configured on the module will be used. If neither is specified, + # an error will be thrown. + # + # The following pod spec fields from the service resource will be used (if present) when executing the test suite: + # * `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 type of Kubernetes resource to sync files to. kind: Deployment @@ -316,12 +381,14 @@ tests: # main container is not the first container in the spec. containerName: - # The name of the resource to sync to. If the chart contains a single resource of the specified Kind, this can - # be omitted. - # This can include a Helm template string, e.g. '{{ template "my-chart.fullname" . }}'. This allows you to - # easily match the dynamic names given by Helm. In most cases you should copy this directly from the template in - # question in order to match it. Note that you may need to add single quotes around the string for the YAML to - # be parsed correctly. + # The name of the resource to sync to. If the chart contains a single resource of the specified Kind, + # this can be omitted. + # + # This can include a Helm template string, e.g. '{{ template "my-chart.fullname" . }}'. + # This allows you to easily match the dynamic names given by Helm. In most cases you should copy this + # directly from the template in question in order to match it. Note that you may need to add single quotes + # around + # the string for the YAML to be parsed correctly. name: # The Garden module that contains the sources for the container. This needs to be specified under @@ -702,8 +769,13 @@ The name of a container in the target. Specify this if the target contains more [serviceResource](#serviceresource) > name -The name of the resource to sync to. If the chart contains a single resource of the specified Kind, this can be omitted. -This can include a Helm template string, e.g. '{{ template "my-chart.fullname" . }}'. This allows you to easily match the dynamic names given by Helm. In most cases you should copy this directly from the template in question in order to match it. Note that you may need to add single quotes around the string for the YAML to be parsed correctly. +The name of the resource to sync to. If the chart contains a single resource of the specified Kind, +this can be omitted. + +This can include a Helm template string, e.g. '{{ template "my-chart.fullname" . }}'. +This allows you to easily match the dynamic names given by Helm. In most cases you should copy this +directly from the template in question in order to match it. Note that you may need to add single quotes around +the string for the YAML to be parsed correctly. | Type | Required | | -------- | -------- | @@ -941,7 +1013,39 @@ tasks: [tasks](#tasks) > resource -The Deployment, DaemonSet or StatefulSet that Garden should use to execute this task. If not specified, the `serviceResource` configured on the module will be used. If neither is specified, an error will be thrown. +The Deployment, DaemonSet or StatefulSet that Garden should use to execute this task. +If not specified, the `serviceResource` configured on the module will be used. If neither is specified, +an error will be thrown. + +The following pod spec fields from the service resource will be used (if present) when executing the task: +* `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 | | -------- | -------- | @@ -971,8 +1075,13 @@ The name of a container in the target. Specify this if the target contains more [tasks](#tasks) > [resource](#tasksresource) > name -The name of the resource to sync to. If the chart contains a single resource of the specified Kind, this can be omitted. -This can include a Helm template string, e.g. '{{ template "my-chart.fullname" . }}'. This allows you to easily match the dynamic names given by Helm. In most cases you should copy this directly from the template in question in order to match it. Note that you may need to add single quotes around the string for the YAML to be parsed correctly. +The name of the resource to sync to. If the chart contains a single resource of the specified Kind, +this can be omitted. + +This can include a Helm template string, e.g. '{{ template "my-chart.fullname" . }}'. +This allows you to easily match the dynamic names given by Helm. In most cases you should copy this +directly from the template in question in order to match it. Note that you may need to add single quotes around +the string for the YAML to be parsed correctly. | Type | Required | | -------- | -------- | @@ -1183,7 +1292,39 @@ tests: [tests](#tests) > resource -The Deployment, DaemonSet or StatefulSet that Garden should use to execute this test suite. If not specified, the `serviceResource` configured on the module will be used. If neither is specified, an error will be thrown. +The Deployment, DaemonSet or StatefulSet that Garden should use to execute this test suite. +If not specified, the `serviceResource` configured on the module will be used. If neither is specified, +an error will be thrown. + +The following pod spec fields from the service resource will be used (if present) when executing the test suite: +* `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 | | -------- | -------- | @@ -1213,8 +1354,13 @@ The name of a container in the target. Specify this if the target contains more [tests](#tests) > [resource](#testsresource) > name -The name of the resource to sync to. If the chart contains a single resource of the specified Kind, this can be omitted. -This can include a Helm template string, e.g. '{{ template "my-chart.fullname" . }}'. This allows you to easily match the dynamic names given by Helm. In most cases you should copy this directly from the template in question in order to match it. Note that you may need to add single quotes around the string for the YAML to be parsed correctly. +The name of the resource to sync to. If the chart contains a single resource of the specified Kind, +this can be omitted. + +This can include a Helm template string, e.g. '{{ template "my-chart.fullname" . }}'. +This allows you to easily match the dynamic names given by Helm. In most cases you should copy this +directly from the template in question in order to match it. Note that you may need to add single quotes around +the string for the YAML to be parsed correctly. | Type | Required | | -------- | -------- | diff --git a/docs/reference/module-types/kubernetes.md b/docs/reference/module-types/kubernetes.md index eaab8a7b64..215023046c 100644 --- a/docs/reference/module-types/kubernetes.md +++ b/docs/reference/module-types/kubernetes.md @@ -204,8 +204,39 @@ tasks: # Maximum duration (in seconds) of the task's execution. timeout: null - # The Deployment, DaemonSet or StatefulSet that Garden should use to execute this task. If not specified, the - # `serviceResource` configured on the module will be used. If neither is specified, an error will be thrown. + # The Deployment, DaemonSet or StatefulSet that Garden should use to execute this task. + # If not specified, the `serviceResource` configured on the module will be used. If neither is specified, + # an error will be thrown. + # + # The following pod spec fields from the service resource will be used (if present) when executing the task: + # * `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 type of Kubernetes resource to sync files to. kind: Deployment @@ -260,8 +291,39 @@ tests: # Maximum duration (in seconds) of the test run. timeout: null - # The Deployment, DaemonSet or StatefulSet that Garden should use to execute this test suite. If not specified, - # the `serviceResource` configured on the module will be used. If neither is specified, an error will be thrown. + # The Deployment, DaemonSet or StatefulSet that Garden should use to execute this test suite. + # If not specified, the `serviceResource` configured on the module will be used. If neither is specified, + # an error will be thrown. + # + # The following pod spec fields from the service resource will be used (if present) when executing the test suite: + # * `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 type of Kubernetes resource to sync files to. kind: Deployment @@ -747,7 +809,39 @@ Maximum duration (in seconds) of the task's execution. [tasks](#tasks) > resource -The Deployment, DaemonSet or StatefulSet that Garden should use to execute this task. If not specified, the `serviceResource` configured on the module will be used. If neither is specified, an error will be thrown. +The Deployment, DaemonSet or StatefulSet that Garden should use to execute this task. +If not specified, the `serviceResource` configured on the module will be used. If neither is specified, +an error will be thrown. + +The following pod spec fields from the service resource will be used (if present) when executing the task: +* `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 | | -------- | -------- | @@ -954,7 +1048,39 @@ Maximum duration (in seconds) of the test run. [tests](#tests) > resource -The Deployment, DaemonSet or StatefulSet that Garden should use to execute this test suite. If not specified, the `serviceResource` configured on the module will be used. If neither is specified, an error will be thrown. +The Deployment, DaemonSet or StatefulSet that Garden should use to execute this test suite. +If not specified, the `serviceResource` configured on the module will be used. If neither is specified, +an error will be thrown. + +The following pod spec fields from the service resource will be used (if present) when executing the test suite: +* `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 | | -------- | -------- |