Skip to content

Commit 02ee248

Browse files
committed
initial commit for tilt
1 parent e46dba9 commit 02ee248

File tree

4 files changed

+287
-1
lines changed

4 files changed

+287
-1
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,7 @@ ginkgo-log.txt
3434
internal/test/e2e/clusters
3535
internal/test/e2e/kind
3636
internal/test/e2e/repository
37-
internal/test/e2e/data/infrastructure-proxmox/*/cluster-template.yaml
37+
internal/test/e2e/data/infrastructure-proxmox/*/cluster-template.yaml
38+
39+
# tilt
40+
.tiltbuild

Makefile

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,19 @@ vet: ## Run go vet against code.
6969
lint: golangci-lint ## Run golangci-lint
7070
$(GOLANGCI_LINT) run
7171

72+
KIND_CLUSTER_NAME := cappx
73+
.PHONY: kind-cluster
74+
kind-cluster: kind
75+
kind create cluster --name=$(KIND_CLUSTER_NAME)
76+
77+
.PHONY: tilt-up
78+
tilt-up: tilt
79+
$(TILT) up
80+
81+
.PHONY: tilt-down
82+
tilt-down: tilt
83+
$(TILT) down
84+
7285
CLUSTER_NAME := cappx-test
7386

7487
.PHONY: create-workload-cluster
@@ -234,12 +247,16 @@ ENVSUBST ?= $(LOCALBIN)/envsubst
234247
KUBECTL ?= $(LOCALBIN)/kubectl
235248
GOLANGCI_LINT ?= $(LOCALBIN)/golangci-lint
236249
GOIMPORTS ?= $(LOCALBIN)/goimports
250+
TILT ?= $(LOCALBIN)/tilt
251+
KIND ?= $(LOCALBIN)/kind
237252

238253
## Tool Versions
239254
KUSTOMIZE_VERSION ?= v5.0.0
240255
CONTROLLER_TOOLS_VERSION ?= v0.11.3
241256
ENVSUBST_VER ?= v1.4.2
242257
KUBECTL_VER := v1.25.10
258+
TILT_VER := 0.33.6
259+
KIND_VER := v0.20.0
243260

244261
KUSTOMIZE_INSTALL_SCRIPT ?= "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh"
245262
.PHONY: kustomize
@@ -287,3 +304,21 @@ $(GOLANGCI_LINT): $(LOCALBIN)
287304
goimports: $(GOIMPORTS)
288305
$(GOIMPORTS): $(LOCALBIN)
289306
GOBIN=$(LOCALBIN) go install golang.org/x/tools/cmd/goimports@latest
307+
308+
TILT_DOWNLOAD_URL ?= https://github.com/tilt-dev/tilt/releases/download/v$(TILT_VER)/tilt.$(TILT_VER).linux.x86_64.tar.gz
309+
.PHONY: tilt
310+
tilt: $(TILT)
311+
$(TILT): $(LOCALBIN)
312+
@if test -x $(LOCALBIN)/tilt && ! $(LOCALBIN)/tilt version | grep -q $(TILT_VER); then \
313+
rm -rf $(LOCALBIN)/tilt; \
314+
fi
315+
test -s $(LOCALBIN)/tilt || (curl -fsSL $(TILT_DOWNLOAD_URL) | tar -xzv tilt && mv tilt $(LOCALBIN)/tilt)
316+
317+
KIND_DOWNLOAD_URL ?= https://kind.sigs.k8s.io/dl/$(KIND_VER)/kind-linux-$(GOARCH)
318+
.PHONY: kind
319+
kind: $(KIND)
320+
$(KIND): $(LOCALBIN)
321+
@if test -x $(LOCALBIN)/kind && ! $(LOCALBIN)/kind version | grep -q $(KIND_VER); then \
322+
rm -rf $(LOCALBIN)/kind; \
323+
fi
324+
test -s $(LOCALBIN)/kind || (curl -Lo $(LOCALBIN)/kind $(KIND_DOWNLOAD_URL) && chmod +x $(LOCALBIN)/kind)

Tiltfile

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
# -*- mode: Python -*-
2+
3+
envsubst_cmd = "./bin/envsubst"
4+
5+
load("ext://uibutton", "cmd_button", "location", "text_input")
6+
7+
# set defaults
8+
settings = {
9+
"capi_version": "v1.5.3",
10+
"allowed_contexts": [
11+
"kind-cappx",
12+
"default"
13+
],
14+
"extra_args": {
15+
"core": [
16+
"--feature-gates=MachinePool=false,ClusterResourceSet=true,ClusterTopology=false,RuntimeSDK=false,MachineSetPreflightChecks=false"
17+
]
18+
}
19+
}
20+
21+
always_enable_providers = ["proxmox"]
22+
providers = {}
23+
extra_args = settings.get("extra_args", {})
24+
25+
# global settings
26+
settings.update(read_json(
27+
"tilt-settings.json",
28+
default = {},
29+
))
30+
31+
if "allowed_contexts" in settings:
32+
allow_k8s_contexts(settings.get("allowed_contexts"))
33+
34+
# deploy core, bootstrap and controlplane provider
35+
def deploy_capi():
36+
version = settings.get("capi_version")
37+
capi_uri = "https://github.com/kubernetes-sigs/cluster-api/releases/download/{}/cluster-api-components.yaml".format(version)
38+
cmd = "curl -sSL {} | {} | kubectl apply -f -".format(capi_uri, envsubst_cmd)
39+
local(cmd, quiet=True)
40+
if settings.get("extra_args"):
41+
extra_args = settings.get("extra_args")
42+
if extra_args.get("core"):
43+
core_extra_args = extra_args.get("core")
44+
if core_extra_args:
45+
for namespace in ["capi-system"]:
46+
patch_args_with_extra_args(namespace, "capi-controller-manager", 0, core_extra_args)
47+
patch_capi_manager_role_with_exp_infra_rbac()
48+
if extra_args.get("kubeadm-bootstrap"):
49+
kb_extra_args = extra_args.get("kubeadm-bootstrap")
50+
if kb_extra_args:
51+
patch_args_with_extra_args("capi-kubeadm-bootstrap-system", "capi-kubeadm-bootstrap-controller-manager", 1, kb_extra_args)
52+
53+
def patch_args_with_extra_args(namespace, name, n_container, extra_args):
54+
args_str = str(local('kubectl get deployments {} -n {} -o jsonpath={{.spec.template.spec.containers[{}].args}}'.format(name, namespace, n_container)))
55+
args_to_add = [arg for arg in extra_args if arg not in args_str]
56+
if args_to_add:
57+
args = args_str[1:-1].split()
58+
args.extend(args_to_add)
59+
patch = [{
60+
"op": "replace",
61+
"path": "/spec/template/spec/containers/{}/args".format(n_container),
62+
"value": args,
63+
}]
64+
local("kubectl patch deployment {} -n {} --type json -p='{}'".format(name, namespace, str(encode_json(patch)).replace("\n", "")))
65+
66+
# patch the CAPI manager role to also provide access to experimental infrastructure
67+
def patch_capi_manager_role_with_exp_infra_rbac():
68+
api_groups_str = str(local('kubectl get clusterrole capi-manager-role -o jsonpath={.rules[1].apiGroups}'))
69+
exp_infra_group = "exp.infrastructure.cluster.x-k8s.io"
70+
if exp_infra_group not in api_groups_str:
71+
groups = api_groups_str[1:-1].split() # "[arg1 arg2 ...]" trim off the first and last, then split
72+
groups.append(exp_infra_group)
73+
patch = [{
74+
"op": "replace",
75+
"path": "/rules/1/apiGroups",
76+
"value": groups,
77+
}]
78+
local("kubectl patch clusterrole capi-manager-role --type json -p='{}'".format(str(encode_json(patch)).replace("\n", "")))
79+
80+
def load_provider_tiltfiles(provider_repos):
81+
for repo in provider_repos:
82+
file = repo + "/tilt-provider.json"
83+
provider_details = read_json(file, default = {})
84+
if type(provider_details) != type([]):
85+
provider_details = [provider_details]
86+
for item in provider_details:
87+
provider_name = item["name"]
88+
provider_config = item["config"]
89+
if "context" in provider_config:
90+
provider_config["context"] = repo + "/" + provider_config["context"]
91+
else:
92+
provider_config["context"] = repo
93+
if "kustomize_config" not in provider_config:
94+
provider_config["kustomize_config"] = True
95+
if "go_main" not in provider_config:
96+
provider_config["go_main"] = "main.go"
97+
providers[provider_name] = provider_config
98+
99+
tilt_helper_dockerfile_header = """
100+
# Tilt image
101+
FROM golang:1.20 as tilt-helper
102+
# Support live reloading with Tilt
103+
RUN wget --output-document /restart.sh --quiet https://raw.githubusercontent.com/windmilleng/rerun-process-wrapper/master/restart.sh && \
104+
wget --output-document /start.sh --quiet https://raw.githubusercontent.com/windmilleng/rerun-process-wrapper/master/start.sh && \
105+
chmod +x /start.sh && chmod +x /restart.sh
106+
"""
107+
108+
tilt_dockerfile_header = """
109+
FROM gcr.io/distroless/base:debug as tilt
110+
WORKDIR /
111+
COPY --from=tilt-helper /start.sh .
112+
COPY --from=tilt-helper /restart.sh .
113+
COPY manager .
114+
"""
115+
116+
# Configures a provider by doing the following:
117+
#
118+
# 1. Enables a local_resource go build of the provider's manager binary
119+
# 2. Configures a docker build for the provider, with live updating of the manager binary
120+
# 3. Runs kustomize for the provider's config/ and applies it
121+
def enable_provider(name):
122+
p = providers.get(name)
123+
124+
name = p.get("name", name)
125+
context = p.get("context")
126+
go_main = p.get("go_main")
127+
label = p.get("label", name)
128+
129+
# Prefix each live reload dependency with context. For example, for if the context is
130+
# test/infra/docker and main.go is listed as a dep, the result is test/infra/docker/main.go. This adjustment is
131+
# needed so Tilt can watch the correct paths for changes.
132+
live_reload_deps = []
133+
for d in p.get("live_reload_deps", []):
134+
live_reload_deps.append(context + "/" + d)
135+
136+
# Set up a local_resource build of the provider's manager binary. The provider is expected to have a main.go in
137+
# manager_build_path or the main.go must be provided via go_main option. The binary is written to .tiltbuild/manager.
138+
local_resource(
139+
label.lower() + "_binary",
140+
cmd = "cd " + context + ';mkdir -p .tiltbuild;CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags \'-extldflags "-static"\' -o .tiltbuild/manager ' + go_main,
141+
deps = live_reload_deps,
142+
labels = [label, "ALL.binaries"],
143+
)
144+
145+
additional_docker_helper_commands = p.get("additional_docker_helper_commands", "")
146+
additional_docker_build_commands = p.get("additional_docker_build_commands", "")
147+
148+
dockerfile_contents = "\n".join([
149+
tilt_helper_dockerfile_header,
150+
additional_docker_helper_commands,
151+
tilt_dockerfile_header,
152+
additional_docker_build_commands,
153+
])
154+
155+
# Set up an image build for the provider. The live update configuration syncs the output from the local_resource
156+
# build into the container.
157+
entrypoint = ["sh", "/start.sh", "/manager"]
158+
provider_args = extra_args.get(name)
159+
if provider_args:
160+
entrypoint.extend(provider_args)
161+
162+
docker_build(
163+
ref = p.get("image"),
164+
context = context + "/.tiltbuild/",
165+
dockerfile_contents = dockerfile_contents,
166+
target = "tilt",
167+
entrypoint = entrypoint,
168+
only = "manager",
169+
live_update = [
170+
sync(context + "/.tiltbuild/manager", "/manager"),
171+
run("sh /restart.sh"),
172+
],
173+
)
174+
175+
if p.get("kustomize_config"):
176+
# Copy all the substitutions from the user's tilt-settings.json into the environment. Otherwise, the substitutions
177+
# are not available and their placeholders will be replaced with the empty string when we call kustomize +
178+
# envsubst below.
179+
substitutions = settings.get("kustomize_substitutions", {})
180+
os.environ.update(substitutions)
181+
182+
# Apply the kustomized yaml for this provider
183+
184+
yaml = str(kustomize(context + "/config/default"))
185+
k8s_yaml(blob(yaml))
186+
get_controller_name(name)
187+
else:
188+
get_controller_name(name)
189+
190+
# Enable core cluster-api plus everything listed in 'enable_providers' in tilt-settings.json
191+
def enable_providers():
192+
# local("make kustomize")
193+
194+
provider_repos = settings.get("provider_repos", [])
195+
union_provider_repos = [ k for k in provider_repos + ["."] ]
196+
load_provider_tiltfiles(union_provider_repos)
197+
198+
user_enable_providers = settings.get("enable_providers", [])
199+
union_enable_providers = {k: "" for k in user_enable_providers + always_enable_providers}.keys()
200+
for name in union_enable_providers:
201+
enable_provider(name)
202+
203+
def get_controller_name(name):
204+
p = providers.get(name)
205+
name = p.get("name", name)
206+
label = p.get("label", name)
207+
manager_name = p.get("manager_name")
208+
if manager_name:
209+
k8s_resource(
210+
workload = manager_name,
211+
new_name = label.lower() + "_controller",
212+
labels = [label, "ALL.controllers"],
213+
)
214+
215+
def kustomize(folder):
216+
yaml = local('./bin/kustomize build {}'.format(folder), quiet=True)
217+
return yaml
218+
219+
##############################
220+
# Actual work happens here
221+
##############################
222+
223+
load("ext://cert_manager", "deploy_cert_manager")
224+
225+
if settings.get("deploy_cert_manager"):
226+
deploy_cert_manager(version=settings.get("cert_manager_version"))
227+
228+
deploy_capi()
229+
230+
enable_providers()

tilt-provider.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"name": "proxmox",
3+
"config": {
4+
"image": "ghcr.io/sp-yduck/cluster-api-provider-proxmox",
5+
"live_reload_deps": [
6+
"api",
7+
"cloud",
8+
"cmd/main.go",
9+
"config",
10+
"controllers",
11+
"go.mod",
12+
"go.sum"
13+
],
14+
"label": "CAPPX",
15+
"manager_name": "cappx-controller-manager",
16+
"go_main": "cmd/main.go"
17+
}
18+
}

0 commit comments

Comments
 (0)