From d629981ef98daa45c3e58030e96c71113b45a586 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ey=C3=BE=C3=B3r=20Magn=C3=BAsson?= Date: Thu, 16 Jan 2025 11:42:24 +0100 Subject: [PATCH] Simplify provider init (#6706) improvement(framework): always run `prepareEnvironment` handler Previously, Garden would first run the `getEnvironmentStatus` handler and depending on the results, either run the `prepareEnvironment` handler or not. Now we always run the `prepareEnvironment` handler (if the provider status is not cached). The reason for this change is that the previous flow is an unneeded abstraction that doesn't serve any purpose at this point and makes the provider initialisation harder to reason about. The specific motivation is that there's bug in the Kubernetes provider where some resources aren't created when the environment is prepared. It's actually more work to first check the statuses of these resources, return those, and then create them. In particular since we have helpers to create them in an idempotent manner. That's why now we just always call `prepareEnvironment` and have that handler figure out what needs to be done. We still keep the `getEnvironmentStatus` handler for status-only commands but now it doesn't have side effects. Whereas before the status handler would e.g. create a namespace. Plugins can then decide to use that if needed. E.g. the `prepareEnvironment` handler for the Terraform plugins uses `getEnvironmentStatus` to decide what needs to happen. We'll fix the actual bug that prompted this change in a follow up commit. --- .../handlers/Provider/getEnvironmentStatus.ts | 8 +-- .../handlers/Provider/prepareEnvironment.ts | 14 ++-- core/src/plugins/exec/exec.ts | 43 +++++++------ .../kubernetes/commands/cluster-init.ts | 1 - core/src/plugins/kubernetes/init.ts | 64 +++++++++++-------- core/src/plugins/kubernetes/local/local.ts | 10 ++- core/src/plugins/kubernetes/namespace.ts | 2 +- .../kubernetes/nginx/default-backend.ts | 2 +- .../nginx/ingress-controller-base.ts | 5 +- .../kubernetes/nginx/ingress-controller.ts | 6 +- .../plugins/kubernetes/nginx/nginx-helm.ts | 4 +- .../plugins/kubernetes/nginx/nginx-kind.ts | 2 +- .../kubernetes/nginx/nginx-microk8s.ts | 2 +- .../kubernetes/nginx/nginx-minikube.ts | 2 +- core/src/tasks/resolve-provider.ts | 49 +++++++------- .../plugins/kubernetes/ingress-controller.ts | 4 -- .../integ/src/plugins/kubernetes/provider.ts | 2 - .../test/unit/src/commands/get/get-outputs.ts | 4 +- core/test/unit/src/garden.ts | 8 ++- core/test/unit/src/outputs.ts | 4 +- core/test/unit/src/router/provider.ts | 1 - plugins/terraform/src/init.ts | 7 ++ plugins/terraform/test/terraform.ts | 4 +- 23 files changed, 134 insertions(+), 114 deletions(-) diff --git a/core/src/plugin/handlers/Provider/getEnvironmentStatus.ts b/core/src/plugin/handlers/Provider/getEnvironmentStatus.ts index 44adae03c6..e210bfddae 100644 --- a/core/src/plugin/handlers/Provider/getEnvironmentStatus.ts +++ b/core/src/plugin/handlers/Provider/getEnvironmentStatus.ts @@ -33,11 +33,11 @@ export interface EnvironmentStatusMap { export const getEnvironmentStatus = () => ({ description: dedent` - Check if the current environment is ready for use by this plugin. Use this action in combination - with \`prepareEnvironment\`. + Check if the current environment is ready for use by this plugin. Only called + with commands that set \`statusOnly: true\`. - Called before \`prepareEnvironment\`. If this returns \`ready: true\`, the - \`prepareEnvironment\` action is not called. + This handler MUST NOT have side effects and should only return the status of the + environment. `, paramsSchema: projectActionParamsSchema(), resultSchema: environmentStatusSchema(), diff --git a/core/src/plugin/handlers/Provider/prepareEnvironment.ts b/core/src/plugin/handlers/Provider/prepareEnvironment.ts index 2b851a6ff5..209c847697 100644 --- a/core/src/plugin/handlers/Provider/prepareEnvironment.ts +++ b/core/src/plugin/handlers/Provider/prepareEnvironment.ts @@ -8,17 +8,13 @@ import type { PluginActionParamsBase } from "../../base.js" import { projectActionParamsSchema } from "../../base.js" -import type { EnvironmentStatus } from "./getEnvironmentStatus.js" +import { type EnvironmentStatus } from "./getEnvironmentStatus.js" import { dedent } from "../../../util/string.js" import { joi } from "../../../config/common.js" import { environmentStatusSchema } from "../../../config/status.js" import type { GenericProviderConfig } from "../../../config/provider.js" -export interface PrepareEnvironmentParams< - C extends GenericProviderConfig = any, - T extends EnvironmentStatus = EnvironmentStatus, -> extends PluginActionParamsBase { - status: T +export interface PrepareEnvironmentParams extends PluginActionParamsBase { force: boolean } @@ -31,7 +27,11 @@ export const prepareEnvironment = () => ({ Make sure the environment is set up for this plugin. Use this action to do any bootstrapping required before deploying services. - Called ahead of any runtime actions (such as \`deployService\`, and \`testModule\`), unless \`getEnvironmentStatus\` returns \`ready: true\`. + This handler MUST BE idempotent since it's called with any command that executes runtime + actions (such as Deploy and Test actions). + + If the plugin implements the \`getEnvironmentStatus\` handler then it can be used by this + handler to determine whether something needs to be done or whether it can return early. `, paramsSchema: projectActionParamsSchema().keys({ force: joi.boolean().description("Force re-configuration of the environment."), diff --git a/core/src/plugins/exec/exec.ts b/core/src/plugins/exec/exec.ts index 4cd4aa7240..6c02b5cb52 100644 --- a/core/src/plugins/exec/exec.ts +++ b/core/src/plugins/exec/exec.ts @@ -87,30 +87,33 @@ execProvider.addHandler("getEnvironmentStatus", async ({ ctx }) => { execProvider.addHandler("prepareEnvironment", async ({ ctx, log }) => { const execLog = log.createLog({ name: "exec" }) - if (ctx.provider.config.initScript) { - try { - execLog.info("Running init script") - const result = await runScript({ - log: execLog, - cwd: ctx.projectRoot, - script: ctx.provider.config.initScript, - }) - return { status: { ready: true, outputs: { initScript: { log: result.stdout.trim() } } } } - } catch (err) { - // Unexpected error (failed to execute script, as opposed to script returning an error code) - if (!(err instanceof ChildProcessError)) { - throw err - } - - throw new RuntimeError({ - message: dedent` + + if (!ctx.provider.config.initScript) { + return { status: { ready: true, outputs: {} } } + } + + try { + execLog.info("Running init script") + const result = await runScript({ + log: execLog, + cwd: ctx.projectRoot, + script: ctx.provider.config.initScript, + }) + + return { status: { ready: true, outputs: { initScript: { log: result.stdout.trim() } } } } + } catch (err) { + // Unexpected error (failed to execute script, as opposed to script returning an error code) + if (!(err instanceof ChildProcessError)) { + throw err + } + + throw new RuntimeError({ + message: dedent` exec provider init script exited with code ${err.details.code}. Script output: ${err.details.output} `, - }) - } + }) } - return { status: { ready: true, outputs: {} } } }) export const gardenPlugin = execPlugin diff --git a/core/src/plugins/kubernetes/commands/cluster-init.ts b/core/src/plugins/kubernetes/commands/cluster-init.ts index 47c50e34ce..11c3459dff 100644 --- a/core/src/plugins/kubernetes/commands/cluster-init.ts +++ b/core/src/plugins/kubernetes/commands/cluster-init.ts @@ -33,7 +33,6 @@ export const clusterInit: PluginCommand = { ctx, log, force: true, - status, }) } diff --git a/core/src/plugins/kubernetes/init.ts b/core/src/plugins/kubernetes/init.ts index f711d107cc..00f62bb694 100644 --- a/core/src/plugins/kubernetes/init.ts +++ b/core/src/plugins/kubernetes/init.ts @@ -9,10 +9,10 @@ import { KubeApi, KubernetesError } from "./api.js" import { getAppNamespace, - prepareNamespaces, + prepareNamespace, deleteNamespaces, - getNamespaceStatus, getSystemNamespace, + namespaceExists, } from "./namespace.js" import type { KubernetesPluginContext, KubernetesConfig, KubernetesProvider, ProviderSecretRef } from "./config.js" import type { @@ -37,7 +37,7 @@ import type { KubernetesResource } from "./types.js" import type { PrimitiveMap } from "../../config/common.js" import { getIngressApiVersion, supportedIngressApiVersions } from "./container/ingress.js" import type { Log } from "../../logger/log-entry.js" -import { ingressControllerInstall, ingressControllerReady } from "./nginx/ingress-controller.js" +import { ensureIngressController, ingressControllerReady } from "./nginx/ingress-controller.js" import { styles } from "../../logger/styles.js" import { isTruthy } from "../../util/util.js" @@ -61,9 +61,9 @@ interface KubernetesEnvironmentDetail { export type KubernetesEnvironmentStatus = EnvironmentStatus /** - * Checks system service statuses (if provider has system services) + * Checks if namespace and secrets exist and whether ingress is ready (if applicable). * - * Returns ready === true if all the above are ready. + * TODO @eysi: Check secret statuses */ export async function getEnvironmentStatus({ ctx, @@ -72,8 +72,9 @@ export async function getEnvironmentStatus({ const k8sCtx = ctx const provider = k8sCtx.provider const api = await KubeApi.factory(log, ctx, provider) - - const namespace = await getNamespaceStatus({ ctx: k8sCtx, log, provider: k8sCtx.provider, skipCreate: true }) + // TODO @eysi: Avoid casting (the namespace is ensured though when the provider config is resolved) + const namespaceName = provider.config.namespace!.name + const namespaceReady = await namespaceExists(api, ctx, namespaceName) const detail: KubernetesEnvironmentDetail = { systemReady: true, @@ -82,31 +83,21 @@ export async function getEnvironmentStatus({ } const result: KubernetesEnvironmentStatus = { - ready: namespace.state === "ready", + ready: namespaceReady, detail, outputs: { - "app-namespace": namespace.namespaceName, + "app-namespace": namespaceName, "default-hostname": provider.config.defaultHostname || null, }, } if (provider.config.setupIngressController === "nginx") { const ingressControllerReadiness = await ingressControllerReady(ctx, log) - result.ready = ingressControllerReadiness && namespace.state === "ready" + result.ready = ingressControllerReadiness && namespaceReady detail.systemReady = ingressControllerReadiness log.info( `${styles.highlight("nginx")} Ingress Controller ${ingressControllerReadiness ? "is ready" : "is not ready"}` ) - } else { - // We only need to warn about missing ingress classes if we're not using garden installed nginx - const ingressApiVersion = await getIngressApiVersion(log, api, supportedIngressApiVersions) - const ingressWarnings = await getIngressMisconfigurationWarnings( - provider.config.ingressClass, - ingressApiVersion, - log, - api - ) - ingressWarnings.forEach((w) => log.warn(w)) } return result @@ -145,26 +136,47 @@ export async function getIngressMisconfigurationWarnings( /** * Deploys system services (if any) and creates the default app namespace. + * + * TODO @eysi: Ensure secrets here */ export async function prepareEnvironment( - params: PrepareEnvironmentParams + params: PrepareEnvironmentParams ): Promise { - const { ctx, log, status } = params + const { ctx, log } = params const k8sCtx = ctx const provider = k8sCtx.provider const config = provider.config + const api = await KubeApi.factory(log, ctx, provider) + // create default app namespace if it doesn't exist - await prepareNamespaces({ ctx, log }) + const nsStatus = await prepareNamespace({ ctx, log }) // make sure that the system namespace exists await getSystemNamespace(ctx, ctx.provider, log) // TODO-0.13/TODO-0.14: remove this option for remote kubernetes clusters? if (config.setupIngressController === "nginx") { - // Install nginx ingress controller - await ingressControllerInstall(k8sCtx, log) + await ensureIngressController(k8sCtx, log) + } else { + // We only need to warn about missing ingress classes if we're not using Garden installed nginx + const ingressApiVersion = await getIngressApiVersion(log, api, supportedIngressApiVersions) + const ingressWarnings = await getIngressMisconfigurationWarnings( + provider.config.ingressClass, + ingressApiVersion, + log, + api + ) + ingressWarnings.forEach((w) => log.warn(w)) } - return { status: { ready: true, outputs: status.outputs } } + return { + status: { + ready: true, + outputs: { + "app-namespace": nsStatus["app-namespace"].namespaceName, + "default-hostname": provider.config.defaultHostname || null, + }, + }, + } } export async function cleanupEnvironment({ diff --git a/core/src/plugins/kubernetes/local/local.ts b/core/src/plugins/kubernetes/local/local.ts index cfeb656c07..70c0993320 100644 --- a/core/src/plugins/kubernetes/local/local.ts +++ b/core/src/plugins/kubernetes/local/local.ts @@ -67,7 +67,13 @@ async function prepareEnvironment( const { ctx, log } = params const provider = ctx.provider - const result = await _prepareEnvironmentBase(params) + // This should be set in the configureProvider handler but we need the + // plugin context to get the cluster type + if (!provider.config.clusterType) { + provider.config.clusterType = await getClusterType(ctx, log) + } + + const prepareEnvResult = await _prepareEnvironmentBase(params) if (provider.config.clusterType === "minikube") { await setMinikubeDockerEnv() @@ -76,7 +82,7 @@ async function prepareEnvironment( await configureMicrok8sAddons(log, microk8sAddons) } - return result + return prepareEnvResult } async function getClusterType(ctx: KubernetesPluginContext, log: Log): Promise { diff --git a/core/src/plugins/kubernetes/namespace.ts b/core/src/plugins/kubernetes/namespace.ts index 7d24393d37..c87fe00b0b 100644 --- a/core/src/plugins/kubernetes/namespace.ts +++ b/core/src/plugins/kubernetes/namespace.ts @@ -278,7 +278,7 @@ export function clearNamespaceCache(provider: KubernetesProvider) { /** * Used by both the remote and local plugin */ -export async function prepareNamespaces({ ctx, log }: GetEnvironmentStatusParams) { +export async function prepareNamespace({ ctx, log }: GetEnvironmentStatusParams) { const k8sCtx = ctx try { diff --git a/core/src/plugins/kubernetes/nginx/default-backend.ts b/core/src/plugins/kubernetes/nginx/default-backend.ts index a0ace68874..f2d9f7099f 100644 --- a/core/src/plugins/kubernetes/nginx/default-backend.ts +++ b/core/src/plugins/kubernetes/nginx/default-backend.ts @@ -16,7 +16,7 @@ import { getDefaultGardenIngressControllerDefaultBackendImagePath } from "../con import { GardenIngressComponent } from "./ingress-controller-base.js" export class GardenDefaultBackend extends GardenIngressComponent { - override async install(ctx: KubernetesPluginContext, log: Log): Promise { + override async ensure(ctx: KubernetesPluginContext, log: Log): Promise { const { deployment, service } = defaultBackendGetManifests(ctx) const status = await this.getStatus(ctx, log) if (status === "ready") { diff --git a/core/src/plugins/kubernetes/nginx/ingress-controller-base.ts b/core/src/plugins/kubernetes/nginx/ingress-controller-base.ts index aa10db0c3d..03c2ea6e18 100644 --- a/core/src/plugins/kubernetes/nginx/ingress-controller-base.ts +++ b/core/src/plugins/kubernetes/nginx/ingress-controller-base.ts @@ -11,7 +11,10 @@ import type { KubernetesPluginContext } from "../config.js" import type { DeployState } from "../../../types/service.js" export abstract class GardenIngressComponent { - abstract install(ctx: KubernetesPluginContext, log: Log): Promise + /** + * Install ingress controller if not ready. Idempotent. + */ + abstract ensure(ctx: KubernetesPluginContext, log: Log): Promise abstract getStatus(ctx: KubernetesPluginContext, log: Log): Promise diff --git a/core/src/plugins/kubernetes/nginx/ingress-controller.ts b/core/src/plugins/kubernetes/nginx/ingress-controller.ts index aee16f483e..3cd8668b7d 100644 --- a/core/src/plugins/kubernetes/nginx/ingress-controller.ts +++ b/core/src/plugins/kubernetes/nginx/ingress-controller.ts @@ -18,7 +18,7 @@ import { GardenIngressComponent } from "./ingress-controller-base.js" import type { DeployState } from "../../../types/service.js" class NoOpGardenIngressController extends GardenIngressComponent { - override install(_ctx: KubernetesPluginContext, _log: Log): Promise { + override ensure(_ctx: KubernetesPluginContext, _log: Log): Promise { return Promise.resolve(undefined) } @@ -61,8 +61,8 @@ export async function ingressControllerReady(ctx: KubernetesPluginContext, log: return await getGardenIngressController(ctx).ready(ctx, log) } -export async function ingressControllerInstall(ctx: KubernetesPluginContext, log: Log) { - await getGardenIngressController(ctx).install(ctx, log) +export async function ensureIngressController(ctx: KubernetesPluginContext, log: Log) { + await getGardenIngressController(ctx).ensure(ctx, log) } export async function ingressControllerUninstall(ctx: KubernetesPluginContext, log: Log) { diff --git a/core/src/plugins/kubernetes/nginx/nginx-helm.ts b/core/src/plugins/kubernetes/nginx/nginx-helm.ts index 155dcc3a19..97dab2f207 100644 --- a/core/src/plugins/kubernetes/nginx/nginx-helm.ts +++ b/core/src/plugins/kubernetes/nginx/nginx-helm.ts @@ -31,7 +31,7 @@ type _HelmValue = number | string | boolean | object | null | undefined export abstract class HelmGardenIngressController extends GardenIngressComponent { private readonly defaultBackend = new GardenDefaultBackend() - override async install(ctx: KubernetesPluginContext, log: Log): Promise { + override async ensure(ctx: KubernetesPluginContext, log: Log): Promise { const ingressControllerReady = await this.ready(ctx, log) if (ingressControllerReady) { return @@ -66,7 +66,7 @@ export abstract class HelmGardenIngressController extends GardenIngressComponent ] log.info(`Installing ${styles.highlight("nginx")} in ${styles.highlight(namespace)} namespace...`) - await this.defaultBackend.install(ctx, log) + await this.defaultBackend.ensure(ctx, log) await helm({ ctx, namespace, log, args, emitLogEvents: false }) const nginxHelmMainResource = getNginxHelmMainResource(values) diff --git a/core/src/plugins/kubernetes/nginx/nginx-kind.ts b/core/src/plugins/kubernetes/nginx/nginx-kind.ts index dd4c418581..ce7e5a1b04 100644 --- a/core/src/plugins/kubernetes/nginx/nginx-kind.ts +++ b/core/src/plugins/kubernetes/nginx/nginx-kind.ts @@ -24,7 +24,7 @@ const nginxKindMainResource = { } export class KindGardenIngressController extends GardenIngressComponent { - override async install(ctx: KubernetesPluginContext, log: Log): Promise { + override async ensure(ctx: KubernetesPluginContext, log: Log): Promise { const status = await this.getStatus(ctx, log) if (status === "ready") { return diff --git a/core/src/plugins/kubernetes/nginx/nginx-microk8s.ts b/core/src/plugins/kubernetes/nginx/nginx-microk8s.ts index e4c4f1204d..bb7008a1b6 100644 --- a/core/src/plugins/kubernetes/nginx/nginx-microk8s.ts +++ b/core/src/plugins/kubernetes/nginx/nginx-microk8s.ts @@ -15,7 +15,7 @@ import { waitForResources } from "../status/status.js" import { GardenIngressComponent } from "./ingress-controller-base.js" export class Microk8sGardenIngressController extends GardenIngressComponent { - override async install(ctx: KubernetesPluginContext, log: Log): Promise { + override async ensure(ctx: KubernetesPluginContext, log: Log): Promise { const provider = ctx.provider const status = await this.getStatus(ctx, log) diff --git a/core/src/plugins/kubernetes/nginx/nginx-minikube.ts b/core/src/plugins/kubernetes/nginx/nginx-minikube.ts index 98750c8205..08a3d010f2 100644 --- a/core/src/plugins/kubernetes/nginx/nginx-minikube.ts +++ b/core/src/plugins/kubernetes/nginx/nginx-minikube.ts @@ -15,7 +15,7 @@ import { checkResourceStatus, waitForResources } from "../status/status.js" import { GardenIngressComponent } from "./ingress-controller-base.js" export class MinikubeGardenIngressController extends GardenIngressComponent { - override async install(ctx: KubernetesPluginContext, log: Log): Promise { + override async ensure(ctx: KubernetesPluginContext, log: Log): Promise { const provider = ctx.provider const status = await this.getStatus(ctx, log) if (status === "ready") { diff --git a/core/src/tasks/resolve-provider.ts b/core/src/tasks/resolve-provider.ts index 11b5412f93..a47200f95a 100644 --- a/core/src/tasks/resolve-provider.ts +++ b/core/src/tasks/resolve-provider.ts @@ -31,7 +31,6 @@ import { stableStringify } from "../util/string.js" import { OtelTraced } from "../util/open-telemetry/decorators.js" import { LogLevel } from "../logger/logger.js" import type { Log } from "../logger/log-entry.js" -import { styles } from "../logger/styles.js" import type { ObjectPath } from "../config/base.js" import fsExtra from "fs-extra" import { RemoteSourceConfigContext } from "../config/template-contexts/project.js" @@ -412,43 +411,41 @@ export class ResolveProviderTask extends BaseTask { return cachedStatus } - // TODO: avoid calling the handler manually (currently doing it to override the plugin context) - const handler = await actions.provider["getPluginHandler"]({ - handlerType: "getEnvironmentStatus", - pluginName, - defaultHandler: async () => defaultEnvironmentStatus, - }) - - let status = await handler!({ ctx, log: providerLog }) - - if (!statusOnly && (this.forceInit || !status.ready)) { - const statusMsg = status.ready - ? `${styles.highlight("Ready")}, will ${styles.highlight("force re-initialize")}` - : `${styles.highlight("Not ready")}, will initialize` - providerLog.info(statusMsg) - // TODO: avoid calling the handler manually - const prepareHandler = await actions.provider["getPluginHandler"]({ - handlerType: "prepareEnvironment", + if (statusOnly) { + // TODO: avoid calling the handler manually (currently doing it to override the plugin context) + const getStatusHandler = await actions.provider["getPluginHandler"]({ + handlerType: "getEnvironmentStatus", pluginName, - defaultHandler: async () => ({ status }), + defaultHandler: async () => defaultEnvironmentStatus, }) - const result = await prepareHandler!({ ctx, log: providerLog, force: this.forceInit, status }) + const envStatus = await getStatusHandler!({ ctx, log: providerLog }) + if (envStatus.ready) { + providerLog.success(`Provider is ready`) + } else { + providerLog.warn(`Provider is not ready (only checking status)`) + } - status = result.status + return envStatus } - if (!status.ready && !statusOnly) { + providerLog.info(`Preparing environment`) + // TODO: avoid calling the handler manually + const prepareHandler = await actions.provider["getPluginHandler"]({ + handlerType: "prepareEnvironment", + pluginName, + defaultHandler: async () => ({ status: { ready: true, outputs: {} } }), + }) + + const result = await prepareHandler!({ ctx, log: providerLog, force: this.forceInit }) + const status = result.status + if (!status.ready) { providerLog.error("Failed initializing provider") throw new PluginError({ message: `Provider ${pluginName} reports status as not ready and could not prepare the configured environment.`, }) } - if (!status.ready && statusOnly) { - providerLog.success("Provider not ready. Current command only checks status, not preparing environment") - return status - } providerLog.success("Provider ready") if (!status.disableCache) { diff --git a/core/test/integ/src/plugins/kubernetes/ingress-controller.ts b/core/test/integ/src/plugins/kubernetes/ingress-controller.ts index 6b7c5191dc..fef3914da3 100644 --- a/core/test/integ/src/plugins/kubernetes/ingress-controller.ts +++ b/core/test/integ/src/plugins/kubernetes/ingress-controller.ts @@ -13,7 +13,6 @@ import { ingressControllerReady } from "../../../../../src/plugins/kubernetes/ng import { uninstallGardenServices } from "../../../../../src/plugins/kubernetes/commands/uninstall-garden-services.js" import { prepareEnvironment } from "../../../../../src/plugins/kubernetes/init.js" import type { PrepareEnvironmentParams } from "../../../../../src/plugin/handlers/Provider/prepareEnvironment.js" -import { defaultEnvironmentStatus } from "../../../../../src/plugin/handlers/Provider/getEnvironmentStatus.js" import { getContainerTestGarden } from "./container/container.js" import type { Garden } from "../../../../../src/garden.js" @@ -59,7 +58,6 @@ describe("It should manage ingress controller for respective cluster type", () = const params: PrepareEnvironmentParams = { ctx, log: garden.log, - status: defaultEnvironmentStatus, force: false, } ctx.provider.config.setupIngressController = "nginx" @@ -72,7 +70,6 @@ describe("It should manage ingress controller for respective cluster type", () = const params: PrepareEnvironmentParams = { ctx, log: garden.log, - status: defaultEnvironmentStatus, force: false, } ctx.provider.config.setupIngressController = "null" @@ -86,7 +83,6 @@ describe("It should manage ingress controller for respective cluster type", () = const params: PrepareEnvironmentParams = { ctx, log: garden.log, - status: defaultEnvironmentStatus, force: false, } ctx.provider.config.setupIngressController = "nginx" diff --git a/core/test/integ/src/plugins/kubernetes/provider.ts b/core/test/integ/src/plugins/kubernetes/provider.ts index 2e0aeae434..c73bb66278 100644 --- a/core/test/integ/src/plugins/kubernetes/provider.ts +++ b/core/test/integ/src/plugins/kubernetes/provider.ts @@ -69,11 +69,9 @@ describe("kubernetes provider handlers", () => { it("should prepare the environment with the prepareEnvironment handler and emit a namespaceStatus event", async () => { garden.events.eventLog = [] - const status = await getEnvironmentStatus({ ctx, log }) const params: PrepareEnvironmentParams = { ctx, log: garden.log, - status, force: false, } const envStatus = await prepareEnvironment(params) diff --git a/core/test/unit/src/commands/get/get-outputs.ts b/core/test/unit/src/commands/get/get-outputs.ts index e5bde8a6ec..0c230da91c 100644 --- a/core/test/unit/src/commands/get/get-outputs.ts +++ b/core/test/unit/src/commands/get/get-outputs.ts @@ -34,8 +34,8 @@ describe("GetOutputsCommand", () => { const plugin = createGardenPlugin({ name: "test", handlers: { - async getEnvironmentStatus() { - return { ready: true, outputs: { test: "test-value" } } + async prepareEnvironment() { + return { status: { ready: true, outputs: { test: "test-value" } } } }, }, }) diff --git a/core/test/unit/src/garden.ts b/core/test/unit/src/garden.ts index 325d2b6bf4..d242c9e9c0 100644 --- a/core/test/unit/src/garden.ts +++ b/core/test/unit/src/garden.ts @@ -2498,10 +2498,12 @@ describe("Garden", () => { const testA = createGardenPlugin({ name: "test-a", handlers: { - getEnvironmentStatus: async () => { + prepareEnvironment: async () => { return { - ready: true, - outputs: { foo: "bar" }, + status: { + ready: true, + outputs: { foo: "bar" }, + }, } }, }, diff --git a/core/test/unit/src/outputs.ts b/core/test/unit/src/outputs.ts index 2378b50bcd..363da9c58f 100644 --- a/core/test/unit/src/outputs.ts +++ b/core/test/unit/src/outputs.ts @@ -48,8 +48,8 @@ describe("resolveProjectOutputs", () => { const plugin = createGardenPlugin({ name: "test", handlers: { - async getEnvironmentStatus() { - return { ready: true, outputs: { test: "test-value" } } + async prepareEnvironment() { + return { status: { ready: true, outputs: { test: "test-value" } } } }, }, }) diff --git a/core/test/unit/src/router/provider.ts b/core/test/unit/src/router/provider.ts index d49de52f03..ecc2612ce8 100644 --- a/core/test/unit/src/router/provider.ts +++ b/core/test/unit/src/router/provider.ts @@ -138,7 +138,6 @@ describe("provider actions", async () => { log, pluginName: "test-plugin-a", force: false, - status: { ready: true, outputs: {} }, events: undefined, }) expect(result).to.eql({ diff --git a/plugins/terraform/src/init.ts b/plugins/terraform/src/init.ts index 3ae27b215e..410976bb5a 100644 --- a/plugins/terraform/src/init.ts +++ b/plugins/terraform/src/init.ts @@ -56,6 +56,13 @@ export const prepareEnvironment: ProviderHandlers["prepareEnvironment"] = async return { status: { ready: true, outputs: {} } } } + const envStatus = await getEnvironmentStatus({ ctx, log }) + if (envStatus.ready) { + return { + status: envStatus, + } + } + const root = getRoot(ctx, provider) const workspace = provider.config.workspace || null diff --git a/plugins/terraform/test/terraform.ts b/plugins/terraform/test/terraform.ts index 24a264ebc2..3af2ad8269 100644 --- a/plugins/terraform/test/terraform.ts +++ b/plugins/terraform/test/terraform.ts @@ -275,9 +275,7 @@ for (const terraformVersion of ["0.13.3", defaultTerraformVersion]) { expect( garden.log.root .getLogEntries() - .filter((l) => - resolveMsg(l)?.match(/Provider not ready. Current command only checks status, not preparing environment/) - ).length + .filter((l) => resolveMsg(l)?.match(/Provider is not ready \(only checking status\)/)).length ).to.be.greaterThan(0) })