Skip to content

Commit 012e180

Browse files
committed
Add kubeconfig to CRS and init settings
1 parent abf14d9 commit 012e180

File tree

1 file changed

+311
-0
lines changed

1 file changed

+311
-0
lines changed
+311
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,311 @@
1+
terraform {
2+
required_providers {
3+
coder = {
4+
source = "coder/coder"
5+
version = "0.4.15"
6+
}
7+
kubernetes = {
8+
source = "hashicorp/kubernetes"
9+
version = "~> 2.12.1"
10+
}
11+
}
12+
}
13+
14+
# https://www.terraform.io/language/providers/configuration#provider-configuration-1
15+
# > You can use expressions in the values of these configuration arguments,
16+
# but can only reference values that are known before the configuration is applied.
17+
# This means you can safely reference input variables, but not attributes
18+
# exported by resources (with an exception for resource arguments that
19+
# are specified directly in the configuration).
20+
#### no data.X :(
21+
# provider "kubernetes" {
22+
# alias = "vcluster"
23+
# host = yamldecode(data.kubernetes_resource.kubeconfig.data)["value"]["clusters"][0]["cluster"]["server"]
24+
# client_certificate = base64decode(yamldecode(data.kubernetes_resource.kubeconfig.data)["value"]["users"][0]["user"]["client-certificate-data"])
25+
# client_key = base64decode(yamldecode(data.kubernetes_resource.kubeconfig.data)["value"]["users"][0]["user"]["client-key-data"])
26+
# cluster_ca_certificate = base64decode(yamldecode(data.kubernetes_resource.kubeconfig.data)["value"]["clusters"][0]["cluster"]["certificate-authority-data"])
27+
# }
28+
29+
variable "base_domain" {
30+
type = string
31+
default = "sanskar.pair.sharing.io"
32+
}
33+
34+
data "coder_workspace" "me" {}
35+
36+
resource "coder_agent" "main" {
37+
os = "linux"
38+
arch = "amd64"
39+
startup_script = <<EOT
40+
#!/bin/bash
41+
42+
# home folder can be empty, so copying default bash settings
43+
if [ ! -f ~/.profile ]; then
44+
cp /etc/skel/.profile $HOME
45+
fi
46+
if [ ! -f ~/.bashrc ]; then
47+
cp /etc/skel/.bashrc $HOME
48+
fi
49+
echo 'export PATH="$PATH:$HOME/bin"' >> $HOME/.bashrc
50+
mkdir -p bin
51+
curl -o bin/kubectl -L https://dl.k8s.io/v1.25.2/bin/linux/amd64/kubectl
52+
chmod +x bin/*
53+
54+
# install and start code-server
55+
curl -fsSL https://code-server.dev/install.sh | sh | tee code-server-install.log
56+
code-server --auth none --port 13337 | tee code-server-install.log &
57+
EOT
58+
}
59+
60+
# code-server
61+
resource "coder_app" "code-server" {
62+
agent_id = coder_agent.main.id
63+
name = "code-server"
64+
icon = "/icon/code.svg"
65+
url = "http://localhost:13337?folder=/home/coder"
66+
relative_path = true
67+
68+
healthcheck {
69+
url = "http://localhost:13337/healthz"
70+
interval = 3
71+
threshold = 10
72+
}
73+
}
74+
75+
resource "kubernetes_namespace" "workspace" {
76+
metadata {
77+
name = data.coder_workspace.me.name
78+
labels = {
79+
cert-manager-tls = "sync"
80+
}
81+
}
82+
}
83+
84+
resource "kubernetes_manifest" "cluster" {
85+
manifest = {
86+
"apiVersion" = "cluster.x-k8s.io/v1beta1"
87+
"kind" = "Cluster"
88+
"metadata" = {
89+
"name" = data.coder_workspace.me.name
90+
"namespace" = data.coder_workspace.me.name
91+
"labels" = {
92+
"cluster-name" = data.coder_workspace.me.name
93+
}
94+
}
95+
"spec" = {
96+
"controlPlaneRef" = {
97+
"apiVersion" = "infrastructure.cluster.x-k8s.io/v1alpha1"
98+
"kind" = "VCluster"
99+
"name" = data.coder_workspace.me.name
100+
}
101+
"infrastructureRef" = {
102+
"apiVersion" = "infrastructure.cluster.x-k8s.io/v1alpha1"
103+
"kind" = "VCluster"
104+
"name" = data.coder_workspace.me.name
105+
}
106+
}
107+
}
108+
}
109+
110+
resource "kubernetes_manifest" "vcluster" {
111+
manifest = {
112+
"apiVersion" = "infrastructure.cluster.x-k8s.io/v1alpha1"
113+
"kind" = "VCluster"
114+
"metadata" = {
115+
"name" = data.coder_workspace.me.name
116+
"namespace" = data.coder_workspace.me.name
117+
}
118+
"spec" = {
119+
"controlPlaneEndpoint" = {
120+
"host" = ""
121+
"port" = 0
122+
}
123+
"kubernetesVersion" = "1.23.4"
124+
"helmRelease" = {
125+
"chart" = {
126+
"name" = null
127+
"repo" = null
128+
"version" = null
129+
}
130+
"values" = <<-EOT
131+
service:
132+
type: NodePort
133+
syncer:
134+
extraArgs:
135+
- --tls-san="${data.coder_workspace.me.name}.${var.base_domain}"
136+
- --tls-san="${data.coder_workspace.me.name}.${data.coder_workspace.me.name}.svc"
137+
EOT
138+
}
139+
}
140+
}
141+
}
142+
143+
resource "kubernetes_manifest" "configmap_capi_init" {
144+
manifest = {
145+
"kind" = "ConfigMap"
146+
"metadata" = {
147+
"name" = "capi-init"
148+
"namespace" = data.coder_workspace.me.name
149+
}
150+
"apiVersion" = "v1"
151+
"data" = {
152+
"cool.yaml" = templatefile("cool.template.yaml",
153+
{
154+
coder_command = jsonencode(["sh", "-c", coder_agent.main.init_script]),
155+
coder_token = coder_agent.main.token
156+
instance_name = data.coder_workspace.me.name
157+
})
158+
}
159+
}
160+
}
161+
162+
data "kubernetes_secret" "vcluster-kubeconfig" {
163+
metadata {
164+
name = "${data.coder_workspace.me.name}-kubeconfig"
165+
namespace = data.coder_workspace.me.name
166+
}
167+
168+
depends_on = [
169+
kubernetes_manifest.cluster,
170+
kubernetes_manifest.vcluster,
171+
kubernetes_manifest.clusterresourceset_capi_init
172+
]
173+
}
174+
175+
// using a manifest instead of secret, so that the wait capability works
176+
resource "kubernetes_manifest" "configmap_capi_kubeconfig" {
177+
manifest = {
178+
"kind" = "Secret"
179+
"metadata" = {
180+
"name" = "vcluster-kubeconfig"
181+
"namespace" = data.coder_workspace.me.name
182+
}
183+
"apiVersion" = "v1"
184+
"type" = "addons.cluster.x-k8s.io/resource-set"
185+
"data" = {
186+
"kubeconfig.yaml" = base64encode(data.kubernetes_secret.vcluster-kubeconfig.data.value)
187+
}
188+
}
189+
190+
depends_on = [
191+
kubernetes_manifest.cluster,
192+
kubernetes_manifest.vcluster,
193+
kubernetes_manifest.clusterresourceset_capi_init,
194+
data.kubernetes_secret.vcluster-kubeconfig
195+
]
196+
197+
wait {
198+
fields = {
199+
"data[\"kubeconfig.yaml\"]" = "*"
200+
}
201+
}
202+
203+
timeouts {
204+
create = "1m"
205+
}
206+
}
207+
208+
resource "kubernetes_manifest" "clusterresourceset_capi_init" {
209+
manifest = {
210+
"apiVersion" = "addons.cluster.x-k8s.io/v1beta1"
211+
"kind" = "ClusterResourceSet"
212+
"metadata" = {
213+
"name" = data.coder_workspace.me.name
214+
"namespace" = data.coder_workspace.me.name
215+
}
216+
"spec" = {
217+
"clusterSelector" = {
218+
"matchLabels" = {
219+
"cluster-name" = data.coder_workspace.me.name
220+
}
221+
}
222+
"resources" = [
223+
{
224+
"kind" = "ConfigMap"
225+
"name" = "capi-init"
226+
},
227+
{
228+
"kind" = "Secret"
229+
"name" = "vcluster-kubeconfig"
230+
},
231+
]
232+
"strategy" = "ApplyOnce"
233+
}
234+
}
235+
}
236+
# data "kubernetes_resource" "cluster-kubeconfig" {
237+
# api_version = "v1"
238+
# kind = "Secret"
239+
# metadata {
240+
# name = "${data.coder_workspace.me.name}-kubeconfig"
241+
# namespace = data.coder_workspace.me.name
242+
# }
243+
244+
# depends_on = [
245+
# kubernetes_namespace.workspace,
246+
# kubernetes_manifest.cluster,
247+
# kubernetes_manifest.vcluster
248+
# ]
249+
# }
250+
251+
# This is generated from the vcluster...
252+
# Need to find a way for it to wait before running, so that the secret exists
253+
254+
# We'll need to use the kubeconfig from above to provision the coder/pair environment
255+
resource "kubernetes_manifest" "ingress_capi_kubeapi" {
256+
manifest = {
257+
"apiVersion" = "networking.k8s.io/v1"
258+
"kind" = "Ingress"
259+
"metadata" = {
260+
"annotations" = {
261+
"nginx.ingress.kubernetes.io/backend-protocol" = "HTTPS"
262+
"nginx.ingress.kubernetes.io/ssl-redirect" = "true"
263+
}
264+
"name" = "kubeapi"
265+
"namespace" = data.coder_workspace.me.name
266+
}
267+
"spec" = {
268+
"ingressClassName" = "contour-external"
269+
"rules" = [
270+
{
271+
"host" = "${data.coder_workspace.me.name}.${var.base_domain}"
272+
"http" = {
273+
"paths" = [
274+
{
275+
"backend" = {
276+
"service" = {
277+
"name" = "vcluster1"
278+
"port" = {
279+
"number" = 443
280+
}
281+
}
282+
}
283+
"path" = "/"
284+
"pathType" = "ImplementationSpecific"
285+
},
286+
]
287+
}
288+
},
289+
]
290+
"tls" = [
291+
{
292+
"hosts" = [
293+
"${data.coder_workspace.me.name}.${var.base_domain}"
294+
]
295+
},
296+
]
297+
}
298+
}
299+
}
300+
301+
resource "coder_app" "vcluster-apiserver" {
302+
agent_id = coder_agent.main.id
303+
name = "APIServer"
304+
url = "https://kubernetes.default.svc:443"
305+
relative_path = true
306+
healthcheck {
307+
url = "https://kubernetes.default.svc:443/healthz"
308+
interval = 5
309+
threshold = 6
310+
}
311+
}

0 commit comments

Comments
 (0)