22Skaffold related tasks
33"""
44
5+ import os
6+
57from invoke import UnexpectedExit , task
68from invoke .exceptions import Exit
79
1113
1214DATADOG_AGENT_MOUNT = "/home/datadog/go/src/github.com/DataDog/datadog-agent"
1315
16+ # Maps a Skaffold artifact name to the invoke task that builds its development image.
17+ SKAFFOLD_BUILD_TASKS = {
18+ "agent" : "agent.hacky-dev-image-build" ,
19+ "clusteragent" : "cluster-agent.hacky-dev-image-build" ,
20+ }
21+
1422
1523@task
1624def minikube_start (ctx , path : str = "." ) -> None :
@@ -50,16 +58,23 @@ def is_minikube_running(ctx) -> bool:
5058 return minikube_status .ok
5159
5260
53- def generate_minikube_env (ctx ) -> list :
61+ def minikube_docker_env (ctx ) -> dict :
5462 """
55- Generate the Minikube environment variables
63+ Return env vars pointing the Docker CLI at Minikube's daemon, for `ctx.run(env=...)`.
5664 """
57- minikube_env = []
58- minikube_env_command = ctx .run ("minikube docker-env" , hide = True )
59- for line in minikube_env_command .stdout .split ("\n " ):
60- if line .startswith ("export" ):
61- minikube_env .append (line .replace ("export " , "" ))
62- return minikube_env
65+ # Shell-agnostic `KEY=value` pairs for easier parsing
66+ result = ctx .run ("minikube docker-env --shell none" , hide = True )
67+ env = {}
68+ for line in result .stdout .splitlines ():
69+ line = line .strip ()
70+ if not line or line .startswith ("#" ):
71+ continue
72+ key , sep , value = line .partition ("=" )
73+ value = value .strip ().strip ('"' )
74+ # Skip empty assignments (e.g. `SSH_AUTH_SOCK=`) so they don't clobber inherited values.
75+ if sep and value :
76+ env [key .strip ()] = value
77+ return env
6378
6479
6580@task
@@ -104,7 +119,7 @@ def devcontainer_start(ctx) -> None:
104119 "sleep infinity" ,
105120 ]
106121
107- ctx .run (" " .join (generate_minikube_env ( ctx ) + docker_command ))
122+ ctx .run (" " .join (docker_command ), env = minikube_docker_env ( ctx ))
108123
109124
110125def is_devcontainer_running (ctx ) -> bool :
@@ -119,21 +134,50 @@ def is_devcontainer_running(ctx) -> bool:
119134 "--format" ,
120135 "{{.Names}}" ,
121136 ]
122- devcontainer_status = ctx .run (" " .join (generate_minikube_env ( ctx ) + command ), hide = True )
137+ devcontainer_status = ctx .run (" " .join (command ), hide = True , env = minikube_docker_env ( ctx ) )
123138 return devcontainer_status .ok and DEVCONTAINER_NAME in devcontainer_status .stdout
124139
125140
141+ def ensure_not_worktree (path : str ) -> None :
142+ """
143+ Exit if `path` is a git worktree.
144+ """
145+ if os .path .isfile (os .path .join (path , ".git" )):
146+ print (
147+ color_message (
148+ f"{ os .path .abspath (path )} is a git worktree, which the Skaffold development flow does not "
149+ "support: only this directory is mounted into the build container, but a worktree's git "
150+ "metadata lives in the main repository outside the mount. Run this from a normal clone instead." ,
151+ Color .RED ,
152+ )
153+ )
154+ raise Exit (code = 1 )
155+
156+
126157@task
127158def create (ctx , path = "." ) -> None :
128159 """
129160 Start the Minikube Cluster and the devcontainer
130161 """
162+ ensure_not_worktree (path )
131163 if not is_minikube_running (ctx ):
132164 minikube_start (ctx , path )
133165 if not is_devcontainer_running (ctx ):
134166 devcontainer_start (ctx )
135167
136168
169+ @task
170+ def destroy (ctx ) -> None :
171+ """
172+ Remove the devcontainer and delete the Minikube cluster, including anything deployed to it.
173+ """
174+ if is_minikube_running (ctx ):
175+ print (color_message ("Removing the devcontainer." , Color .BLUE ))
176+ ctx .run (f"docker rm -f { DEVCONTAINER_NAME } " , warn = True , env = minikube_docker_env (ctx ))
177+ print (color_message ("Deleting the Minikube cluster." , Color .BLUE ))
178+ ctx .run ("minikube delete" )
179+
180+
137181@task
138182def dev (ctx ) -> None :
139183 """
@@ -158,6 +202,14 @@ def dev(ctx) -> None:
158202 # Create Minikube Cluster and devcontainer if they are not running.
159203 create (ctx )
160204
205+ # The deploy installs the `datadog/datadog` remote chart, so ensure its Helm repo is
206+ # registered and its index cache (kept under a temp dir that may not persist) is fresh.
207+ if not is_installed ("helm" ):
208+ print (color_message ("Helm is not installed. Check https://helm.sh/docs/intro/install." , Color .RED ))
209+ raise Exit (code = 1 )
210+ ctx .run ("helm repo add datadog https://helm.datadoghq.com --force-update" , warn = True )
211+ ctx .run ("helm repo update datadog" )
212+
161213 # Create Skaffold Dev command
162214 skaffold_command = [
163215 "skaffold" ,
@@ -170,4 +222,24 @@ def dev(ctx) -> None:
170222 "--status-check=true" ,
171223 "--verbosity warn" ,
172224 ]
173- ctx .run (" " .join (generate_minikube_env (ctx ) + skaffold_command ))
225+ ctx .run (" " .join (skaffold_command ), env = minikube_docker_env (ctx ))
226+
227+
228+ @task
229+ def build (ctx , target = "agent" ) -> None :
230+ """
231+ Build a development image in the running devcontainer, for Skaffold's custom builder.
232+
233+ Assumes that Skaffold has already set the `IMAGE` env var to the target tag.
234+ """
235+ build_task = SKAFFOLD_BUILD_TASKS .get (target )
236+ if build_task is None :
237+ raise Exit (f"Unknown target '{ target } '. Valid targets: { ', ' .join (SKAFFOLD_BUILD_TASKS )} ." , code = 1 )
238+
239+ target_image = os .environ .get ("IMAGE" )
240+ if not target_image :
241+ raise Exit ("The IMAGE environment variable is not set (it is provided by Skaffold)." , code = 1 )
242+
243+ # Run via a login shell to ensure proper environment setup.
244+ inner = f"dda inv -- { build_task } --target-image={ target_image } "
245+ ctx .run (f'docker exec { DEVCONTAINER_NAME } bash -lc "{ inner } "' , env = minikube_docker_env (ctx ))
0 commit comments