Skip to content

Commit

Permalink
fix(cloud): emit ns statuses for in-cluster builds
Browse files Browse the repository at this point in the history
We now emit a `namespaceStatus` event whenever one of our internal
helpers for checking the status of a Kubernetes namespace is called.
This is done whenever we e.g. perform a Deploy, Test or Run in that
namespace, or when we perform an in-cluster Build in that namespace
(e.g. via BuildKit or Kaniko).

Here, we also remove namespace statuses from the relevant result types
(e.g. `ServiceStatus`, `RunStatus` and `EnvironmentStatus` and the
associated schemas). These added unwanted noise to the interfaces and
schemas.

Instead, we emit the `namespaceStatus` events on the plugin event
broker (`ctx.events`) and re-emit them to `garden.events` in the
base router.
  • Loading branch information
thsig committed Jun 14, 2023
1 parent b32bd1f commit aa4bfa9
Show file tree
Hide file tree
Showing 44 changed files with 269 additions and 373 deletions.
2 changes: 0 additions & 2 deletions core/src/config/status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

import { namespaceStatusesSchema } from "../types/namespace"
import { createSchema, joi, joiVariables } from "./common"

export const environmentStatusSchema = createSchema({
Expand All @@ -19,7 +18,6 @@ export const environmentStatusSchema = createSchema({
.optional()
.meta({ extendable: true })
.description("Use this to include additional information that is specific to the provider."),
namespaceStatuses: namespaceStatusesSchema().optional(),
outputs: joiVariables()
.meta({ extendable: true })
.description("Output variables that modules and other variables can reference."),
Expand Down
1 change: 0 additions & 1 deletion core/src/events/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,6 @@ export function makeActionCompletePayload<
deployStatus = pick(deployResult.detail, [
"createdAt",
"mode",
"namespaceStatuses",
"externalId",
"externalVersion",
"forwardablePorts",
Expand Down
2 changes: 0 additions & 2 deletions core/src/graph/results.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,6 @@ function filterResultForExport(result: any) {
"mode",
"syncMode",
"localMode",
"namespaceStatuses",
"externalId",
"externalVersion",
"forwardablePorts",
Expand All @@ -219,7 +218,6 @@ function filterResultForExport(result: any) {
"exitCode",
"startedAt",
"completedAt",
"namespaceStatus"
),
detail: filteredDetail,
}
Expand Down
4 changes: 3 additions & 1 deletion core/src/plugin-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { EventEmitter } from "eventemitter3"
import { CreateEventLogParams, EventLogger, LogLevel, StringLogLevel } from "./logger/logger"
import { Memoize } from "typescript-memoize"
import type { ParameterValues } from "./cli/params"
import { NamespaceStatus } from "./types/namespace"

type WrappedFromGarden = Pick<
Garden,
Expand Down Expand Up @@ -116,13 +117,14 @@ export type PluginEventLogMessage = PluginEventLogContext & {
msg: string
}

// Define your emitter's types like that:
// Define your emitter's types as follows:
// Key: Event name; Value: Listener function signature
type PluginEvents = {
abort: (reason?: string) => void
done: () => void
failed: (error?: Error) => void
log: (msg: PluginEventLogMessage) => void
namespaceStatus: (status: NamespaceStatus) => void
}

type PluginEventType = keyof PluginEvents
Expand Down
3 changes: 1 addition & 2 deletions core/src/plugin/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import type { BuildAction } from "../actions/build"
import type { DeployAction } from "../actions/deploy"
import type { RunAction } from "../actions/run"
import type { TestAction } from "../actions/test"
import { NamespaceStatus, namespaceStatusSchema } from "../types/namespace"
import { NamespaceStatus } from "../types/namespace"
import Joi from "@hapi/joi"
import { memoize } from "lodash"
import { BaseProviderConfig } from "../config/provider"
Expand Down Expand Up @@ -131,7 +131,6 @@ export const runResultSchema = createSchema({
startedAt: joi.date().required().description("When the module run was started."),
completedAt: joi.date().required().description("When the module run was completed."),
log: joi.string().allow("").default("").description("The output log from the run."),
namespaceStatus: namespaceStatusSchema().optional(),
}),
allowUnknown: true,
})
Expand Down
7 changes: 2 additions & 5 deletions core/src/plugin/handlers/Provider/cleanupEnvironment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,11 @@
import { PluginActionParamsBase, projectActionParamsSchema } from "../../base"
import { dedent } from "../../../util/string"
import { joi } from "../../../config/common"
import { NamespaceStatus, namespaceStatusesSchema } from "../../../types/namespace"
import type { BaseProviderConfig } from "../../../config/provider"

export interface CleanupEnvironmentParams<C extends BaseProviderConfig = any> extends PluginActionParamsBase<C> {}

export interface CleanupEnvironmentResult {
namespaceStatuses?: NamespaceStatus[]
}
export interface CleanupEnvironmentResult {}

export const cleanupEnvironment = () => ({
description: dedent`
Expand All @@ -28,5 +25,5 @@ export const cleanupEnvironment = () => ({
Called by the \`garden delete environment\` command.
`,
paramsSchema: projectActionParamsSchema(),
resultSchema: joi.object().keys({ namespaceStatuses: namespaceStatusesSchema().optional() }),
resultSchema: joi.object(),
})
2 changes: 0 additions & 2 deletions core/src/plugin/handlers/Provider/getEnvironmentStatus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,13 @@
import { PluginActionParamsBase, projectActionParamsSchema } from "../../base"
import { dedent } from "../../../util/string"
import { environmentStatusSchema } from "../../../config/status"
import type { NamespaceStatus } from "../../../types/namespace"
import type { BaseProviderConfig } from "../../../config/provider"

export interface GetEnvironmentStatusParams<C extends BaseProviderConfig = any> extends PluginActionParamsBase<C> {}

export interface EnvironmentStatus<O extends {} = any, D extends {} = any> {
ready: boolean
detail?: D
namespaceStatuses?: NamespaceStatus[]
outputs: O
disableCache?: boolean
cached?: boolean
Expand Down
5 changes: 0 additions & 5 deletions core/src/plugins/kubernetes/container/status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import { DeployActionHandler } from "../../../plugin/action-types"
import { getDeployedImageId } from "./util"
import { ActionMode, Resolved } from "../../../actions/types"
import { deployStateToActionState, DeployStatus } from "../../../plugin/handlers/Deploy/get-status"
import { NamespaceStatus } from "../../../types/namespace"

interface ContainerStatusDetail {
remoteResources: KubernetesServerResource[]
Expand Down Expand Up @@ -65,7 +64,6 @@ export const k8sGetContainerDeployStatus: DeployActionHandler<"getStatus", Conta
workload,
selectorChangedResourceKeys,
state,
namespaceStatus,
ingresses,
})
}
Expand All @@ -78,7 +76,6 @@ export function prepareContainerDeployStatus({
workload,
selectorChangedResourceKeys,
state,
namespaceStatus,
ingresses,
}: {
action: Resolved<ContainerDeployAction>
Expand All @@ -88,7 +85,6 @@ export function prepareContainerDeployStatus({
workload: KubernetesWorkload
selectorChangedResourceKeys: string[]
state: DeployState
namespaceStatus: NamespaceStatus
ingresses: ServiceIngress[] | undefined
}): DeployStatus<ContainerDeployAction> {
// Local mode has its own port-forwarding configuration
Expand All @@ -114,7 +110,6 @@ export function prepareContainerDeployStatus({
forwardablePorts,
ingresses,
state,
namespaceStatuses: [namespaceStatus],
detail: { remoteResources, workload, selectorChangedResourceKeys },
mode: deployedMode,
outputs,
Expand Down
1 change: 0 additions & 1 deletion core/src/plugins/kubernetes/helm/deployment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,6 @@ export const helmDeploy: DeployActionHandler<"deploy", HelmDeployAction> = async
state: "ready",
version: action.versionString(),
detail: { remoteResources: statuses.map((s) => s.resource) },
namespaceStatuses: [namespaceStatus],
},
attached,
// TODO-0.13.1
Expand Down
1 change: 0 additions & 1 deletion core/src/plugins/kubernetes/helm/status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ export const getHelmDeployStatus: DeployActionHandler<"getStatus", HelmDeployAct
version: state === "ready" ? action.versionString() : undefined,
detail,
mode: deployedMode,
namespaceStatuses: [namespaceStatus],
ingresses,
},
// TODO-0.13.1
Expand Down
10 changes: 6 additions & 4 deletions core/src/plugins/kubernetes/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,9 +187,9 @@ export async function prepareEnvironment(

// Prepare system services
await prepareSystem({ ...params, clusterInit: false })
const ns = await getAppNamespaceStatus(k8sCtx, log, k8sCtx.provider)

return { status: { namespaceStatuses: [ns], ready: true, outputs: status.outputs } }
// This call is only to emit a `namespaceStatus` event.
await getAppNamespaceStatus(k8sCtx, log, k8sCtx.provider)
return { status: { ready: true, outputs: status.outputs } }
}

export async function prepareSystem({
Expand Down Expand Up @@ -337,7 +337,9 @@ export async function cleanupEnvironment({
// Since we've deleted one or more namespaces, we invalidate the NS cache for this provider instance.
clearNamespaceCache(provider)

return { namespaceStatuses: [{ namespaceName: namespace, state: "missing", pluginName: provider.name }] }
ctx.events.emit("namespaceStatus", { namespaceName: namespace, state: "missing", pluginName: provider.name })

return {}
}

export function getKubernetesSystemVariables(config: KubernetesConfig) {
Expand Down
38 changes: 16 additions & 22 deletions core/src/plugins/kubernetes/kubernetes-type/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

import Bluebird from "bluebird"
import { isEmpty, omit, partition, uniq } from "lodash"
import type { NamespaceStatus } from "../../../types/namespace"
import type { ModuleActionHandlers } from "../../../plugin/plugin"
import { ServiceStatus } from "../../../types/service"
import { gardenAnnotationKey } from "../../../util/string"
Expand Down Expand Up @@ -210,7 +209,6 @@ export const getKubernetesDeployStatus: DeployActionHandler<"getStatus", Kuberne
version: state === "ready" ? action.versionString() : undefined,
detail: { remoteResources },
mode: deployedMode,
namespaceStatuses: [namespaceStatus],
ingresses: getK8sIngresses(remoteResources),
},
// TODO-0.13.1
Expand Down Expand Up @@ -310,27 +308,21 @@ export const kubernetesDeploy: DeployActionHandler<"deploy", KubernetesDeployAct
}
}

const namespaceStatuses = [namespaceStatus]
ctx.events.emit("namespaceStatus", namespaceStatus)

if (namespaceManifests.length > 0) {
namespaceStatuses.push(
...namespaceManifests.map(
(m) =>
({
pluginName: provider.name,
namespaceName: m.metadata.name,
state: "ready",
} as NamespaceStatus)
)
)
for (const ns of namespaceManifests) {
ctx.events.emit("namespaceStatus", {
pluginName: provider.name,
namespaceName: ns.metadata.name,
state: "ready",
})
}
}

return {
...status,
detail: {
...status.detail!,
namespaceStatuses,
},
detail: status.detail!,
// Tell the framework that the mutagen process is attached, if applicable
attached,
}
Expand Down Expand Up @@ -386,11 +378,13 @@ export const deleteKubernetesDeploy: DeployActionHandler<"delete", KubernetesDep
const status: KubernetesServiceStatus = { state: "missing", detail: { remoteResources: [] } }

if (namespaceManifests.length > 0) {
status.namespaceStatuses = namespaceManifests.map((m) => ({
namespaceName: m.metadata.name,
state: "missing",
pluginName: provider.name,
}))
for (const ns of namespaceManifests) {
ctx.events.emit("namespaceStatus", {
namespaceName: ns.metadata.name,
state: "missing",
pluginName: provider.name,
})
}
}

return {
Expand Down
11 changes: 9 additions & 2 deletions core/src/plugins/kubernetes/namespace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,10 @@ interface GetNamespaceParams {
* ensures it exists in the target cluster (unless skipCreate=true).
*
* Returns a namespace status (which includes the namespace's name).
*
* Also emits a `namespaceStatus` event on the provided plugin context's event bus. This means that the caller doesn't
* need to worry about remembering to emit namespace events (they are then caught by the base router and re-emitted on
* the Garden instance's event bus).
*/
export async function getNamespaceStatus({
log,
Expand All @@ -187,20 +191,23 @@ export async function getNamespaceStatus({
const namespace = cloneDeep(override || provider.config.namespace)!

const api = await KubeApi.factory(log, ctx, provider)
let status: NamespaceStatus
if (!skipCreate) {
await ensureNamespace(api, ctx, namespace, log)
return {
status = {
pluginName: provider.name,
namespaceName: namespace.name,
state: "ready",
}
} else {
return {
status = {
pluginName: provider.name,
namespaceName: namespace.name,
state: (await namespaceExists(api, ctx, namespace.name)) ? "ready" : "missing",
}
}
ctx.events.emit("namespaceStatus", status)
return status
}

export async function getSystemNamespace(
Expand Down
22 changes: 6 additions & 16 deletions core/src/router/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,21 +63,6 @@ export abstract class BaseRouter {
this.loadedPlugins = keyBy(params.loadedPlugins, "name")
}

emitNamespaceEvents(namespaceStatuses: NamespaceStatus[] | undefined) {
if (namespaceStatuses && namespaceStatuses.length > 0) {
for (const status of namespaceStatuses) {
this.emitNamespaceEvent(status)
}
}
}

emitNamespaceEvent(namespaceStatus: NamespaceStatus | undefined) {
if (namespaceStatus) {
const { pluginName, state, namespaceName } = namespaceStatus
this.garden.events.emit("namespaceStatus", { pluginName, state, namespaceName })
}
}

protected async commonParams(
handler: WrappedActionHandler<any, any> | WrappedActionTypeHandler<any, any>,
log: Log,
Expand All @@ -86,8 +71,13 @@ export abstract class BaseRouter {
): Promise<PluginActionParamsBase> {
const provider = await this.garden.resolveProvider(log, handler.pluginName)

const ctx = await this.garden.getPluginContext({ provider, templateContext, events })

// Forward plugin events that don't need any action-specific metadata (currently just `namespaceStatus` events).
ctx.events.on("namespaceStatus", (status: NamespaceStatus) => this.garden.events.emit("namespaceStatus", status))

return {
ctx: await this.garden.getPluginContext({ provider, templateContext, events }),
ctx,
log,
base: handler.base,
}
Expand Down
10 changes: 0 additions & 10 deletions core/src/router/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,7 @@ export const deployRouter = (baseParams: BaseRouterParams) =>

const output = await router.callHandler({ params, handlerType: "deploy" })
const result = output.result

await router.validateActionOutputs(action, "runtime", result.outputs)

router.emitNamespaceEvents(result.detail?.namespaceStatuses)

return output
},

Expand Down Expand Up @@ -78,7 +74,6 @@ export const deployRouter = (baseParams: BaseRouterParams) =>
},
})

router.emitNamespaceEvents(output.result.detail?.namespaceStatuses)

log.success(`Done`)

Expand Down Expand Up @@ -106,14 +101,9 @@ export const deployRouter = (baseParams: BaseRouterParams) =>

getStatus: async (params) => {
const { router, action } = params

const output = await router.callHandler({ params, handlerType: "getStatus" })
const result = output.result

router.emitNamespaceEvents(result.detail?.namespaceStatuses)

await router.validateActionOutputs(action, "runtime", result.outputs)

return output
},

Expand Down
2 changes: 0 additions & 2 deletions core/src/router/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@ export class ProviderRouter extends BaseRouter {
defaultHandler: async () => ({ status: { ready: true, outputs: {} } }),
})

this.emitNamespaceEvents(res.status.namespaceStatuses)

return res
}
Expand All @@ -149,7 +148,6 @@ export class ProviderRouter extends BaseRouter {
defaultHandler: async () => ({}),
})

this.emitNamespaceEvents(res.namespaceStatuses)

return res
}
Expand Down
Loading

0 comments on commit aa4bfa9

Please sign in to comment.