Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(k8s): local mode for kubernetes modules
Browse files Browse the repository at this point in the history
vvagaytsev committed Jun 27, 2022

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent 8c8b495 commit ac2b10f
Showing 3 changed files with 99 additions and 26 deletions.
70 changes: 45 additions & 25 deletions core/src/plugins/kubernetes/kubernetes-module/handlers.ts
Original file line number Diff line number Diff line change
@@ -16,9 +16,9 @@ import { DeployServiceParams } from "../../../types/plugin/service/deployService
import { GetServiceLogsParams } from "../../../types/plugin/service/getServiceLogs"
import { GetServiceStatusParams } from "../../../types/plugin/service/getServiceStatus"
import { ServiceStatus } from "../../../types/service"
import { gardenAnnotationKey } from "../../../util/string"
import { deline, gardenAnnotationKey } from "../../../util/string"
import { KubeApi } from "../api"
import { KubernetesPluginContext } from "../config"
import { KubernetesPluginContext, ServiceResourceSpec } from "../config"
import { configureDevMode, startDevModeSync } from "../dev-mode"
import { HelmService } from "../helm/config"
import { configureHotReload, getHotReloadContainerName, getHotReloadSpec } from "../hot-reload/helpers"
@@ -38,6 +38,9 @@ import { configureKubernetesModule, KubernetesModule, KubernetesService } from "
import { execInKubernetesService } from "./exec"
import { runKubernetesTask } from "./run"
import { testKubernetesModule } from "./test"
import { configureLocalMode, startServiceInLocalMode } from "../local-mode"
import { ConfigurationError } from "../../../exceptions"
import chalk from "chalk"

export const kubernetesHandlers: Partial<ModuleAndRuntimeActionHandlers<KubernetesModule>> = {
configure: configureKubernetesModule,
@@ -94,15 +97,16 @@ export async function getKubernetesServiceStatus({
manifests,
})

let { state, remoteResources, deployedWithDevMode, deployedWithHotReloading } = await compareDeployedResources(
k8sCtx,
api,
namespace,
prepareResult.manifests,
log
)
let {
state,
remoteResources,
deployedWithDevMode,
deployedWithHotReloading,
deployedWithLocalMode,
} = await compareDeployedResources(k8sCtx, api, namespace, prepareResult.manifests, log)

const forwardablePorts = getForwardablePorts(remoteResources, service)
// Local mode has its own port-forwarding configuration
const forwardablePorts = deployedWithLocalMode ? [] : getForwardablePorts(remoteResources, service)

if (state === "ready" && devMode && service.spec.devMode) {
// Need to start the dev-mode sync here, since the deployment handler won't be called.
@@ -138,6 +142,7 @@ export async function getKubernetesServiceStatus({
version: state === "ready" ? service.version : undefined,
detail: { remoteResources },
devMode: deployedWithDevMode || deployedWithHotReloading,
localMode: deployedWithLocalMode,
namespaceStatuses: [namespaceStatus],
ingresses: getK8sIngresses(remoteResources),
}
@@ -217,8 +222,15 @@ export async function deployKubernetesService(
if (target) {
// local mode always takes precedence over dev mode
if (localMode && service.spec.localMode) {
// todo
// configureLocalMode()
await startServiceInLocalMode({
ctx,
spec: service.spec.localMode,
service,
target,
namespace,
log,
containerName: service.spec.localMode.containerName,
})
} else if (devMode && service.spec.devMode) {
await startDevModeSync({
ctx,
@@ -363,9 +375,9 @@ async function configureSpecialModesForManifests({
const localModeSpec = service.spec.localMode

let target: HotReloadableResource

let resourceSpec: ServiceResourceSpec
try {
const resourceSpec = getServiceResourceSpec(module, undefined)
resourceSpec = getServiceResourceSpec(module, undefined)

target = cloneDeep(
await getServiceResource({
@@ -379,7 +391,7 @@ async function configureSpecialModesForManifests({
)
} catch (err) {
const enableLocalMode = localMode && localModeSpec
const enableDevMode = devModeSpec && devMode
const enableDevMode = devMode && devModeSpec
// This is only an error if we're actually trying to hot reload, or start dev or local mode.
if (enableDevMode || hotReload || enableLocalMode) {
throw err
@@ -395,16 +407,25 @@ async function configureSpecialModesForManifests({

// local mode always takes precedence over dev mode
if (localMode && localModeSpec) {
if (!resourceSpec.containerName) {
throw new ConfigurationError(
chalk.red(
deline`${module.type} module ${chalk.white(module.name)} doesn't specify a ${chalk.underline(
"serviceResource.containerName"
)}
in its configuration. You must to specify a container name to start it in local mode.`
),
{ resourceSpec }
)
}
// The "local-mode" annotation is set in `configureLocalMode`.
// todo
// await configureLocalMode({
// ctx,
// target,
// spec: localModeSpec,
// service,
// log,
// containerName: localModeSpec.containerName,
// })
await configureLocalMode({
ctx,
spec: localModeSpec,
target,
log,
containerName: localModeSpec.containerName,
})
} else if (devMode && devModeSpec) {
// The "dev-mode" annotation is set in `configureDevMode`.
configureDevMode({
@@ -413,7 +434,6 @@ async function configureSpecialModesForManifests({
containerName: devModeSpec.containerName,
})
} else if (hotReload && hotReloadSpec) {
const resourceSpec = getServiceResourceSpec(module, undefined)
configureHotReload({
target,
hotReloadSpec,
Original file line number Diff line number Diff line change
@@ -8,6 +8,9 @@ devMode:
- source: "*"
target: /app

localMode:
localPort: 8090

manifests:
- apiVersion: apps/v1
kind: Deployment
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@ import { KubernetesPluginContext, KubernetesProvider } from "../../../../../../s
import { getModuleNamespace } from "../../../../../../src/plugins/kubernetes/namespace"
import { getDeployedResource } from "../../../../../../src/plugins/kubernetes/status/status"
import { ModuleConfig } from "../../../../../../src/config/module"
import { KubernetesResource, BaseResource } from "../../../../../../src/plugins/kubernetes/types"
import { BaseResource, KubernetesResource } from "../../../../../../src/plugins/kubernetes/types"
import { DeleteServiceTask } from "../../../../../../src/tasks/delete-service"
import {
deployKubernetesService,
@@ -32,6 +32,7 @@ import Bluebird from "bluebird"
import { buildHelmModules } from "../helm/common"
import { gardenAnnotationKey } from "../../../../../../src/util/string"
import { getServiceStatuses } from "../../../../../../src/tasks/base"
import { LocalModeProcessRegistry } from "../../../../../../src/plugins/kubernetes/local-mode"

describe("kubernetes-module handlers", () => {
let tmpDir: tmp.DirectoryResult
@@ -269,6 +270,55 @@ describe("kubernetes-module handlers", () => {
expect(res3[0].metadata.annotations![gardenAnnotationKey("dev-mode")]).to.equal("false")
})

it("should toggle localMode", async () => {
const graph = await garden.getConfigGraph({ log: garden.log, emit: false })
const service = graph.getService("with-source-module")
const namespace = await getModuleNamespace({
ctx,
log,
module: service.module,
provider: ctx.provider,
skipCreate: true,
})
const deployParams = {
ctx,
log: garden.log,
module: service.module,
service,
force: false,
devMode: false,
hotReload: false,
localMode: false,
runtimeContext: emptyRuntimeContext,
}
const manifests = await getManifests({
ctx,
api,
log,
module: service.module,
defaultNamespace: namespace,
readFromSrcDir: true,
})

// Deploy without dev mode
await deployKubernetesService(deployParams)
const res1 = await findDeployedResources(manifests, log)

// Deploy with dev mode
await deployKubernetesService({ ...deployParams, localMode: true })
const res2 = await findDeployedResources(manifests, log)
// shut down local app and tunnels to avoid retrying after redeploy
LocalModeProcessRegistry.getInstance().shutdown()

// Deploy without dev mode again
await deployKubernetesService(deployParams)
const res3 = await findDeployedResources(manifests, log)

expect(res1[0].metadata.annotations![gardenAnnotationKey("local-mode")]).to.equal("false")
expect(res2[0].metadata.annotations![gardenAnnotationKey("local-mode")]).to.equal("true")
expect(res3[0].metadata.annotations![gardenAnnotationKey("local-mode")]).to.equal("false")
})

it("should not delete previously deployed namespace resources", async () => {
garden.setModuleConfigs([withNamespace(nsModuleConfig, "kubernetes-module-ns-1")])
let graph = await garden.getConfigGraph({ log, emit: false })

0 comments on commit ac2b10f

Please sign in to comment.