@@ -6,6 +6,9 @@ terraform {
6
6
aws = {
7
7
source = " hashicorp/aws"
8
8
}
9
+ cloudinit = {
10
+ source = " hashicorp/cloudinit"
11
+ }
9
12
envbuilder = {
10
13
source = " coder/envbuilder"
11
14
}
@@ -153,13 +156,16 @@ data "aws_iam_instance_profile" "vm_instance_profile" {
153
156
locals {
154
157
# TODO: provide a way to pick the availability zone.
155
158
aws_availability_zone = " ${ module . aws_region . value } a"
156
- linux_user = " coder"
157
- # Name the container after the workspace and owner.
158
- container_name = " coder-${ data . coder_workspace_owner . me . name } -${ lower (data. coder_workspace . me . name )} "
159
+
160
+ hostname = lower (data. coder_workspace . me . name )
161
+ linux_user = " coder"
162
+
159
163
# The devcontainer builder image is the image that will build the devcontainer.
160
164
devcontainer_builder_image = data. coder_parameter . devcontainer_builder . value
165
+
161
166
# We may need to authenticate with a registry. If so, the user will provide a path to a docker config.json.
162
167
docker_config_json_base64 = try (data. local_sensitive_file . cache_repo_dockerconfigjson [0 ]. content_base64 , " " )
168
+
163
169
# The envbuilder provider requires a key-value map of environment variables. Build this here.
164
170
envbuilder_env = {
165
171
# ENVBUILDER_GIT_URL and ENVBUILDER_CACHE_REPO will be overridden by the provider
@@ -172,7 +178,7 @@ locals {
172
178
# The agent init script is required for the agent to start up. We base64 encode it here
173
179
# to avoid quoting issues.
174
180
" ENVBUILDER_INIT_SCRIPT" : " echo ${ base64encode (try (coder_agent. dev [0 ]. init_script , " " ))} | base64 -d | sh" ,
175
- " ENVBUILDER_DOCKER_CONFIG_BASE64" : try (data . local_sensitive_file . cache_repo_dockerconfigjson [ 0 ] . content_base64 , " " ) ,
181
+ " ENVBUILDER_DOCKER_CONFIG_BASE64" : local.docker_config_json_base64 ,
176
182
# The fallback image is the image that will run if the devcontainer fails to build.
177
183
" ENVBUILDER_FALLBACK_IMAGE" : data.coder_parameter.fallback_image.value,
178
184
# The following are used to push the image to the cache repo, if defined.
@@ -181,87 +187,6 @@ locals {
181
187
# You can add other required environment variables here.
182
188
# See: https://github.com/coder/envbuilder/?tab=readme-ov-file#environment-variables
183
189
}
184
- # If we have a cached image, use the cached image's environment variables. Otherwise, just use
185
- # the environment variables we've defined above.
186
- docker_env_input = try (envbuilder_cached_image. cached . 0 . env_map , local. envbuilder_env )
187
- # Convert the above to the list of arguments for the Docker run command.
188
- # The startup script will write this to a file, which the Docker run command will reference.
189
- docker_env_list_base64 = base64encode (join (" \n " , [for k , v in local . docker_env_input : " ${ k } =${ v } " ]))
190
- # Builder image will either be the builder image parameter, or the cached image, if cache is provided.
191
- builder_image = try (envbuilder_cached_image. cached [0 ]. image , data. coder_parameter . devcontainer_builder . value )
192
- # User data to start the workspace.
193
- user_data = <<- EOT
194
- Content-Type: multipart/mixed; boundary="//"
195
- MIME-Version: 1.0
196
-
197
- --//
198
- Content-Type: text/cloud-config; charset="us-ascii"
199
- MIME-Version: 1.0
200
- Content-Transfer-Encoding: 7bit
201
- Content-Disposition: attachment; filename="cloud-config.txt"
202
-
203
- #cloud-config
204
- cloud_final_modules:
205
- - [scripts-user, always]
206
- hostname: ${ lower (data. coder_workspace . me . name )}
207
- users:
208
- - name: ${ local . linux_user }
209
- sudo: ALL=(ALL) NOPASSWD:ALL
210
- shell: /bin/bash
211
- ssh_authorized_keys:
212
- - "${ data . coder_parameter . ssh_pubkey . value } "
213
- # Automatically grow the partition
214
- growpart:
215
- mode: auto
216
- devices: ['/']
217
- ignore_growroot_disabled: false
218
-
219
- --//
220
- Content-Type: text/x-shellscript; charset="us-ascii"
221
- MIME-Version: 1.0
222
- Content-Transfer-Encoding: 7bit
223
- Content-Disposition: attachment; filename="userdata.txt"
224
-
225
- #!/bin/bash
226
- # Install Docker
227
- if ! command -v docker &> /dev/null
228
- then
229
- echo "Docker not found, installing..."
230
- curl -fsSL https://get.docker.com -o get-docker.sh && sh get-docker.sh 2>&1 >/dev/null
231
- usermod -aG docker ${ local . linux_user }
232
- newgrp docker
233
- else
234
- echo "Docker is already installed."
235
- fi
236
-
237
- # Set up Docker credentials
238
- mkdir -p "/home/${ local . linux_user } /.docker"
239
- if [ -n "${ local . docker_config_json_base64 } " ]; then
240
- # Write the Docker config JSON to disk if it is provided.
241
- printf "%s" "${ local . docker_config_json_base64 } " | base64 -d | tee "/home/${ local . linux_user } /.docker/config.json"
242
- else
243
- # Assume that we're going to use the instance IAM role to pull from the cache repo if we need to.
244
- # Set up the ecr credential helper.
245
- apt-get update -y && apt-get install -y amazon-ecr-credential-helper
246
- mkdir -p .docker
247
- printf '{"credsStore": "ecr-login"}' | tee "/home/${ local . linux_user } /.docker/config.json"
248
- fi
249
- chown -R ${ local . linux_user } :${ local . linux_user } "/home/${ local . linux_user } /.docker"
250
-
251
- # Write the container env to disk.
252
- printf "%s" "${ local . docker_env_list_base64 } " | base64 -d | tee "/home/${ local . linux_user } /env.txt"
253
-
254
- # Start envbuilder
255
- sudo -u coder docker run \
256
- --rm \
257
- --net=host \
258
- -h ${ lower (data. coder_workspace . me . name )} \
259
- -v /home/${ local . linux_user } /envbuilder:/workspaces \
260
- -v /var/run/docker.sock:/var/run/docker.sock \
261
- --env-file /home/${ local . linux_user } /env.txt \
262
- ${ local . builder_image }
263
- --//--
264
- EOT
265
190
}
266
191
267
192
# Check for the presence of a prebuilt image in the cache repo
@@ -274,9 +199,47 @@ resource "envbuilder_cached_image" "cached" {
274
199
extra_env = local. envbuilder_env
275
200
}
276
201
202
+ data "cloudinit_config" "user_data" {
203
+ gzip = false
204
+ base64_encode = false
205
+
206
+ boundary = " //"
207
+
208
+ part {
209
+ filename = " cloud-config.yaml"
210
+ content_type = " text/cloud-config"
211
+
212
+ content = templatefile (" ${ path . module } /cloud-init/cloud-config.yaml.tftpl" , {
213
+ hostname = local.hostname
214
+ linux_user = local.linux_user
215
+
216
+ ssh_pubkey = data.coder_parameter.ssh_pubkey.value
217
+ })
218
+ }
219
+
220
+ part {
221
+ filename = " userdata.sh"
222
+ content_type = " text/x-shellscript"
223
+
224
+ content = templatefile (" ${ path . module } /cloud-init/userdata.sh.tftpl" , {
225
+ hostname = local.hostname
226
+ linux_user = local.linux_user
227
+
228
+ # If we have a cached image, use the cached image's environment variables.
229
+ # Otherwise, just use the environment variables we've defined in locals.
230
+ environment = try (envbuilder_cached_image. cached [0 ]. env_map , local. envbuilder_env )
231
+
232
+ # Builder image will either be the builder image parameter, or the cached image, if cache is provided.
233
+ builder_image = try (envbuilder_cached_image. cached [0 ]. image , data. coder_parameter . devcontainer_builder . value )
234
+
235
+ docker_config_json_base64 = local.docker_config_json_base64
236
+ })
237
+ }
238
+ }
239
+
277
240
# This is useful for debugging the startup script. Left here for reference.
278
241
# resource local_file "startup_script" {
279
- # content = local. user_data
242
+ # content = data.cloudinit_config. user_data.rendered
280
243
# filename = "${path.module}/user_data.txt"
281
244
# }
282
245
@@ -289,9 +252,9 @@ resource "aws_instance" "vm" {
289
252
volume_size = data. coder_parameter . root_volume_size_gb . value
290
253
}
291
254
292
- user_data = local . user_data
255
+ user_data = data . cloudinit_config . user_data . rendered
293
256
tags = {
294
- Name = " coder-${ data . coder_workspace_owner . me . name } -${ data . coder_workspace . me . name } "
257
+ Name = " coder-${ data . coder_workspace_owner . me . name } -${ lower ( data. coder_workspace . me . name ) } "
295
258
# Required if you are using our example policy, see template README
296
259
Coder_Provisioned = " true"
297
260
}
0 commit comments