Skip to content

Commit 7adbba0

Browse files
authored
feat: add support to module (root module and build submodule) to do a code engine build. Previously this functionality was only available in the DA, but is now available in the modules. If you were using the build feature in the DA and are now upgrading to this version, you will see the expected old build run destroyed, and a new build run created. (#220)
1 parent e0c78d6 commit 7adbba0

File tree

14 files changed

+380
-188
lines changed

14 files changed

+380
-188
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,11 +157,12 @@ No resources.
157157
|------|-------------|------|---------|:--------:|
158158
| <a name="input_apps"></a> [apps](#input\_apps) | A map of code engine apps to be created. | <pre>map(object({<br/> image_reference = string<br/> image_secret = optional(string)<br/> run_env_variables = optional(list(object({<br/> type = optional(string)<br/> name = optional(string)<br/> value = optional(string)<br/> prefix = optional(string)<br/> key = optional(string)<br/> reference = optional(string)<br/> })))<br/> run_volume_mounts = optional(list(object({<br/> mount_path = string<br/> reference = string<br/> name = optional(string)<br/> type = string<br/> })))<br/> image_port = optional(number)<br/> managed_domain_mappings = optional(string)<br/> run_arguments = optional(list(string))<br/> run_as_user = optional(number)<br/> run_commands = optional(list(string))<br/> run_service_account = optional(string)<br/> scale_concurrency = optional(number)<br/> scale_concurrency_target = optional(number)<br/> scale_cpu_limit = optional(string)<br/> scale_ephemeral_storage_limit = optional(string)<br/> scale_initial_instances = optional(number)<br/> scale_max_instances = optional(number)<br/> scale_memory_limit = optional(string)<br/> scale_min_instances = optional(number)<br/> scale_request_timeout = optional(number)<br/> scale_down_delay = optional(number)<br/> }))</pre> | `{}` | no |
159159
| <a name="input_bindings"></a> [bindings](#input\_bindings) | A map of code engine bindings to be created. | <pre>map(object({<br/> secret_name = string<br/> components = list(object({<br/> name = string<br/> resource_type = string<br/> }))<br/> }))</pre> | `{}` | no |
160-
| <a name="input_builds"></a> [builds](#input\_builds) | A map of code engine builds to be created. | <pre>map(object({<br/> output_image = string<br/> output_secret = string # pragma: allowlist secret<br/> source_url = string<br/> strategy_type = string<br/> source_context_dir = optional(string)<br/> source_revision = optional(string)<br/> source_secret = optional(string)<br/> source_type = optional(string)<br/> strategy_size = optional(string)<br/> strategy_spec_file = optional(string)<br/> timeout = optional(number)<br/> }))</pre> | `{}` | no |
160+
| <a name="input_builds"></a> [builds](#input\_builds) | A map of code engine builds to be created. Requires 'ibmcloud\_api\_key' to be set for authentication and execution. | <pre>map(object({<br/> output_image = string<br/> output_secret = string # pragma: allowlist secret<br/> source_url = string<br/> strategy_type = string<br/> source_context_dir = optional(string)<br/> source_revision = optional(string)<br/> source_secret = optional(string)<br/> source_type = optional(string)<br/> strategy_size = optional(string)<br/> strategy_spec_file = optional(string)<br/> timeout = optional(number)<br/> }))</pre> | `{}` | no |
161161
| <a name="input_cbr_rules"></a> [cbr\_rules](#input\_cbr\_rules) | The list of context-based restrictions rules to create. | <pre>list(object({<br/> description = string<br/> account_id = string<br/> rule_contexts = list(object({<br/> attributes = optional(list(object({<br/> name = string<br/> value = string<br/> }))) }))<br/> enforcement_mode = string<br/> operations = optional(list(object({<br/> api_types = list(object({<br/> api_type_id = string<br/> }))<br/> })))<br/> }))</pre> | `[]` | no |
162162
| <a name="input_config_maps"></a> [config\_maps](#input\_config\_maps) | A map of code engine config maps to be created. | <pre>map(object({<br/> data = map(string)<br/> }))</pre> | `{}` | no |
163163
| <a name="input_domain_mappings"></a> [domain\_mappings](#input\_domain\_mappings) | A map of code engine domain mappings to be created. | <pre>map(object({<br/> tls_secret = string # pragma: allowlist secret<br/> components = list(object({<br/> name = string<br/> resource_type = string<br/> }))<br/> }))</pre> | `{}` | no |
164164
| <a name="input_existing_project_id"></a> [existing\_project\_id](#input\_existing\_project\_id) | The ID of the existing project to which code engine resources will be added. It is required if var.project\_name is null. | `string` | `null` | no |
165+
| <a name="input_ibmcloud_api_key"></a> [ibmcloud\_api\_key](#input\_ibmcloud\_api\_key) | The IBM Cloud API key. Required only when 'builds' are specified and used. | `string` | `null` | no |
165166
| <a name="input_jobs"></a> [jobs](#input\_jobs) | A map of code engine jobs to be created. | <pre>map(object({<br/> image_reference = string<br/> image_secret = optional(string)<br/> run_env_variables = optional(list(object({<br/> type = optional(string)<br/> name = optional(string)<br/> value = optional(string)<br/> prefix = optional(string)<br/> key = optional(string)<br/> reference = optional(string)<br/> })))<br/> run_volume_mounts = optional(list(object({<br/> mount_path = string<br/> reference = string<br/> name = optional(string)<br/> type = string<br/> })))<br/> run_arguments = optional(list(string))<br/> run_as_user = optional(number)<br/> run_commands = optional(list(string))<br/> run_mode = optional(string)<br/> run_service_account = optional(string)<br/> scale_array_spec = optional(string)<br/> scale_cpu_limit = optional(string)<br/> scale_ephemeral_storage_limit = optional(string)<br/> scale_max_execution_time = optional(number)<br/> scale_memory_limit = optional(string)<br/> scale_retry_limit = optional(number)<br/> }))</pre> | `{}` | no |
166167
| <a name="input_project_name"></a> [project\_name](#input\_project\_name) | The name of the project to which code engine resources will be added. It is required if var.existing\_project\_id is null. | `string` | `null` | no |
167168
| <a name="input_resource_group_id"></a> [resource\_group\_id](#input\_resource\_group\_id) | ID of the resource group to use when creating resources. | `string` | n/a | yes |

examples/jobs/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ An end-to-end jobs example that will provision the following:
66
- Code Engine Job
77
- Code Engine Generic Secret
88
- Code Engine Build
9+
- Run Code Engine Build

examples/jobs/main.tf

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,23 @@ module "resource_group" {
1010
existing_resource_group_name = var.resource_group
1111
}
1212

13+
locals {
14+
cr_namespace = "private.us.icr.io/${resource.ibm_cr_namespace.my_namespace.name}/${var.prefix}-build"
15+
}
16+
17+
resource "ibm_cr_namespace" "my_namespace" {
18+
name = "${var.prefix}-cr-namespace"
19+
resource_group_id = module.resource_group.resource_group_id
20+
}
21+
1322
########################################################################################################################
1423
# Code Engine instance
1524
########################################################################################################################
1625

1726
module "code_engine" {
1827
source = "../.."
1928
resource_group_id = module.resource_group.resource_group_id
29+
ibmcloud_api_key = var.ibmcloud_api_key
2030
project_name = "${var.prefix}-project"
2131
jobs = {
2232
"${var.prefix}-job" = {
@@ -50,12 +60,20 @@ module "code_engine" {
5060
"${var.prefix}-s" = {
5161
format = "generic"
5262
data = { "key_1" : "value_1", "key_2" : "value_2" }
53-
}
63+
},
64+
"${var.prefix}-rs" = {
65+
format = "registry"
66+
data = {
67+
password = var.ibmcloud_api_key,
68+
username = "iamapikey",
69+
server = "private.us.icr.io"
70+
}
71+
},
5472
}
5573
builds = {
5674
"${var.prefix}-build" = {
57-
output_image = "private.de.icr.io/icr_namespace/image-name"
58-
output_secret = "icr-private" # pragma: allowlist secret
75+
output_image = local.cr_namespace
76+
output_secret = "${var.prefix}-rs" # pragma: allowlist secret
5977
source_url = "https://github.com/IBM/CodeEngine"
6078
strategy_type = "dockerfile"
6179
}

main.tf

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -99,23 +99,24 @@ module "secret" {
9999
# Code Engine Build
100100
##############################################################################
101101
module "build" {
102-
depends_on = [module.secret]
103-
source = "./modules/build"
104-
for_each = var.builds
105-
project_id = local.project_id
106-
name = each.key
107-
output_image = each.value.output_image
108-
output_secret = each.value.output_secret
109-
source_url = each.value.source_url
110-
strategy_type = each.value.strategy_type
111-
source_context_dir = each.value.source_context_dir
112-
source_revision = each.value.source_revision
113-
source_secret = each.value.source_secret
114-
source_type = each.value.source_type
115-
strategy_size = each.value.strategy_size
116-
strategy_spec_file = each.value.strategy_spec_file
117-
timeout = each.value.timeout
118-
102+
depends_on = [module.secret]
103+
source = "./modules/build"
104+
for_each = var.builds
105+
ibmcloud_api_key = var.ibmcloud_api_key
106+
existing_resource_group_id = var.resource_group_id
107+
project_id = local.project_id
108+
name = each.key
109+
output_image = each.value.output_image
110+
output_secret = each.value.output_secret
111+
source_url = each.value.source_url
112+
strategy_type = each.value.strategy_type
113+
source_context_dir = each.value.source_context_dir
114+
source_revision = each.value.source_revision
115+
source_secret = each.value.source_secret
116+
source_type = each.value.source_type
117+
strategy_size = each.value.strategy_size
118+
strategy_spec_file = each.value.strategy_spec_file
119+
timeout = each.value.timeout
119120
}
120121

121122
##############################################################################

modules/build/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,20 @@ No modules.
4747
| Name | Type |
4848
|------|------|
4949
| [ibm_code_engine_build.ce_build](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/code_engine_build) | resource |
50+
| [terraform_data.run_build](https://registry.terraform.io/providers/hashicorp/terraform/latest/docs/resources/data) | resource |
51+
| [ibm_code_engine_project.code_engine_project](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/data-sources/code_engine_project) | data source |
5052

5153
### Inputs
5254

5355
| Name | Description | Type | Default | Required |
5456
|------|-------------|------|---------|:--------:|
57+
| <a name="input_existing_resource_group_id"></a> [existing\_resource\_group\_id](#input\_existing\_resource\_group\_id) | The ID of an existing resource group where build will be provisioned. This must be the same resource group in which the code engine project was created. | `string` | n/a | yes |
58+
| <a name="input_ibmcloud_api_key"></a> [ibmcloud\_api\_key](#input\_ibmcloud\_api\_key) | The IBM Cloud API key. | `string` | n/a | yes |
5559
| <a name="input_name"></a> [name](#input\_name) | The name of the build. | `string` | n/a | yes |
5660
| <a name="input_output_image"></a> [output\_image](#input\_output\_image) | The name of the image. | `string` | n/a | yes |
5761
| <a name="input_output_secret"></a> [output\_secret](#input\_output\_secret) | The secret that is required to access the image registry. | `string` | n/a | yes |
5862
| <a name="input_project_id"></a> [project\_id](#input\_project\_id) | The ID of the project where build will be created. | `string` | n/a | yes |
63+
| <a name="input_region"></a> [region](#input\_region) | The region in which to provision the build. This must be the same region in which the code engine project was created. | `string` | `"us-south"` | no |
5964
| <a name="input_source_context_dir"></a> [source\_context\_dir](#input\_source\_context\_dir) | The directory in the repository that contains the buildpacks file or the Dockerfile. | `string` | `null` | no |
6065
| <a name="input_source_revision"></a> [source\_revision](#input\_source\_revision) | Commit, tag, or branch in the source repository to pull. | `string` | `null` | no |
6166
| <a name="input_source_secret"></a> [source\_secret](#input\_source\_secret) | The name of the secret that is used access the repository source. If the var.source\_type value is `local`, this field must be omitted. | `string` | `null` | no |

modules/build/main.tf

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,23 @@ resource "ibm_code_engine_build" "ce_build" {
1919
strategy_spec_file = var.strategy_spec_file
2020
timeout = var.timeout
2121
}
22+
23+
data "ibm_code_engine_project" "code_engine_project" {
24+
project_id = var.project_id
25+
}
26+
27+
resource "terraform_data" "run_build" {
28+
depends_on = [ibm_code_engine_build.ce_build]
29+
30+
provisioner "local-exec" {
31+
interpreter = ["/bin/bash", "-c"]
32+
command = "${path.module}/scripts/build-run.sh"
33+
environment = {
34+
IBMCLOUD_API_KEY = var.ibmcloud_api_key
35+
RESOURCE_GROUP_ID = var.existing_resource_group_id
36+
CE_PROJECT_NAME = data.ibm_code_engine_project.code_engine_project.name
37+
REGION = var.region
38+
BUILD_NAME = ibm_code_engine_build.ce_build.name
39+
}
40+
}
41+
}

modules/build/scripts/build-run.sh

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
#!/bin/bash
2+
set -e
3+
4+
# Log in to IBM Cloud
5+
function ibmcloud_login() {
6+
printf "\n#### IBM CLOUD LOGIN ####\n\n"
7+
attempts=1
8+
until ibmcloud login -r "${REGION}" -g "${RESOURCE_GROUP_ID}" --quiet || [ $attempts -ge 3 ]; do
9+
attempts=$((attempts + 1))
10+
echo "Error logging in to IBM Cloud CLI..."
11+
sleep 3
12+
done
13+
printf "\nLogin complete\n"
14+
}
15+
16+
# max wait time = 60 × 10s = 10 minutes
17+
MAX_RETRIES=60
18+
RETRY_INTERVAL=10 # seconds
19+
20+
if [[ -z "${IBMCLOUD_API_KEY}" ]]; then
21+
echo "IBMCLOUD_API_KEY is required" >&2
22+
exit 1
23+
fi
24+
25+
if [[ -z "${RESOURCE_GROUP_ID}" ]]; then
26+
echo "RESOURCE_GROUP_ID is required" >&2
27+
exit 1
28+
fi
29+
30+
if [[ -z "${CE_PROJECT_NAME}" ]]; then
31+
echo "CE_PROJECT_NAME is required" >&2
32+
exit 1
33+
fi
34+
35+
if [[ -z "${REGION}" ]]; then
36+
echo "REGION is required" >&2
37+
exit 1
38+
fi
39+
40+
if [[ -z "${BUILD_NAME}" ]]; then
41+
echo "BUILD_NAME is required" >&2
42+
exit 1
43+
fi
44+
45+
# ibm cloud login
46+
ibmcloud_login
47+
48+
# selecet the right code engine project
49+
ibmcloud ce project select -n "${CE_PROJECT_NAME}"
50+
51+
# check the image build status
52+
image_build_status=$(ibmcloud ce build get --name "${BUILD_NAME}" -o json | jq -r '.status')
53+
if [[ "$image_build_status" != "ready" ]]; then
54+
echo "Error: Image build '${BUILD_NAME}' has status: ${image_build_status}"
55+
exit 1
56+
fi
57+
58+
# Ensure the build status is 'succeeded' before continuing.
59+
# This is required because the application deployment depends on a completed build run.
60+
echo "Submitting build: $BUILD_NAME"
61+
run_build_name=$(ibmcloud ce buildrun submit --build "$BUILD_NAME" --output json | jq -r '.name')
62+
63+
echo "Waiting for build run $run_build_name to complete..."
64+
retries=0
65+
66+
while true; do
67+
status=$(ibmcloud ce buildrun get --name "$run_build_name" --output json | jq -r '.status')
68+
echo "Status: '$status'"
69+
if [[ "$status" == "succeeded" ]]; then
70+
echo "Build $BUILD_NAME succeeded"
71+
break
72+
elif [[ "$status" == "Failed" || "$status" == "Error" ]]; then
73+
echo "Error: Build $BUILD_NAME has status '{$status}'"
74+
exit 1
75+
fi
76+
77+
# if max time timeout then finish with error
78+
if [[ $retries -ge $MAX_RETRIES ]]; then
79+
echo "Build $BUILD_NAME did not complete after $MAX_RETRIES retries. Timing out."
80+
exit 1
81+
fi
82+
83+
retries=$((retries + 1))
84+
sleep "$RETRY_INTERVAL"
85+
done

modules/build/variables.tf

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,17 @@
22
# Input Variables
33
########################################################################################################################
44

5+
variable "ibmcloud_api_key" {
6+
type = string
7+
description = "The IBM Cloud API key."
8+
sensitive = true
9+
}
10+
11+
variable "existing_resource_group_id" {
12+
description = "The ID of an existing resource group where build will be provisioned. This must be the same resource group in which the code engine project was created."
13+
type = string
14+
}
15+
516
variable "project_id" {
617
description = "The ID of the project where build will be created."
718
type = string
@@ -22,6 +33,12 @@ variable "output_secret" {
2233
type = string
2334
}
2435

36+
variable "region" {
37+
type = string
38+
description = "The region in which to provision the build. This must be the same region in which the code engine project was created."
39+
default = "us-south"
40+
}
41+
2542
variable "source_context_dir" {
2643
description = "The directory in the repository that contains the buildpacks file or the Dockerfile."
2744
type = string

0 commit comments

Comments
 (0)