diff --git a/.secrets.baseline b/.secrets.baseline index 0a4efa4a..b7be98b6 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -3,7 +3,7 @@ "files": "go.sum|^.secrets.baseline$", "lines": null }, - "generated_at": "2024-11-22T17:36:38Z", + "generated_at": "2025-01-08T20:11:33Z", "plugins_used": [ { "name": "AWSKeyDetector" @@ -77,12 +77,12 @@ } ], "results": { - "README.md": [ + "solutions/deploy/README.md": [ { - "hashed_secret": "ff9ee043d85595eb255c05dfe32ece02a53efbb2", + "hashed_secret": "2254481e1661d8f017a712b0d1ad9a14fd9460a3", "is_secret": false, "is_verified": false, - "line_number": 74, + "line_number": 138, "type": "Secret Keyword", "verified_result": null } diff --git a/README.md b/README.md index b8d632cb..fe4b64d6 100644 --- a/README.md +++ b/README.md @@ -7,152 +7,16 @@ Update status and "latest release" badges: 2. Update the "latest release" badge to point to the correct module's repo. Replace "terraform-ibm-module-template" in two places. --> [![Incubating (Not yet consumable)](https://img.shields.io/badge/status-Incubating%20(Not%20yet%20consumable)-red)](https://terraform-ibm-modules.github.io/documentation/#/badge-status) -[![latest release](https://img.shields.io/github/v/release/terraform-ibm-modules/terraform-ibm-module-template?logo=GitHub&sort=semver)](https://github.com/terraform-ibm-modules/terraform-ibm-module-template/releases/latest) +[![latest release](https://img.shields.io/github/v/release/terraform-ibm-modules/terraform-ibm-cloudpak-data?logo=GitHub&sort=semver)](https://github.com/terraform-ibm-modules/terraform-ibm-cloudpak-data/releases/latest) [![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit) [![Renovate enabled](https://img.shields.io/badge/renovate-enabled-brightgreen.svg)](https://renovatebot.com/) [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) - - -TODO: Replace this with a description of the modules in this repo. - - - - -## Overview -* [terraform-ibm-module-template](#terraform-ibm-module-template) -* [Examples](./examples) - * [Advanced example](./examples/advanced) - * [Basic example](./examples/basic) -* [Contributing](#contributing) - - - - - - - - -## terraform-ibm-module-template - -### Usage - - - -```hcl -terraform { - required_version = ">= 1.9.0" - required_providers { - ibm = { - source = "IBM-Cloud/ibm" - version = "X.Y.Z" # Lock into a provider version that satisfies the module constraints - } - } -} - -locals { - region = "us-south" -} - -provider "ibm" { - ibmcloud_api_key = "XXXXXXXXXX" # replace with apikey value - region = local.region -} - -module "module_template" { - source = "terraform-ibm-modules//ibm" - version = "X.Y.Z" # Replace "X.Y.Z" with a release version to lock into a specific release - region = local.region - name = "instance-name" - resource_group_id = "xxXXxxXXxXxXXXXxxXxxxXXXXxXXXXX" # Replace with the actual ID of resource group to use -} -``` - -### Required access policies - - - - - - - - - - - - -### Requirements - -| Name | Version | -|------|---------| -| [terraform](#requirement\_terraform) | >= 1.9.0 | -| [ibm](#requirement\_ibm) | >= 1.71.2, < 2.0.0 | - -### Modules - -No modules. - -### Resources - -| Name | Type | -|------|------| -| [ibm_resource_instance.cos_instance](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/resource_instance) | resource | - -### Inputs - -| Name | Description | Type | Default | Required | -|------|-------------|------|---------|:--------:| -| [name](#input\_name) | A descriptive name used to identify the resource instance. | `string` | n/a | yes | -| [plan](#input\_plan) | The name of the plan type supported by service. | `string` | `"standard"` | no | -| [resource\_group\_id](#input\_resource\_group\_id) | The ID of the resource group where you want to create the service. | `string` | n/a | yes | -| [resource\_tags](#input\_resource\_tags) | List of resource tag to associate with the instance. | `list(string)` | `[]` | no | -### Outputs +This repository contains the following deployment an Red Hat OpenShift cluster: +- [IBM Cloud Cloud Pak for Data](./solutions/deploy) -| Name | Description | -|------|-------------| -| [account\_id](#output\_account\_id) | An alpha-numeric value identifying the account ID. | -| [crn](#output\_crn) | The CRN of the resource instance. | -| [guid](#output\_guid) | The GUID of the resource instance. | -| [id](#output\_id) | The unique identifier of the resource instance. | - +**NB:** These solutions are not intended to be called by one or more other modules since they contain a provider configurations, meaning they are not compatible with the `for_each`, `count`, and `depends_on` arguments. For more information see [Providers Within Modules](https://developer.hashicorp.com/terraform/language/modules/develop/providers) ## Contributing diff --git a/cra-config.yaml b/cra-config.yaml index 9a4c7faa..5eda8e30 100644 --- a/cra-config.yaml +++ b/cra-config.yaml @@ -7,11 +7,11 @@ version: "v1" CRA_TARGETS: - - CRA_TARGET: "examples/advanced" # Target directory for CRA scan. If not provided, the CRA Scan will not be run. + - CRA_TARGET: "examples/basic" # Target directory for CRA scan. If not provided, the CRA Scan will not be run. CRA_IGNORE_RULES_FILE: "cra-tf-validate-ignore-rules.json" PROFILE_ID: "fe96bd4d-9b37-40f2-b39f-a62760e326a3" # SCC profile ID (currently set to 'IBM Cloud Framework for Financial Services' '1.7.0' profile). # SCC_INSTANCE_ID: "" # The SCC instance ID to use to download profile for CRA scan. If not provided, a default global value will be used. # SCC_REGION: "" # The IBM Cloud region that the SCC instance is in. If not provided, a default global value will be used. - CRA_ENVIRONMENT_VARIABLES: # An optional map of environment variables for CRA, where the key is the variable name and value is the value. Useful for providing TF_VARs. - TF_VAR_prefix: "mock" - TF_VAR_region: "us-south" + CRA_ENVIRONMENT_VARIABLES: # An optional map of environment variables for CRA, where the key is the variable name and value is the value. Useful for providing TF_VARs. + TF_VAR_prefix: "roks-cpd" + TF_VAR_region: "au-syd" diff --git a/examples/advanced/README.md b/examples/advanced/README.md deleted file mode 100644 index d52511a3..00000000 --- a/examples/advanced/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Advanced example - - - diff --git a/examples/advanced/main.tf b/examples/advanced/main.tf deleted file mode 100644 index 29e41045..00000000 --- a/examples/advanced/main.tf +++ /dev/null @@ -1,32 +0,0 @@ -######################################################################################################################## -# Resource group -######################################################################################################################## - -module "resource_group" { - source = "terraform-ibm-modules/resource-group/ibm" - version = "1.1.6" - # if an existing resource group is not set (null) create a new one using prefix - resource_group_name = var.resource_group == null ? "${var.prefix}-resource-group" : null - existing_resource_group_name = var.resource_group -} - -######################################################################################################################## -# COS -######################################################################################################################## - -# -# Developer tips: -# - Call the local module / modules in the example to show how they can be consumed -# - Include the actual module source as a code comment like below so consumers know how to consume from correct location -# - -module "cos" { - source = "../.." - # remove the above line and uncomment the below 2 lines to consume the module from the registry - # source = "terraform-ibm-modules//ibm" - # version = "X.Y.Z" # Replace "X.Y.Z" with a release version to lock into a specific release - name = "${var.prefix}-cos" - resource_group_id = module.resource_group.resource_group_id - resource_tags = var.resource_tags - plan = "cos-one-rate-plan" -} diff --git a/examples/advanced/outputs.tf b/examples/advanced/outputs.tf deleted file mode 100644 index 316751fb..00000000 --- a/examples/advanced/outputs.tf +++ /dev/null @@ -1,38 +0,0 @@ -############################################################################## -# Outputs -############################################################################## - -# -# Developer tips: -# - Include all relevant outputs from the modules being called in the example -# - -output "account_id" { - description = "An alpha-numeric value identifying the account ID." - value = module.cos.account_id -} - -output "guid" { - description = "The GUID of the resource instance." - value = module.cos.account_id -} - -output "id" { - description = "The unique identifier of the resource instance." - value = module.cos.id -} - -output "crn" { - description = "The CRN of the resource instance." - value = module.cos.crn -} - -output "resource_group_name" { - description = "Resource group name." - value = module.resource_group.resource_group_name -} - -output "resource_group_id" { - description = "Resource group ID." - value = module.resource_group.resource_group_id -} diff --git a/examples/advanced/provider.tf b/examples/advanced/provider.tf deleted file mode 100644 index 2080946b..00000000 --- a/examples/advanced/provider.tf +++ /dev/null @@ -1,8 +0,0 @@ -############################################################################## -# Provider config -############################################################################## - -provider "ibm" { - ibmcloud_api_key = var.ibmcloud_api_key - region = var.region -} diff --git a/examples/advanced/variables.tf b/examples/advanced/variables.tf deleted file mode 100644 index d4603642..00000000 --- a/examples/advanced/variables.tf +++ /dev/null @@ -1,39 +0,0 @@ -######################################################################################################################## -# Input variables -######################################################################################################################## - -# -# Module developer tips: -# - Examples are references that consumers can use to see how the module can be consumed. They are not designed to be -# flexible re-usable solutions for general consumption, so do not expose any more variables here and instead hard -# code things in the example main.tf with code comments explaining the different configurations. -# - For the same reason as above, do not add default values to the example inputs. -# - -variable "ibmcloud_api_key" { - type = string - description = "The IBM Cloud API Key." - sensitive = true -} - -variable "region" { - type = string - description = "Region to provision all resources created by this example." -} - -variable "prefix" { - type = string - description = "A string value to prefix to all resources created by this example." -} - -variable "resource_group" { - type = string - description = "The name of an existing resource group to provision resources in to. If not set a new resource group will be created using the prefix variable." - default = null -} - -variable "resource_tags" { - type = list(string) - description = "List of resource tag to associate with all resource instances created by this example." - default = [] -} diff --git a/examples/advanced/version.tf b/examples/advanced/version.tf deleted file mode 100644 index ecfa9780..00000000 --- a/examples/advanced/version.tf +++ /dev/null @@ -1,16 +0,0 @@ -terraform { - required_version = ">= 1.9.0" - - # - # Developer tips: - # - Ensure that there is always 1 example locked into the lowest provider version of the range defined in the main - # module's version.tf (usually a basic example), and 1 example that will always use the latest provider version. - # - - required_providers { - ibm = { - source = "IBM-Cloud/ibm" - version = ">= 1.71.2, < 2.0.0" - } - } -} diff --git a/examples/basic/README.md b/examples/basic/README.md deleted file mode 100644 index e5977ae2..00000000 --- a/examples/basic/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Basic example - - - -An end-to-end basic example that will provision the following: -- A new resource group if one is not passed in. -- A new standard plan Cloud Object Storage instance using the root level module. diff --git a/examples/basic/main.tf b/examples/basic/main.tf index 410054ad..3c6eb12e 100644 --- a/examples/basic/main.tf +++ b/examples/basic/main.tf @@ -1,31 +1,27 @@ -######################################################################################################################## -# Resource group -######################################################################################################################## +############################################################################## +# ROKS Landing zone +############################################################################## -module "resource_group" { - source = "terraform-ibm-modules/resource-group/ibm" - version = "1.1.6" - # if an existing resource group is not set (null) create a new one using prefix - resource_group_name = var.resource_group == null ? "${var.prefix}-resource-group" : null - existing_resource_group_name = var.resource_group +module "roks_landing_zone" { + source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-landing-zone.git//patterns/roks-quickstart?ref=v6.6.1" + ibmcloud_api_key = var.ibmcloud_api_key + prefix = var.prefix + region = var.region + resource_tags = var.resource_tags } -######################################################################################################################## -# COS -######################################################################################################################## - -# -# Developer tips: -# - Call the local module / modules in the example to show how they can be consumed -# - include the actual module source as a code comment like below so consumers know how to consume from correct location -# - -module "cos" { - source = "../.." - # remove the above line and uncomment the below 2 lines to consume the module from the registry - # source = "terraform-ibm-modules//ibm" - # version = "X.Y.Z" # Replace "X.Y.Z" with a release version to lock into a specific release - name = "${var.prefix}-cos" - resource_group_id = module.resource_group.resource_group_id - resource_tags = var.resource_tags +############################################################################## +# Deploy cloudpak_data +############################################################################## +module "cloudpak_data" { + source = "../../solutions/deploy" + ibmcloud_api_key = var.ibmcloud_api_key + prefix = var.prefix + region = var.region + cluster_name = module.roks_landing_zone.workload_cluster_id + cloud_pak_deployer_image = "quay.io/cloud-pak-deployer/cloud-pak-deployer" + cpd_admin_password = "Passw0rd" #pragma: allowlist secret + cpd_entitlement_key = "entitlementKey" + install_odf_cluster_addon = var.install_odf_cluster_addon + wait_for_cpd_job_completion = false } diff --git a/examples/basic/outputs.tf b/examples/basic/outputs.tf index 552db482..e69de29b 100644 --- a/examples/basic/outputs.tf +++ b/examples/basic/outputs.tf @@ -1,38 +0,0 @@ -######################################################################################################################## -# Outputs -######################################################################################################################## - -# -# Developer tips: -# - Include all relevant outputs from the modules being called in the example -# - -output "account_id" { - description = "An alpha-numeric value identifying the account ID." - value = module.cos.account_id -} - -output "guid" { - description = "The GUID of the resource instance." - value = module.cos.account_id -} - -output "id" { - description = "The unique identifier of the resource instance." - value = module.cos.id -} - -output "crn" { - description = "The CRN of the resource instance." - value = module.cos.crn -} - -output "resource_group_name" { - description = "Resource group name." - value = module.resource_group.resource_group_name -} - -output "resource_group_id" { - description = "Resource group ID." - value = module.resource_group.resource_group_id -} diff --git a/examples/basic/provider.tf b/examples/basic/provider.tf deleted file mode 100644 index 84b69850..00000000 --- a/examples/basic/provider.tf +++ /dev/null @@ -1,8 +0,0 @@ -######################################################################################################################## -# Provider config -######################################################################################################################## - -provider "ibm" { - ibmcloud_api_key = var.ibmcloud_api_key - region = var.region -} diff --git a/examples/basic/providers.tf b/examples/basic/providers.tf new file mode 100644 index 00000000..df45ef50 --- /dev/null +++ b/examples/basic/providers.tf @@ -0,0 +1,4 @@ +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key + region = var.region +} diff --git a/examples/basic/variables.tf b/examples/basic/variables.tf index d4603642..6271210d 100644 --- a/examples/basic/variables.tf +++ b/examples/basic/variables.tf @@ -1,35 +1,28 @@ -######################################################################################################################## -# Input variables -######################################################################################################################## - -# -# Module developer tips: -# - Examples are references that consumers can use to see how the module can be consumed. They are not designed to be -# flexible re-usable solutions for general consumption, so do not expose any more variables here and instead hard -# code things in the example main.tf with code comments explaining the different configurations. -# - For the same reason as above, do not add default values to the example inputs. -# +############################################################################## +# Account Variables +############################################################################## variable "ibmcloud_api_key" { + description = "The IBM Cloud platform API key needed to deploy IAM enabled resources." type = string - description = "The IBM Cloud API Key." sensitive = true } -variable "region" { - type = string - description = "Region to provision all resources created by this example." -} - variable "prefix" { + description = "A unique identifier for resources that is prepended to resources that are provisioned. Must begin with a lowercase letter and end with a lowercase letter or number. Must be 13 or fewer characters." type = string - description = "A string value to prefix to all resources created by this example." + default = "lz-roks-cp4d" + + validation { + error_message = "Prefix must begin with a letter and contain only lowercase letters, numbers, and - characters. Prefixes must end with a lowercase letter or number and be 13 or fewer characters." + condition = can(regex("^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$", var.prefix)) && length(var.prefix) <= 13 + } } -variable "resource_group" { +variable "region" { + description = "Region where VPC will be created. To find your VPC region, use `ibmcloud is regions` command to find available regions." type = string - description = "The name of an existing resource group to provision resources in to. If not set a new resource group will be created using the prefix variable." - default = null + default = "au-syd" } variable "resource_tags" { @@ -37,3 +30,9 @@ variable "resource_tags" { description = "List of resource tag to associate with all resource instances created by this example." default = [] } + +variable "install_odf_cluster_addon" { + description = "Install the odf cluster addon" + type = bool + default = false +} diff --git a/examples/basic/version.tf b/examples/basic/version.tf deleted file mode 100644 index 401504c5..00000000 --- a/examples/basic/version.tf +++ /dev/null @@ -1,16 +0,0 @@ -terraform { - required_version = ">= 1.9.0" - - # - # Developer tips: - # - Ensure that there is always 1 example locked into the lowest provider version of the range defined in the main - # module's version.tf (usually a basic example), and 1 example that will always use the latest provider version. - # - - required_providers { - ibm = { - source = "IBM-Cloud/ibm" - version = "1.71.2" - } - } -} diff --git a/examples/basic/versions.tf b/examples/basic/versions.tf new file mode 100644 index 00000000..4c869c16 --- /dev/null +++ b/examples/basic/versions.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 1.3" + required_providers { + # renovate is set up to keep provider version at the latest for all DA solutions + ibm = { + source = "IBM-Cloud/ibm" + version = "1.71.3" + } + } +} diff --git a/main.tf b/main.tf deleted file mode 100644 index b6b879e2..00000000 --- a/main.tf +++ /dev/null @@ -1,13 +0,0 @@ -# -# Developer tips: -# - Below code should be replaced with the code for the root level module -# - -resource "ibm_resource_instance" "cos_instance" { - name = var.name - resource_group_id = var.resource_group_id - service = "cloud-object-storage" - plan = var.plan - location = "global" - tags = var.resource_tags -} diff --git a/outputs.tf b/outputs.tf deleted file mode 100644 index 1c0cf4cc..00000000 --- a/outputs.tf +++ /dev/null @@ -1,30 +0,0 @@ -######################################################################################################################## -# Outputs -######################################################################################################################## - -# -# Developer tips: -# - Below are some good practise sample outputs -# - They should be updated for outputs applicable to the module being added -# - Use variable validation when possible -# - -output "account_id" { - description = "An alpha-numeric value identifying the account ID." - value = ibm_resource_instance.cos_instance.account_id -} - -output "guid" { - description = "The GUID of the resource instance." - value = ibm_resource_instance.cos_instance.account_id -} - -output "id" { - description = "The unique identifier of the resource instance." - value = ibm_resource_instance.cos_instance.id -} - -output "crn" { - description = "The CRN of the resource instance." - value = ibm_resource_instance.cos_instance.crn -} diff --git a/solutions/deploy/README.md b/solutions/deploy/README.md new file mode 100644 index 00000000..3760a3bf --- /dev/null +++ b/solutions/deploy/README.md @@ -0,0 +1,174 @@ + +# IBM Cloud Pak for Data module + + +[![Incubating (Not yet consumable)](https://img.shields.io/badge/status-Incubating%20(Not%20yet%20consumable)-red)](https://terraform-ibm-modules.github.io/documentation/#/badge-status) +[![latest release](https://img.shields.io/github/v/release/terraform-ibm-modules/terraform-ibm-cloudpak-data?logo=GitHub&sort=semver)](https://github.com/terraform-ibm-modules/terraform-ibm-cloudpak-data/releases/latest) +[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit) +[![Renovate enabled](https://img.shields.io/badge/renovate-enabled-brightgreen.svg)](https://renovatebot.com/) +[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) + + + +Install IBM Cloud Pak for Data and its services onto an existing Red Hat OpenShift cluster. The following services are currently supported: +- watsonx.ai +- Watson Assistant +- Watson Discovery + + + +## Overview +* [terraform-ibm-cloudpak-data](#terraform-ibm-cloudpak-data) +* [Contributing](#contributing) + + + + + + + + +## terraform-ibm-cloudpak-data + +### Usage + + + +```hcl +module "cloudpak_data" { + source = "../../solutions/deploy" + ibmcloud_api_key = var.ibmcloud_api_key #pragma: allowlist secret + prefix = var.prefix + region = var.region + cluster_name = + cpd_admin_password = + cpd_entitlement_key = +} +``` + +### Required access policies + + + +You need the following permissions to run this module: + +- Service + - **Resource group only** + - `Viewer` access on the specific resource group + - **Kubernetes** service + - `Viewer` platform access + - `Manager` service access + - **Code Engine service + - `Administrator` platform access + - `Manager` service access + - **Container Registry service + - `Administrator` platform access + - `Manager` service access + + + + +### Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.2.0 | +| [external](#requirement\_external) | >= 2.3.4 | +| [ibm](#requirement\_ibm) | >= 1.66.0, < 2.0.0 | +| [kubernetes](#requirement\_kubernetes) | 2.35.1 | +| [null](#requirement\_null) | 3.2.2 | +| [restapi](#requirement\_restapi) | 1.18.2 | + +### Modules + +| Name | Source | Version | +|------|--------|---------| +| [build\_cpd\_image](#module\_build\_cpd\_image) | ./cpd-image-build | n/a | +| [cloud\_pak\_deployer](#module\_cloud\_pak\_deployer) | ./cloud-pak-deployer | n/a | +| [config](#module\_config) | ./cloud-pak-deployer/config | n/a | +| [watsonx\_ai](#module\_watsonx\_ai) | ./watsonx-ai | n/a | +| [watsonx\_data](#module\_watsonx\_data) | ./watsonx-data | n/a | + +### Resources + +| Name | Type | +|------|------| +| [ibm_container_addons.odf_cluster_addon](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/container_addons) | resource | +| [null_resource.oc_login](https://registry.terraform.io/providers/hashicorp/null/3.2.2/docs/resources/resource) | resource | +| [external_external.schematics](https://registry.terraform.io/providers/hashicorp/external/latest/docs/data-sources/external) | data source | +| [ibm_container_cluster_config.cluster_config](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/container_cluster_config) | data source | +| [ibm_container_vpc_cluster.cluster_info](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/container_vpc_cluster) | data source | +| [ibm_iam_auth_token.tokendata](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/iam_auth_token) | data source | + +### Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [cloud\_pak\_deployer\_image](#input\_cloud\_pak\_deployer\_image) | Cloud Pak Deployer image location. If not defined, it will build the image via code engine | `string` | `null` | no | +| [cloud\_pak\_deployer\_release](#input\_cloud\_pak\_deployer\_release) | Release of Cloud Pak Deployer version to use. View releases at: https://github.com/IBM/cloud-pak-deployer/releases. | `string` | `"v3.1.2"` | no | +| [cloud\_pak\_deployer\_secret](#input\_cloud\_pak\_deployer\_secret) | Image pull secret for the cloud pak deployer image |
object({
username = string
password = string
server = string
email = optional(string)
})
| `null` | no | +| [cluster\_name](#input\_cluster\_name) | Name of Red Hat OpenShift cluster to install watsonx onto | `string` | n/a | yes | +| [code\_engine\_project\_id](#input\_code\_engine\_project\_id) | If you want to use an existing project, you can pass the code engine project id and the cloud pak deployer build will be built within the existing project vs a new one being created. | `string` | `null` | no | +| [code\_engine\_project\_name](#input\_code\_engine\_project\_name) | If the variable cloud\_pak\_deployer\_image is null, it will build the image with code engine and store it within a private icr registry. Provide a name if you want to set the name. If not defined, default will be {prefix}-cpd-{random-suffix} | `string` | `null` | no | +| [cpd\_accept\_license](#input\_cpd\_accept\_license) | When set to 'true', it is understood that the user has read the terms of the Cloud Pak license(s) and agrees to the terms outlined | `bool` | `false` | no | +| [cpd\_admin\_password](#input\_cpd\_admin\_password) | Password to be used by the admin user to access the Cloud Pak for Data UI. | `string` | n/a | yes | +| [cpd\_entitlement\_key](#input\_cpd\_entitlement\_key) | Cloud Pak for Data entitlement key for access to the IBM Entitled Registry. Can be fetched from https://myibm.ibm.com/products-services/containerlibrary. | `string` | n/a | yes | +| [cpd\_version](#input\_cpd\_version) | Cloud Pak for Data version to install. Only version 5.x.x is supported | `string` | `"5.0.3"` | no | +| [ibmcloud\_api\_key](#input\_ibmcloud\_api\_key) | APIkey that's associated with the account to use | `string` | n/a | yes | +| [install\_odf\_cluster\_addon](#input\_install\_odf\_cluster\_addon) | Install the odf cluster addon | `bool` | `true` | no | +| [odf\_config](#input\_odf\_config) | Version of ODF to install | `map(string)` |
{
"addSingleReplicaPool": "false",
"billingType": "essentials",
"clusterEncryption": "false",
"disableNoobaaLB": "false",
"enableNFS": "false",
"encryptionInTransit": "false",
"hpcsBaseUrl": "",
"hpcsEncryption": "false",
"hpcsInstanceId": "",
"hpcsSecretName": "",
"hpcsServiceName": "",
"hpcsTokenUrl": "",
"ignoreNoobaa": "true",
"numOfOsd": "1",
"ocsUpgrade": "false",
"odfDeploy": "true",
"osdDevicePaths": "",
"osdSize": "512Gi",
"osdStorageClassName": "ibmc-vpc-block-metro-10iops-tier",
"prepareForDisasterRecovery": "false",
"resourceProfile": "balanced",
"taintNodes": "false",
"useCephRBDAsDefaultStorageClass": "false",
"workerNodes": "all",
"workerPool": ""
}
| no | +| [odf\_version](#input\_odf\_version) | Version of ODF to install | `string` | `"4.16.0"` | no | +| [prefix](#input\_prefix) | A unique identifier for resources that is prepended to resources that are provisioned. Must begin with a lowercase letter and end with a lowercase letter or number. Must be 16 or fewer characters. | `string` | n/a | yes | +| [region](#input\_region) | Region where resources wills be created. To find your VPC region, use `ibmcloud is regions` command to find available regions. | `string` | n/a | yes | +| [resource\_group](#input\_resource\_group) | Resource group to provision services within. If not defined, a resource group called {prefix}-cpd will be created | `string` | `null` | no | +| [resource\_group\_exists](#input\_resource\_group\_exists) | Resource group exists or not within the account. | `bool` | `false` | no | +| [wait\_for\_cpd\_job\_completion](#input\_wait\_for\_cpd\_job\_completion) | Wait for the cloud-pak-deployer to complete before continuing | `bool` | `true` | no | +| [watson\_assistant\_install](#input\_watson\_assistant\_install) | If watsonx.ai is being installed, also install watson assistant | `bool` | `false` | no | +| [watson\_discovery\_install](#input\_watson\_discovery\_install) | If watsonx.ai is being installed, also install watson discovery | `bool` | `false` | no | +| [watsonx\_ai\_install](#input\_watsonx\_ai\_install) | Determine whether the watsonx.ai cartridge for the deployer will be installed | `bool` | `false` | no | +| [watsonx\_ai\_models](#input\_watsonx\_ai\_models) | List of watsonx.ai models to install. Information on the foundation models including pre-reqs can be found here - https://www.ibm.com/docs/en/cloud-paks/cp-data/5.0.x?topic=install-foundation-models. Use the ModelID as input | `list(string)` |
[
"ibm-granite-13b-instruct-v2"
]
| no | +| [watsonx\_data\_install](#input\_watsonx\_data\_install) | Determine whether the watsonx.data cartridge for the deployer will be installed | `bool` | `false` | no | + +### Outputs + +| Name | Description | +|------|-------------| +| [cloud\_pak\_deployer\_config\_path](#output\_cloud\_pak\_deployer\_config\_path) | Path to the required config for the Cloud Pak Deployer | +| [kube\_config\_path](#output\_kube\_config\_path) | Path to the kube config file being used | + + + +## Contributing + +You can report issues and request features for this module in GitHub issues in the module repo. See [Report an issue or request a feature](https://github.com/terraform-ibm-modules/.github/blob/main/.github/SUPPORT.md). + +To set up your local development environment, see [Local development setup](https://terraform-ibm-modules.github.io/documentation/#/local-dev-setup) in the project documentation. diff --git a/solutions/deploy/cloud-pak-deployer/.secrets.baseline b/solutions/deploy/cloud-pak-deployer/.secrets.baseline new file mode 100644 index 00000000..d9d7acb7 --- /dev/null +++ b/solutions/deploy/cloud-pak-deployer/.secrets.baseline @@ -0,0 +1,85 @@ +{ + "exclude": { + "files": "^.secrets.baseline$", + "lines": null + }, + "generated_at": "2024-12-20T20:40:41Z", + "plugins_used": [ + { + "name": "AWSKeyDetector" + }, + { + "name": "ArtifactoryDetector" + }, + { + "name": "AzureStorageKeyDetector" + }, + { + "base64_limit": 4.5, + "name": "Base64HighEntropyString" + }, + { + "name": "BasicAuthDetector" + }, + { + "name": "BoxDetector" + }, + { + "name": "CloudantDetector" + }, + { + "ghe_instance": "github.ibm.com", + "name": "GheDetector" + }, + { + "name": "GitHubTokenDetector" + }, + { + "hex_limit": 3, + "name": "HexHighEntropyString" + }, + { + "name": "IbmCloudIamDetector" + }, + { + "name": "IbmCosHmacDetector" + }, + { + "name": "JwtTokenDetector" + }, + { + "keyword_exclude": null, + "name": "KeywordDetector" + }, + { + "name": "MailchimpDetector" + }, + { + "name": "NpmDetector" + }, + { + "name": "PrivateKeyDetector" + }, + { + "name": "SlackDetector" + }, + { + "name": "SoftlayerDetector" + }, + { + "name": "SquareOAuthDetector" + }, + { + "name": "StripeDetector" + }, + { + "name": "TwilioKeyDetector" + } + ], + "results": {}, + "version": "0.13.1+ibm.62.dss", + "word_list": { + "file": null, + "hash": null + } +} diff --git a/solutions/deploy/cloud-pak-deployer/config/main.tf b/solutions/deploy/cloud-pak-deployer/config/main.tf new file mode 100644 index 00000000..03bed865 --- /dev/null +++ b/solutions/deploy/cloud-pak-deployer/config/main.tf @@ -0,0 +1,51 @@ +locals { + cloud_pak_deployer_config_base = { + "global_config" = { + cloud_platform = "existing-ocp" + confirm_destroy = "True" + # env_id = var.cluster_name + environment_name = "cpdenv" + } + "openshift" = [ + { + cluster_name = var.cluster_name + domain_name = var.cluster_name + name = var.cluster_name + ocp_version = var.openshift_version + openshift_storage = [ + { + storage_name = "auto-storage" + storage_type = "auto" + } + ], + gpu = { + install = "False" + }, + openshift_ai = { + install = "False", + channel = "fast" + } + } + ] + "cp4d" = [ + { + cp4d_version = var.cpd_version + openshift_cluster_name = var.cluster_name + project = "cpd" + sequential_install = "True" + cartridges = [ + { + name = "cp-foundation" + license_service = { + state = "disabled" + threads_per_core = 2 + } + }, + { + name = "lite" + } + ] + } + ] + } +} diff --git a/solutions/deploy/cloud-pak-deployer/config/outputs.tf b/solutions/deploy/cloud-pak-deployer/config/outputs.tf new file mode 100644 index 00000000..e946c24f --- /dev/null +++ b/solutions/deploy/cloud-pak-deployer/config/outputs.tf @@ -0,0 +1,4 @@ +output "cloud_pak_deployer_config_base" { + description = "Base Cloud Pak Deployer configuration object definition, with all required properties" + value = local.cloud_pak_deployer_config_base +} diff --git a/solutions/deploy/cloud-pak-deployer/config/variables.tf b/solutions/deploy/cloud-pak-deployer/config/variables.tf new file mode 100644 index 00000000..32ef728a --- /dev/null +++ b/solutions/deploy/cloud-pak-deployer/config/variables.tf @@ -0,0 +1,16 @@ +variable "cluster_name" { + description = "Name of Red Hat OpenShift cluster to install watsonx onto" + type = string +} + +variable "cpd_version" { + default = "5.0.2" + description = "Cloud Pak for Data version to install" + type = string +} + +variable "openshift_version" { + default = "4.16" + description = "OpenShift version" + type = string +} diff --git a/solutions/deploy/cloud-pak-deployer/config/versions.tf b/solutions/deploy/cloud-pak-deployer/config/versions.tf new file mode 100644 index 00000000..aa1de10f --- /dev/null +++ b/solutions/deploy/cloud-pak-deployer/config/versions.tf @@ -0,0 +1,5 @@ +terraform { + required_version = ">= 1.2.0" + required_providers { + } +} diff --git a/solutions/deploy/cloud-pak-deployer/definitions/.gitkeep b/solutions/deploy/cloud-pak-deployer/definitions/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/solutions/deploy/cloud-pak-deployer/main.tf b/solutions/deploy/cloud-pak-deployer/main.tf new file mode 100644 index 00000000..cec87fc4 --- /dev/null +++ b/solutions/deploy/cloud-pak-deployer/main.tf @@ -0,0 +1,307 @@ +locals { + cloud_pak_deployer = { + cluster_role_binding_name = "cloud-pak-deployer-sa-rbac" + cluster_role_name = "cluster-admin" + config_map_name = "cloud-pak-deployer-config" + config_path = "${var.schematics_workspace.persistent_dir_exists ? "${var.schematics_workspace.persistent_dir_path}/" : ""}${path.module}/config/config.yaml" + image = var.cloud_pak_deployer_image + job_label = "cloud-pak-deployer" + job_name = "cloud-pak-deployer" + namespace_name = "cloud-pak-deployer" + persistent_volume_claim_name = "cloud-pak-deployer-status" + script_accept_license_flag = var.cpd_accept_license ? "--accept-all-licenses" : "" + security_context_constraint_name = "privileged" + service_account_name = "cloud-pak-deployer-sa" + } + cpd = { + entitlement_key_secret_key_name = "cp-entitlement-key" # data key inside secret # checkov:skip=CKV_SECRET_6:Base64 High Entropy String + entitlement_key_secret_name = "cloud-pak-entitlement-key" # kubernetes resource name + } + oc = "oc --kubeconfig ${var.kube_config_path}" + paths = { + definitions = "${var.schematics_workspace.persistent_dir_exists ? "${var.schematics_workspace.persistent_dir_path}/" : ""}${path.module}/definitions" + templates = "${path.module}/templates" + } + yaml_files = { + job_uninstall_cpd = "job-uninstall-cpd.yaml.tftpl" + } + image_secret_map = var.cloud_pak_deployer_secret != null ? { name = "cpd-docker-cfg" } : {} +} + +# Generate configuration file +# https://ibm.github.io/cloud-pak-deployer/50-advanced/run-on-openshift/build-image-and-run-deployer-on-openshift/#create-configuration +resource "local_file" "config" { + content = replace(yamlencode(var.cloud_pak_deployer_config), "\"", "") + filename = local.cloud_pak_deployer.config_path +} + +resource "local_file" "deployer_definitions" { + for_each = local.yaml_files + content = templatefile("${local.paths.templates}/${each.value}", { + cloud_pak_deployer_config_map_name = local.cloud_pak_deployer.config_map_name + cloud_pak_deployer_image = local.cloud_pak_deployer.image + cloud_pak_deployer_job_label = local.cloud_pak_deployer.job_label + cloud_pak_deployer_job_name = local.cloud_pak_deployer.job_name + cloud_pak_deployer_namespace_name = local.cloud_pak_deployer.namespace_name + cloud_pak_deployer_persistent_volume_claim_name = local.cloud_pak_deployer.persistent_volume_claim_name + cloud_pak_deployer_service_account_name = local.cloud_pak_deployer.service_account_name + cloud_pak_deployer_image_secret = local.image_secret_map == null || local.image_secret_map == {} ? "" : join(",", [for key, value in local.image_secret_map : "- ${key}: ${value}"]) + }) + filename = "${local.paths.definitions}/${each.value}" +} + +resource "kubernetes_namespace_v1" "cloud_pak_deployer_namespace" { + metadata { + name = local.cloud_pak_deployer.namespace_name + } +} + + +resource "kubernetes_secret" "cpd_entitlement_key_secret" { + depends_on = [ + kubernetes_namespace_v1.cloud_pak_deployer_namespace + ] + + metadata { + name = local.cpd.entitlement_key_secret_name + namespace = local.cloud_pak_deployer.namespace_name + } + + data = { + (local.cpd.entitlement_key_secret_key_name) = var.cpd_entitlement_key + } +} + +resource "kubernetes_service_account_v1" "cloud_pak_deployer_service_account" { + depends_on = [ + kubernetes_namespace_v1.cloud_pak_deployer_namespace + ] + + metadata { + name = local.cloud_pak_deployer.service_account_name + namespace = local.cloud_pak_deployer.namespace_name + } +} + +resource "null_resource" "cloud_pak_deployer_security_context_constraint" { + depends_on = [ + kubernetes_service_account_v1.cloud_pak_deployer_service_account + ] + + triggers = { + namespace_name = local.cloud_pak_deployer.namespace_name + security_context_constraint_name = local.cloud_pak_deployer.security_context_constraint_name + service_account_name = local.cloud_pak_deployer.service_account_name + oc = local.oc + } + provisioner "local-exec" { + command = "${self.triggers.oc} adm policy add-scc-to-user ${self.triggers.security_context_constraint_name} -z ${self.triggers.service_account_name} -n ${self.triggers.namespace_name}" + } + provisioner "local-exec" { + when = destroy + command = "${self.triggers.oc} adm policy remove-scc-from-user ${self.triggers.security_context_constraint_name} -z ${self.triggers.service_account_name} -n ${self.triggers.namespace_name}" + } +} + +resource "kubernetes_cluster_role_binding_v1" "cloud_pak_deployer_cluster_role_binding" { + depends_on = [ + kubernetes_namespace_v1.cloud_pak_deployer_namespace, + kubernetes_service_account_v1.cloud_pak_deployer_service_account + ] + + metadata { + name = local.cloud_pak_deployer.cluster_role_binding_name + } + role_ref { + api_group = "rbac.authorization.k8s.io" + kind = "ClusterRole" + name = local.cloud_pak_deployer.cluster_role_name + } + subject { + kind = "ServiceAccount" + name = local.cloud_pak_deployer.service_account_name + namespace = local.cloud_pak_deployer.namespace_name + } +} + +resource "kubernetes_secret" "docker_cfg_secret" { + count = var.cloud_pak_deployer_secret != null ? 1 : 0 + depends_on = [ + kubernetes_namespace_v1.cloud_pak_deployer_namespace + ] + + metadata { + name = "cpd-docker-cfg" + namespace = local.cloud_pak_deployer.namespace_name + } + + type = "kubernetes.io/dockerconfigjson" + + data = { + ".dockerconfigjson" = jsonencode({ + auths = { + (var.cloud_pak_deployer_secret.server) = { + "username" = var.cloud_pak_deployer_secret.username + "password" = var.cloud_pak_deployer_secret.password + "email" = lookup(var.cloud_pak_deployer_secret, "email", "") + "auth" = base64encode("${var.cloud_pak_deployer_secret.username}:${var.cloud_pak_deployer_secret.password}") + } + } + }) + } +} + +resource "kubernetes_config_map_v1" "cloud_pak_deployer_configmap" { + depends_on = [ + kubernetes_namespace_v1.cloud_pak_deployer_namespace + ] + + metadata { + name = local.cloud_pak_deployer.config_map_name + namespace = local.cloud_pak_deployer.namespace_name + } + + data = { + "cpd-config.yaml" = local_file.config.content + } +} + +resource "kubernetes_persistent_volume_claim_v1" "cloud_pak_deployer_persistent_volume_claim" { + depends_on = [kubernetes_namespace_v1.cloud_pak_deployer_namespace] + + metadata { + name = local.cloud_pak_deployer.persistent_volume_claim_name + namespace = local.cloud_pak_deployer.namespace_name + } + spec { + resources { + requests = { + storage = "10Gi" + } + } + access_modes = ["ReadWriteOnce"] + } + + wait_until_bound = true +} + +resource "kubernetes_job_v1" "cloud_pak_deployer_job" { + depends_on = [ + kubernetes_namespace_v1.cloud_pak_deployer_namespace, + kubernetes_secret.cpd_entitlement_key_secret, + kubernetes_service_account_v1.cloud_pak_deployer_service_account, + null_resource.cloud_pak_deployer_security_context_constraint, + kubernetes_cluster_role_binding_v1.cloud_pak_deployer_cluster_role_binding, + kubernetes_secret.docker_cfg_secret, + kubernetes_config_map_v1.cloud_pak_deployer_configmap, + kubernetes_persistent_volume_claim_v1.cloud_pak_deployer_persistent_volume_claim + ] + + metadata { + labels = { + App = local.cloud_pak_deployer.job_label + } + name = local.cloud_pak_deployer.job_name + namespace = local.cloud_pak_deployer.namespace_name + } + spec { + parallelism = 1 + completions = 1 + backoff_limit = 0 + template { + metadata { + name = local.cloud_pak_deployer.job_name + labels = { + App = local.cloud_pak_deployer.job_label + } + } + spec { + dynamic "image_pull_secrets" { + for_each = local.image_secret_map + + content { + name = image_pull_secrets.value + } + } + + container { + name = local.cloud_pak_deployer.job_name + image = local.cloud_pak_deployer.image + image_pull_policy = "Always" + termination_message_path = "/dev/termination-log" + termination_message_policy = "File" + env { + name = "CONFIG_DIR" + value = "/Data/cpd-config" + } + env { + name = "STATUS_DIR" + value = "/Data/cpd-status" + } + env { + name = "CP_ENTITLEMENT_KEY" + value_from { + secret_key_ref { + name = local.cpd.entitlement_key_secret_name + key = local.cpd.entitlement_key_secret_key_name + } + } + } + volume_mount { + name = "config-volume" + mount_path = "/Data/cpd-config/config" + } + volume_mount { + name = "status-volume" + mount_path = "/Data/cpd-status" + } + command = ["/bin/sh", "-xc"] + args = ["/cloud-pak-deployer/cp-deploy.sh vault set -vs cp4d_admin_cpd_${replace(var.cluster_name, "-", "_")} -vsv ${var.cpd_admin_password} && /cloud-pak-deployer/cp-deploy.sh env apply -vvvv ${local.cloud_pak_deployer.script_accept_license_flag}"] + } + restart_policy = "Never" + security_context { + run_as_user = 0 + } + service_account_name = local.cloud_pak_deployer.service_account_name + volume { + name = "config-volume" + config_map { + name = local.cloud_pak_deployer.config_map_name + } + } + volume { + name = "status-volume" + persistent_volume_claim { + claim_name = local.cloud_pak_deployer.persistent_volume_claim_name + } + } + } + } + } + wait_for_completion = var.wait_for_cpd_job_completion + timeouts { + create = "5h" + } + lifecycle { + replace_triggered_by = [ + local_file.config, + kubernetes_config_map_v1.cloud_pak_deployer_configmap + ] + } +} + +resource "shell_script" "uninstall" { + depends_on = [kubernetes_job_v1.cloud_pak_deployer_job] + + lifecycle_commands { + create = "" + delete = file("${path.module}/scripts/uninstall.sh.tftpl") + } + + environment = { + JOB_NAME = yamldecode(local_file.deployer_definitions["job_uninstall_cpd"].content).metadata.name + JOB_UNINSTALL_CPD_FILENAME = local_file.deployer_definitions["job_uninstall_cpd"].filename + NAMESPACE_NAME = local.cloud_pak_deployer.namespace_name + OC = local.oc + } +} diff --git a/solutions/deploy/cloud-pak-deployer/outputs.tf b/solutions/deploy/cloud-pak-deployer/outputs.tf new file mode 100644 index 00000000..bcb768b0 --- /dev/null +++ b/solutions/deploy/cloud-pak-deployer/outputs.tf @@ -0,0 +1,4 @@ +output "cloud_pak_deployer_config_path" { + description = "Path to the required config for the Cloud Pak Deployer" + value = local.cloud_pak_deployer.config_path +} diff --git a/solutions/deploy/cloud-pak-deployer/scripts/uninstall.sh.tftpl b/solutions/deploy/cloud-pak-deployer/scripts/uninstall.sh.tftpl new file mode 100644 index 00000000..39e9041b --- /dev/null +++ b/solutions/deploy/cloud-pak-deployer/scripts/uninstall.sh.tftpl @@ -0,0 +1,40 @@ +#!/bin/bash + +${OC} create -f ${JOB_UNINSTALL_CPD_FILENAME} +if [ $? -ne 0 ]; then echo "Unable to create job ${JOB_NAME}; exiting..." && exit 1; fi + +timeout_seconds=1800 # 30 minutes +sleep_seconds=5 +number_of_tries=$((timeout_seconds / sleep_seconds)) +complete=false +failed=false + +i=0 +while [ $i -lt $number_of_tries ]; do + +echo "Running job ... $i" +${OC} get jobs -n ${NAMESPACE_NAME} + +${OC} wait --for=condition=complete job ${JOB_NAME} -n ${NAMESPACE_NAME} --timeout=0 2>/dev/null +if [ $? -eq 0 ]; then complete=true && break; fi + +${OC} wait --for=condition=failed job ${JOB_NAME} -n ${NAMESPACE_NAME} --timeout=0 2>/dev/null +if [ $? -eq 0 ]; then failed=true && break; fi + +i=`expr $i + 1` + +sleep $sleep_seconds + +done + +${OC} describe pods -n ${NAMESPACE_NAME} + +if $failed; then + echo "Job ${JOB_NAME} failed" + exit 1 +elif $complete; then + echo "Job ${JOB_NAME} completed successfully" + ${OC} delete -f ${JOB_UNINSTALL_CPD_FILENAME} + if [ $? -ne 0 ]; then echo "Unable to delete job ${JOB_NAME}; exiting..." && exit 1; fi + exit 0 +fi diff --git a/solutions/deploy/cloud-pak-deployer/templates/job-uninstall-cpd.yaml.tftpl b/solutions/deploy/cloud-pak-deployer/templates/job-uninstall-cpd.yaml.tftpl new file mode 100644 index 00000000..70422a98 --- /dev/null +++ b/solutions/deploy/cloud-pak-deployer/templates/job-uninstall-cpd.yaml.tftpl @@ -0,0 +1,49 @@ +apiVersion: batch/v1 +kind: Job +metadata: + labels: + app: ${cloud_pak_deployer_job_label}-uninstall-cpd + name: ${cloud_pak_deployer_job_name}-uninstall-cpd + namespace: ${cloud_pak_deployer_namespace_name} +spec: + parallelism: 1 + completions: 1 + backoffLimit: 0 + template: + metadata: + name: ${cloud_pak_deployer_job_name}-uninstall-cpd + labels: + app: ${cloud_pak_deployer_job_label}-uninstall-cpd + spec: + imagePullSecrets: + ${cloud_pak_deployer_image_secret} + containers: + - name: ${cloud_pak_deployer_job_name}-uninstall-cpd + image: ${cloud_pak_deployer_image} + imagePullPolicy: Always + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + env: + - name: CONFIG_DIR + value: /Data/cpd-config + - name: STATUS_DIR + value: /Data/cpd-status + volumeMounts: + - name: config-volume + mountPath: /Data/cpd-config/config + - name: status-volume + mountPath: /Data/cpd-status + command: ["/bin/sh", "-xc"] + args: + - /cloud-pak-deployer/scripts/cp4d/cp4d-delete-instance.sh cpd <<< "y" + restartPolicy: Never + securityContext: + runAsUser: 0 + serviceAccountName: ${cloud_pak_deployer_service_account_name} + volumes: + - name: config-volume + configMap: + name: ${cloud_pak_deployer_config_map_name} + - name: status-volume + persistentVolumeClaim: + claimName: ${cloud_pak_deployer_persistent_volume_claim_name} diff --git a/solutions/deploy/cloud-pak-deployer/variables.tf b/solutions/deploy/cloud-pak-deployer/variables.tf new file mode 100644 index 00000000..9f951dfc --- /dev/null +++ b/solutions/deploy/cloud-pak-deployer/variables.tf @@ -0,0 +1,62 @@ +variable "cloud_pak_deployer_config" { + description = "Object definition of the Cloud Pak Deployer configuration" + type = any +} + +variable "cloud_pak_deployer_image" { + default = null + description = "The cloud pak deployer image location" + type = string +} + +variable "cloud_pak_deployer_secret" { + description = "Image pull secret for the cloud pak deployer image" + type = object({ + username = string + password = string + server = string + email = optional(string) + }) + + default = null +} + + +variable "cluster_name" { + description = "Name of Red Hat OpenShift cluster to install watsonx onto" + type = string +} + +variable "cpd_accept_license" { + default = false + description = "When set to 'true', it is understood that the user has read the terms of the Cloud Pak license(s) and agrees to the terms outlined" + type = bool +} + +variable "cpd_admin_password" { + description = "Password to be used by the admin user to access the Cloud Pak for Data UI." + sensitive = true + type = string +} + +variable "cpd_entitlement_key" { + description = "Cloud Pak for Data entitlement key for access to the IBM Entitled Registry. Can be fetched from https://myibm.ibm.com/products-services/containerlibrary." + sensitive = true + type = string +} + +variable "kube_config_path" { + description = "Path to the kube config file being used" + type = string +} + +variable "schematics_workspace" { + description = "Object containing general information on the IBM Cloud Schematics Workspace this automation may be running on" + type = any +} + +variable "wait_for_cpd_job_completion" { + description = "Wait for the cloud-pak-deployer to complete before continuing" + type = bool + default = true +} diff --git a/solutions/deploy/cloud-pak-deployer/versions.tf b/solutions/deploy/cloud-pak-deployer/versions.tf new file mode 100644 index 00000000..c90c7256 --- /dev/null +++ b/solutions/deploy/cloud-pak-deployer/versions.tf @@ -0,0 +1,21 @@ +terraform { + required_version = ">= 1.2.0" + required_providers { + kubernetes = { + source = "hashicorp/kubernetes" + version = "2.35.1" + } + local = { + source = "hashicorp/local" + version = "2.4.0" + } + null = { + source = "hashicorp/null" + version = "3.2.2" + } + shell = { + source = "scottwinkler/shell" + version = "1.7.10" + } + } +} diff --git a/solutions/deploy/cpd-image-build/main.tf b/solutions/deploy/cpd-image-build/main.tf new file mode 100644 index 00000000..5a8c9a12 --- /dev/null +++ b/solutions/deploy/cpd-image-build/main.tf @@ -0,0 +1,107 @@ +locals { + resource_group_name = var.resource_group == null ? "${var.prefix}-cpd" : var.resource_group + + container_registry_namespace = var.container_registry_namespace != null ? var.container_registry_namespace : "${var.prefix}-cpd-${random_string.random.result}" + container_registry_server = lookup(local.registry_server_map, var.region, null) != null ? local.registry_server_map[var.region] : "private.icr.io" + container_registry_output_image = "${local.container_registry_server}/${local.container_registry_namespace}/deployer:${var.cloud_pak_deployer_release}" + + code_engine_project_name = var.code_engine_project_name != null ? var.code_engine_project_name : "${var.prefix}-cpd-${random_string.random.result}" + + registry_server_map = { + au-syd = "private.au.icr.io" + br-sao = "private.br.icr.io" + ca-tor = "private.ca.icr.io" + eu-de = "private.de.icr.io" + eu-es = "private.es.icr.io" + jp-tok = "private.jp.icr.io" + eu-gb = "private.uk.icr.io" + us-south = "private.us.icr.io" + } + + resource_group_id = var.code_engine_project_id != null ? data.ibm_code_engine_project.code_engine_project[0].resource_group_id : module.resource_group[0].resource_group_id +} + +############################################################################## +# Generate a random seed since some resources need unique names +############################################################################## +resource "random_string" "random" { + length = 8 + lower = true + upper = false + special = false +} + +data "ibm_code_engine_project" "code_engine_project" { + count = var.code_engine_project_id != null ? 1 : 0 + project_id = var.code_engine_project_id +} + +module "resource_group" { + count = var.code_engine_project_id == null ? 1 : 0 + source = "terraform-ibm-modules/resource-group/ibm" + version = "1.1.6" + + resource_group_name = var.resource_group_exists ? null : local.resource_group_name + existing_resource_group_name = var.resource_group_exists ? var.resource_group : null +} + +############################################################################## +# Container registry resources +############################################################################## +resource "ibm_cr_namespace" "cr_namespace" { + name = local.container_registry_namespace + resource_group_id = local.resource_group_id +} + +############################################################################## +# Code engine resources +############################################################################## +module "code_engine" { + source = "terraform-ibm-modules/code-engine/ibm" + version = "2.1.5" + project_name = var.code_engine_project_id == null ? local.code_engine_project_name : null + existing_project_id = var.code_engine_project_id + resource_group_id = local.resource_group_id + secrets = { + "registry-secret" = { + format = "registry" + data = { + "password" : var.ibmcloud_api_key, + "server" : local.container_registry_server, + "username" : "iamapikey" + } + } + } +} + +module "code_engine_build" { + source = "terraform-ibm-modules/code-engine/ibm//modules/build" + version = "2.1.5" + + name = "cpd-build" + project_id = module.code_engine.project_id + output_image = local.container_registry_output_image + output_secret = "registry-secret" # pragma: allowlist secret + source_url = "https://github.com/IBM/cloud-pak-deployer" + source_revision = var.cloud_pak_deployer_release + strategy_type = "dockerfile" + + depends_on = [module.code_engine] +} + +resource "restapi_object" "buildrun" { + path = "/v2/projects/${module.code_engine.project_id}/build_runs" + data = jsonencode( + { + build_name = module.code_engine_build.name + } + ) +} + +resource "time_sleep" "wait_for_build" { + create_duration = "10m" + + depends_on = [ + restapi_object.buildrun + ] +} diff --git a/solutions/deploy/cpd-image-build/outputs.tf b/solutions/deploy/cpd-image-build/outputs.tf new file mode 100644 index 00000000..afd18f60 --- /dev/null +++ b/solutions/deploy/cpd-image-build/outputs.tf @@ -0,0 +1,24 @@ +output "resource_group" { + description = "The resource group that was used for the resources within" + value = local.resource_group_name +} + +output "container_registry_namespace" { + description = "The name of the container registry namespace" + value = local.container_registry_namespace +} + +output "container_registry_server" { + description = "The url of the container registry" + value = local.container_registry_server +} + +output "container_registry_output_image" { + description = "The path to the cpd container that was built" + value = local.container_registry_output_image +} + +output "code_engine_project_name" { + description = "The name of the code engine project that was created" + value = local.code_engine_project_name +} diff --git a/solutions/deploy/cpd-image-build/variables.tf b/solutions/deploy/cpd-image-build/variables.tf new file mode 100644 index 00000000..1b3f1333 --- /dev/null +++ b/solutions/deploy/cpd-image-build/variables.tf @@ -0,0 +1,56 @@ +variable "ibmcloud_api_key" { + description = "APIkey that's associated with the account to use" + type = string + sensitive = true +} + +variable "prefix" { + description = "The value that you would like to prefix to the name of the resources provisioned by this module. Explicitly set to null if you do not wish to use a prefix. This value is ignored if using one of the optional variables for explicit control over naming." + type = string + default = null +} + +variable "region" { + description = "Region where resources will be provisioned" + type = string +} + +variable "resource_group" { + description = "Resource groups to create or reference" + type = string + + default = null +} + +variable "resource_group_exists" { + description = "Boolean value representing if the resource groups exists or not" + type = bool + + default = false +} + +variable "container_registry_namespace" { + description = "The name of the container registry namespace" + type = string + + default = null +} + +variable "code_engine_project_name" { + description = "The name of the code engine project to be created for the image build" + type = string + + default = null +} + +variable "code_engine_project_id" { + description = "If you want to use an existing project, you can pass the code engine project id vs a new project being created." + type = string + default = null +} + +variable "cloud_pak_deployer_release" { + description = "The release of cloud pak deployer to build the image off of" + type = string + default = "latest" +} diff --git a/solutions/deploy/cpd-image-build/versions.tf b/solutions/deploy/cpd-image-build/versions.tf new file mode 100644 index 00000000..0ebc2970 --- /dev/null +++ b/solutions/deploy/cpd-image-build/versions.tf @@ -0,0 +1,21 @@ +terraform { + required_version = ">= 1.2.0" + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + version = ">= 1.68.1, < 2.0.0" + } + random = { + source = "hashicorp/random" + version = ">= 3.4.3, < 4.0.0" + } + restapi = { + source = "Mastercard/restapi" + version = "1.18.2" + } + time = { + source = "hashicorp/time" + version = "0.12.1" + } + } +} diff --git a/solutions/deploy/data.tf b/solutions/deploy/data.tf new file mode 100644 index 00000000..22c4bdea --- /dev/null +++ b/solutions/deploy/data.tf @@ -0,0 +1,3 @@ +data "external" "schematics" { + program = ["bash", "${local.paths.scripts}/get-schematics-tmp-dir.sh"] +} diff --git a/solutions/deploy/main.tf b/solutions/deploy/main.tf new file mode 100644 index 00000000..c86b25f1 --- /dev/null +++ b/solutions/deploy/main.tf @@ -0,0 +1,114 @@ +locals { + kube_config_dir = local.schematics_workspace.persistent_dir_exists ? local.schematics_workspace.persistent_dir_path : path.module + kube_config_path = data.ibm_container_cluster_config.cluster_config.config_file_path + oc = "oc --kubeconfig ${local.kube_config_path}" + openshift_version = join(".", slice(split(".", data.ibm_container_vpc_cluster.cluster_info.kube_version), 0, 2)) # Only use major and minor — no patch + paths = { + scripts = "${path.module}/scripts" + } + schematics_workspace = { + persistent_dir_exists = data.external.schematics.result.schematics_tmp_dir_exists ? true : false + persistent_dir_path = "/tmp/.schematics" + } +} + +# Retrieve the openshift cluster info +data "ibm_container_vpc_cluster" "cluster_info" { + name = var.cluster_name +} + +module "build_cpd_image" { + count = var.cloud_pak_deployer_image == null ? 1 : 0 + source = "./cpd-image-build" + ibmcloud_api_key = var.ibmcloud_api_key + prefix = var.prefix + region = var.region + code_engine_project_name = var.code_engine_project_name + code_engine_project_id = var.code_engine_project_id + resource_group = var.resource_group + resource_group_exists = var.resource_group_exists + cloud_pak_deployer_release = var.cloud_pak_deployer_release +} + +resource "ibm_container_addons" "odf_cluster_addon" { + count = var.install_odf_cluster_addon ? 1 : 0 + cluster = var.cluster_name + manage_all_addons = false + addons { + name = "openshift-data-foundation" + version = var.odf_version + parameters_json = jsonencode(var.odf_config) + } +} + +module "watsonx_ai" { + source = "./watsonx-ai" + depends_on = [null_resource.oc_login, ibm_container_addons.odf_cluster_addon] + watson_assistant_install = var.watson_assistant_install + watson_discovery_install = var.watson_discovery_install + watsonx_ai_install = var.watsonx_ai_install + watsonx_ai_models = var.watsonx_ai_models +} + +module "watsonx_data" { + source = "./watsonx-data" + depends_on = [null_resource.oc_login, ibm_container_addons.odf_cluster_addon] + watsonx_data_install = var.watsonx_data_install +} + +module "cloud_pak_deployer" { + depends_on = [module.watsonx_ai, module.watsonx_data, module.build_cpd_image] + source = "./cloud-pak-deployer" + cloud_pak_deployer_config = merge( + module.config.cloud_pak_deployer_config_base, + { + cp4d = [merge( + module.config.cloud_pak_deployer_config_base["cp4d"][0], + { + cartridges = concat( + module.config.cloud_pak_deployer_config_base["cp4d"][0]["cartridges"], + module.watsonx_ai.watsonx_ai_cloud_pak_deployer_config.cartridges, + module.watsonx_data.watsonx_data_cloud_pak_deployer_config.cartridges + ) + } + )] + } + ) + cloud_pak_deployer_image = var.cloud_pak_deployer_image != null ? var.cloud_pak_deployer_image : module.build_cpd_image[0].container_registry_output_image + + cloud_pak_deployer_secret = var.cloud_pak_deployer_secret != null ? var.cloud_pak_deployer_secret : (var.cloud_pak_deployer_image == null ? + { username : "iamapikey", password : var.ibmcloud_api_key, server : module.build_cpd_image[0].container_registry_server } : null) + + cluster_name = var.cluster_name + cpd_accept_license = var.cpd_accept_license + cpd_admin_password = var.cpd_admin_password + cpd_entitlement_key = var.cpd_entitlement_key + kube_config_path = local.kube_config_path + schematics_workspace = local.schematics_workspace + wait_for_cpd_job_completion = var.wait_for_cpd_job_completion +} + +# Cloud Pak Deployer configuration file local variable(s) only +module "config" { + source = "./cloud-pak-deployer/config" + cluster_name = var.cluster_name + cpd_version = var.cpd_version + openshift_version = local.openshift_version +} + +# Log into the OpenShift cluster as administrator +resource "null_resource" "oc_login" { + triggers = { + always_run = timestamp() + kube_config_path = local.kube_config_path + oc = local.oc + } + provisioner "local-exec" { + command = <