Skip to content

Commit

Permalink
feat(config): templating for actions and workflows + new RenderTempla…
Browse files Browse the repository at this point in the history
…te kind

This adds support for templating actions and workflows in ConfigTemplate
configs (formerly ModuleTemplate).

The old way of referencing templates (a Module with `type: templated`) is also
superseded by a new `kind: RenderTemplate` config, with largely the same
semantics, except with an added `configs` field that supports actions and
workflows.

The resolution flow is very similar for actions and workflows, as it was (and
remains for now) for modules.

For now we have left out the option to generate files in the source tree, which
is possible with the now-deprecated `generateFiles` field on modules. We may
later consider making that a native feature on `RenderTemplate` configs as
opposed to on the templated configs themselves, but it may be an unnecessary
feature since that can in most cases be handled by `exec` actions.
  • Loading branch information
edvald authored and thsig committed Mar 24, 2023
1 parent 655d300 commit 9ec9ccd
Show file tree
Hide file tree
Showing 76 changed files with 2,509 additions and 795 deletions.
10 changes: 5 additions & 5 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -934,11 +934,11 @@ workflows:
# name: e2e-tasks-modules
# project: tasks-modules
# requires: [build]
# - e2e-project:
# <<: *only-internal-prs
# name: e2e-templated-k8s-container
# project: templated-k8s-container
# requires: [build]
- e2e-project:
<<: *only-internal-prs
name: e2e-templated-k8s-container
project: templated-k8s-container
requires: [build]
- e2e-project:
<<: *only-internal-prs
name: e2e-templated-k8s-container-modules
Expand Down
2 changes: 2 additions & 0 deletions .gitbook.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ redirects:
module-types/openfaas: ./reference/module-types/openfaas.md
module-types/persistentvolumeclaim: ./reference/module-types/persistentvolumeclaim.md
module-types/terraform: ./reference/module-types/terraform.md
reference/module-template-config: ./reference/config-template-config.md
using-garden/module-templates: ./using-garden/config-templates.md
# Redirects after docs restructure (https://github.com/garden-io/garden/pull/3467)
advanced/terraform: ./terraform-plugin/about.md
advanced/pulumi: ./pulumi-plugin/about.md
Expand Down
37 changes: 21 additions & 16 deletions core/src/actions/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ import {
ResolvedAction,
ResolvedActionWrapperParams,
} from "./types"
import { varfileDescription } from "../config/base"
import { baseInternalFieldsSchema, varfileDescription } from "../config/base"
import { PickTypeByKind } from "../graph/config-graph"
import { DeployAction } from "./deploy"
import { TestAction } from "./test"
Expand All @@ -63,6 +63,18 @@ import { uuidv4 } from "../util/random"

// TODO-G2: split this file

const actionInternalFieldsSchema = createSchema({
name: "action-config-internal-fields",
extend: baseInternalFieldsSchema,
keys: {
groupName: joi.string().optional().meta({ internal: true }),
moduleName: joi.string().optional().meta({ internal: true }),
resolved: joi.boolean().optional().meta({ internal: true }),
},
allowUnknown: true,
meta: { internal: true },
})

const actionSourceSpecSchema = () =>
joi
.object()
Expand Down Expand Up @@ -122,20 +134,7 @@ export const baseActionConfigSchema = createSchema({
description: joi.string().description("A description of the action.").meta({ templateContext: null }),

// Internal metadata fields (these are rejected in `loadConfigResources()` if specified by users)
internal: joi
.object()
.keys({
basePath: joi.string().required().meta({ internal: true }),
configFilePath: joi.string().optional().meta({ internal: true }),
groupName: joi.string().optional().meta({ internal: true }),
moduleName: joi.string().optional().meta({ internal: true }),
resolved: joi.boolean().optional().meta({ internal: true }),
inputs: joi.object().optional().meta({ internal: true }),
parentName: joi.string().optional().meta({ internal: true }),
templateName: joi.string().optional().meta({ internal: true }),
})
.unknown(true)
.meta({ internal: true }),
internal: actionInternalFieldsSchema,

// Location
source: actionSourceSpecSchema(),
Expand Down Expand Up @@ -526,6 +525,10 @@ export abstract class BaseAction<C extends BaseActionConfig = BaseActionConfig,
return this.getFullVersion().versionString
}

getInternal(): BaseActionConfig["internal"] {
return { ...this.getConfig("internal") }
}

getConfig(): C
getConfig<K extends keyof C>(key: K): C[K]
getConfig(key?: keyof C["spec"]) {
Expand Down Expand Up @@ -634,7 +637,8 @@ export abstract class ResolvedRuntimeAction<
Outputs extends {} = any
>
extends RuntimeAction<Config, Outputs>
implements ResolvedActionExtension<Config, Outputs> {
implements ResolvedActionExtension<Config, Outputs>
{
protected graph: ResolvedConfigGraph
protected readonly params: ResolvedActionWrapperParams<Config>
protected readonly resolved: true
Expand All @@ -652,6 +656,7 @@ export abstract class ResolvedRuntimeAction<
this.resolvedDependencies = params.resolvedDependencies
this._staticOutputs = params.staticOutputs
this._config.spec = params.spec
this._config.internal.inputs = params.inputs
}

/**
Expand Down
1 change: 1 addition & 0 deletions core/src/actions/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ export class ResolvedBuildAction<
this.resolved = true
this._staticOutputs = params.staticOutputs
this._config.spec = params.spec
this._config.internal.inputs = params.inputs
}
getExecutedDependencies() {
return this.executedDependencies
Expand Down
23 changes: 8 additions & 15 deletions core/src/actions/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import type { ActionKind } from "../plugin/action-types"
import type { GraphResults } from "../graph/results"
import type { BaseAction } from "./base"
import type { ValidResultType } from "../tasks/base"
import type { BaseGardenResource, GardenResourceInternalFields } from "../config/base"

// TODO-G2: split this file

Expand All @@ -42,7 +43,8 @@ export interface ActionSourceSpec {
*
* See inline comments below for information on what templating is allowed on different fields.
*/
export interface BaseActionConfig<K extends ActionKind = ActionKind, T = string, Spec = any> {
export interface BaseActionConfig<K extends ActionKind = ActionKind, T = string, Spec = any>
extends BaseGardenResource {
// Basics
// -> No templating is allowed on these.
apiVersion?: string
Expand All @@ -57,15 +59,9 @@ export interface BaseActionConfig<K extends ActionKind = ActionKind, T = string,

// Internal metadata
// -> No templating is allowed on these.
internal: {
basePath: string
configFilePath?: string
internal: GardenResourceInternalFields & {
groupName?: string
resolved?: boolean // Set to true if no resolution is required, e.g. set for actions converted from modules
// -> set by templates
inputs?: DeepPrimitiveMap
parentName?: string
templateName?: string
// For backwards-compatibility, applied on actions returned from module conversion handlers
moduleName?: string
moduleVersion?: ModuleVersion
Expand Down Expand Up @@ -104,17 +100,13 @@ export interface ActionConfigTypes {
* See https://melvingeorge.me/blog/convert-array-into-string-literal-union-type-typescript
*/
export const actionStateTypes = ["ready", "not-ready", "processing", "failed", "unknown"] as const
export type ActionState = typeof actionStateTypes[number]
export type ActionState = (typeof actionStateTypes)[number]

/**
* These are the states emitted in status events. Here, we include additional states to help distinguish status event
* emitted around status/cache checks VS statuses emitted around the execution after a failed status check.
*/
export const actionStateTypesForEvent = [
...actionStateTypes,
"getting-status",
"cached",
] as const
export const actionStateTypesForEvent = [...actionStateTypes, "getting-status", "cached"] as const
/**
* This type represents the lifecycle of an individual action execution.
*
Expand Down Expand Up @@ -158,7 +150,7 @@ export const actionStateTypesForEvent = [
* - `"failed"`: The action was executed, but a failure or error occurred, so no up-to-date result was created for
* the action.
*/
export type ActionStateForEvent = typeof actionStateTypesForEvent[number]
export type ActionStateForEvent = (typeof actionStateTypesForEvent)[number]

export const stateForCacheStatusEvent = (state: ActionState): ActionStateForEvent => {
return state === "ready" ? "cached" : state
Expand Down Expand Up @@ -220,6 +212,7 @@ export interface ResolveActionParams<C extends BaseActionConfig, Outputs extends
resolvedDependencies: ResolvedAction[]
spec: C["spec"]
staticOutputs: Outputs
inputs: DeepPrimitiveMap
variables: DeepPrimitiveMap
}

Expand Down
6 changes: 3 additions & 3 deletions core/src/commands/custom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ export class CustomCommandWrapper extends Command {
const exec = validateWithPath({
config: resolveTemplateStrings(this.spec.exec, commandContext),
schema: customCommandExecSchema(),
path: this.spec.path,
path: this.spec.internal.basePath,
projectRoot: garden.projectRoot,
configType: `exec field in custom Command '${this.name}'`,
})
Expand Down Expand Up @@ -169,7 +169,7 @@ export class CustomCommandWrapper extends Command {
let gardenCommand = validateWithPath({
config: resolveTemplateStrings(this.spec.gardenCommand, commandContext),
schema: customCommandGardenCommandSchema(),
path: this.spec.path,
path: this.spec.internal.basePath,
projectRoot: garden.projectRoot,
configType: `gardenCommand field in custom Command '${this.name}'`,
})
Expand Down Expand Up @@ -265,7 +265,7 @@ export async function getCustomCommands(log: Log, projectRoot: string) {
exec: joi.any(),
gardenCommand: joi.any(),
}),
path: config.path,
path: (<CommandResource>config).internal.basePath,
projectRoot,
configType: `custom Command '${config.name}'`,
})
Expand Down
1 change: 1 addition & 0 deletions core/src/commands/run-workflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ export class RunWorkflowCommand extends Command<Args, {}> {
garden,
resolvedSteps: result.steps,
stepName,
workflow,
})

const stepStartedAt = new Date()
Expand Down
Loading

0 comments on commit 9ec9ccd

Please sign in to comment.