diff --git a/.catalog-onboard-pipeline.yaml b/.catalog-onboard-pipeline.yaml new file mode 100644 index 0000000..1bd8ee6 --- /dev/null +++ b/.catalog-onboard-pipeline.yaml @@ -0,0 +1,13 @@ +--- +apiVersion: v1 +offerings: + - name: deploy-arch-ibm-monitoring-agent + kind: solution + catalog_id: 7df1e4ca-d54c-4fd0-82ce-3d13247308cd + offering_id: b0a00765-ee91-4c2a-87fc-df46dbc58cdb + variations: + - name: fully-configurable + mark_ready: true + install_type: fullstack + pre_validation: "tests/scripts/pre-validation-deploy-base-ocp-and-monitoring-instances.sh" + post_validation: "tests/scripts/post-validation-deploy-base-ocp-and-monitoring-instances.sh" diff --git a/.github/settings.yml b/.github/settings.yml index 17bf0bd..3d9e92e 100644 --- a/.github/settings.yml +++ b/.github/settings.yml @@ -22,7 +22,7 @@ repository: # Uncomment this description property # and update the description to the current repo description. - # description: "" + description: "Terraform module to install and configure the Monitoring Agent on IBM Cloud Kubernetes Service and Red Hat OpenShift on IBM Cloud." # Use a comma-separated list of topics to set on the repo (ensure not to use any caps in the topic string). - topics: terraform, ibm-cloud, terraform-module, core-team, monitoring-agent, sysdig-agent, observability, agent, sysdig + topics: terraform, ibm-cloud, terraform-module, core-team, monitoring-agent, sysdig-agent, observability, monitoring, agent, sysdig diff --git a/.releaserc b/.releaserc index 708916f..4160e57 100644 --- a/.releaserc +++ b/.releaserc @@ -10,6 +10,9 @@ }], ["@semantic-release/exec", { "successCmd": "echo \"SEMVER_VERSION=${nextRelease.version}\" >> $GITHUB_ENV" + }], + ["@semantic-release/exec",{ + "publishCmd": "./ci/trigger-catalog-onboarding-pipeline.sh --version=v${nextRelease.version}" }] ] } diff --git a/.secrets.baseline b/.secrets.baseline index 0a4efa4..ef74d64 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-03-24T23:50:52Z", "plugins_used": [ { "name": "AWSKeyDetector" @@ -76,18 +76,7 @@ "name": "TwilioKeyDetector" } ], - "results": { - "README.md": [ - { - "hashed_secret": "ff9ee043d85595eb255c05dfe32ece02a53efbb2", - "is_secret": false, - "is_verified": false, - "line_number": 74, - "type": "Secret Keyword", - "verified_result": null - } - ] - }, + "results": {}, "version": "0.13.1+ibm.62.dss", "word_list": { "file": null, diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 0000000..713bd26 --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,2 @@ +# Primary owner should be listed first in list of global owners, followed by any secondary owners +* @jor2 @Aashiq-J diff --git a/README.md b/README.md index 73b5c74..28a8c02 100644 --- a/README.md +++ b/README.md @@ -1,129 +1,89 @@ - -# Terraform modules template project - - -[![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-monitoring-agent?logo=GitHub&sort=semver)](https://github.com/terraform-ibm-modules/terraform-ibm-monitoring-agent/releases/latest) +# Terraform IBM Monitoring agent module + +[![Graduated (Supported)](https://img.shields.io/badge/Status-Graduated%20(Supported)-brightgreen)](https://terraform-ibm-modules.github.io/documentation/#/badge-status) [![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit) +[![latest release](https://img.shields.io/github/v/release/terraform-ibm-modules/terraform-ibm-monitoring-agent?logo=GitHub&sort=semver)](https://github.com/terraform-ibm-modules/terraform-ibm-monitoring-agent/releases/latest) [![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) - +- [Monitoring agent](https://cloud.ibm.com/docs/monitoring?topic=monitoring-about-collect-metrics) -TODO: Replace this with a description of the modules in this repo. - - - + ## Overview * [terraform-ibm-monitoring-agent](#terraform-ibm-monitoring-agent) * [Examples](./examples) - * [Advanced example](./examples/advanced) - * [Basic example](./examples/basic) + * [Monitoring agent on Kubernetes using CSE ingress endpoint with an apikey](./examples/obs-agent-iks) + * [Monitoring agent](./examples/obs-agent-ocp) * [Contributing](#contributing) - - - - - - ## terraform-ibm-monitoring-agent ### 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 - } - } -} +# ############################################################################ +# Init cluster config for helm +# ############################################################################ -locals { - region = "us-south" +data "ibm_container_cluster_config" "cluster_config" { + # update this value with the Id of the cluster where these agent will be provisioned + cluster_name_id = "cluster_id" } +# ############################################################################ +# Config providers +# ############################################################################ + provider "ibm" { - ibmcloud_api_key = "XXXXXXXXXX" # replace with apikey value - region = local.region + # update this value with your IBM Cloud API key value + ibmcloud_api_key = "XXXXXXXXXXXXXXXXX" # pragma: allowlist secret } -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 +provider "helm" { + kubernetes { + host = data.ibm_container_cluster_config.cluster_config.host + token = data.ibm_container_cluster_config.cluster_config.token + cluster_ca_certificate = data.ibm_container_cluster_config.cluster_config.ca_certificate + } } -``` - -### Required access policies - +# ############################################################################ +# Install monitoring agents +# ############################################################################ + +module "monitoring_agents" { + source = "terraform-ibm-modules/monitoring-agent/ibm" + version = "X.X.X" # Replace "X.X.X" with a release version to lock into a specific release + is_vpc_cluster = true # Change to false if target cluster is running on classic infrastructure + cluster_id = "cluster id" # update this with your cluster id where the agent will be installed + cluster_resource_group_id = "resource group id" # update this with the Id of your IBM Cloud resource group + access_key = "XXXXXXXX" + cloud_monitoring_instance_region = "us-south" +} +``` - - - - - - - ### Requirements | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.9.0 | -| [ibm](#requirement\_ibm) | >= 1.71.2, < 2.0.0 | +| [helm](#requirement\_helm) | >= 2.15.0, <3.0.0 | +| [ibm](#requirement\_ibm) | >= 1.76.1, <2.0.0 | ### Modules @@ -133,28 +93,42 @@ No modules. | Name | Type | |------|------| -| [ibm_resource_instance.cos_instance](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/resource_instance) | resource | +| [helm_release.cloud_monitoring_agent](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource | +| [ibm_container_cluster.cluster](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/data-sources/container_cluster) | 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](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/data-sources/container_vpc_cluster) | data source | ### 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 | +| [access\_key](#input\_access\_key) | Access key used by the IBM Cloud Monitoring agent to communicate with the instance | `string` | n/a | yes | +| [chart](#input\_chart) | The name of the Helm chart to deploy. | `string` | `"sysdig-deploy"` | no | +| [chart\_location](#input\_chart\_location) | The location of the Cloud Monitoring agent helm chart. | `string` | `"https://charts.sysdig.com"` | no | +| [chart\_version](#input\_chart\_version) | The version of the Cloud Monitoring agent helm chart to deploy. | `string` | `"1.79.0"` | no | +| [cloud\_monitoring\_instance\_endpoint\_type](#input\_cloud\_monitoring\_instance\_endpoint\_type) | Specify the IBM Cloud Monitoring instance endpoint type (public or private) to use. Used to construct the ingestion endpoint. | `string` | `"private"` | no | +| [cloud\_monitoring\_instance\_region](#input\_cloud\_monitoring\_instance\_region) | The IBM Cloud Monitoring instance region. Used to construct the ingestion endpoint. | `string` | n/a | yes | +| [cluster\_config\_endpoint\_type](#input\_cluster\_config\_endpoint\_type) | Specify which type of endpoint to use for for cluster config access: 'default', 'private', 'vpe', 'link'. 'default' value will use the default endpoint of the cluster. | `string` | `"default"` | no | +| [cluster\_id](#input\_cluster\_id) | The ID of the cluster you wish to deploy the agent in | `string` | n/a | yes | +| [cluster\_resource\_group\_id](#input\_cluster\_resource\_group\_id) | The Resource Group ID of the cluster | `string` | n/a | yes | +| [container\_filter](#input\_container\_filter) | To filter custom containers, specify which containers to include or exclude from metrics collection for the cloud monitoring agent. See https://cloud.ibm.com/docs/monitoring?topic=monitoring-change_kube_agent#change_kube_agent_filter_data. |
list(object({
type = string
parameter = string
name = string
}))
| `[]` | no | +| [image\_registry](#input\_image\_registry) | The image registry to use for the Cloud Monitoring agent. | `string` | `"icr.io/ext/sysdig/agent"` | no | +| [image\_tag\_digest](#input\_image\_tag\_digest) | The image tag digest to use for the Cloud Monitoring agent. | `string` | `"13.8.1@sha256:e5d1c63edf07c9f861249432c00873e32141381c15fbcff80b90a12b272dc0b9"` | no | +| [is\_vpc\_cluster](#input\_is\_vpc\_cluster) | Specify true if the target cluster for the monitoring agent is a VPC cluster, false if it is a classic cluster. | `bool` | `true` | no | +| [metrics\_filter](#input\_metrics\_filter) | To filter custom metrics, specify the Cloud Monitoring metrics to include or to exclude. See https://cloud.ibm.com/docs/monitoring?topic=monitoring-change_kube_agent#change_kube_agent_inc_exc_metrics. |
list(object({
type = string
name = string
}))
| `[]` | no | +| [name](#input\_name) | Cloud Monitoring agent name. Used for naming all kubernetes and helm resources on the cluster. | `string` | `"sysdig-agent"` | no | +| [namespace](#input\_namespace) | Namespace where to deploy the Cloud Monitoring agent. Default value is 'ibm-observe' | `string` | `"ibm-observe"` | no | +| [tolerations](#input\_tolerations) | List of tolerations to apply to Cloud Monitoring agent. |
list(object({
key = optional(string)
operator = optional(string)
value = optional(string)
effect = optional(string)
tolerationSeconds = optional(number)
}))
|
[
{
"operator": "Exists"
},
{
"effect": "NoSchedule",
"key": "node-role.kubernetes.io/master",
"operator": "Exists"
}
]
| no | +| [wait\_till](#input\_wait\_till) | To avoid long wait times when you run your Terraform code, you can specify the stage when you want Terraform to mark the cluster resource creation as completed. Depending on what stage you choose, the cluster creation might not be fully completed and continues to run in the background. However, your Terraform code can continue to run without waiting for the cluster to be fully created. Supported args are `MasterNodeReady`, `OneWorkerNodeReady`, `IngressReady` and `Normal` | `string` | `"Normal"` | no | +| [wait\_till\_timeout](#input\_wait\_till\_timeout) | Timeout for wait\_till in minutes. | `number` | `90` | no | ### Outputs -| 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. | +No outputs. - + + ## 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). diff --git a/cra-config.yaml b/cra-config.yaml index 9a4c7fa..05b674a 100644 --- a/cra-config.yaml +++ b/cra-config.yaml @@ -1,17 +1,6 @@ -# -# Developer tips: -# - CRA = Code Risk Analyzer (more info on CRA: https://cloud.ibm.com/docs/code-risk-analyzer-cli-plugin?topic=code-risk-analyzer-cli-plugin-cra-cli-plugin) -# - Multiple directories can be scanned by CRA. Ensure if there are any deployable architecture in the repository that they are all scanned -# - More info about supported configurations at https://github.com/terraform-ibm-modules/common-pipeline-assets/blob/main/.github/workflows/terraform-test-pipeline.md#cra-config-yaml -# - +# More info about this file at https://github.com/terraform-ibm-modules/common-pipeline-assets/blob/main/.github/workflows/terraform-test-pipeline.md#cra-config-yaml version: "v1" CRA_TARGETS: - - CRA_TARGET: "examples/advanced" # 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_TARGET: "examples/obs-agent-ocp" # 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" # CRA Ignore file to use. If not provided, it checks the repo root directory for `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). diff --git a/cra-tf-validate-ignore-rules.json b/cra-tf-validate-ignore-rules.json index adbff6e..1904716 100644 --- a/cra-tf-validate-ignore-rules.json +++ b/cra-tf-validate-ignore-rules.json @@ -1,3 +1,22 @@ { - "scc_rules": [] + "scc_rules": [ + { + "scc_rule_id": "rule-216e2449-27d7-4afc-929a-b66e196a9cf9", + "description": "Check whether Flow Logs for VPC are enabled", + "ignore_reason": "This rule is not relevant to the module itself, just the VPC resource that is used in the example that is scanned", + "is_valid": false + }, + { + "scc_rule_id": "rule-2325054a-c338-474a-9740-0b7034487e40", + "description:": "Check whether OpenShift clusters are accessible only by using private endpoints", + "ignore_reason": "This rule is not relevant to the module itself, just the cluster resource that is used in the example that is scanned", + "is_valid": false + }, + { + "scc_rule_id": "rule-64c0bea0-8760-4a6b-a56c-ee375a48961e", + "description:": "Check whether Virtual Private Cloud (VPC) has no public gateways attached", + "ignore_reason": "This rule is not relevant to the module itself, just the VPC resource that is used in the example that is scanned", + "is_valid": false + } + ] } diff --git a/examples/advanced/README.md b/examples/advanced/README.md deleted file mode 100644 index d52511a..0000000 --- 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 88360af..0000000 --- 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.2.0" - # 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 316751f..0000000 --- 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/variables.tf b/examples/advanced/variables.tf deleted file mode 100644 index d460364..0000000 --- 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 ecfa978..0000000 --- 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 e5977ae..0000000 --- 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 deleted file mode 100644 index cf665db..0000000 --- a/examples/basic/main.tf +++ /dev/null @@ -1,31 +0,0 @@ -######################################################################################################################## -# Resource group -######################################################################################################################## - -module "resource_group" { - source = "terraform-ibm-modules/resource-group/ibm" - version = "1.2.0" - # 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 -} diff --git a/examples/basic/outputs.tf b/examples/basic/outputs.tf deleted file mode 100644 index 552db48..0000000 --- a/examples/basic/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/basic/provider.tf b/examples/basic/provider.tf deleted file mode 100644 index 84b6985..0000000 --- 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/variables.tf b/examples/basic/variables.tf deleted file mode 100644 index d460364..0000000 --- a/examples/basic/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/basic/version.tf b/examples/basic/version.tf deleted file mode 100644 index 401504c..0000000 --- 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/obs-agent-iks/README.md b/examples/obs-agent-iks/README.md new file mode 100644 index 0000000..66baa8c --- /dev/null +++ b/examples/obs-agent-iks/README.md @@ -0,0 +1,10 @@ +# Monitoring agent on Kubernetes using CSE ingress endpoint with an apikey + +An example that shows how to deploy a Monitoring agent in a Kubernetes cluster to send Logs directly to IBM a Cloud Monitoring instance. + +The example provisions the following resources: +- A new resource group, if an existing one is not passed in. +- A basic VPC (if `is_vpc_cluster` is true). +- A Kubernetes cluster. +- An IBM Cloud Monitoring instance +- Monitoring agent diff --git a/examples/obs-agent-iks/main.tf b/examples/obs-agent-iks/main.tf new file mode 100644 index 0000000..3297872 --- /dev/null +++ b/examples/obs-agent-iks/main.tf @@ -0,0 +1,122 @@ +############################################################################## +# 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 +} + +######################################################################################################################## +# VPC + Subnet + Public Gateway +# +# NOTE: This is a very simple VPC with single subnet in a single zone with a public gateway enabled, that will allow +# all traffic ingress/egress by default. +# For production use cases this would need to be enhanced by adding more subnets and zones for resiliency, and +# ACLs/Security Groups for network security. +######################################################################################################################## + +resource "ibm_is_vpc" "vpc" { + name = "${var.prefix}-vpc" + resource_group = module.resource_group.resource_group_id + address_prefix_management = "auto" + tags = var.resource_tags +} + +resource "ibm_is_public_gateway" "gateway" { + name = "${var.prefix}-gateway-1" + vpc = ibm_is_vpc.vpc.id + resource_group = module.resource_group.resource_group_id + zone = "${var.region}-1" +} + +resource "ibm_is_subnet" "subnet_zone_1" { + name = "${var.prefix}-subnet-1" + vpc = ibm_is_vpc.vpc.id + resource_group = module.resource_group.resource_group_id + zone = "${var.region}-1" + total_ipv4_address_count = 256 + public_gateway = ibm_is_public_gateway.gateway.id +} + +######################################################################################################################## +# OCP VPC cluster (single zone) +######################################################################################################################## + +locals { + cluster_vpc_subnets = { + default = [ + { + id = ibm_is_subnet.subnet_zone_1.id + cidr_block = ibm_is_subnet.subnet_zone_1.ipv4_cidr_block + zone = ibm_is_subnet.subnet_zone_1.zone + } + ] + } + + worker_pools = [ + { + subnet_prefix = "default" + pool_name = "default" # ibm_container_vpc_cluster automatically names default pool "default" (See https://github.com/IBM-Cloud/terraform-provider-ibm/issues/2849) + machine_type = "bx2.4x16" + operating_system = "REDHAT_8_64" + workers_per_zone = 2 # minimum of 2 is allowed when using single zone + } + ] +} + +module "ocp_base" { + source = "terraform-ibm-modules/base-ocp-vpc/ibm" + version = "3.41.7" + resource_group_id = module.resource_group.resource_group_id + region = var.region + tags = var.resource_tags + cluster_name = var.prefix + force_delete_storage = true + vpc_id = ibm_is_vpc.vpc.id + vpc_subnets = local.cluster_vpc_subnets + worker_pools = local.worker_pools + disable_outbound_traffic_protection = true # set as True to enable outbound traffic +} + +data "ibm_container_cluster_config" "cluster_config" { + cluster_name_id = module.ocp_base.cluster_id + resource_group_id = module.resource_group.resource_group_id +} + +# Sleep to allow RBAC sync on cluster +resource "time_sleep" "wait_operators" { + depends_on = [data.ibm_container_cluster_config.cluster_config] + create_duration = "45s" +} + +############################################################################## +# Monitoring Instance +############################################################################## + +module "cloud_monitoring" { + source = "terraform-ibm-modules/observability-instances/ibm//modules/cloud_monitoring" + version = "3.5.0" + instance_name = "${var.prefix}-cloud-monitoring" + resource_group_id = module.resource_group.resource_group_id + region = var.region + plan = "graduated-tier" + enable_platform_metrics = var.enable_platform_metrics +} + +############################################################################## +# Monitoring Agents +############################################################################## + +module "monitoring_agents" { + source = "../.." + depends_on = [time_sleep.wait_operators] + cluster_id = module.ocp_base.cluster_id + cluster_resource_group_id = module.resource_group.resource_group_id + # # Monitoring agent + access_key = module.cloud_monitoring.access_key + cloud_monitoring_instance_region = var.region +} diff --git a/examples/obs-agent-iks/outputs.tf b/examples/obs-agent-iks/outputs.tf new file mode 100644 index 0000000..135186b --- /dev/null +++ b/examples/obs-agent-iks/outputs.tf @@ -0,0 +1,11 @@ +############################################################################## +# Outputs +############################################################################## + +#output "myoutput" { +# description = "Description of my output" +# value = "value" +# depends_on = [] +#} + +############################################################################## diff --git a/examples/obs-agent-iks/provider.tf b/examples/obs-agent-iks/provider.tf new file mode 100644 index 0000000..13202b7 --- /dev/null +++ b/examples/obs-agent-iks/provider.tf @@ -0,0 +1,18 @@ +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key + region = var.region +} + +provider "helm" { + kubernetes { + host = data.ibm_container_cluster_config.cluster_config.host + token = data.ibm_container_cluster_config.cluster_config.token + cluster_ca_certificate = data.ibm_container_cluster_config.cluster_config.ca_certificate + } +} + +provider "kubernetes" { + host = data.ibm_container_cluster_config.cluster_config.host + token = data.ibm_container_cluster_config.cluster_config.token + cluster_ca_certificate = data.ibm_container_cluster_config.cluster_config.ca_certificate +} diff --git a/examples/obs-agent-iks/variables.tf b/examples/obs-agent-iks/variables.tf new file mode 100644 index 0000000..8cbcb21 --- /dev/null +++ b/examples/obs-agent-iks/variables.tf @@ -0,0 +1,35 @@ +variable "ibmcloud_api_key" { + type = string + description = "The IBM Cloud api token" + sensitive = true +} + +variable "prefix" { + type = string + description = "A prefix for the name of all resources that are created by this example" + default = "obs-agent-iks" +} + +variable "resource_group" { + type = string + description = "An existing resource group name to use for this example. If not specified, a new resource group is created." + default = null +} + +variable "resource_tags" { + type = list(string) + description = "A list of tags to add to the resources that are created." + default = [] +} + +variable "region" { + type = string + description = "The region where the resources are created." + default = "au-syd" +} + +variable "enable_platform_metrics" { + type = bool + description = "Enable platform metrics" + default = false +} diff --git a/examples/obs-agent-iks/version.tf b/examples/obs-agent-iks/version.tf new file mode 100644 index 0000000..8033b51 --- /dev/null +++ b/examples/obs-agent-iks/version.tf @@ -0,0 +1,26 @@ +terraform { + required_version = ">= 1.9.0" + + # Ensure that there is always 1 example locked into the lowest provider version of the range defined in the main + # module's version.tf (this example), and 1 example that will always use the latest provider version (logs-agent-ocp). + required_providers { + ibm = { + source = "ibm-cloud/ibm" + version = "1.76.1" + } + helm = { + source = "hashicorp/helm" + version = "2.15.0" + } + # The kubernetes provider is not actually required by the module itself, just this example, so OK to use ">=" here instead of locking into a version + kubernetes = { + source = "hashicorp/kubernetes" + version = ">= 2.16.1" + } + # The time provider is not actually required by the module itself, just this example, so OK to use ">=" here instead of locking into a version + time = { + source = "hashicorp/time" + version = ">= 0.9.1" + } + } +} diff --git a/examples/obs-agent-ocp/README.md b/examples/obs-agent-ocp/README.md new file mode 100644 index 0000000..1c29c3a --- /dev/null +++ b/examples/obs-agent-ocp/README.md @@ -0,0 +1,11 @@ +# Monitoring agent + +An example that shows how to deploy Monitoring agent in an Red Hat OpenShift container platform cluster to send Logs directly to a Cloud Monitoring instance. + +The example provisions the following resources: + +- A new resource group, if an existing one is not passed in. +- A basic VPC. +- A Red Hat OpenShift Container Platform VPC cluster. +- An IBM Cloud Monitoring instance. +- Monitoring agent diff --git a/examples/obs-agent-ocp/main.tf b/examples/obs-agent-ocp/main.tf new file mode 100644 index 0000000..b088401 --- /dev/null +++ b/examples/obs-agent-ocp/main.tf @@ -0,0 +1,121 @@ +############################################################################## +# 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 +} + +######################################################################################################################## +# VPC + Subnet + Public Gateway +# +# NOTE: This is a very simple VPC with single subnet in a single zone with a public gateway enabled, that will allow +# all traffic ingress/egress by default. +# For production use cases this would need to be enhanced by adding more subnets and zones for resiliency, and +# ACLs/Security Groups for network security. +######################################################################################################################## + +resource "ibm_is_vpc" "vpc" { + name = "${var.prefix}-vpc" + resource_group = module.resource_group.resource_group_id + address_prefix_management = "auto" + tags = var.resource_tags +} + +resource "ibm_is_public_gateway" "gateway" { + name = "${var.prefix}-gateway-1" + vpc = ibm_is_vpc.vpc.id + resource_group = module.resource_group.resource_group_id + zone = "${var.region}-1" +} + +resource "ibm_is_subnet" "subnet_zone_1" { + name = "${var.prefix}-subnet-1" + vpc = ibm_is_vpc.vpc.id + resource_group = module.resource_group.resource_group_id + zone = "${var.region}-1" + total_ipv4_address_count = 256 + public_gateway = ibm_is_public_gateway.gateway.id +} + +######################################################################################################################## +# OCP VPC cluster (single zone) +######################################################################################################################## + +locals { + cluster_vpc_subnets = { + default = [ + { + id = ibm_is_subnet.subnet_zone_1.id + cidr_block = ibm_is_subnet.subnet_zone_1.ipv4_cidr_block + zone = ibm_is_subnet.subnet_zone_1.zone + } + ] + } + + worker_pools = [ + { + subnet_prefix = "default" + pool_name = "default" # ibm_container_vpc_cluster automatically names default pool "default" (See https://github.com/IBM-Cloud/terraform-provider-ibm/issues/2849) + machine_type = "bx2.4x16" + operating_system = "REDHAT_8_64" + workers_per_zone = 2 # minimum of 2 is allowed when using single zone + } + ] +} + +module "ocp_base" { + source = "terraform-ibm-modules/base-ocp-vpc/ibm" + version = "3.41.7" + resource_group_id = module.resource_group.resource_group_id + region = var.region + tags = var.resource_tags + cluster_name = var.prefix + force_delete_storage = true + vpc_id = ibm_is_vpc.vpc.id + vpc_subnets = local.cluster_vpc_subnets + ocp_version = var.ocp_version + worker_pools = local.worker_pools + access_tags = var.access_tags + ocp_entitlement = var.ocp_entitlement + disable_outbound_traffic_protection = true # set as True to enable outbound traffic +} + +data "ibm_container_cluster_config" "cluster_config" { + cluster_name_id = module.ocp_base.cluster_id + resource_group_id = module.resource_group.resource_group_id +} + +############################################################################## +# Monitoring Instance +############################################################################## + +module "cloud_monitoring" { + source = "terraform-ibm-modules/observability-instances/ibm//modules/cloud_monitoring" + version = "3.5.0" + instance_name = "${var.prefix}-cloud-monitoring" + resource_group_id = module.resource_group.resource_group_id + region = var.region + plan = "graduated-tier" + enable_platform_metrics = var.enable_platform_metrics +} + +############################################################################## +# Monitoring Agents +############################################################################## + +module "monitoring_agents" { + source = "../.." + cluster_id = module.ocp_base.cluster_id + cluster_resource_group_id = module.resource_group.resource_group_id + # Monitoring agent + access_key = module.cloud_monitoring.access_key + # example of how to include / exclude metrics - more info https://cloud.ibm.com/docs/monitoring?topic=monitoring-change_kube_agent#change_kube_agent_log_metrics + metrics_filter = [{ type = "exclude", name = "metricA.*" }, { type = "include", name = "metricB.*" }] + container_filter = [{ type = "exclude", parameter = "kubernetes.namespace.name", name = "kube-system" }] + cloud_monitoring_instance_region = var.region +} diff --git a/examples/obs-agent-ocp/outputs.tf b/examples/obs-agent-ocp/outputs.tf new file mode 100644 index 0000000..135186b --- /dev/null +++ b/examples/obs-agent-ocp/outputs.tf @@ -0,0 +1,11 @@ +############################################################################## +# Outputs +############################################################################## + +#output "myoutput" { +# description = "Description of my output" +# value = "value" +# depends_on = [] +#} + +############################################################################## diff --git a/examples/obs-agent-ocp/provider.tf b/examples/obs-agent-ocp/provider.tf new file mode 100644 index 0000000..13202b7 --- /dev/null +++ b/examples/obs-agent-ocp/provider.tf @@ -0,0 +1,18 @@ +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key + region = var.region +} + +provider "helm" { + kubernetes { + host = data.ibm_container_cluster_config.cluster_config.host + token = data.ibm_container_cluster_config.cluster_config.token + cluster_ca_certificate = data.ibm_container_cluster_config.cluster_config.ca_certificate + } +} + +provider "kubernetes" { + host = data.ibm_container_cluster_config.cluster_config.host + token = data.ibm_container_cluster_config.cluster_config.token + cluster_ca_certificate = data.ibm_container_cluster_config.cluster_config.ca_certificate +} diff --git a/examples/obs-agent-ocp/variables.tf b/examples/obs-agent-ocp/variables.tf new file mode 100644 index 0000000..5202064 --- /dev/null +++ b/examples/obs-agent-ocp/variables.tf @@ -0,0 +1,53 @@ +variable "ibmcloud_api_key" { + type = string + description = "The IBM Cloud api token" + sensitive = true +} + +variable "prefix" { + type = string + description = "A prefix for the name of all resources that are created by this example" + default = "obs-agent-ocp" +} + +variable "resource_group" { + type = string + description = "An existing resource group name to use for this example. If not specified, a new resource group is created." + default = null +} + +variable "resource_tags" { + type = list(string) + description = "A list of tags to add to the resources that are created." + default = [] +} + +variable "access_tags" { + type = list(string) + description = "Optional list of access management tags to add to resources that are created" + default = [] +} + +variable "region" { + type = string + description = "The region where the resources are created." + default = "au-syd" +} + +variable "ocp_version" { + type = string + description = "Version of the OCP cluster to provision" + default = null +} + +variable "ocp_entitlement" { + type = string + description = "Value that is applied to the entitlements for OCP cluster provisioning" + default = null +} + +variable "enable_platform_metrics" { + type = bool + description = "Enable platform metrics" + default = false +} diff --git a/examples/obs-agent-ocp/version.tf b/examples/obs-agent-ocp/version.tf new file mode 100644 index 0000000..10709c5 --- /dev/null +++ b/examples/obs-agent-ocp/version.tf @@ -0,0 +1,20 @@ +terraform { + required_version = ">= 1.3.0" + + # Ensure that there is always 1 example locked into the lowest provider version of the range defined in the main + # module's version.tf (obs-agent-iks), and 1 example that will always use the latest provider version (this exammple). + required_providers { + ibm = { + source = "ibm-cloud/ibm" + version = ">= 1.71.0" + } + helm = { + source = "hashicorp/helm" + version = ">= 2.15.0" + } + kubernetes = { + source = "hashicorp/kubernetes" + version = ">= 2.16.1" + } + } +} diff --git a/ibm_catalog.json b/ibm_catalog.json new file mode 100644 index 0000000..c7de5b9 --- /dev/null +++ b/ibm_catalog.json @@ -0,0 +1,210 @@ +{ + "products": [ + { + "label": "Cloud automation for Monitoring agent", + "name": "deploy-arch-ibm-monitoring-agent", + "product_kind": "solution", + "tags": [ + "ibm_created", + "logging", + "logging_monitoring", + "terraform", + "target_terraform", + "solution" + ], + "keywords": [ + "monitoring", + "agent", + "IaC", + "infrastructure as code", + "terraform", + "solution" + ], + "provider_name": "IBM", + "short_description": "Deploys IBM Monitoring Agent to a cluster", + "long_description": "Solution that supports deploying an IBM Monitoring Agent.", + "offering_docs_url": "https://github.com/terraform-ibm-modules/terraform-ibm-monitoring-agent/blob/main/solutions/fully-configurable/README.md", + "offering_icon_url": "https://raw.githubusercontent.com/terraform-ibm-modules/terraform-ibm-monitoring-agent/main/images/monitoring-icon.svg", + "flavors": [ + { + "label": "Fully Configurable", + "name": "fully-configurable", + "working_directory": "solutions/fully-configurable", + "compliance": {}, + "iam_permissions": [ + { + "service_name": "containers-kubernetes", + "role_crns": [ + "crn:v1:bluemix:public:iam::::serviceRole:Manager", + "crn:v1:bluemix:public:iam::::role:Viewer" + ] + } + ], + "architecture": { + "features": [ + { + "title": "Works with any Openshift or k8s cluster", + "description": "Yes" + }, + { + "title": "Deploys the IBM Monitoring Agent on an existing cluster.", + "description": "Yes" + } + ], + "diagrams": [ + { + "diagram": { + "url": "https://raw.githubusercontent.com/terraform-ibm-modules/terraform-ibm-monitoring-agent/tree/main/reference-architecture/deployable-architecture-monitoring-agent.svg", + "caption": "Monitoring Agent on a cluster", + "type": "image/svg+xml" + }, + "description": "Monitoring Agent deployed on a cluster." + } + ] + }, + "configuration": [ + { + "key": "ibmcloud_api_key", + "required": true + }, + { + "key": "cluster_id", + "custom_config": { + "type": "cluster_var", + "grouping": "deployment", + "original_grouping": "deployment" + }, + "required": true + }, + { + "key": "cluster_resource_group_id", + "custom_config": { + "type": "resource_group", + "grouping": "deployment", + "original_grouping": "deployment", + "config_constraints": { + "identifier": "rg_id" + } + }, + "required": true + }, + { + "key": "access_key", + "required": true + }, + { + "key": "cloud_monitoring_instance_region", + "required": true, + "options": [ + { + "displayname": "eu-gb", + "value": "eu-gb" + }, + { + "displayname": "eu-de", + "value": "eu-de" + }, + { + "displayname": "us-east", + "value": "us-east" + }, + { + "displayname": "us-south", + "value": "us-south" + }, + { + "displayname": "jp-tok", + "value": "jp-tok" + }, + { + "displayname": "au-syd", + "value": "au-syd" + } + ] + }, + { + "key": "is_vpc_cluster", + "required": true + }, + { + "key": "image_registry" + }, + { + "key": "image_tag_digest" + }, + { + "key": "chart" + }, + { + "key": "chart_location" + }, + { + "key": "chart_version" + }, + { + "key": "name" + }, + { + "key": "namespace" + }, + { + "key": "tolerations" + }, + { + "key": "cloud_monitoring_instance_endpoint_type" + }, + { + "key": "metrics_filter" + }, + { + "key": "cluster_config_endpoint_type", + "options": [ + { + "displayname": "Default", + "value": "default" + }, + { + "displayname": "Private", + "value": "private" + }, + { + "displayname": "VPE", + "value": "vpe" + }, + { + "displayname": "Link", + "value": "link" + } + ] + }, + { + "key": "wait_till", + "options": [ + { + "displayname": "Master Node Ready", + "value": "MasterNodeReady" + }, + { + "displayname": "One Worker NodeReady", + "value": "OneWorkerNodeReady" + }, + { + "displayname": "Ingress Ready", + "value": "IngressReady" + }, + { + "displayname": "Normal", + "value": "Normal" + } + ] + }, + { + "key": "wait_till_timeout" + } + ], + "install_type": "fullstack" + } + ] + } + ] +} diff --git a/images/monitoring-icon.svg b/images/monitoring-icon.svg new file mode 100644 index 0000000..3be9c06 --- /dev/null +++ b/images/monitoring-icon.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/kubeconfig/.gitignore b/kubeconfig/.gitignore new file mode 100644 index 0000000..632a28f --- /dev/null +++ b/kubeconfig/.gitignore @@ -0,0 +1,6 @@ +# Ignore everything +* + +# But not these files... +!.gitignore +!README.md diff --git a/kubeconfig/README.md b/kubeconfig/README.md new file mode 100644 index 0000000..e85afee --- /dev/null +++ b/kubeconfig/README.md @@ -0,0 +1,2 @@ +This directory must exist in source control so the `ibm_container_cluster_config` data lookup can use it to place the +config.yml used to connect to a kubernetes cluster. diff --git a/main.tf b/main.tf index b6b879e..5bff0bf 100644 --- a/main.tf +++ b/main.tf @@ -1,13 +1,96 @@ -# -# 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 +############################################################################## +# terraform-ibm-monitoring-agent +############################################################################## + +# Lookup cluster name from ID. The is_vpc_cluster variable defines whether to use the VPC data block or the Classic data block +data "ibm_container_vpc_cluster" "cluster" { + count = var.is_vpc_cluster ? 1 : 0 + name = var.cluster_id + resource_group_id = var.cluster_resource_group_id + wait_till = var.wait_till + wait_till_timeout = var.wait_till_timeout +} + +data "ibm_container_cluster" "cluster" { + count = var.is_vpc_cluster ? 0 : 1 + name = var.cluster_id + resource_group_id = var.cluster_resource_group_id + wait_till = var.wait_till + wait_till_timeout = var.wait_till_timeout +} + +# Download cluster config which is required to connect to cluster +data "ibm_container_cluster_config" "cluster_config" { + cluster_name_id = var.is_vpc_cluster ? data.ibm_container_vpc_cluster.cluster[0].name : data.ibm_container_cluster.cluster[0].name + resource_group_id = var.cluster_resource_group_id + config_dir = "${path.module}/kubeconfig" + endpoint_type = var.cluster_config_endpoint_type != "default" ? var.cluster_config_endpoint_type : null # null value represents default +} + +locals { + # LOCALS + cluster_name = var.is_vpc_cluster ? data.ibm_container_vpc_cluster.cluster[0].resource_name : data.ibm_container_cluster.cluster[0].resource_name # Not publically documented in provider. See https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4485 + collector_host = var.cloud_monitoring_instance_endpoint_type == "private" ? "ingest.private.${var.cloud_monitoring_instance_region}.monitoring.cloud.ibm.com" : "${var.cloud_monitoring_instance_region}.monitoring.cloud.ibm.com" +} + +resource "helm_release" "cloud_monitoring_agent" { + name = var.name + chart = var.chart + repository = var.chart_location + version = var.chart_version + namespace = var.namespace + create_namespace = true + timeout = 1200 + wait = true + recreate_pods = true + force_update = true + reset_values = true + + set { + name = "agent.collectorSettings.collectorHost" + type = "string" + value = local.collector_host + } + set { + name = "global.sysdig.accessKey" + type = "string" + value = var.access_key + } + set { + name = "global.clusterConfig.name" + type = "string" + value = local.cluster_name + } + set { + name = "image.version" + type = "string" + value = var.image_tag_digest + } + set { + name = "image.registry" + type = "string" + value = var.image_registry + } + # Specific to SCC WP, enabled by default + set { + name = "nodeAnalyzer.enabled" + type = "auto" + value = false + } + + values = [yamlencode({ + metrics_filter = var.metrics_filter + }), yamlencode({ + tolerations = var.tolerations + }), yamlencode({ + container_filter = var.container_filter + })] + + provisioner "local-exec" { + command = "${path.module}/scripts/confirm-rollout-status.sh ${var.name} ${var.namespace}" + interpreter = ["/bin/bash", "-c"] + environment = { + KUBECONFIG = data.ibm_container_cluster_config.cluster_config.config_file_path + } + } } diff --git a/outputs.tf b/outputs.tf index 1c0cf4c..586e7dd 100644 --- a/outputs.tf +++ b/outputs.tf @@ -1,30 +1,6 @@ -######################################################################################################################## +############################################################################## # 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/reference-architecture/deployable-architecture-monitoring-agent.svg b/reference-architecture/deployable-architecture-monitoring-agent.svg new file mode 100644 index 0000000..332cbe4 --- /dev/null +++ b/reference-architecture/deployable-architecture-monitoring-agent.svg @@ -0,0 +1,4 @@ + + + +
IBM Cloud
IBM Cloud
Existing Resource Group
Existing Resource Group
Existing Cluster
Existing Cluster
Existing Monitoring Agent
metrics
metrics
Monitoring Instance
Text is not SVG - cannot display
\ No newline at end of file diff --git a/renovate.json b/renovate.json index 8954b60..f8ed3bd 100644 --- a/renovate.json +++ b/renovate.json @@ -1,4 +1,33 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": ["github>terraform-ibm-modules/common-dev-assets:commonRenovateConfig"] + "extends": ["github>terraform-ibm-modules/common-dev-assets:commonRenovateConfig"], + "customManagers": [ + { + "customType": "regex", + "description": "Update docker image digest to latest in variables.tf", + "fileMatch": ["variables.tf$"], + "datasourceTemplate": "docker", + "matchStrings": [ + "default\\s*=\\s*\"(?[\\w.-]+)@(?sha256:[a-f0-9]+)\"\\s*# datasource: (?[^\\s]+)" + ] + }, + { + "customType": "regex", + "description": "Update sysdig-deploy helm chart version to latest in variables.tf", + "fileMatch": ["variables.tf$"], + "matchStrings": ["default\\s*=\\s*\"(?.*?)\"\\s*# registryUrl: charts.sysdig.com\\n"], + "depNameTemplate": "sysdig-deploy", + "datasourceTemplate": "helm", + "registryUrlTemplate": "https://charts.sysdig.com" + } + ], + "packageRules": [ + { + "description": "Bundle image + helm chart updates into the same PR", + "matchPackageNames": ["icr.io/ext/sysdig/agent", "sysdig-deploy"], + "groupName": "Charts and Images", + "commitMessageExtra": "to latest", + "group": true + } + ] } diff --git a/scripts/confirm-rollout-status.sh b/scripts/confirm-rollout-status.sh new file mode 100755 index 0000000..4197143 --- /dev/null +++ b/scripts/confirm-rollout-status.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +set -e + +daemonset=$1 +namespace=$2 + +kubectl rollout status ds "${daemonset}" -n "${namespace}" --timeout 30m diff --git a/solutions/fully-configurable/README.md b/solutions/fully-configurable/README.md new file mode 100644 index 0000000..9e8741f --- /dev/null +++ b/solutions/fully-configurable/README.md @@ -0,0 +1,15 @@ +# Cloud automation for Cloud Monitoring Agent + +This architecture deploys the following monitoring agent on a Red Hat OpenShift cluster: + +* Cloud Monitoring agent + +## Before you begin + +* Make sure that the Red Hat OpenShift Cluster is deployed. + +* Make sure that the Cloud Monitoring for which specific agent are required are deployed. + +![monitoring-agent-deployable-architecture](../../reference-architecture/deployable-architecture-monitoring-agent.svg) + +**NB:** This solution is not intended to be called by one or more other modules since it contains a provider configurations, meaning it is 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) diff --git a/solutions/fully-configurable/catalogValidationValues.json.template b/solutions/fully-configurable/catalogValidationValues.json.template new file mode 100644 index 0000000..f48a7e3 --- /dev/null +++ b/solutions/fully-configurable/catalogValidationValues.json.template @@ -0,0 +1,3 @@ +{ + "ibmcloud_api_key": $VALIDATION_APIKEY +} diff --git a/solutions/fully-configurable/kubeconfig/.gitignore b/solutions/fully-configurable/kubeconfig/.gitignore new file mode 100644 index 0000000..632a28f --- /dev/null +++ b/solutions/fully-configurable/kubeconfig/.gitignore @@ -0,0 +1,6 @@ +# Ignore everything +* + +# But not these files... +!.gitignore +!README.md diff --git a/solutions/fully-configurable/kubeconfig/README.md b/solutions/fully-configurable/kubeconfig/README.md new file mode 100644 index 0000000..e85afee --- /dev/null +++ b/solutions/fully-configurable/kubeconfig/README.md @@ -0,0 +1,2 @@ +This directory must exist in source control so the `ibm_container_cluster_config` data lookup can use it to place the +config.yml used to connect to a kubernetes cluster. diff --git a/solutions/fully-configurable/main.tf b/solutions/fully-configurable/main.tf new file mode 100644 index 0000000..6c502bc --- /dev/null +++ b/solutions/fully-configurable/main.tf @@ -0,0 +1,33 @@ +############################################################################## +# Monitoring Agents +############################################################################## + +data "ibm_container_cluster_config" "cluster_config" { + cluster_name_id = var.is_vpc_cluster ? data.ibm_container_vpc_cluster.cluster[0].name : data.ibm_container_cluster.cluster[0].name + resource_group_id = var.cluster_resource_group_id + config_dir = "${path.module}/kubeconfig" + endpoint_type = var.cluster_config_endpoint_type != "default" ? var.cluster_config_endpoint_type : null +} + +module "monitoring_agent" { + source = "../.." + cluster_id = var.cluster_id + cluster_resource_group_id = var.cluster_resource_group_id + cluster_config_endpoint_type = var.cluster_config_endpoint_type + wait_till = var.wait_till + wait_till_timeout = var.wait_till_timeout + is_vpc_cluster = var.is_vpc_cluster + # Cloud Monitoring Agent + name = var.name + namespace = var.namespace + cloud_monitoring_instance_endpoint_type = var.cloud_monitoring_instance_endpoint_type + access_key = var.access_key + metrics_filter = var.metrics_filter + cloud_monitoring_instance_region = var.cloud_monitoring_instance_region + tolerations = var.tolerations + chart = var.chart + chart_location = var.chart_location + chart_version = var.chart_version + image_registry = var.image_registry + image_tag_digest = var.image_tag_digest +} diff --git a/examples/advanced/provider.tf b/solutions/fully-configurable/outputs.tf similarity index 58% rename from examples/advanced/provider.tf rename to solutions/fully-configurable/outputs.tf index 2080946..586e7dd 100644 --- a/examples/advanced/provider.tf +++ b/solutions/fully-configurable/outputs.tf @@ -1,8 +1,6 @@ ############################################################################## -# Provider config +# Outputs ############################################################################## -provider "ibm" { - ibmcloud_api_key = var.ibmcloud_api_key - region = var.region -} + +############################################################################## diff --git a/solutions/fully-configurable/provider.tf b/solutions/fully-configurable/provider.tf new file mode 100644 index 0000000..5f2229e --- /dev/null +++ b/solutions/fully-configurable/provider.tf @@ -0,0 +1,33 @@ +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key +} + +provider "kubernetes" { + host = data.ibm_container_cluster_config.cluster_config.host + token = data.ibm_container_cluster_config.cluster_config.token + cluster_ca_certificate = data.ibm_container_cluster_config.cluster_config.ca_certificate +} + +provider "helm" { + kubernetes { + host = data.ibm_container_cluster_config.cluster_config.host + token = data.ibm_container_cluster_config.cluster_config.token + cluster_ca_certificate = data.ibm_container_cluster_config.cluster_config.ca_certificate + } +} + +# Retrieve information about an existing VPC cluster +data "ibm_container_vpc_cluster" "cluster" { + count = var.is_vpc_cluster ? 1 : 0 + name = var.cluster_id + wait_till = var.wait_till + wait_till_timeout = var.wait_till_timeout +} + +# Retrieve information about an existing Classic cluster +data "ibm_container_cluster" "cluster" { + count = var.is_vpc_cluster ? 0 : 1 + name = var.cluster_id + wait_till = var.wait_till + wait_till_timeout = var.wait_till_timeout +} diff --git a/solutions/fully-configurable/variables.tf b/solutions/fully-configurable/variables.tf new file mode 100644 index 0000000..db7f566 --- /dev/null +++ b/solutions/fully-configurable/variables.tf @@ -0,0 +1,147 @@ +variable "ibmcloud_api_key" { + type = string + description = "The IBM Cloud API key." + sensitive = true +} + +############################################################################## +# Cluster variables +############################################################################## + +variable "cluster_id" { + type = string + description = "The ID of the cluster to deploy the agent in." + nullable = false +} + +variable "cluster_resource_group_id" { + type = string + description = "The resource group ID of the cluster." + nullable = false +} + +variable "cluster_config_endpoint_type" { + description = "Specify the type of endpoint to use to access the cluster configuration. Possible values: `default`, `private`, `vpe`, `link`. The `default` value uses the default endpoint of the cluster." + type = string + default = "private" + nullable = false # use default if null is passed in +} + +variable "is_vpc_cluster" { + type = bool + description = "Specify true if the target cluster for the DA is a VPC cluster, false if it is classic cluster." + default = true +} + +variable "wait_till" { + description = "Specify the stage when Terraform should mark the cluster resource creation as completed. Supported values: `MasterNodeReady`, `OneWorkerNodeReady`, `IngressReady`, `Normal`." + type = string + default = "Normal" +} + +variable "wait_till_timeout" { + description = "Timeout for wait_till in minutes." + type = number + default = 90 +} + +############################################################################## +# Cloud Monitoring variables +############################################################################## + +variable "access_key" { + type = string + description = "The access key that is used by the IBM Cloud Monitoring agent to communicate with the instance." + sensitive = true + nullable = false +} + +variable "cloud_monitoring_instance_region" { + type = string + description = "The name of the region where the IBM Cloud Monitoring instance is created. This name is used to construct the ingestion endpoint." + nullable = false +} + +variable "cloud_monitoring_instance_endpoint_type" { + type = string + description = "Specify the IBM Cloud Monitoring instance endpoint type (`public` or `private`) to use to construct the ingestion endpoint." + default = "private" +} + +variable "metrics_filter" { + type = list(object({ + type = string + name = string + })) + description = "To filter on custom metrics, specify the IBM Cloud Monitoring metrics to include or exclude. [Learn more](https://cloud.ibm.com/docs/monitoring?topic=monitoring-change_kube_agent#change_kube_agent_inc_exc_metrics) and [here](https://github.com/terraform-ibm-modules/terraform-ibm-monitoring-agent/tree/main/solutions/fully-configurable/DA-types.md)." + default = [] # [{ type = "exclude", name = "metricA.*" }, { type = "include", name = "metricB.*" }] +} + +variable "name" { + description = "The name of the IBM Cloud Monitoring agent that is used to name the Kubernetes and Helm resources on the cluster." + type = string + default = "sysdig-agent" +} + +variable "namespace" { + type = string + description = "The namespace to deploy the IBM Cloud Monitoring agent in. Default value: `ibm-observe`." + default = "ibm-observe" + nullable = false +} + +variable "tolerations" { + description = "The list of tolerations to apply to the IBM Cloud Monitoring agent. The default operator value `Exists` matches any taint on any node except the master node. [Learn more](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/)" + type = list(object({ + key = optional(string) + operator = optional(string) + value = optional(string) + effect = optional(string) + tolerationSeconds = optional(number) + })) + default = [ + { + operator = "Exists" + }, + { + operator = "Exists" + effect = "NoSchedule" + key = "node-role.kubernetes.io/master" + } + ] +} + +variable "chart" { + description = "The name of the Helm chart to deploy." + type = string + default = "sysdig-deploy" # Replace with the actual chart location if different + nullable = false +} + +variable "chart_location" { + description = "The location of the Cloud Monitoring agent helm chart." + type = string + default = "https://charts.sysdig.com" # Replace with the actual repository URL if different + nullable = false +} + +variable "chart_version" { + description = "The version of the Cloud Monitoring agent helm chart to deploy." + type = string + default = "1.79.0" # registryUrl: charts.sysdig.com + nullable = false +} + +variable "image_registry" { + description = "The image registry to use for the Cloud Monitoring agent." + type = string + default = "icr.io/ext/sysdig/agent" + nullable = false +} + +variable "image_tag_digest" { + description = "The image tag digest to use for the Cloud Monitoring agent." + type = string + default = "13.8.1@sha256:e5d1c63edf07c9f861249432c00873e32141381c15fbcff80b90a12b272dc0b9" # datasource: icr.io/ext/sysdig/agent + nullable = false +} diff --git a/solutions/fully-configurable/version.tf b/solutions/fully-configurable/version.tf new file mode 100644 index 0000000..ef2dbfc --- /dev/null +++ b/solutions/fully-configurable/version.tf @@ -0,0 +1,20 @@ +terraform { + # module uses nullable feature which is only available in versions >= 1.1.0 + required_version = ">= 1.9.0" + + required_providers { + # Lock DA into an exact provider version - renovate automation will keep it updated + ibm = { + source = "ibm-cloud/ibm" + version = "1.76.1" + } + helm = { + source = "hashicorp/helm" + version = "2.16.0" + } + kubernetes = { + source = "hashicorp/kubernetes" + version = "2.33.0" + } + } +} diff --git a/tests/README.md b/tests/README.md index dfd6842..05d524e 100644 --- a/tests/README.md +++ b/tests/README.md @@ -1,5 +1,3 @@ # Tests For information about how to create and run tests, see [Validation tests](https://terraform-ibm-modules.github.io/documentation/#/tests) in the project documentation. - - diff --git a/tests/other_test.go b/tests/other_test.go deleted file mode 100644 index 88d360d..0000000 --- a/tests/other_test.go +++ /dev/null @@ -1,2 +0,0 @@ -// Tests in this file are NOT run in the PR pipeline. They are run in the continuous testing pipeline along with the ones in pr_test.go -package test diff --git a/tests/pr_test.go b/tests/pr_test.go index 8867ed0..b71e397 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -1,60 +1,263 @@ -// Tests in this file are run in the PR pipeline and the continuous testing pipeline +// Tests in this file are run in the PR pipeline package test import ( + "fmt" + "math/rand/v2" + "os" + "strings" "testing" + "github.com/gruntwork-io/terratest/modules/files" + "github.com/gruntwork-io/terratest/modules/logger" + "github.com/gruntwork-io/terratest/modules/random" + "github.com/gruntwork-io/terratest/modules/terraform" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/cloudinfo" "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/testhelper" + "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/testschematic" ) -// Use existing resource group -const resourceGroup = "geretain-test-resources" +const resourceGroup = "geretain-test-observability-agents" +const fullyConfigurableSolutionDir = "solutions/fully-configurable" +const fullyConfigurableSolutionKubeconfigDir = "solutions/fully-configurable/kubeconfig" +const terraformDirMonitoringAgentIKS = "examples/obs-agent-iks" +const terraformDirMonitoringAgentROKS = "examples/obs-agent-ocp" -// Ensure every example directory has a corresponding test -const advancedExampleDir = "examples/advanced" -const basicExampleDir = "examples/basic" +var sharedInfoSvc *cloudinfo.CloudInfoService + +// Currently only including regions that Event Notification support +var validRegions = []string{ + "au-syd", + "eu-gb", + "eu-de", + "eu-es", + "us-south", +} + +// TestMain will be run before any parallel tests, used to set up a shared InfoService object to track region usage +// for multiple tests +func TestMain(m *testing.M) { + sharedInfoSvc, _ = cloudinfo.NewCloudInfoServiceFromEnv("TF_VAR_ibmcloud_api_key", cloudinfo.CloudInfoServiceOptions{}) + + os.Exit(m.Run()) +} + +func setupOptions(t *testing.T, prefix string, terraformDir string) *testhelper.TestOptions { -func setupOptions(t *testing.T, prefix string, dir string) *testhelper.TestOptions { options := testhelper.TestOptionsDefaultWithVars(&testhelper.TestOptions{ Testing: t, - TerraformDir: dir, + TerraformDir: terraformDir, Prefix: prefix, ResourceGroup: resourceGroup, + IgnoreUpdates: testhelper.Exemptions{ // Ignore for consistency check + List: []string{ + "module.monitoring_agent.helm_release.cloud_monitoring_agent", + }, + }, + CloudInfoService: sharedInfoSvc, }) + + // add ocp entitlement to keep costs down for tests + if terraformDir == terraformDirMonitoringAgentROKS { + options.TerraformVars["ocp_entitlement"] = "cloud_pak" + } + + options.TerraformVars["enable_platform_metrics"] = false + return options } -// Consistency test for the basic example -func TestRunBasicExample(t *testing.T) { +func TestFullyConfigurableSolution(t *testing.T) { t.Parallel() - options := setupOptions(t, "mod-template-basic", basicExampleDir) + var region = validRegions[rand.IntN(len(validRegions))] + // ------------------------------------------------------------------------------------------------------ + // Deploy SLZ ROKS Cluster and Monitoring instances since it is needed to deploy Monitoring Agent + // ------------------------------------------------------------------------------------------------------ + + prefix := fmt.Sprintf("slz-%s", strings.ToLower(random.UniqueId())) + realTerraformDir := "./resources" + tempTerraformDir, _ := files.CopyTerraformFolderToTemp(realTerraformDir, fmt.Sprintf(prefix+"-%s", strings.ToLower(random.UniqueId()))) + + // Verify ibmcloud_api_key variable is set + checkVariable := "TF_VAR_ibmcloud_api_key" + val, present := os.LookupEnv(checkVariable) + require.True(t, present, checkVariable+" environment variable not set") + require.NotEqual(t, "", val, checkVariable+" environment variable is empty") + + logger.Log(t, "Tempdir: ", tempTerraformDir) + existingTerraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ + TerraformDir: tempTerraformDir, + Vars: map[string]any{ + "prefix": prefix, + "region": region, + }, + // Set Upgrade to true to ensure latest version of providers and modules are used by terratest. + // This is the same as setting the -upgrade=true flag with terraform. + Upgrade: true, + }) + + terraform.WorkspaceSelectOrNew(t, existingTerraformOptions, prefix) + _, existErr := terraform.InitAndApplyE(t, existingTerraformOptions) + + if existErr != nil { + assert.True(t, existErr == nil, "Init and Apply of temp resources (SLZ-ROKS and Monitoring Instances) failed") + } else { + + options := testschematic.TestSchematicOptionsDefault(&testschematic.TestSchematicOptions{ + Testing: t, + Prefix: "monitoring-agent", + TarIncludePatterns: []string{ + "*.tf", + "kubeconfig/*.*", + "scripts/*.*", + fullyConfigurableSolutionDir + "/*.*", + fullyConfigurableSolutionKubeconfigDir + "/*.*", + }, + IgnoreUpdates: testhelper.Exemptions{ // Ignore for consistency check + List: []string{ + "module.monitoring_agent.helm_release.cloud_monitoring_agent", + }, + }, + ResourceGroup: resourceGroup, + TemplateFolder: fullyConfigurableSolutionDir, + Tags: []string{"test-schematic"}, + DeleteWorkspaceOnFail: false, + WaitJobCompleteMinutes: 60, + Region: region, + }) + + options.TerraformVars = []testschematic.TestSchematicTerraformVar{ + {Name: "ibmcloud_api_key", Value: options.RequiredEnvironmentVars["TF_VAR_ibmcloud_api_key"], DataType: "string", Secure: true}, + {Name: "cloud_monitoring_instance_region", Value: region, DataType: "string"}, + {Name: "cluster_id", Value: terraform.Output(t, existingTerraformOptions, "cluster_id"), DataType: "string"}, + {Name: "cluster_resource_group_id", Value: terraform.Output(t, existingTerraformOptions, "cluster_resource_group_id"), DataType: "string"}, + {Name: "access_key", Value: terraform.Output(t, existingTerraformOptions, "access_key"), DataType: "string", Secure: true}, + } + + err := options.RunSchematicTest() + assert.Nil(t, err, "This should not have errored") + } + + // Check if "DO_NOT_DESTROY_ON_FAILURE" is set + envVal, _ := os.LookupEnv("DO_NOT_DESTROY_ON_FAILURE") + // Destroy the temporary existing resources if required + if t.Failed() && strings.ToLower(envVal) == "true" { + fmt.Println("Terratest failed. Debug the test and delete resources manually.") + } else { + logger.Log(t, "START: Destroy (existing resources)") + terraform.Destroy(t, existingTerraformOptions) + terraform.WorkspaceDelete(t, existingTerraformOptions, prefix) + logger.Log(t, "END: Destroy (existing resources)") + } +} + +func TestFullyConfigurableUpgradeSolution(t *testing.T) { + t.Parallel() + var region = validRegions[rand.IntN(len(validRegions))] + + // ------------------------------------------------------------------------------------------------------ + // Deploy SLZ ROKS Cluster and Monitoring instances since it is needed to deploy Monitoring Agent + // ------------------------------------------------------------------------------------------------------ + + prefix := fmt.Sprintf("slz-%s", strings.ToLower(random.UniqueId())) + realTerraformDir := "./resources" + tempTerraformDir, _ := files.CopyTerraformFolderToTemp(realTerraformDir, fmt.Sprintf(prefix+"-%s", strings.ToLower(random.UniqueId()))) + + // Verify ibmcloud_api_key variable is set + checkVariable := "TF_VAR_ibmcloud_api_key" + val, present := os.LookupEnv(checkVariable) + require.True(t, present, checkVariable+" environment variable not set") + require.NotEqual(t, "", val, checkVariable+" environment variable is empty") + + logger.Log(t, "Tempdir: ", tempTerraformDir) + existingTerraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ + TerraformDir: tempTerraformDir, + Vars: map[string]any{ + "prefix": prefix, + "region": region, + }, + // Set Upgrade to true to ensure latest version of providers and modules are used by terratest. + // This is the same as setting the -upgrade=true flag with terraform. + Upgrade: true, + }) + + terraform.WorkspaceSelectOrNew(t, existingTerraformOptions, prefix) + _, existErr := terraform.InitAndApplyE(t, existingTerraformOptions) + + if existErr != nil { + assert.True(t, existErr == nil, "Init and Apply of temp resources (SLZ-ROKS and Monitoring Instances) failed") + } else { + + options := testschematic.TestSchematicOptionsDefault(&testschematic.TestSchematicOptions{ + Testing: t, + Prefix: "monitoring-agent", + TarIncludePatterns: []string{ + "*.tf", + "kubeconfig/*.*", + "scripts/*.*", + fullyConfigurableSolutionDir + "/*.*", + fullyConfigurableSolutionKubeconfigDir + "/*.*", + }, + ResourceGroup: resourceGroup, + TemplateFolder: fullyConfigurableSolutionDir, + Tags: []string{"test-schematic"}, + DeleteWorkspaceOnFail: false, + WaitJobCompleteMinutes: 60, + Region: region, + }) + + options.TerraformVars = []testschematic.TestSchematicTerraformVar{ + {Name: "ibmcloud_api_key", Value: options.RequiredEnvironmentVars["TF_VAR_ibmcloud_api_key"], DataType: "string", Secure: true}, + {Name: "cloud_monitoring_instance_region", Value: region, DataType: "string"}, + {Name: "cluster_id", Value: terraform.Output(t, existingTerraformOptions, "cluster_id"), DataType: "string"}, + {Name: "cluster_resource_group_id", Value: terraform.Output(t, existingTerraformOptions, "cluster_resource_group_id"), DataType: "string"}, + {Name: "access_key", Value: terraform.Output(t, existingTerraformOptions, "access_key"), DataType: "string", Secure: true}, + } + + err := options.RunSchematicUpgradeTest() + assert.Nil(t, err, "This should not have errored") + } + + // Check if "DO_NOT_DESTROY_ON_FAILURE" is set + envVal, _ := os.LookupEnv("DO_NOT_DESTROY_ON_FAILURE") + // Destroy the temporary existing resources if required + if t.Failed() && strings.ToLower(envVal) == "true" { + fmt.Println("Terratest failed. Debug the test and delete resources manually.") + } else { + logger.Log(t, "START: Destroy (existing resources)") + terraform.Destroy(t, existingTerraformOptions) + terraform.WorkspaceDelete(t, existingTerraformOptions, prefix) + logger.Log(t, "END: Destroy (existing resources)") + } +} + +func TestRunAgentVpcKubernetes(t *testing.T) { + t.Parallel() + + options := setupOptions(t, "obs-agent-iks", terraformDirMonitoringAgentIKS) output, err := options.RunTestConsistency() assert.Nil(t, err, "This should not have errored") assert.NotNil(t, output, "Expected some output") } -func TestRunAdvancedExample(t *testing.T) { +func TestRunAgentVpcOcp(t *testing.T) { t.Parallel() - options := setupOptions(t, "mod-template-adv", advancedExampleDir) - + options := setupOptions(t, "obs-agent-roks", terraformDirMonitoringAgentROKS) output, err := options.RunTestConsistency() assert.Nil(t, err, "This should not have errored") assert.NotNil(t, output, "Expected some output") } -// Upgrade test (using advanced example) -func TestRunUpgradeExample(t *testing.T) { +func TestRunAgentClassicKubernetes(t *testing.T) { t.Parallel() - options := setupOptions(t, "mod-template-adv-upg", advancedExampleDir) - - output, err := options.RunTestUpgrade() - if !options.UpgradeTestSkipped { - assert.Nil(t, err, "This should not have errored") - assert.NotNil(t, output, "Expected some output") - } + options := setupOptions(t, "obs-agent-iks", terraformDirMonitoringAgentIKS) + output, err := options.RunTestConsistency() + assert.Nil(t, err, "This should not have errored") + assert.NotNil(t, output, "Expected some output") } diff --git a/tests/resources/README.md b/tests/resources/README.md new file mode 100644 index 0000000..4bb3621 --- /dev/null +++ b/tests/resources/README.md @@ -0,0 +1 @@ +The terraform code in this directory is used by the existing resource test in tests/pr_test.go diff --git a/tests/resources/main.tf b/tests/resources/main.tf new file mode 100644 index 0000000..4609707 --- /dev/null +++ b/tests/resources/main.tf @@ -0,0 +1,104 @@ +############################################################################## +# 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 +} + +######################################################################################################################## +# VPC + Subnet + Public Gateway +# +# NOTE: This is a very simple VPC with single subnet in a single zone with a public gateway enabled, that will allow +# all traffic ingress/egress by default. +# For production use cases this would need to be enhanced by adding more subnets and zones for resiliency, and +# ACLs/Security Groups for network security. +######################################################################################################################## + +resource "ibm_is_vpc" "vpc" { + name = "${var.prefix}-vpc" + resource_group = module.resource_group.resource_group_id + address_prefix_management = "auto" + tags = var.resource_tags +} + +resource "ibm_is_public_gateway" "gateway" { + name = "${var.prefix}-gateway-1" + vpc = ibm_is_vpc.vpc.id + resource_group = module.resource_group.resource_group_id + zone = "${var.region}-1" +} + +resource "ibm_is_subnet" "subnet_zone_1" { + name = "${var.prefix}-subnet-1" + vpc = ibm_is_vpc.vpc.id + resource_group = module.resource_group.resource_group_id + zone = "${var.region}-1" + total_ipv4_address_count = 256 + public_gateway = ibm_is_public_gateway.gateway.id +} + +######################################################################################################################## +# OCP VPC cluster (single zone) +######################################################################################################################## + +locals { + cluster_vpc_subnets = { + default = [ + { + id = ibm_is_subnet.subnet_zone_1.id + cidr_block = ibm_is_subnet.subnet_zone_1.ipv4_cidr_block + zone = ibm_is_subnet.subnet_zone_1.zone + } + ] + } + + worker_pools = [ + { + subnet_prefix = "default" + pool_name = "default" # ibm_container_vpc_cluster automatically names default pool "default" (See https://github.com/IBM-Cloud/terraform-provider-ibm/issues/2849) + machine_type = "bx2.4x16" + workers_per_zone = 2 # minimum of 2 is allowed when using single zone + operating_system = "REDHAT_8_64" + } + ] +} + +locals { + cluster_name = "${var.prefix}-cluster" +} + +module "ocp_base" { + source = "terraform-ibm-modules/base-ocp-vpc/ibm" + version = "3.43.1" + resource_group_id = module.resource_group.resource_group_id + region = var.region + tags = var.resource_tags + cluster_name = local.cluster_name + force_delete_storage = true + vpc_id = ibm_is_vpc.vpc.id + vpc_subnets = local.cluster_vpc_subnets + worker_pools = local.worker_pools + access_tags = [] + disable_outbound_traffic_protection = true # set as True to enable outbound traffic +} + +############################################################################## +# Monitoring: +# - Cloud Monitoring instance +############################################################################## + +module "cloud_monitoring" { + source = "terraform-ibm-modules/observability-instances/ibm//modules/cloud_monitoring" + version = "3.5.0" + instance_name = "${var.prefix}-cloud-monitoring" + resource_group_id = module.resource_group.resource_group_id + region = var.region + plan = "graduated-tier" + tags = var.resource_tags + enable_platform_metrics = false +} diff --git a/tests/resources/outputs.tf b/tests/resources/outputs.tf new file mode 100644 index 0000000..fbcde56 --- /dev/null +++ b/tests/resources/outputs.tf @@ -0,0 +1,39 @@ +############################################################################## +# Outputs +############################################################################## + +output "region" { + value = var.region + description = "Region where SLZ ROKS Cluster is deployed." +} + +output "cluster_id" { + value = module.ocp_base.cluster_id + description = "ID of the cluster." +} + +output "cluster_crn" { + value = module.ocp_base.cluster_crn + description = "CRN of the cluster." +} + +output "cluster_resource_group_id" { + value = module.ocp_base.resource_group_id + description = "Resource group ID of the cluster." +} + +output "cluster_name" { + value = local.cluster_name + description = "Name of the cluster." +} + +output "instance_id" { + value = module.cloud_monitoring.crn + description = "The cloud monitoring instance crn." +} + +output "access_key" { + value = module.cloud_monitoring.access_key + description = "The access key of the provisioned IBM Cloud Monitoring instance." + sensitive = true +} diff --git a/tests/resources/provider.tf b/tests/resources/provider.tf new file mode 100644 index 0000000..df45ef5 --- /dev/null +++ b/tests/resources/provider.tf @@ -0,0 +1,4 @@ +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key + region = var.region +} diff --git a/tests/resources/variables.tf b/tests/resources/variables.tf new file mode 100644 index 0000000..07a76de --- /dev/null +++ b/tests/resources/variables.tf @@ -0,0 +1,29 @@ +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." + default = "us-south" +} + +variable "prefix" { + type = string + description = "Prefix to append to all resources created by this example." + default = "agent-da" +} + +variable "resource_tags" { + type = list(string) + description = "Optional list of tags to be added to created resources." + default = ["logs-agent-ocp"] +} + +variable "resource_group" { + type = string + description = "The name of an existing resource group to provision resources in. If not specified, a new resource group is created with the `prefix` variable." + default = null +} diff --git a/tests/resources/version.tf b/tests/resources/version.tf new file mode 100644 index 0000000..2ac74ba --- /dev/null +++ b/tests/resources/version.tf @@ -0,0 +1,10 @@ + +terraform { + required_version = ">= 1.9.0" + required_providers { + ibm = { + source = "ibm-cloud/ibm" + version = ">= 1.76.1" + } + } +} diff --git a/tests/scripts/post-validation-deploy-base-ocp-and-monitoring-instances.sh b/tests/scripts/post-validation-deploy-base-ocp-and-monitoring-instances.sh new file mode 100755 index 0000000..39e7b62 --- /dev/null +++ b/tests/scripts/post-validation-deploy-base-ocp-and-monitoring-instances.sh @@ -0,0 +1,20 @@ +#! /bin/bash + +######################################################################################################################## +## This script is used by the catalog pipeline to destroy the SLZ OCP Cluster, which was provisioned as a ## +## prerequisite for the WAS extension that is published to the catalog ## +######################################################################################################################## + +set -e + +TERRAFORM_SOURCE_DIR="tests/resources" +TF_VARS_FILE="terraform.tfvars" + +( + cd ${TERRAFORM_SOURCE_DIR} + echo "Destroying prerequisite SLZ OCP Cluster and Monitoring instances .." + terraform destroy -input=false -auto-approve -var-file=${TF_VARS_FILE} || exit 1 + rm -f "${TF_VARS_FILE}" + + echo "Post-validation completed successfully" +) diff --git a/tests/scripts/pre-validation-deploy-base-ocp-and-monitoring-instances.sh b/tests/scripts/pre-validation-deploy-base-ocp-and-monitoring-instances.sh new file mode 100755 index 0000000..7b6db41 --- /dev/null +++ b/tests/scripts/pre-validation-deploy-base-ocp-and-monitoring-instances.sh @@ -0,0 +1,54 @@ +#! /bin/bash + +############################################################################################################ +## This script is used by the catalog pipeline to deploy the SLZ ROKS and Monitoring instances, +## which are the prerequisites for the Monitoring Agent extension. +############################################################################################################ + +set -e + +DA_DIR="solutions/fully-configurable" +TERRAFORM_SOURCE_DIR="tests/resources" +JSON_FILE="${DA_DIR}/catalogValidationValues.json" +REGION="us-south" +TF_VARS_FILE="terraform.tfvars" + +( + cwd=$(pwd) + cd ${TERRAFORM_SOURCE_DIR} + echo "Provisioning prerequisite SLZ ROKS CLUSTER and Monitoring Instances .." + terraform init || exit 1 + # $VALIDATION_APIKEY is available in the catalog runtime + { + echo "ibmcloud_api_key=\"${VALIDATION_APIKEY}\"" + echo "region=\"${REGION}\"" + echo "prefix=\"slz-$(openssl rand -hex 2)\"" + } >> ${TF_VARS_FILE} + terraform apply -input=false -auto-approve -var-file=${TF_VARS_FILE} || exit 1 + + region_var_name="region" + cluster_id_var_name="cluster_id" + cluster_id_value=$(terraform output -state=terraform.tfstate -raw cluster_id) + cluster_resource_group_id_var_name="cluster_resource_group_id" + cluster_resource_group_id_value=$(terraform output -state=terraform.tfstate -raw cluster_resource_group_id) + cloud_monitoring_instance_region_var_name="instance_region" + access_key_var_name="access_key" + access_key_value=$(terraform output -state=terraform.tfstate -raw access_key) + + echo "Appending '${cluster_id_var_name}' and '${region_var_name}' input variable values to ${JSON_FILE}.." + + cd "${cwd}" + jq -r --arg region_var_name "${region_var_name}" \ + --arg region_var_value "${REGION}" \ + --arg cluster_id_var_name "${cluster_id_var_name}" \ + --arg cluster_id_value "${cluster_id_value}" \ + --arg cluster_resource_group_id_var_name "${cluster_resource_group_id_var_name}" \ + --arg cluster_resource_group_id_value "${cluster_resource_group_id_value}" \ + --arg access_key_var_name "${access_key_var_name}" \ + --arg access_key_value "${access_key_value}" \ + --arg cloud_monitoring_instance_region_var_name "${cloud_monitoring_instance_region_var_name}" \ + --arg cloud_monitoring_instance_region_var_value "${REGION}" \ + '. + {($region_var_name): $region_var_value, ($cluster_id_var_name): $cluster_id_value, ($cluster_resource_group_id_var_name): $cluster_resource_group_id_value, ($cloud_monitoring_instance_region_var_name): $cloud_monitoring_instance_region_var_value, ($access_key_var_name): $access_key_value}' "${JSON_FILE}" > tmpfile && mv tmpfile "${JSON_FILE}" || exit 1 + + echo "Pre-validation complete successfully" +) diff --git a/variables.tf b/variables.tf index a9d9899..f38bc5f 100644 --- a/variables.tf +++ b/variables.tf @@ -1,36 +1,175 @@ -######################################################################################################################## -# Input Variables -######################################################################################################################## +############################################################################## +# Cluster variables +############################################################################## -# -# Developer tips: -# - Below are some common module input variables -# - They should be updated for input variables applicable to the module being added -# - Use variable validation when possible -# +variable "cluster_id" { + type = string + description = "The ID of the cluster you wish to deploy the agent in" + nullable = false +} -variable "name" { +variable "cluster_resource_group_id" { type = string - description = "A descriptive name used to identify the resource instance." + description = "The Resource Group ID of the cluster" + nullable = false +} + +variable "cluster_config_endpoint_type" { + description = "Specify which type of endpoint to use for for cluster config access: 'default', 'private', 'vpe', 'link'. 'default' value will use the default endpoint of the cluster." + type = string + default = "default" + nullable = false # use default if null is passed in + validation { + error_message = "Invalid Endpoint Type! Valid values are 'default', 'private', 'vpe', or 'link'" + condition = contains(["default", "private", "vpe", "link"], var.cluster_config_endpoint_type) + } +} + +variable "is_vpc_cluster" { + description = "Specify true if the target cluster for the monitoring agent is a VPC cluster, false if it is a classic cluster." + type = bool + default = true } -variable "plan" { +variable "wait_till" { + description = "To avoid long wait times when you run your Terraform code, you can specify the stage when you want Terraform to mark the cluster resource creation as completed. Depending on what stage you choose, the cluster creation might not be fully completed and continues to run in the background. However, your Terraform code can continue to run without waiting for the cluster to be fully created. Supported args are `MasterNodeReady`, `OneWorkerNodeReady`, `IngressReady` and `Normal`" type = string - description = "The name of the plan type supported by service." - default = "standard" + default = "Normal" + validation { - condition = contains(["standard", "cos-one-rate-plan"], var.plan) - error_message = "The specified pricing plan is not available. The following plans are supported: 'standard', 'cos-one-rate-plan'" + error_message = "`wait_till` value must be one of `MasterNodeReady`, `OneWorkerNodeReady`, `IngressReady` or `Normal`." + condition = contains([ + "MasterNodeReady", + "OneWorkerNodeReady", + "IngressReady", + "Normal" + ], var.wait_till) } } -variable "resource_group_id" { +variable "wait_till_timeout" { + description = "Timeout for wait_till in minutes." + type = number + default = 90 +} + +############################################################################## +# Cloud Monitoring variables +############################################################################## + +variable "access_key" { type = string - description = "The ID of the resource group where you want to create the service." + description = "Access key used by the IBM Cloud Monitoring agent to communicate with the instance" + sensitive = true + nullable = false +} + +variable "cloud_monitoring_instance_region" { + type = string + description = "The IBM Cloud Monitoring instance region. Used to construct the ingestion endpoint." + nullable = false +} + +variable "cloud_monitoring_instance_endpoint_type" { + type = string + description = "Specify the IBM Cloud Monitoring instance endpoint type (public or private) to use. Used to construct the ingestion endpoint." + default = "private" + validation { + error_message = "The specified endpoint type can be private or public only." + condition = contains(["private", "public"], var.cloud_monitoring_instance_endpoint_type) + } +} + +variable "metrics_filter" { + type = list(object({ + type = string + name = string + })) + description = "To filter custom metrics, specify the Cloud Monitoring metrics to include or to exclude. See https://cloud.ibm.com/docs/monitoring?topic=monitoring-change_kube_agent#change_kube_agent_inc_exc_metrics." + default = [] + validation { + condition = alltrue([for filter in var.metrics_filter : can(regex("^(include|exclude)$", filter.type)) && filter.name != ""]) + error_message = "The specified `type` for the `metrics_filter` is not valid. Specify either `include` or `exclude`. The `name` field cannot be empty." + } } -variable "resource_tags" { - type = list(string) - description = "List of resource tag to associate with the instance." +variable "container_filter" { + type = list(object({ + type = string + parameter = string + name = string + })) + description = "To filter custom containers, specify which containers to include or exclude from metrics collection for the cloud monitoring agent. See https://cloud.ibm.com/docs/monitoring?topic=monitoring-change_kube_agent#change_kube_agent_filter_data." default = [] + validation { + condition = length(var.container_filter) == 0 || can(regex("^(include|exclude)$", var.container_filter[0].type)) + error_message = "Invalid input for `container_filter`. Valid options for 'type' are: `include` and `exclude`. If empty, no containers are included or excluded." + } +} + +variable "name" { + description = "Cloud Monitoring agent name. Used for naming all kubernetes and helm resources on the cluster." + type = string + default = "sysdig-agent" +} + +variable "namespace" { + type = string + description = "Namespace where to deploy the Cloud Monitoring agent. Default value is 'ibm-observe'" + default = "ibm-observe" + nullable = false +} + +variable "tolerations" { + description = "List of tolerations to apply to Cloud Monitoring agent." + type = list(object({ + key = optional(string) + operator = optional(string) + value = optional(string) + effect = optional(string) + tolerationSeconds = optional(number) + })) + default = [{ + operator = "Exists" + }, + { + operator = "Exists" + effect = "NoSchedule" + key = "node-role.kubernetes.io/master" + }] +} + +variable "chart" { + description = "The name of the Helm chart to deploy." + type = string + default = "sysdig-deploy" # Replace with the actual chart location if different + nullable = false +} + +variable "chart_location" { + description = "The location of the Cloud Monitoring agent helm chart." + type = string + default = "https://charts.sysdig.com" # Replace with the actual repository URL if different + nullable = false +} + +variable "chart_version" { + description = "The version of the Cloud Monitoring agent helm chart to deploy." + type = string + default = "1.79.0" # registryUrl: charts.sysdig.com + nullable = false +} + +variable "image_registry" { + description = "The image registry to use for the Cloud Monitoring agent." + type = string + default = "icr.io/ext/sysdig/agent" + nullable = false +} + +variable "image_tag_digest" { + description = "The image tag digest to use for the Cloud Monitoring agent." + type = string + default = "13.8.1@sha256:e5d1c63edf07c9f861249432c00873e32141381c15fbcff80b90a12b272dc0b9" # datasource: icr.io/ext/sysdig/agent + nullable = false } diff --git a/version.tf b/version.tf index e51de7f..2faf16c 100644 --- a/version.tf +++ b/version.tf @@ -11,8 +11,12 @@ terraform { required_providers { ibm = { - source = "IBM-Cloud/ibm" - version = ">= 1.71.2, < 2.0.0" + source = "ibm-cloud/ibm" + version = ">= 1.76.1, <2.0.0" + } + helm = { + source = "hashicorp/helm" + version = ">= 2.15.0, <3.0.0" } } }