diff --git a/garden-cli/src/plugins/kubernetes/actions.ts b/garden-cli/src/plugins/kubernetes/actions.ts index 4ab287206c..8d8bcd6881 100644 --- a/garden-cli/src/plugins/kubernetes/actions.ts +++ b/garden-cli/src/plugins/kubernetes/actions.ts @@ -163,7 +163,7 @@ export async function deleteService(params: DeleteServiceParams): Promise{}) - if (!deploymentOnly) { - await deleteObjectsByLabel(context, namespace, "service", serviceName) - } } catch (err) { if (err.code === 404) { found = false diff --git a/garden-cli/src/plugins/kubernetes/kubectl.ts b/garden-cli/src/plugins/kubernetes/kubectl.ts index 91d429bdfe..58f9e12777 100644 --- a/garden-cli/src/plugins/kubernetes/kubectl.ts +++ b/garden-cli/src/plugins/kubernetes/kubectl.ts @@ -37,11 +37,6 @@ export interface ApplyOptions { namespace?: string, } -export interface DeleteOptions { - includeUninitialized?: boolean, - objectTypes?: string[] -} - export const KUBECTL_DEFAULT_TIMEOUT = 300 export class Kubectl { @@ -199,12 +194,24 @@ export async function applyMany( } } -const defaultObjectTypesForDelete = ["deployment", "service", "ingress"] +export interface DeleteObjectsParams { + context: string, + namespace: string, + labelKey: string, + labelValue: string, + objectTypes: string[], + includeUninitialized?: boolean, +} export async function deleteObjectsByLabel( - context: string, namespace: string, labelKey: string, labelValue: string, - { includeUninitialized = false, objectTypes = defaultObjectTypesForDelete }: DeleteOptions = {}, -) { + { + context, + namespace, + labelKey, + labelValue, + objectTypes, + includeUninitialized = false, + }: DeleteObjectsParams) { let args = [ "delete", diff --git a/garden-cli/src/plugins/openfaas/faas-cli.ts b/garden-cli/src/plugins/openfaas/faas-cli.ts new file mode 100644 index 0000000000..48b6458dd0 --- /dev/null +++ b/garden-cli/src/plugins/openfaas/faas-cli.ts @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2018 Garden Technologies, Inc. + * + * 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 { builderWorkDir, stackFilename } from "./openfaas" + +export interface FaasCliCmdParams { + buildPath: string, + imageId: string, + faasCmd: string, + faasOpts?: string[], + dockerOpts?: string[], +} + +export function faasCliCmd( + cmdParams: FaasCliCmdParams, +): string[] { + + return [ + "docker", + ...(faasCliDockerArgs(cmdParams)), + ] + +} + +export function faasCliDockerArgs( + { buildPath, imageId, faasCmd, faasOpts = [], dockerOpts = [] }: FaasCliCmdParams): string[] { + + return [ + "run", "-i", + "-v", `${buildPath}:${builderWorkDir}`, + "-v", "/var/run/docker.sock:/var/run/docker.sock", + "--workdir", builderWorkDir, + ...dockerOpts, + imageId, + "faas-cli", faasCmd, "-f", stackFilename, + ...faasOpts, + ] + +} diff --git a/garden-cli/src/plugins/openfaas.ts b/garden-cli/src/plugins/openfaas/openfaas.ts similarity index 83% rename from garden-cli/src/plugins/openfaas.ts rename to garden-cli/src/plugins/openfaas/openfaas.ts index ce9249b599..fb713be06d 100644 --- a/garden-cli/src/plugins/openfaas.ts +++ b/garden-cli/src/plugins/openfaas/openfaas.ts @@ -9,24 +9,24 @@ import * as Joi from "joi" import { join, resolve } from "path" import { resolve as urlResolve } from "url" -import { STATIC_DIR } from "../constants" -import { PluginError, ConfigurationError } from "../exceptions" -import { Garden } from "../garden" -import { PluginContext } from "../plugin-context" -import { joiArray, validate, PrimitiveMap } from "../config/common" -import { Module } from "../types/module" -import { ValidateModuleResult } from "../types/plugin/outputs" +import { STATIC_DIR } from "../../constants" +import { PluginError, ConfigurationError } from "../../exceptions" +import { Garden } from "../../garden" +import { PluginContext } from "../../plugin-context" +import { joiArray, validate, PrimitiveMap } from "../../config/common" +import { Module } from "../../types/module" +import { ValidateModuleResult } from "../../types/plugin/outputs" import { PrepareEnvironmentParams, GetEnvironmentStatusParams, ValidateModuleParams, DeleteServiceParams, -} from "../types/plugin/params" +} from "../../types/plugin/params" import { ServiceStatus, ServiceIngress, Service, -} from "../types/service" +} from "../../types/service" import { buildGenericModule, GenericModuleSpec, @@ -34,30 +34,31 @@ import { GenericTestSpec, testGenericModule, getGenericModuleBuildStatus, -} from "./generic" -import { KubernetesProvider } from "./kubernetes/kubernetes" -import { getNamespace, getAppNamespace } from "./kubernetes/namespace" +} from "../generic" +import { KubernetesProvider } from "../kubernetes/kubernetes" +import { getNamespace, getAppNamespace } from "../kubernetes/namespace" import { DeployServiceParams, GetServiceStatusParams, BuildModuleParams, GetServiceOutputsParams, -} from "../types/plugin/params" +} from "../../types/plugin/params" import { every, values } from "lodash" -import { dumpYaml, findByName } from "../util/util" +import { dumpYaml, findByName } from "../../util/util" import * as execa from "execa" -import { KubeApi } from "./kubernetes/api" -import { waitForObjects, checkDeploymentStatus } from "./kubernetes/status" -import { systemSymbol } from "./kubernetes/system" -import { BaseServiceSpec } from "../config/service" -import { GardenPlugin } from "../types/plugin/plugin" -import { deleteContainerService } from "./kubernetes/deployment" -import { Provider, providerConfigBaseSchema } from "../config/project" +import { KubeApi } from "../kubernetes/api" +import { waitForObjects, checkDeploymentStatus } from "../kubernetes/status" +import { systemSymbol } from "../kubernetes/system" +import { BaseServiceSpec } from "../../config/service" +import { GardenPlugin } from "../../types/plugin/plugin" +import { Provider, providerConfigBaseSchema } from "../../config/project" import dedent = require("dedent") +import { faasCliCmd, faasCliDockerArgs } from "./faas-cli" const systemProjectPath = join(STATIC_DIR, "openfaas", "system") -const stackFilename = "stack.yml" -const builderWorkDir = "/wd" +export const stackFilename = "stack.yml" +export const builderWorkDir = "/wd" +export const FAAS_CLI_IMAGE_ID = "openfaas/faas-cli:0.7.3" export interface OpenFaasModuleSpec extends GenericModuleSpec { handler: string @@ -151,14 +152,11 @@ export function gardenPlugin({ config }: { config: OpenFaasConfig }): GardenPlug ) // FIXME: this feels too magicky and convoluted, we should make this type of flow feel more natural - moduleConfig.build.command = [ - "docker", "run", "-i", - "-v", `\${modules.${moduleConfig.name}.buildPath}:${builderWorkDir}`, - "-v", "/var/run/docker.sock:/var/run/docker.sock", - "--workdir", builderWorkDir, - `openfaas--builder:\${modules.openfaas--builder.version}`, - "faas-cli", "build", "-f", stackFilename, - ] + moduleConfig.build.command = faasCliCmd({ + buildPath: `\${modules.${moduleConfig.name}.buildPath}`, + imageId: `openfaas--builder:\${modules.openfaas--builder.version}`, + faasCmd: "build", + }) moduleConfig.build.dependencies.push({ name: "builder", @@ -216,15 +214,12 @@ export function gardenPlugin({ config }: { config: OpenFaasConfig }): GardenPlug await writeStackFile(ctx, module, runtimeContext.envVars) // use faas-cli to do the deployment - await execa("docker", [ - "run", "-i", - "-v", `${module.buildPath}:${builderWorkDir}`, - "-v", "/var/run/docker.sock:/var/run/docker.sock", - "--workdir", builderWorkDir, - "--net", "host", - "openfaas/faas-cli:0.7.3", - "faas-cli", "deploy", "-f", stackFilename, - ]) + await execa("docker", faasCliDockerArgs({ + buildPath: module.buildPath, + imageId: FAAS_CLI_IMAGE_ID, + faasCmd: "deploy", + dockerOpts: ["--net", "host"], + })) // wait until deployment is ready const k8sProvider = getK8sProvider(ctx) @@ -240,16 +235,37 @@ export function gardenPlugin({ config }: { config: OpenFaasConfig }): GardenPlug }, async deleteService(params: DeleteServiceParams): Promise { - const { ctx, logEntry, service } = params - const provider = getK8sProvider(ctx) - const namespace = await getAppNamespace(ctx, provider) + const { ctx, logEntry, service, runtimeContext } = params + let status + let found = true + + try { + + status = await getServiceStatus({ + ctx, + service, + runtimeContext, + module: service.module, + }) + + found = !!status.state + + await execa("docker", faasCliDockerArgs({ + buildPath: service.module.buildPath, + imageId: FAAS_CLI_IMAGE_ID, + faasCmd: "remove", + dockerOpts: ["--net", "host"], + })) + + } catch (err) { + found = false + } - await deleteContainerService({ - namespace, provider, serviceName: service.name, - deploymentOnly: true, logEntry, - }) + if (logEntry) { + found ? logEntry.setSuccess("Service deleted") : logEntry.setWarn("Service not deployed") + } - return await getServiceStatus(params) + return status }, }, }, diff --git a/garden-cli/src/plugins/plugins.ts b/garden-cli/src/plugins/plugins.ts index 7c6e346706..1842a392d0 100644 --- a/garden-cli/src/plugins/plugins.ts +++ b/garden-cli/src/plugins/plugins.ts @@ -20,7 +20,7 @@ export const builtinPlugins: RegisterPluginParam[] = [ "./kubernetes/local", "./npm-package", "./google/google-app-engine", - "./openfaas", + "./openfaas/openfaas", ].map(p => resolve(__dirname, p)) // These plugins are always loaded