Skip to content

Commit

Permalink
feat(k8s): provider-level defaults for dev mode
Browse files Browse the repository at this point in the history
Excludes and permission/owner/group settings can now be set on the
provider level for `kubernetes` and `local-kubernetes`.

Defaults specified there will be extended/overridden by corresponding
settings on individual sync specs.

This helps reduce clutter when the same excludes and permission settings
are commonly applied across services/modules.
thsig committed Sep 28, 2021
1 parent a133e09 commit d6c6228
Showing 16 changed files with 770 additions and 127 deletions.
78 changes: 50 additions & 28 deletions core/src/plugins/container/config.ts
Original file line number Diff line number Diff line change
@@ -29,6 +29,7 @@ import { joiStringMap } from "../../config/common"
import { dedent, deline } from "../../util/string"
import { getModuleTypeUrl } from "../../docs/common"
import { ContainerModuleOutputs } from "./container"
import { devModeGuideLink } from "../kubernetes/dev-mode"

export const defaultContainerLimits: ServiceLimitSpec = {
cpu: 1000, // = 1000 millicpu = 1 CPU
@@ -202,13 +203,52 @@ const permissionsDocs =
const ownerDocs =
"Specify either an integer ID or a string name. See the [Mutagen docs](https://mutagen.io/documentation/synchronization/permissions#owners-and-groups) for more information."

export const syncExcludeSchema = () =>
joi
.array()
.items(joi.posixPath().allowGlobs().subPathOnly())
.description(
dedent`
Specify a list of POSIX-style paths or glob patterns that should be excluded from the sync.
\`.git\` directories and \`.garden\` directories are always ignored.
`
)
.example(["dist/**/*", "*.log"])

export const syncDefaultFileModeSchema = () =>
joi
.number()
.min(0)
.max(0o777)
.description(
"The default permission bits, specified as an octal, to set on files at the sync target. Defaults to 0600 (user read/write). " +
permissionsDocs
)

export const syncDefaultDirectoryModeSchema = () =>
joi
.number()
.min(0)
.max(0o777)
.description(
"The default permission bits, specified as an octal, to set on directories at the sync target. Defaults to 0700 (user read/write). " +
permissionsDocs
)

export const syncDefaultOwnerSchema = () =>
joi
.alternatives(joi.number().integer(), joi.string())
.description("Set the default owner of files and directories at the target. " + ownerDocs)

export const syncDefaultGroupSchema = () =>
joi
.alternatives(joi.number().integer(), joi.string())
.description("Set the default group on files and directories at the target. " + ownerDocs)

const devModeSyncSchema = () =>
hotReloadSyncSchema().keys({
exclude: joi
.array()
.items(joi.posixPath().allowGlobs().subPathOnly())
.description(`Specify a list of POSIX-style paths or glob patterns that should be excluded from the sync.`)
.example(["dist/**/*", "*.log"]),
exclude: syncExcludeSchema(),
mode: joi
.string()
.allow("one-way", "one-way-replica", "two-way")
@@ -217,28 +257,10 @@ const devModeSyncSchema = () =>
.description(
"The sync mode to use for the given paths. Allowed options: `one-way`, `one-way-replica`, `two-way`."
),
defaultFileMode: joi
.number()
.min(0)
.max(0o777)
.description(
"The default permission bits, specified as an octal, to set on files at the sync target. Defaults to 0600 (user read/write). " +
permissionsDocs
),
defaultDirectoryMode: joi
.number()
.min(0)
.max(0o777)
.description(
"The default permission bits, specified as an octal, to set on directories at the sync target. Defaults to 0700 (user read/write). " +
permissionsDocs
),
defaultOwner: joi
.alternatives(joi.number().integer(), joi.string())
.description("Set the default owner of files and directories at the target. " + ownerDocs),
defaultGroup: joi
.alternatives(joi.number().integer(), joi.string())
.description("Set the default group on files and directories at the target. " + ownerDocs),
defaultFileMode: syncDefaultFileModeSchema(),
defaultDirectoryMode: syncDefaultDirectoryModeSchema(),
defaultOwner: syncDefaultOwnerSchema(),
defaultGroup: syncDefaultGroupSchema(),
})

export interface ContainerDevModeSpec {
@@ -263,7 +285,7 @@ export const containerDevModeSchema = () =>
Dev mode is enabled when running the \`garden dev\` command, and by setting the \`--dev\` flag on the \`garden deploy\` command.
See the [Code Synchronization guide](https://docs.garden.io/guides/code-synchronization-dev-mode) for more information.
See the [Code Synchronization guide](${devModeGuideLink}) for more information.
`)

export type ContainerServiceConfig = ServiceConfig<ContainerServiceSpec>
20 changes: 16 additions & 4 deletions core/src/plugins/kubernetes/config.ts
Original file line number Diff line number Diff line change
@@ -37,6 +37,7 @@ import { baseTestSpecSchema, BaseTestSpec } from "../../config/test"
import { ArtifactSpec } from "../../config/validation"
import { V1Toleration } from "@kubernetes/client-node"
import { runPodSpecIncludeFields } from "./run"
import { KubernetesDevModeDefaults, kubernetesDevModeDefaultsSchema } from "./dev-mode"

export const DEFAULT_KANIKO_IMAGE = "gcr.io/kaniko-project/executor:v1.6.0-debug"
export interface ProviderSecretRef {
@@ -126,6 +127,9 @@ export interface KubernetesConfig extends BaseProviderConfig {
defaultHostname?: string
deploymentRegistry?: ContainerRegistryConfig
deploymentStrategy?: DeploymentStrategy
devMode?: {
defaults?: KubernetesDevModeDefaults
}
forceSsl: boolean
imagePullSecrets: ProviderSecretRef[]
ingressHttpPort: number
@@ -437,14 +441,22 @@ export const kubernetesConfigBase = () =>
.allow("rolling", "blue-green")
.description(
dedent`
Defines the strategy for deploying the project services.
Default is "rolling update" and there is experimental support for "blue/green" deployment.
The feature only supports modules of type \`container\`: other types will just deploy using the default strategy.
`
Sets the deployment strategy for \`container\` services.
The default is \`"rolling"\`, which performs rolling updates. There is also experimental support for blue/green deployments (via the \`"blue-green"\` strategy).
Note that this setting only applies to \`container\` services (and not, for example, \`kubernetes\` or \`helm\` services).
`
)
.meta({
experimental: true,
}),
devMode: joi
.object()
.keys({
defaults: kubernetesDevModeDefaultsSchema(),
})
.description("Configuration options for dev mode."),
forceSsl: joi
.boolean()
.default(false)
101 changes: 88 additions & 13 deletions core/src/plugins/kubernetes/dev-mode.ts
Original file line number Diff line number Diff line change
@@ -6,7 +6,16 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

import { containerDevModeSchema, ContainerDevModeSpec } from "../container/config"
import {
containerDevModeSchema,
ContainerDevModeSpec,
DevModeSyncSpec,
syncDefaultDirectoryModeSchema,
syncDefaultFileModeSchema,
syncDefaultGroupSchema,
syncDefaultOwnerSchema,
syncExcludeSchema,
} from "../container/config"
import { dedent, gardenAnnotationKey } from "../../util/string"
import { set } from "lodash"
import { getResourceContainer, getResourcePodSpec } from "./util"
@@ -16,12 +25,22 @@ import { joinWithPosix } from "../../util/fs"
import chalk from "chalk"
import { PluginContext } from "../../plugin-context"
import { ConfigurationError } from "../../exceptions"
import { ensureMutagenSync, getKubectlExecDestination, mutagenAgentPath, mutagenConfigLock } from "./mutagen"
import { joiIdentifier } from "../../config/common"
import { KubernetesPluginContext } from "./config"
import {
ensureMutagenSync,
getKubectlExecDestination,
mutagenAgentPath,
mutagenConfigLock,
SyncConfig,
} from "./mutagen"
import { joi, joiIdentifier } from "../../config/common"
import { KubernetesPluginContext, KubernetesProvider } from "./config"

const syncUtilImageName = "gardendev/k8s-sync:0.1.1"

export const builtInExcludes = ["**/*.git", "**/*.garden"]

export const devModeGuideLink = "https://docs.garden.io/guides/code-synchronization-dev-mode"

interface ConfigureDevModeParams {
target: HotReloadableResource
spec: ContainerDevModeSpec
@@ -32,6 +51,40 @@ export interface KubernetesDevModeSpec extends ContainerDevModeSpec {
containerName?: string
}

export interface KubernetesDevModeDefaults {
exclude?: string[]
fileMode?: number
directoryMode?: number
owner?: number | string
group?: number | string
}

/**
* Provider-level dev mode settings for the local and remote k8s providers.
*/
export const kubernetesDevModeDefaultsSchema = () =>
joi.object().keys({
exclude: syncExcludeSchema().description(dedent`
Specify a list of POSIX-style paths or glob patterns that should be excluded from the sync.
Any exclusion patterns defined in individual dev mode sync specs will be applied in addition to these patterns.
\`.git\` directories and \`.garden\` directories are always ignored.
`),
fileMode: syncDefaultFileModeSchema(),
directoryMode: syncDefaultDirectoryModeSchema(),
owner: syncDefaultOwnerSchema(),
group: syncDefaultGroupSchema(),
}).description(dedent`
Specifies default settings for dev mode syncs (e.g. for \`container\`, \`kubernetes\` and \`helm\` services).
These are overridden/extended by the settings of any individual dev mode sync specs for a given module or service.
Dev mode is enabled when running the \`garden dev\` command, and by setting the \`--dev\` flag on the \`garden deploy\` command.
See the [Code Synchronization guide](${devModeGuideLink}) for more information.
`)

export const kubernetesDevModeSchema = () =>
containerDevModeSchema().keys({
containerName: joiIdentifier().description(
@@ -44,7 +97,7 @@ export const kubernetesDevModeSchema = () =>
Dev mode is enabled when running the \`garden dev\` command, and by setting the \`--dev\` flag on the \`garden deploy\` command.
See the [Code Synchronization guide](https://docs.garden.io/guides/code-synchronization-dev-mode) for more information.
See the [Code Synchronization guide](${devModeGuideLink}) for more information.
`)

/**
@@ -152,14 +205,16 @@ export async function startDevModeSync({
}

const k8sCtx = <KubernetesPluginContext>ctx
const k8sProvider = <KubernetesProvider>k8sCtx.provider
const defaults = k8sProvider.config.devMode?.defaults || {}

let i = 0

for (const s of spec.sync) {
const key = `${keyBase}-${i}`

const alpha = joinWithPosix(moduleRoot, s.source)
const beta = await getKubectlExecDestination({
const localPath = joinWithPosix(moduleRoot, s.source)
const remoteDestination = await getKubectlExecDestination({
ctx: k8sCtx,
log,
namespace,
@@ -181,15 +236,35 @@ export async function startDevModeSync({
logSection: serviceName,
sourceDescription,
targetDescription,
config: {
alpha,
beta,
mode: s.mode,
ignore: s.exclude || [],
},
config: makeSyncConfig({ defaults, spec: s, localPath, remoteDestination }),
})

i++
}
})
}

export function makeSyncConfig({
localPath,
remoteDestination,
defaults,
spec,
}: {
localPath: string
remoteDestination: string
defaults: KubernetesDevModeDefaults | null
spec: DevModeSyncSpec
}): SyncConfig {
const s = spec
const d = defaults || {}
return {
alpha: localPath,
beta: remoteDestination,
mode: s.mode,
ignore: [...builtInExcludes, ...(d["exclude"] || []), ...(s.exclude || [])],
defaultOwner: s.defaultOwner === undefined ? d["owner"] : s.defaultOwner,
defaultGroup: s.defaultGroup === undefined ? d["group"] : s.defaultGroup,
defaultDirectoryMode: s.defaultDirectoryMode === undefined ? d["directoryMode"] : s.defaultDirectoryMode,
defaultFileMode: s.defaultFileMode === undefined ? d["fileMode"] : s.defaultFileMode,
}
}
2 changes: 1 addition & 1 deletion core/src/plugins/kubernetes/mutagen.ts
Original file line number Diff line number Diff line change
@@ -35,7 +35,7 @@ export const mutagenModeMap = {
"two-way": "two-way-safe",
}

interface SyncConfig {
export interface SyncConfig {
alpha: string
beta: string
mode: keyof typeof mutagenModeMap
2 changes: 1 addition & 1 deletion core/test/data/test-projects/container/dev-mode/garden.yml
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@ services:
command: [sh, -c, "echo Server running... && nc -l -p 8080"]
devMode:
sync:
- target: /tmp
- target: /tmp/
mode: two-way
healthCheck:
command: ["echo", "ok"]
4 changes: 4 additions & 0 deletions core/test/data/test-projects/container/garden.yml
Original file line number Diff line number Diff line change
@@ -17,6 +17,10 @@ environments:
providers:
- name: local-kubernetes
environments: [local]
devMode:
defaults:
exclude:
- "**/prefix-*"
- name: local-kubernetes
deploymentRegistry: &deploymentRegistry
hostname: index.docker.io
69 changes: 1 addition & 68 deletions core/test/integ/src/plugins/kubernetes/container/deployment.ts
Original file line number Diff line number Diff line change
@@ -7,7 +7,6 @@
*/

import { expect } from "chai"
import { join } from "path"
import { Garden } from "../../../../../../src/garden"
import { ConfigGraph } from "../../../../../../src/config-graph"
import { emptyRuntimeContext } from "../../../../../../src/runtime-context"
@@ -23,10 +22,7 @@ import { getServiceStatuses } from "../../../../../../src/tasks/base"
import { expectError, grouped } from "../../../../../helpers"
import stripAnsi = require("strip-ansi")
import { gardenAnnotationKey } from "../../../../../../src/util/string"
import { getContainerServiceStatus } from "../../../../../../src/plugins/kubernetes/container/status"
import { sleep } from "../../../../../../src/util/util"
import { pathExists, readFile, remove, writeFile } from "fs-extra"
import { execInWorkload, kilobytesToString, millicpuToString } from "../../../../../../src/plugins/kubernetes/util"
import { kilobytesToString, millicpuToString } from "../../../../../../src/plugins/kubernetes/util"
import { getResourceRequirements } from "../../../../../../src/plugins/kubernetes/container/util"

describe("kubernetes container deployment handlers", () => {
@@ -567,69 +563,6 @@ describe("kubernetes container deployment handlers", () => {
{ name: "test", mountPath: "/volume" },
])
})

it("should deploy a service in dev mode and successfully set up the sync", async () => {
const service = graph.getService("dev-mode")
const module = service.module
const log = garden.log
const deployTask = new DeployTask({
garden,
graph,
log,
service,
force: true,
forceBuild: false,
devModeServiceNames: [service.name],
hotReloadServiceNames: [],
})

await garden.processTasks([deployTask], { throwOnError: true })
const status = await getContainerServiceStatus({
ctx,
module,
service,
runtimeContext: emptyRuntimeContext,
log,
devMode: true,
hotReload: false,
})

// First, we create a file locally and verify that it gets synced into the pod
await writeFile(join(module.path, "made_locally"), "foo")
await sleep(300)
const execRes = await execInWorkload({
command: ["/bin/sh", "-c", "cat /tmp/made_locally"],
ctx,
provider,
log,
namespace: provider.config.namespace!.name!,
workload: status.detail.workload!,
interactive: false,
})
expect(execRes.output.trim()).to.eql("foo")

// Then, we create a file in the pod and verify that it gets synced back
await execInWorkload({
command: ["/bin/sh", "-c", "echo bar > /tmp/made_in_pod"],
ctx,
provider,
log,
namespace: provider.config.namespace!.name!,
workload: status.detail.workload!,
interactive: false,
})
await sleep(300)
const localPath = join(module.path, "made_in_pod")
expect(await pathExists(localPath)).to.eql(true)
expect((await readFile(localPath)).toString().trim()).to.eql("bar")

// Clean up the files we created locally
for (const filename of ["made_locally", "made_in_pod"]) {
try {
await remove(join(module.path, filename))
} catch {}
}
})
})

grouped("cluster-docker").context("cluster-docker mode", () => {
190 changes: 190 additions & 0 deletions core/test/integ/src/plugins/kubernetes/dev-mode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
/*
* Copyright (C) 2018-2021 Garden Technologies, Inc. <info@garden.io>
*
* 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 { expect } from "chai"
import { mkdirp, pathExists, readFile, remove, writeFile } from "fs-extra"
import { join } from "path"
import { ConfigGraph } from "../../../../../src/config-graph"
import { Garden } from "../../../../../src/garden"
import { LogEntry } from "../../../../../src/logger/log-entry"
import { ContainerService } from "../../../../../src/plugins/container/config"
import { KubernetesPluginContext, KubernetesProvider } from "../../../../../src/plugins/kubernetes/config"
import { getContainerServiceStatus } from "../../../../../src/plugins/kubernetes/container/status"
import { KubernetesWorkload } from "../../../../../src/plugins/kubernetes/types"
import { execInWorkload } from "../../../../../src/plugins/kubernetes/util"
import { emptyRuntimeContext } from "../../../../../src/runtime-context"
import { DeployTask } from "../../../../../src/tasks/deploy"
import { dedent } from "../../../../../src/util/string"
import { sleep } from "../../../../../src/util/util"
import { getContainerTestGarden } from "./container/container"

describe("dev mode deployments and sync behavior", () => {
let garden: Garden
let graph: ConfigGraph
let ctx: KubernetesPluginContext
let provider: KubernetesProvider

const execInPod = async (command: string[], log: LogEntry, workload: KubernetesWorkload) => {
const execRes = await execInWorkload({
command,
ctx,
provider,
log,
namespace: provider.config.namespace!.name!,
workload,
interactive: false,
})
return execRes
}

before(async () => {
await init("local")
})

beforeEach(async () => {
graph = await garden.getConfigGraph({ log: garden.log, emit: false })
})

afterEach(async () => {
if (garden) {
await garden.close()
}
})

const init = async (environmentName: string) => {
garden = await getContainerTestGarden(environmentName)
provider = <KubernetesProvider>await garden.resolveProvider(garden.log, "local-kubernetes")
ctx = <KubernetesPluginContext>await garden.getPluginContext(provider)
}

it("should deploy a service in dev mode and successfully set a two-way sync", async () => {
await init("local")
const service = graph.getService("dev-mode")
const module = service.module
const log = garden.log
const deployTask = new DeployTask({
garden,
graph,
log,
service,
force: true,
forceBuild: false,
devModeServiceNames: [service.name],
hotReloadServiceNames: [],
})

await garden.processTasks([deployTask], { throwOnError: true })
const status = await getContainerServiceStatus({
ctx,
module,
service,
runtimeContext: emptyRuntimeContext,
log,
devMode: true,
hotReload: false,
})

const workload = status.detail.workload!

// First, we create a file locally and verify that it gets synced into the pod
await writeFile(join(module.path, "made_locally"), "foo")
await sleep(300)
const execRes = await execInPod(["/bin/sh", "-c", "cat /tmp/made_locally"], log, workload)
expect(execRes.output.trim()).to.eql("foo")

// Then, we create a file in the pod and verify that it gets synced back
await execInPod(["/bin/sh", "-c", "echo bar > /tmp/made_in_pod"], log, workload)
await sleep(500)
const localPath = join(module.path, "made_in_pod")
expect(await pathExists(localPath)).to.eql(true)
expect((await readFile(localPath)).toString().trim()).to.eql("bar")

// This is to make sure that the two-way sync doesn't recreate the local files we're about to delete here.
const actions = await garden.getActionRouter()
await actions.deleteService({ graph, log: garden.log, service })

// Clean up the files we created locally
for (const filename of ["made_locally", "made_in_pod"]) {
try {
await remove(join(module.path, filename))
} catch {}
}
})

it("should apply ignore rules from the sync spec and the provider-level dev mode defaults", async () => {
await init("local")
const service: ContainerService = graph.getService("dev-mode")

// We want to ignore the following directories (all at module root)
// somedir
// prefix-a <--- matched by provider-level default excludes
// nested/prefix-b <--- matched by provider-level default excludes

service.spec.devMode!.sync[0].mode = "one-way-replica"
service.spec.devMode!.sync[0].exclude = ["somedir"]
const module = service.module
const log = garden.log
const deployTask = new DeployTask({
garden,
graph,
log,
service,
force: true,
forceBuild: false,
devModeServiceNames: [service.name],
hotReloadServiceNames: [],
})

await garden.processTasks([deployTask], { throwOnError: true })
const status = await getContainerServiceStatus({
ctx,
module,
service,
runtimeContext: emptyRuntimeContext,
log,
devMode: true,
hotReload: false,
})

const workload = status.detail.workload!

// First, we create a non-ignored file locally
await writeFile(join(module.path, "made_locally"), "foo")

// Then, we create files in each of the directories we intended to ignore in the `exclude` spec above, and
// verify that they didn't get synced into the pod.
await mkdirp(join(module.path, "somedir"))
await writeFile(join(module.path, "somedir", "file"), "foo")
await mkdirp(join(module.path, "prefix-a"))
await writeFile(join(module.path, "prefix-a", "file"), "foo")
await mkdirp(join(module.path, "nested", "prefix-b"))
await writeFile(join(module.path, "nested", "prefix-b", "file"), "foo")
await sleep(500)
const ignoreExecRes = await execInPod(["/bin/sh", "-c", "ls -a /tmp /tmp/nested"], log, workload)
// Clean up the files we created locally
for (const filename of ["made_locally", "somedir", "prefix-a", "nested"]) {
try {
await remove(join(module.path, filename))
} catch {}
}

expect(ignoreExecRes.output.trim()).to.eql(dedent`
/tmp:
.
..
Dockerfile
garden.yml
made_locally
nested
/tmp/nested:
.
..
`)
})
})
107 changes: 107 additions & 0 deletions core/test/unit/src/plugins/kubernetes/dev-mode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* Copyright (C) 2018-2021 Garden Technologies, Inc. <info@garden.io>
*
* 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 { expect } from "chai"
import { builtInExcludes, makeSyncConfig } from "../../../../../src/plugins/kubernetes/dev-mode"

describe("k8s dev mode helpers", () => {
const localPath = "/path/to/module/src"
const remoteDestination = "exec:'various fun connection parameters'"
const source = "src"
const target = "/app/src"
describe("makeSyncConfig", () => {
it("should generate a simple sync config", () => {
const config = makeSyncConfig({
localPath,
remoteDestination,
defaults: {},
spec: {
source,
target,
mode: "one-way",
},
})

expect(config).to.eql({
alpha: localPath,
beta: remoteDestination,
ignore: [...builtInExcludes],
mode: "one-way",
defaultOwner: undefined,
defaultGroup: undefined,
defaultDirectoryMode: undefined,
defaultFileMode: undefined,
})
})

it("should apply provider-level defaults", () => {
const config = makeSyncConfig({
localPath,
remoteDestination,
defaults: {
exclude: ["**/*.log"],
owner: "node",
group: "admin",
fileMode: 600,
directoryMode: 700,
},
spec: {
source,
target,
mode: "one-way",
},
})

expect(config).to.eql({
alpha: localPath,
beta: remoteDestination,
ignore: [...builtInExcludes, "**/*.log"],
mode: "one-way",
defaultOwner: "node",
defaultGroup: "admin",
defaultFileMode: 600,
defaultDirectoryMode: 700,
})
})

it("should override/extend provider-level defaults with settings on the sync spec", () => {
const config = makeSyncConfig({
localPath,
remoteDestination,
defaults: {
exclude: ["**/*.log"],
owner: "node",
group: "admin",
fileMode: 600,
directoryMode: 700,
},
spec: {
source,
target,
mode: "one-way",
exclude: ["node_modules"],
defaultOwner: "owner_from_spec",
defaultGroup: "group_from_spec",
defaultFileMode: 700,
defaultDirectoryMode: 777,
},
})

expect(config).to.eql({
alpha: localPath,
beta: remoteDestination,
ignore: [...builtInExcludes, "**/*.log", "node_modules"],
mode: "one-way",
defaultOwner: "owner_from_spec",
defaultGroup: "group_from_spec",
defaultFileMode: 700,
defaultDirectoryMode: 777,
})
})
})
})
4 changes: 4 additions & 0 deletions docs/reference/module-types/container.md
Original file line number Diff line number Diff line change
@@ -247,6 +247,8 @@ services:
target:

# Specify a list of POSIX-style paths or glob patterns that should be excluded from the sync.
#
# `.git` directories and `.garden` directories are always ignored.
exclude:

# The sync mode to use for the given paths. Allowed options: `one-way`, `one-way-replica`, `two-way`.
@@ -1228,6 +1230,8 @@ services:

Specify a list of POSIX-style paths or glob patterns that should be excluded from the sync.

`.git` directories and `.garden` directories are always ignored.

| Type | Required |
| ------------------ | -------- |
| `array[posixPath]` | No |
4 changes: 4 additions & 0 deletions docs/reference/module-types/helm.md
Original file line number Diff line number Diff line change
@@ -185,6 +185,8 @@ devMode:
target:

# Specify a list of POSIX-style paths or glob patterns that should be excluded from the sync.
#
# `.git` directories and `.garden` directories are always ignored.
exclude:

# The sync mode to use for the given paths. Allowed options: `one-way`, `one-way-replica`, `two-way`.
@@ -946,6 +948,8 @@ devMode:

Specify a list of POSIX-style paths or glob patterns that should be excluded from the sync.

`.git` directories and `.garden` directories are always ignored.

| Type | Required |
| ------------------ | -------- |
| `array[posixPath]` | No |
4 changes: 4 additions & 0 deletions docs/reference/module-types/jib-container.md
Original file line number Diff line number Diff line change
@@ -265,6 +265,8 @@ services:
target:

# Specify a list of POSIX-style paths or glob patterns that should be excluded from the sync.
#
# `.git` directories and `.garden` directories are always ignored.
exclude:

# The sync mode to use for the given paths. Allowed options: `one-way`, `one-way-replica`, `two-way`.
@@ -1286,6 +1288,8 @@ services:

Specify a list of POSIX-style paths or glob patterns that should be excluded from the sync.

`.git` directories and `.garden` directories are always ignored.

| Type | Required |
| ------------------ | -------- |
| `array[posixPath]` | No |
4 changes: 4 additions & 0 deletions docs/reference/module-types/kubernetes.md
Original file line number Diff line number Diff line change
@@ -171,6 +171,8 @@ devMode:
target:

# Specify a list of POSIX-style paths or glob patterns that should be excluded from the sync.
#
# `.git` directories and `.garden` directories are always ignored.
exclude:

# The sync mode to use for the given paths. Allowed options: `one-way`, `one-way-replica`, `two-way`.
@@ -829,6 +831,8 @@ devMode:

Specify a list of POSIX-style paths or glob patterns that should be excluded from the sync.

`.git` directories and `.garden` directories are always ignored.

| Type | Required |
| ------------------ | -------- |
| `array[posixPath]` | No |
4 changes: 4 additions & 0 deletions docs/reference/module-types/maven-container.md
Original file line number Diff line number Diff line change
@@ -247,6 +247,8 @@ services:
target:

# Specify a list of POSIX-style paths or glob patterns that should be excluded from the sync.
#
# `.git` directories and `.garden` directories are always ignored.
exclude:

# The sync mode to use for the given paths. Allowed options: `one-way`, `one-way-replica`, `two-way`.
@@ -1238,6 +1240,8 @@ services:

Specify a list of POSIX-style paths or glob patterns that should be excluded from the sync.

`.git` directories and `.garden` directories are always ignored.

| Type | Required |
| ------------------ | -------- |
| `array[posixPath]` | No |
152 changes: 146 additions & 6 deletions docs/reference/providers/kubernetes.md
Original file line number Diff line number Diff line change
@@ -111,11 +111,56 @@ providers:
# A default hostname to use when no hostname is explicitly configured for a service.
defaultHostname:

# Defines the strategy for deploying the project services.
# Default is "rolling update" and there is experimental support for "blue/green" deployment.
# The feature only supports modules of type `container`: other types will just deploy using the default strategy.
# Sets the deployment strategy for `container` services.
#
# The default is `"rolling"`, which performs rolling updates. There is also experimental support for blue/green
# deployments (via the `"blue-green"` strategy).
#
# Note that this setting only applies to `container` services (and not, for example, `kubernetes` or `helm`
# services).
deploymentStrategy: rolling

# Configuration options for dev mode.
devMode:
# Specifies default settings for dev mode syncs (e.g. for `container`, `kubernetes` and `helm` services).
#
# These are overridden/extended by the settings of any individual dev mode sync specs for a given module or
# service.
#
# Dev mode is enabled when running the `garden dev` command, and by setting the `--dev` flag on the `garden
# deploy` command.
#
# See the [Code Synchronization guide](https://docs.garden.io/guides/code-synchronization-dev-mode) for more
# information.
defaults:
# Specify a list of POSIX-style paths or glob patterns that should be excluded from the sync.
#
# Any exclusion patterns defined in individual dev mode sync specs will be applied in addition to these
# patterns.
#
# `.git` directories and `.garden` directories are always ignored.
exclude:

# The default permission bits, specified as an octal, to set on files at the sync target. Defaults to 0600
# (user read/write). See the [Mutagen
# docs](https://mutagen.io/documentation/synchronization/permissions#permissions) for more information.
fileMode:

# The default permission bits, specified as an octal, to set on directories at the sync target. Defaults to
# 0700 (user read/write). See the [Mutagen
# docs](https://mutagen.io/documentation/synchronization/permissions#permissions) for more information.
directoryMode:

# Set the default owner of files and directories at the target. Specify either an integer ID or a string name.
# See the [Mutagen docs](https://mutagen.io/documentation/synchronization/permissions#owners-and-groups) for
# more information.
owner:

# Set the default group on files and directories at the target. Specify either an integer ID or a string name.
# See the [Mutagen docs](https://mutagen.io/documentation/synchronization/permissions#owners-and-groups) for
# more information.
group:

# Require SSL on all `container` module services. If set to true, an error is raised when no certificate is
# available for a configured hostname on a `container` module.
forceSsl: false
@@ -627,14 +672,109 @@ providers:
**Experimental**: this is an experimental feature and the API might change in the future.
{% endhint %}

Defines the strategy for deploying the project services.
Default is "rolling update" and there is experimental support for "blue/green" deployment.
The feature only supports modules of type `container`: other types will just deploy using the default strategy.
Sets the deployment strategy for `container` services.

The default is `"rolling"`, which performs rolling updates. There is also experimental support for blue/green deployments (via the `"blue-green"` strategy).

Note that this setting only applies to `container` services (and not, for example, `kubernetes` or `helm` services).

| Type | Default | Required |
| -------- | ----------- | -------- |
| `string` | `"rolling"` | No |

### `providers[].devMode`

[providers](#providers) > devMode

Configuration options for dev mode.

| Type | Required |
| -------- | -------- |
| `object` | No |

### `providers[].devMode.defaults`

[providers](#providers) > [devMode](#providersdevmode) > defaults

Specifies default settings for dev mode syncs (e.g. for `container`, `kubernetes` and `helm` services).

These are overridden/extended by the settings of any individual dev mode sync specs for a given module or service.

Dev mode is enabled when running the `garden dev` command, and by setting the `--dev` flag on the `garden deploy` command.

See the [Code Synchronization guide](https://docs.garden.io/guides/code-synchronization-dev-mode) for more information.

| Type | Required |
| -------- | -------- |
| `object` | No |

### `providers[].devMode.defaults.exclude[]`

[providers](#providers) > [devMode](#providersdevmode) > [defaults](#providersdevmodedefaults) > exclude

Specify a list of POSIX-style paths or glob patterns that should be excluded from the sync.

Any exclusion patterns defined in individual dev mode sync specs will be applied in addition to these patterns.

`.git` directories and `.garden` directories are always ignored.

| Type | Required |
| ------------------ | -------- |
| `array[posixPath]` | No |

Example:

```yaml
providers:
- devMode:
...
defaults:
...
exclude:
- dist/**/*
- '*.log'
```

### `providers[].devMode.defaults.fileMode`

[providers](#providers) > [devMode](#providersdevmode) > [defaults](#providersdevmodedefaults) > fileMode

The default permission bits, specified as an octal, to set on files at the sync target. Defaults to 0600 (user read/write). See the [Mutagen docs](https://mutagen.io/documentation/synchronization/permissions#permissions) for more information.

| Type | Required |
| -------- | -------- |
| `number` | No |

### `providers[].devMode.defaults.directoryMode`

[providers](#providers) > [devMode](#providersdevmode) > [defaults](#providersdevmodedefaults) > directoryMode

The default permission bits, specified as an octal, to set on directories at the sync target. Defaults to 0700 (user read/write). See the [Mutagen docs](https://mutagen.io/documentation/synchronization/permissions#permissions) for more information.

| Type | Required |
| -------- | -------- |
| `number` | No |

### `providers[].devMode.defaults.owner`

[providers](#providers) > [devMode](#providersdevmode) > [defaults](#providersdevmodedefaults) > owner

Set the default owner of files and directories at the target. Specify either an integer ID or a string name. See the [Mutagen docs](https://mutagen.io/documentation/synchronization/permissions#owners-and-groups) for more information.

| Type | Required |
| ----------------- | -------- |
| `number | string` | No |

### `providers[].devMode.defaults.group`

[providers](#providers) > [devMode](#providersdevmode) > [defaults](#providersdevmodedefaults) > group

Set the default group on files and directories at the target. Specify either an integer ID or a string name. See the [Mutagen docs](https://mutagen.io/documentation/synchronization/permissions#owners-and-groups) for more information.

| Type | Required |
| ----------------- | -------- |
| `number | string` | No |

### `providers[].forceSsl`

[providers](#providers) > forceSsl
152 changes: 146 additions & 6 deletions docs/reference/providers/local-kubernetes.md
Original file line number Diff line number Diff line change
@@ -107,11 +107,56 @@ providers:
# A default hostname to use when no hostname is explicitly configured for a service.
defaultHostname:

# Defines the strategy for deploying the project services.
# Default is "rolling update" and there is experimental support for "blue/green" deployment.
# The feature only supports modules of type `container`: other types will just deploy using the default strategy.
# Sets the deployment strategy for `container` services.
#
# The default is `"rolling"`, which performs rolling updates. There is also experimental support for blue/green
# deployments (via the `"blue-green"` strategy).
#
# Note that this setting only applies to `container` services (and not, for example, `kubernetes` or `helm`
# services).
deploymentStrategy: rolling

# Configuration options for dev mode.
devMode:
# Specifies default settings for dev mode syncs (e.g. for `container`, `kubernetes` and `helm` services).
#
# These are overridden/extended by the settings of any individual dev mode sync specs for a given module or
# service.
#
# Dev mode is enabled when running the `garden dev` command, and by setting the `--dev` flag on the `garden
# deploy` command.
#
# See the [Code Synchronization guide](https://docs.garden.io/guides/code-synchronization-dev-mode) for more
# information.
defaults:
# Specify a list of POSIX-style paths or glob patterns that should be excluded from the sync.
#
# Any exclusion patterns defined in individual dev mode sync specs will be applied in addition to these
# patterns.
#
# `.git` directories and `.garden` directories are always ignored.
exclude:

# The default permission bits, specified as an octal, to set on files at the sync target. Defaults to 0600
# (user read/write). See the [Mutagen
# docs](https://mutagen.io/documentation/synchronization/permissions#permissions) for more information.
fileMode:

# The default permission bits, specified as an octal, to set on directories at the sync target. Defaults to
# 0700 (user read/write). See the [Mutagen
# docs](https://mutagen.io/documentation/synchronization/permissions#permissions) for more information.
directoryMode:

# Set the default owner of files and directories at the target. Specify either an integer ID or a string name.
# See the [Mutagen docs](https://mutagen.io/documentation/synchronization/permissions#owners-and-groups) for
# more information.
owner:

# Set the default group on files and directories at the target. Specify either an integer ID or a string name.
# See the [Mutagen docs](https://mutagen.io/documentation/synchronization/permissions#owners-and-groups) for
# more information.
group:

# Require SSL on all `container` module services. If set to true, an error is raised when no certificate is
# available for a configured hostname on a `container` module.
forceSsl: false
@@ -589,14 +634,109 @@ providers:
**Experimental**: this is an experimental feature and the API might change in the future.
{% endhint %}

Defines the strategy for deploying the project services.
Default is "rolling update" and there is experimental support for "blue/green" deployment.
The feature only supports modules of type `container`: other types will just deploy using the default strategy.
Sets the deployment strategy for `container` services.

The default is `"rolling"`, which performs rolling updates. There is also experimental support for blue/green deployments (via the `"blue-green"` strategy).

Note that this setting only applies to `container` services (and not, for example, `kubernetes` or `helm` services).

| Type | Default | Required |
| -------- | ----------- | -------- |
| `string` | `"rolling"` | No |

### `providers[].devMode`

[providers](#providers) > devMode

Configuration options for dev mode.

| Type | Required |
| -------- | -------- |
| `object` | No |

### `providers[].devMode.defaults`

[providers](#providers) > [devMode](#providersdevmode) > defaults

Specifies default settings for dev mode syncs (e.g. for `container`, `kubernetes` and `helm` services).

These are overridden/extended by the settings of any individual dev mode sync specs for a given module or service.

Dev mode is enabled when running the `garden dev` command, and by setting the `--dev` flag on the `garden deploy` command.

See the [Code Synchronization guide](https://docs.garden.io/guides/code-synchronization-dev-mode) for more information.

| Type | Required |
| -------- | -------- |
| `object` | No |

### `providers[].devMode.defaults.exclude[]`

[providers](#providers) > [devMode](#providersdevmode) > [defaults](#providersdevmodedefaults) > exclude

Specify a list of POSIX-style paths or glob patterns that should be excluded from the sync.

Any exclusion patterns defined in individual dev mode sync specs will be applied in addition to these patterns.

`.git` directories and `.garden` directories are always ignored.

| Type | Required |
| ------------------ | -------- |
| `array[posixPath]` | No |

Example:

```yaml
providers:
- devMode:
...
defaults:
...
exclude:
- dist/**/*
- '*.log'
```

### `providers[].devMode.defaults.fileMode`

[providers](#providers) > [devMode](#providersdevmode) > [defaults](#providersdevmodedefaults) > fileMode

The default permission bits, specified as an octal, to set on files at the sync target. Defaults to 0600 (user read/write). See the [Mutagen docs](https://mutagen.io/documentation/synchronization/permissions#permissions) for more information.

| Type | Required |
| -------- | -------- |
| `number` | No |

### `providers[].devMode.defaults.directoryMode`

[providers](#providers) > [devMode](#providersdevmode) > [defaults](#providersdevmodedefaults) > directoryMode

The default permission bits, specified as an octal, to set on directories at the sync target. Defaults to 0700 (user read/write). See the [Mutagen docs](https://mutagen.io/documentation/synchronization/permissions#permissions) for more information.

| Type | Required |
| -------- | -------- |
| `number` | No |

### `providers[].devMode.defaults.owner`

[providers](#providers) > [devMode](#providersdevmode) > [defaults](#providersdevmodedefaults) > owner

Set the default owner of files and directories at the target. Specify either an integer ID or a string name. See the [Mutagen docs](https://mutagen.io/documentation/synchronization/permissions#owners-and-groups) for more information.

| Type | Required |
| ----------------- | -------- |
| `number | string` | No |

### `providers[].devMode.defaults.group`

[providers](#providers) > [devMode](#providersdevmode) > [defaults](#providersdevmodedefaults) > group

Set the default group on files and directories at the target. Specify either an integer ID or a string name. See the [Mutagen docs](https://mutagen.io/documentation/synchronization/permissions#owners-and-groups) for more information.

| Type | Required |
| ----------------- | -------- |
| `number | string` | No |

### `providers[].forceSsl`

[providers](#providers) > forceSsl

0 comments on commit d6c6228

Please sign in to comment.