Skip to content

Commit

Permalink
Merge pull request #553 from garden-io/fix-minikube-issue
Browse files Browse the repository at this point in the history
Fix minikube issues
  • Loading branch information
edvald authored Feb 22, 2019
2 parents 2b303d3 + 9eb6052 commit beafe6a
Show file tree
Hide file tree
Showing 13 changed files with 233 additions and 200 deletions.
2 changes: 1 addition & 1 deletion garden-service/src/docs/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { execModuleSpecSchema } from "../plugins/exec"
import { projectSchema } from "../config/project"
import { baseModuleSpecSchema } from "../config/module"
import handlebars = require("handlebars")
import { configSchema as localK8sConfigSchema } from "../plugins/kubernetes/local"
import { configSchema as localK8sConfigSchema } from "../plugins/kubernetes/local/config"
import { configSchema as k8sConfigSchema } from "../plugins/kubernetes/kubernetes"
import { configSchema as openfaasConfigSchema } from "../plugins/openfaas/openfaas"
import { openfaasModuleSpecSchema } from "../plugins/openfaas/openfaas"
Expand Down
19 changes: 14 additions & 5 deletions garden-service/src/garden.ts
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,7 @@ export class Garden {
}

private async loadPlugin(pluginName: string, config: ProviderConfig) {
this.log.silly(`Loading plugin ${pluginName}`)
const factory = this.registeredPlugins[pluginName]

if (!factory) {
Expand Down Expand Up @@ -444,20 +445,28 @@ export class Garden {

// call configureProvider action if provided
const configureHandler = actions.configureProvider
if (configureHandler) {
const configureOutput = await configureHandler({ config: providerConfig })
providerConfig = configureOutput.config
}

if (plugin.configSchema) {
providerConfig = validate(providerConfig, plugin.configSchema, { context: `${pluginName} configuration` })
}

if (configureHandler) {
this.log.silly(`Calling configureProvider on ${pluginName}`)
const configureOutput = await configureHandler({
config: providerConfig,
projectName: this.projectName,
log: this.log,
})
providerConfig = configureOutput.config
}

if (providerIndex === -1) {
this.environment.providers.push({ name: pluginName, config: providerConfig })
} else {
this.environment.providers[providerIndex].config = providerConfig
}

this.log.silly(`Done loading plugin ${pluginName}`)
}

getPlugin(pluginName: string) {
Expand Down Expand Up @@ -508,7 +517,7 @@ export class Garden {
})
const ctx = this.getPluginContext(configureHandler["pluginName"])

config = await configureHandler({ ctx, moduleConfig: config })
config = await configureHandler({ ctx, moduleConfig: config, log: this.log })

// FIXME: We should be able to avoid this
config.name = getModuleKey(config.name, config.plugin)
Expand Down
2 changes: 0 additions & 2 deletions garden-service/src/plugins/kubernetes/helm/deployment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ export async function deployService(
"--name", releaseName,
"--namespace", namespace,
"--values", valuesPath,
"--wait",
]
if (force) {
installArgs.push("--replace")
Expand All @@ -70,7 +69,6 @@ export async function deployService(
"--install",
"--namespace", namespace,
"--values", valuesPath,
"--wait",
]
if (force) {
upgradeArgs.push("--force")
Expand Down
160 changes: 0 additions & 160 deletions garden-service/src/plugins/kubernetes/local.ts

This file was deleted.

146 changes: 146 additions & 0 deletions garden-service/src/plugins/kubernetes/local/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/*
* 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 * as execa from "execa"
import { safeLoad } from "js-yaml"
import * as Joi from "joi"
import { join } from "path"
import { readFile } from "fs-extra"
import { homedir } from "os"
import { KubernetesBaseConfig, kubernetesConfigBase } from "../kubernetes"
import { ConfigureProviderParams } from "../../../types/plugin/params"

// TODO: split this into separate plugins to handle Docker for Mac and Minikube

// note: this is in order of preference, in case neither is set as the current kubectl context
// and none is explicitly configured in the garden.yml
const supportedContexts = ["docker-for-desktop", "minikube"]
const kubeConfigPath = join(homedir(), ".kube", "config")

async function getKubeConfig(): Promise<any> {
try {
return safeLoad((await readFile(kubeConfigPath)).toString())
} catch {
return {}
}
}

/**
* Automatically set docker environment variables for minikube
* TODO: it would be better to explicitly provide those to docker instead of using process.env
*/
async function setMinikubeDockerEnv() {
const minikubeEnv = await execa.stdout("minikube", ["docker-env", "--shell=bash"])
for (const line of minikubeEnv.split("\n")) {
const matched = line.match(/^export (\w+)="(.+)"$/)
if (matched) {
process.env[matched[1]] = matched[2]
}
}
}

export interface LocalKubernetesConfig extends KubernetesBaseConfig {
_system?: Symbol
setupIngressController: string | null
}

export const configSchema = kubernetesConfigBase
.keys({
namespace: Joi.string()
.default(undefined, "<project name>")
.description(
"Specify which namespace to deploy services to (defaults to the project name). " +
"Note that the framework generates other namespaces as well with this name as a prefix.",
),
setupIngressController: Joi.string()
.allow("nginx", false, null)
.default("nginx")
.description("Set this to null or false to skip installing/enabling the `nginx` ingress controller."),
_system: Joi.any().meta({ internal: true }),
})
.description("The provider configuration for the local-kubernetes plugin.")

export async function configureProvider({ config, log, projectName }: ConfigureProviderParams<LocalKubernetesConfig>) {
let context = config.context
let defaultHostname = config.defaultHostname
let setupIngressController = config.setupIngressController

if (!context) {
// automatically detect supported kubectl context if not explicitly configured
const kubeConfig = await getKubeConfig()
const currentContext = kubeConfig["current-context"]

if (currentContext && supportedContexts.includes(currentContext)) {
// prefer current context if set and supported
context = currentContext
log.debug({ section: config.name, msg: `Using current context: ${context}` })
} else if (kubeConfig.contexts) {
const availableContexts = kubeConfig.contexts.map(c => c.name)

for (const supportedContext of supportedContexts) {
if (availableContexts.includes(supportedContext)) {
context = supportedContext
log.debug({ section: config.name, msg: `Using detected context: ${context}` })
break
}
}
}
}

if (!context) {
context = supportedContexts[0]
log.debug({ section: config.name, msg: `No kubectl context auto-detected, using default: ${context}` })
}

if (context === "minikube") {
await execa("minikube", ["config", "set", "WantUpdateNotification", "false"])

if (!defaultHostname) {
// use the nip.io service to give a hostname to the instance, if none is explicitly configured
const minikubeIp = await execa.stdout("minikube", ["ip"])
defaultHostname = `${projectName}.${minikubeIp}.nip.io`
}

if (config.setupIngressController === "nginx") {
log.silly("Using minikube's ingress addon")
await execa("minikube", ["addons", "enable", "ingress"])
// make sure the prepare handler doesn't also set up the ingress controller
setupIngressController = null
}

await setMinikubeDockerEnv()

} else {
if (!defaultHostname) {
defaultHostname = `${projectName}.local.app.garden`
}
}

const ingressClass = config.ingressClass || config.setupIngressController || undefined

config = {
name: config.name,
context,
defaultHostname,
deploymentRegistry: {
hostname: "foo.garden", // this is not used by this plugin, but required by the base plugin
namespace: "_",
},
forceSsl: false,
imagePullSecrets: config.imagePullSecrets,
ingressHttpPort: 80,
ingressHttpsPort: 443,
ingressClass,
namespace: config.namespace || projectName,
setupIngressController,
tlsCertificates: config.tlsCertificates,
_system: config._system,
}

return { name: config.name, config }
}
Loading

0 comments on commit beafe6a

Please sign in to comment.