-
Notifications
You must be signed in to change notification settings - Fork 273
/
Copy pathconfig.ts
163 lines (138 loc) · 5.96 KB
/
config.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/*
* Copyright (C) 2018-2023 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 {
KubernetesConfig,
kubernetesConfigBase,
k8sContextSchema,
KubernetesProvider,
namespaceSchema,
} from "../config"
import { ConfigureProviderParams } from "../../../plugin/handlers/Provider/configureProvider"
import { joiProviderName, joi } from "../../../config/common"
import { getKubeConfig } from "../api"
import { configureMicrok8sAddons } from "./microk8s"
import { setMinikubeDockerEnv } from "./minikube"
import { exec } from "../../../util/util"
import { remove } from "lodash"
import chalk from "chalk"
import { isKindCluster } from "./kind"
import { getK8sClientServerVersions, K8sClientServerVersions } from "../util"
// 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", "docker-desktop", "microk8s", "minikube", "kind-kind", "colima"]
const nginxServices = ["ingress-controller", "default-backend"]
function isSupportedContext(context: string) {
return supportedContexts.includes(context) || context.startsWith("kind-")
}
export interface LocalKubernetesConfig extends KubernetesConfig {
setupIngressController: string | null
}
export const configSchema = () =>
kubernetesConfigBase()
.keys({
name: joiProviderName("local-kubernetes"),
context: k8sContextSchema().optional(),
namespace: namespaceSchema().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."),
})
.description("The provider configuration for the local-kubernetes plugin.")
export async function configureProvider(params: ConfigureProviderParams<LocalKubernetesConfig>) {
const { base, log, projectName, ctx } = params
let { config } = await base!(params)
const providerLog = log.createLog({ name: config.name })
const provider = ctx.provider as KubernetesProvider
provider.config = config
const _systemServices = config._systemServices
const kubeConfig: any = await getKubeConfig(providerLog, ctx, provider)
const currentContext = kubeConfig["current-context"]!
if (!config.context) {
// automatically detect supported kubectl context if not explicitly configured
if (currentContext && isSupportedContext(currentContext)) {
// prefer current context if set and supported
config.context = currentContext
providerLog.debug(`Using current context: ${config.context}`)
} else {
const availableContexts = kubeConfig.contexts?.map((c: any) => c.name) || []
for (const context of availableContexts) {
if (isSupportedContext(context)) {
config.context = context
providerLog.debug(`Using detected context: ${config.context}`)
break
}
}
}
if (!config.context && kubeConfig.contexts?.length > 0) {
config.context = kubeConfig.contexts[0]!.name
providerLog.debug(`No kubectl context auto-detected, using first available: ${config.context}`)
}
}
// TODO: change this in 0.12 to use the current context
if (!config.context) {
config.context = supportedContexts[0]
providerLog.debug(`No kubectl context configured, using default: ${config.context}`)
}
if (await isKindCluster(ctx, provider, providerLog)) {
config.clusterType = "kind"
if (config.setupIngressController === "nginx") {
providerLog.debug("Using nginx-kind service for ingress")
remove(_systemServices, (s) => nginxServices.includes(s))
let versions: K8sClientServerVersions | undefined
try {
versions = await getK8sClientServerVersions(config.context)
} catch (err) {
providerLog.debug("failed to get k8s version with error: " + err)
}
// TODO: remove this once we no longer support k8s v1.20
if (versions && versions.serverVersion.minor >= 21) {
_systemServices.push("nginx-kind-new")
} else {
_systemServices.push("nginx-kind-old")
}
}
} else if (config.context === "minikube") {
await exec("minikube", ["config", "set", "WantUpdateNotification", "false"])
config.clusterType = "minikube"
if (!config.defaultHostname) {
// use the nip.io service to give a hostname to the instance, if none is explicitly configured
const { stdout } = await exec("minikube", ["ip"])
config.defaultHostname = `${projectName}.${stdout}.nip.io`
}
if (config.setupIngressController === "nginx") {
providerLog.debug("Using minikube's ingress addon")
try {
await exec("minikube", ["addons", "enable", "ingress"])
} catch (err) {
providerLog.warn(chalk.yellow(`Unable to enable minikube ingress addon: ${err.all}`))
}
remove(_systemServices, (s) => nginxServices.includes(s))
}
await setMinikubeDockerEnv()
} else if (config.context === "microk8s") {
const addons = ["dns", "registry", "storage"]
config.clusterType = "microk8s"
if (config.setupIngressController === "nginx") {
providerLog.debug("Using microk8s's ingress addon")
addons.push("ingress")
remove(_systemServices, (s) => nginxServices.includes(s))
_systemServices.push("nginx-ingress-class")
}
await configureMicrok8sAddons(providerLog, addons)
}
if (!config.defaultHostname) {
config.defaultHostname = `${projectName}.local.demo.garden`
}
return { config }
}