Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: incl. ingresses & services in delete command. #286

Merged
merged 2 commits into from
Sep 20, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion garden-cli/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion garden-cli/src/plugins/kubernetes/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,10 @@ export async function cleanupEnvironment({ ctx, logEntry }: CleanupEnvironmentPa
export async function deleteService(params: DeleteServiceParams): Promise<ServiceStatus> {
const { ctx, logEntry, service } = params
const namespace = await getAppNamespace(ctx, ctx.provider)
const provider = ctx.provider

await deleteContainerService({ provider: ctx.provider, logEntry, namespace, serviceName: service.name })
await deleteContainerService(
{ provider, namespace, serviceName: service.name, logEntry })

return getContainerServiceStatus(params)
}
Expand Down
33 changes: 23 additions & 10 deletions garden-cli/src/plugins/kubernetes/deployment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,12 @@ import { RuntimeContext, ServiceStatus } from "../../types/service"
import { createIngresses, getIngresses } from "./ingress"
import { createServices } from "./service"
import { waitForObjects, compareDeployedObjects } from "./status"
import { applyMany } from "./kubectl"
import { applyMany, deleteObjectsByLabel } from "./kubectl"
import { getAppNamespace } from "./namespace"
import { KubernetesObject } from "./helm"
import { PluginContext } from "../../plugin-context"
import { KubernetesProvider } from "./kubernetes"
import { GARDEN_ANNOTATION_KEYS_VERSION } from "../../constants"
import { KubeApi } from "./api"
import { LogEntry } from "../../logger/log-entry"

export const DEFAULT_CPU_REQUEST = "10m"
export const DEFAULT_CPU_LIMIT = "500m"
Expand Down Expand Up @@ -324,14 +322,29 @@ export async function createDeployment(
return deployment
}

export async function deleteContainerService({ namespace, provider, serviceName, logEntry }: {
namespace: string,
provider: KubernetesProvider,
serviceName: string,
logEntry?: LogEntry,
}) {
const api = new KubeApi(provider)
export async function deleteContainerService(
{ namespace, provider, serviceName, logEntry },
) {

const context = provider.config.context
await deleteContainerDeployment({ namespace, provider, serviceName, logEntry })
await deleteObjectsByLabel({
context,
namespace,
labelKey: "service",
labelValue: serviceName,
objectTypes: ["deployment", "service", "ingress"],
includeUninitialized: false,
})

}

export async function deleteContainerDeployment(
{ namespace, provider, serviceName, logEntry },
) {

let found = true
const api = new KubeApi(provider)

try {
await api.extensions.deleteNamespacedDeployment(serviceName, namespace, <any>{})
Expand Down
37 changes: 37 additions & 0 deletions garden-cli/src/plugins/kubernetes/kubectl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,3 +193,40 @@ export async function applyMany(
return result.output
}
}

export interface DeleteObjectsParams {
context: string,
namespace: string,
labelKey: string,
labelValue: string,
objectTypes: string[],
includeUninitialized?: boolean,
}

export async function deleteObjectsByLabel(
{
context,
namespace,
labelKey,
labelValue,
objectTypes,
includeUninitialized = false,
}: DeleteObjectsParams) {

let args = [
"delete",
objectTypes.join(","),
"-l",
`${labelKey}=${labelValue}`,
]

includeUninitialized && args.push("--include-uninitialized")

const result = await kubectl(context, namespace).call(args)

try {
return JSON.parse(result.output)
} catch (_) {
return result.output
}
}
44 changes: 44 additions & 0 deletions garden-cli/src/plugins/openfaas/faas-cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright (C) 2018 Garden Technologies, Inc. <[email protected]>
*
* 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,
]

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,55 +9,56 @@
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,
genericModuleSpecSchema,
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
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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)
Expand All @@ -240,13 +235,37 @@ export function gardenPlugin({ config }: { config: OpenFaasConfig }): GardenPlug
},

async deleteService(params: DeleteServiceParams<OpenFaasModule>): Promise<ServiceStatus> {
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({ provider, logEntry, namespace, serviceName: service.name })
if (logEntry) {
found ? logEntry.setSuccess("Service deleted") : logEntry.setWarn("Service not deployed")
}

return await getServiceStatus(params)
return status
},
},
},
Expand Down
2 changes: 1 addition & 1 deletion garden-cli/src/plugins/plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down