diff --git a/.secrets.baseline b/.secrets.baseline index a5828d7d..1496b7e9 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -3,7 +3,7 @@ "files": "go.sum|^.secrets.baseline$", "lines": null }, - "generated_at": "2023-12-09T09:50:09Z", + "generated_at": "2024-10-02T13:57:09Z", "plugins_used": [ { "name": "AWSKeyDetector" @@ -76,7 +76,28 @@ "name": "TwilioKeyDetector" } ], - "results": {}, + "results": { + "README.md": [ + { + "hashed_secret": "3f0155e75563ab3adc0505000a86da5baa207d1f", + "is_secret": false, + "is_verified": false, + "line_number": 64, + "type": "Secret Keyword", + "verified_result": null + } + ], + "modules/logs-agent/README.md": [ + { + "hashed_secret": "3f0155e75563ab3adc0505000a86da5baa207d1f", + "is_secret": false, + "is_verified": false, + "line_number": 36, + "type": "Secret Keyword", + "verified_result": null + } + ] + }, "version": "0.13.1+ibm.62.dss", "word_list": { "file": null, diff --git a/README.md b/README.md index 14dfdf70..df6657e8 100644 --- a/README.md +++ b/README.md @@ -6,21 +6,30 @@ [![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) -This module deploys the following observability agents to a Red Hat OpenShift Container Platform or Kubernetes cluster: +This module deploys the following observability agents to an IBM Cloud Red Hat OpenShift Container Platform or Kubernetes cluster: -- [Logging agent](https://cloud.ibm.com/docs/log-analysis?topic=log-analysis-log_analysis_agent) +- [Logs agent](https://cloud.ibm.com/docs/cloud-logs?topic=cloud-logs-agent-about) - [Monitoring agent](https://cloud.ibm.com/docs/monitoring?topic=monitoring-about-collect-metrics) +- [DEPRECATED: Log Analysis agent](https://cloud.ibm.com/docs/log-analysis?topic=log-analysis-log_analysis_agent) + +> [!IMPORTANT] +> The IBM Log Analysis service is deprecated. [IBM Cloud Logs](https://www.ibm.com/products/cloud-logs) is the replacement service and is now the default agent created with this module. + ## Overview * [terraform-ibm-observability-agents](#terraform-ibm-observability-agents) +* [Submodules](./modules) + * [logs-agent](./modules/logs-agent) * [Examples](./examples) - * [Deploy basic observability agents](./examples/basic) + * [Monitoring agent + Cloud Logs agent on Kubernetes using CSE ingress endpoint with an apikey](./examples/obs-agent-iks) + * [Monitoring agent + Cloud Logs agent on OCP using VPE ingress endpoint with a Trusted Profile](./examples/obs-agent-ocp) * [Contributing](#contributing) ## terraform-ibm-observability-agents + ### Usage ```hcl @@ -39,7 +48,7 @@ data "ibm_container_cluster_config" "cluster_config" { provider "ibm" { # update this value with your IBM Cloud API key value - ibmcloud_api_key = "api key value" # pragma: allowlist secret + ibmcloud_api_key = "XXXXXXXXXXXXXXXXX" } provider "helm" { @@ -48,6 +57,12 @@ provider "helm" { token = data.ibm_container_cluster_config.cluster_config.token cluster_ca_certificate = data.ibm_container_cluster_config.cluster_config.ca_certificate } + # IBM Cloud credentials are required to authenticate to the helm repo + registry { + url = "oci://icr.io/ibm/observe/logs-agent-helm" + username = "iamapikey" + password = "XXXXXXXXXXXXXXXXX" # replace with an IBM cloud apikey + } } # ############################################################################ @@ -60,14 +75,16 @@ module "observability_agents" { 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 agents will be installed cluster_resource_group_id = "resource group id" # update this with the Id of your IBM Cloud resource group - log_analysis_ingestion_key = "XXXXXXXX" - log_analysis_instance_region = "us-south" cloud_monitoring_access_key = "XXXXXXXX" cloud_monitoring_instance_region = "us-south" + # Logs Agent variables + logs_agent_trusted_profile = "XXXXXXXX" + cloud_logs_ingress_endpoint = ".ingress.us-south.logs.cloud.ibm.com" + cloud_logs_ingress_port = 443 } ``` -### Configuration for Kubernetes metadata filtering in the logging agent +### (DEPRECATED) Log Analysis agent configuration for Kubernetes metadata filtering You can configure the logging agent to filter log lines according to the Kubernetes resources metadata by setting the exclusion and inclusion parameters. @@ -92,32 +109,27 @@ For more information, see [Configuration for Kubernetes Metadata Filtering](http ### Required IAM access policies You need the following permissions to run this module. -- IAM Services - - **IBM Cloud Activity Tracker** service - - `Viewer` platform access - - `Reader` service access - - **IBM Cloud Monitoring** service - - `Viewer` platform access - - `Reader` service access - - **IBM Log Analysis** service - - `Viewer` platform access - - `Reader` service access - - **Kubernetes** service - - `Viewer` platform access - - `Manager` service access +- Service + - **Resource group only** + - `Viewer` access on the specific resource group + - **Kubernetes** service + - `Viewer` platform access + - `Manager` service access ### Requirements | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.1.0 | -| [helm](#requirement\_helm) | >= 2.8.0, <3.0.0 | -| [ibm](#requirement\_ibm) | >= 1.59.0, <2.0.0 | +| [terraform](#requirement\_terraform) | >= 1.9.0 | +| [helm](#requirement\_helm) | >= 2.15.0, <3.0.0 | +| [ibm](#requirement\_ibm) | >= 1.69.2, <2.0.0 | ### Modules -No modules. +| Name | Source | Version | +|------|--------|---------| +| [logs\_agent](#module\_logs\_agent) | ./modules/logs-agent | n/a | ### Resources @@ -133,6 +145,8 @@ No modules. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| +| [cloud\_logs\_ingress\_endpoint](#input\_cloud\_logs\_ingress\_endpoint) | The host for IBM Cloud Logs ingestion. Ensure you use the ingress endpoint. See https://cloud.ibm.com/docs/cloud-logs?topic=cloud-logs-endpoints_ingress. | `string` | `null` | no | +| [cloud\_logs\_ingress\_port](#input\_cloud\_logs\_ingress\_port) | The target port for the IBM Cloud Logs ingestion endpoint. The port must be 443 if you connect by using a VPE gateway, or port 3443 when you connect by using CSEs. | `number` | `3443` | no | | [cloud\_monitoring\_access\_key](#input\_cloud\_monitoring\_access\_key) | Access key used by the IBM Cloud Monitoring agent to communicate with the instance | `string` | `null` | no | | [cloud\_monitoring\_add\_cluster\_name](#input\_cloud\_monitoring\_add\_cluster\_name) | If true, configure the cloud monitoring agent to attach a tag containing the cluster name to all metric data. | `bool` | `true` | no | | [cloud\_monitoring\_agent\_name](#input\_cloud\_monitoring\_agent\_name) | Cloud Monitoring agent name. Used for naming all kubernetes and helm resources on the cluster. | `string` | `"sysdig-agent"` | no | @@ -148,18 +162,32 @@ No modules. | [cluster\_id](#input\_cluster\_id) | The ID of the cluster you wish to deploy the agents 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 | | [is\_vpc\_cluster](#input\_is\_vpc\_cluster) | Specify true if the target cluster for the observability agents is a VPC cluster, false if it is a classic cluster. | `bool` | `true` | no | -| [log\_analysis\_add\_cluster\_name](#input\_log\_analysis\_add\_cluster\_name) | If true, configure the log analysis agent to attach a tag containing the cluster name to all log messages. | `bool` | `true` | no | -| [log\_analysis\_agent\_custom\_line\_exclusion](#input\_log\_analysis\_agent\_custom\_line\_exclusion) | Log Analysis agent custom configuration for line exclusion setting LOGDNA\_K8S\_METADATA\_LINE\_EXCLUSION. See https://github.com/logdna/logdna-agent-v2/blob/master/docs/KUBERNETES.md#configuration-for-kubernetes-metadata-filtering for more info. | `string` | `null` | no | -| [log\_analysis\_agent\_custom\_line\_inclusion](#input\_log\_analysis\_agent\_custom\_line\_inclusion) | Log Analysis agent custom configuration for line inclusion setting LOGDNA\_K8S\_METADATA\_LINE\_INCLUSION. See https://github.com/logdna/logdna-agent-v2/blob/master/docs/KUBERNETES.md#configuration-for-kubernetes-metadata-filtering for more info. | `string` | `null` | no | -| [log\_analysis\_agent\_name](#input\_log\_analysis\_agent\_name) | Log Analysis agent name. Used for naming all kubernetes and helm resources on the cluster. | `string` | `"logdna-agent"` | no | -| [log\_analysis\_agent\_namespace](#input\_log\_analysis\_agent\_namespace) | Namespace where to deploy the Log Analysis agent. Default value is 'ibm-observe' | `string` | `"ibm-observe"` | no | -| [log\_analysis\_agent\_tags](#input\_log\_analysis\_agent\_tags) | List of tags to associate to all log records that the agent collects so that you can identify the agent's data quicker in the logging UI. NOTE: Use the 'log\_analysis\_add\_cluster\_name' variable to add the cluster name as a tag. | `list(string)` | `[]` | no | -| [log\_analysis\_agent\_tolerations](#input\_log\_analysis\_agent\_tolerations) | List of tolerations to apply to Log Analysis agent. |
list(object({
key = optional(string)
operator = optional(string)
value = optional(string)
effect = optional(string)
tolerationSeconds = optional(number)
}))
|
[
{
"operator": "Exists"
}
]
| no | -| [log\_analysis\_enabled](#input\_log\_analysis\_enabled) | Deploy IBM Cloud Logging agent | `bool` | `true` | no | -| [log\_analysis\_endpoint\_type](#input\_log\_analysis\_endpoint\_type) | Specify the IBM Log Analysis instance endpoint type (public or private) to use. Used to construct the ingestion endpoint. | `string` | `"private"` | no | -| [log\_analysis\_ingestion\_key](#input\_log\_analysis\_ingestion\_key) | Ingestion key for the IBM Cloud Logging agent to communicate with the instance | `string` | `null` | no | -| [log\_analysis\_instance\_region](#input\_log\_analysis\_instance\_region) | The IBM Log Analysis instance region. Used to construct the ingestion endpoint. | `string` | `null` | no | -| [log\_analysis\_secret\_name](#input\_log\_analysis\_secret\_name) | The name of the secret which will store the ingestion key. | `string` | `"logdna-agent"` | no | +| [log\_analysis\_add\_cluster\_name](#input\_log\_analysis\_add\_cluster\_name) | DEPRECATED: If true, configure the Log Analysis agent to attach a tag containing the cluster name to all log messages. | `bool` | `true` | no | +| [log\_analysis\_agent\_custom\_line\_exclusion](#input\_log\_analysis\_agent\_custom\_line\_exclusion) | DEPRECATED: Log Analysis agent custom configuration for line exclusion setting LOGDNA\_K8S\_METADATA\_LINE\_EXCLUSION. See https://github.com/logdna/logdna-agent-v2/blob/master/docs/KUBERNETES.md#configuration-for-kubernetes-metadata-filtering for more info. | `string` | `null` | no | +| [log\_analysis\_agent\_custom\_line\_inclusion](#input\_log\_analysis\_agent\_custom\_line\_inclusion) | DEPRECATED: Log Analysis agent custom configuration for line inclusion setting LOGDNA\_K8S\_METADATA\_LINE\_INCLUSION. See https://github.com/logdna/logdna-agent-v2/blob/master/docs/KUBERNETES.md#configuration-for-kubernetes-metadata-filtering for more info. | `string` | `null` | no | +| [log\_analysis\_agent\_name](#input\_log\_analysis\_agent\_name) | DEPRECATED: Log Analysis agent name. Used for naming all kubernetes and helm resources on the cluster. | `string` | `"logdna-agent"` | no | +| [log\_analysis\_agent\_namespace](#input\_log\_analysis\_agent\_namespace) | DEPRECATED: Namespace where to deploy the Log Analysis agent. Default value is 'ibm-observe' | `string` | `"ibm-observe"` | no | +| [log\_analysis\_agent\_tags](#input\_log\_analysis\_agent\_tags) | DEPRECATED: List of tags to associate to all log records that the agent collects so that you can identify the agent's data quicker in the logging UI. NOTE: Use the 'log\_analysis\_add\_cluster\_name' variable to add the cluster name as a tag. | `list(string)` | `[]` | no | +| [log\_analysis\_agent\_tolerations](#input\_log\_analysis\_agent\_tolerations) | DEPRECATED: List of tolerations to apply to Log Analysis agent. |
list(object({
key = optional(string)
operator = optional(string)
value = optional(string)
effect = optional(string)
tolerationSeconds = optional(number)
}))
|
[
{
"operator": "Exists"
}
]
| no | +| [log\_analysis\_enabled](#input\_log\_analysis\_enabled) | DEPRECATED: Deploy IBM Cloud Log Analysis agent | `bool` | `false` | no | +| [log\_analysis\_endpoint\_type](#input\_log\_analysis\_endpoint\_type) | DEPRECATED: Specify the IBM Log Analysis instance endpoint type (public or private) to use. Used to construct the ingestion endpoint. | `string` | `"private"` | no | +| [log\_analysis\_ingestion\_key](#input\_log\_analysis\_ingestion\_key) | DEPRECATED: Ingestion key for the Log Analysis agent to communicate with the instance | `string` | `null` | no | +| [log\_analysis\_instance\_region](#input\_log\_analysis\_instance\_region) | DEPRECATED: The IBM Log Analysis instance region. Used to construct the ingestion endpoint. | `string` | `null` | no | +| [log\_analysis\_secret\_name](#input\_log\_analysis\_secret\_name) | DEPRECATED: The name of the secret which will store the Log Analysis ingestion key. | `string` | `"logdna-agent"` | no | +| [logs\_agent\_additional\_log\_source\_paths](#input\_logs\_agent\_additional\_log\_source\_paths) | The list of additional log sources. By default, the Logs agent collects logs from a single source at `/var/log/containers/*.log`. | `list(string)` | `[]` | no | +| [logs\_agent\_additional\_metadata](#input\_logs\_agent\_additional\_metadata) | The list of additional metadata fields to add to the routed logs. |
list(object({
key = optional(string)
value = optional(string)
}))
| `[]` | no | +| [logs\_agent\_enable\_scc](#input\_logs\_agent\_enable\_scc) | Whether to enable creation of Security Context Constraints in Openshift. When installing on an OpenShift cluster, this setting is mandatory to configure permissions for pods within your cluster. | `bool` | `true` | no | +| [logs\_agent\_enabled](#input\_logs\_agent\_enabled) | Whether to deploy the Logs agent. | `bool` | `true` | no | +| [logs\_agent\_exclude\_log\_source\_paths](#input\_logs\_agent\_exclude\_log\_source\_paths) | The list of log sources to exclude. Specify the paths that the Logs agent ignores. | `list(string)` | `[]` | no | +| [logs\_agent\_iam\_api\_key](#input\_logs\_agent\_iam\_api\_key) | The IBM Cloud API key for the Logs agent to authenticate and communicate with the IBM Cloud Logs. It is required if `logs_agent_iam_mode` is set to `IAMAPIKey`. | `string` | `null` | no | +| [logs\_agent\_iam\_environment](#input\_logs\_agent\_iam\_environment) | IAM authentication Environment: `Production` or `PrivateProduction` or `Staging` or `PrivateStaging`. `Production` specifies the public endpoint & `PrivateProduction` specifies the private endpoint. | `string` | `"PrivateProduction"` | no | +| [logs\_agent\_iam\_mode](#input\_logs\_agent\_iam\_mode) | IAM authentication mode: `TrustedProfile` or `IAMAPIKey`. | `string` | `"TrustedProfile"` | no | +| [logs\_agent\_log\_source\_namespaces](#input\_logs\_agent\_log\_source\_namespaces) | The list of namespaces from which logs should be forwarded by agent. If namespaces are not listed, logs from all namespaces will be sent. | `list(string)` | `[]` | no | +| [logs\_agent\_name](#input\_logs\_agent\_name) | The name of the Logs agent. The name is used in all Kubernetes and Helm resources in the cluster. | `string` | `"logs-agent"` | no | +| [logs\_agent\_namespace](#input\_logs\_agent\_namespace) | The namespace where the Logs agent is deployed. The default value is `ibm-observe`. | `string` | `"ibm-observe"` | no | +| [logs\_agent\_selected\_log\_source\_paths](#input\_logs\_agent\_selected\_log\_source\_paths) | The list of specific log sources paths. Logs will only be collected from the specified log source paths. If no paths are specified, it will send logs from `/var/log/containers`. | `list(string)` | `[]` | no | +| [logs\_agent\_tolerations](#input\_logs\_agent\_tolerations) | List of tolerations to apply to Logs agent. The default value means a pod will run on every node. |
list(object({
key = optional(string)
operator = optional(string)
value = optional(string)
effect = optional(string)
tolerationSeconds = optional(number)
}))
|
[
{
"operator": "Exists"
}
]
| no | +| [logs\_agent\_trusted\_profile](#input\_logs\_agent\_trusted\_profile) | The IBM Cloud trusted profile ID. Used only when `logs_agent_iam_mode` is set to `TrustedProfile`. The trusted profile must have an IBM Cloud Logs `Sender` role. | `string` | `null` | no | ### Outputs diff --git a/cra-config.yaml b/cra-config.yaml index 492111a4..71209dcb 100644 --- a/cra-config.yaml +++ b/cra-config.yaml @@ -1,7 +1,7 @@ # 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/basic" # Target directory for CRA scan. If not provided, the CRA Scan will not be run. + - 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: "0e6e7b5a-817d-4344-ab6f-e5d7a9c49520" # SCC profile ID (currently set to the FSCloud 1.4.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. diff --git a/examples/basic/README.md b/examples/basic/README.md deleted file mode 100644 index ab150588..00000000 --- a/examples/basic/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Deploy basic observability agents - -An end-to-end example that uses the module's default variable values. - -The example sets up the logging agent for [Kubernetes metadata filtering](https://github.com/logdna/logdna-agent-v2/blob/3.8/docs/KUBERNETES.md#configuration-for-kubernetes-metadata-filtering). - -The example configures the agent to include all log lines coming from the `default` Kubernetes namespace and excludes anything with a label `app.kubernetes.io/name` and value `sample-app` or an annotation `annotation.user` with the value `sample-user`. diff --git a/examples/basic/version.tf b/examples/basic/version.tf deleted file mode 100644 index a62da592..00000000 --- a/examples/basic/version.tf +++ /dev/null @@ -1,27 +0,0 @@ -terraform { - # module uses nullable feature which is only available in versions >= 1.1.0 - required_version = ">= 1.1.0" - - required_providers { - ibm = { - source = "ibm-cloud/ibm" - version = ">= 1.59.0" - } - helm = { - source = "hashicorp/helm" - version = ">= 2.8.0" - } - kubernetes = { - source = "hashicorp/kubernetes" - version = ">= 2.16.1" - } - time = { - source = "hashicorp/time" - version = ">= 0.9.1" - } - logdna = { - source = "logdna/logdna" - version = ">= 1.14.2" - } - } -} diff --git a/examples/obs-agent-iks/README.md b/examples/obs-agent-iks/README.md new file mode 100644 index 00000000..760a7b5b --- /dev/null +++ b/examples/obs-agent-iks/README.md @@ -0,0 +1,11 @@ +# Monitoring agent + Cloud Logs agent on Kubernetes using CSE ingress endpoint with an apikey + +An example that shows how to deploy Logs agents and Monitoring agent in a Kubernetes cluster to send Logs directly to IBM Cloud Logs and Cloud Monitoring instance respectively. + +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. +- A Service ID with `Sender` role to `logs` service and an apikey. +- An IBM Cloud Logs and Cloud Monitoring instance +- Logs agents and Monitoring agent diff --git a/examples/basic/main.tf b/examples/obs-agent-iks/main.tf similarity index 53% rename from examples/basic/main.tf rename to examples/obs-agent-iks/main.tf index 0d60c1d0..df63ec39 100644 --- a/examples/basic/main.tf +++ b/examples/obs-agent-iks/main.tf @@ -3,36 +3,36 @@ ############################################################################## module "resource_group" { - source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-resource-group.git?ref=v1.1.6" + 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 } ############################################################################## -# Observability Instances +# Service ID with logs sender role + apikey ############################################################################## -module "observability_instances" { - source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-observability-instances?ref=v2.18.1" - providers = { - logdna.at = logdna.at - logdna.ld = logdna.ld +# As a `Sender`, you can send logs to your IBM Cloud Logs service instance - but not query or tail logs. This role is meant to be used by agents and routers sending logs. +module "iam_service_id" { + source = "terraform-ibm-modules/iam-service-id/ibm" + version = "1.2.0" + iam_service_id_name = "${var.prefix}-service-id" + iam_service_id_description = "Logs Agent service id" + iam_service_id_apikey_provision = true + iam_service_policies = { + logs = { + roles = ["Sender"] + resources = [{ + service = "logs" + }] + } } - resource_group_id = module.resource_group.resource_group_id - region = var.region - log_analysis_plan = "7-day" - cloud_monitoring_plan = "graduated-tier" - activity_tracker_provision = false - enable_platform_logs = false - enable_platform_metrics = false - cloud_logs_provision = false - log_analysis_instance_name = "${var.prefix}-log-analysis" - cloud_monitoring_instance_name = "${var.prefix}-cloud-monitoring" } ############################################################################## -# Create VPC and Cluster +# Create VPC and IKS Cluster ############################################################################## resource "ibm_is_vpc" "example_vpc" { @@ -42,14 +42,6 @@ resource "ibm_is_vpc" "example_vpc" { tags = var.resource_tags } -resource "ibm_is_public_gateway" "public_gateway" { - count = var.is_vpc_cluster ? 1 : 0 - name = "${var.prefix}-gateway-1" - vpc = ibm_is_vpc.example_vpc[0].id - resource_group = module.resource_group.resource_group_id - zone = "${var.region}-1" -} - resource "ibm_is_subnet" "testacc_subnet" { count = var.is_vpc_cluster ? 1 : 0 name = "${var.prefix}-subnet" @@ -57,26 +49,14 @@ resource "ibm_is_subnet" "testacc_subnet" { zone = "${var.region}-1" total_ipv4_address_count = 256 resource_group = module.resource_group.resource_group_id - public_gateway = ibm_is_public_gateway.public_gateway[0].id -} - -resource "ibm_resource_instance" "cos_instance" { - count = var.is_openshift ? 1 : 0 - name = "${var.prefix}-cos" - service = "cloud-object-storage" - plan = "standard" - location = "global" - resource_group_id = module.resource_group.resource_group_id - tags = var.resource_tags } # Lookup the current default kube version data "ibm_container_cluster_versions" "cluster_versions" {} locals { - default_version = var.is_openshift ? "${data.ibm_container_cluster_versions.cluster_versions.default_openshift_version}_openshift" : data.ibm_container_cluster_versions.cluster_versions.default_kube_version + default_version = data.ibm_container_cluster_versions.cluster_versions.default_kube_version } -# Create either a VPC or classic cluster, depending on the is_vpc_cluster variable resource "ibm_container_vpc_cluster" "cluster" { count = var.is_vpc_cluster ? 1 : 0 name = var.prefix @@ -84,21 +64,14 @@ resource "ibm_container_vpc_cluster" "cluster" { kube_version = local.default_version flavor = "bx2.4x16" worker_count = "2" - entitlement = var.is_openshift ? "cloud_pak" : null - cos_instance_crn = var.is_openshift ? ibm_resource_instance.cos_instance[0].id : null force_delete_storage = true - wait_till = "Normal" + wait_till = "IngressReady" zones { subnet_id = ibm_is_subnet.testacc_subnet[0].id name = "${var.region}-1" } resource_group_id = module.resource_group.resource_group_id tags = var.resource_tags - - timeouts { - delete = "2h" - create = "3h" - } } resource "ibm_container_cluster" "cluster" { @@ -109,7 +82,6 @@ resource "ibm_container_cluster" "cluster" { default_pool_size = 2 hardware = "shared" kube_version = local.default_version - entitlement = var.is_openshift ? "cloud_pak" : null force_delete_storage = true machine_type = "b3c.4x16" public_vlan_id = ibm_network_vlan.public_vlan[0].id @@ -124,6 +96,10 @@ resource "ibm_container_cluster" "cluster" { } } +locals { + cluster_name_id = var.is_vpc_cluster ? ibm_container_vpc_cluster.cluster[0].id : ibm_container_cluster.cluster[0].id +} + resource "ibm_network_vlan" "public_vlan" { count = var.is_vpc_cluster ? 0 : 1 datacenter = var.datacenter @@ -137,39 +113,56 @@ resource "ibm_network_vlan" "private_vlan" { } data "ibm_container_cluster_config" "cluster_config" { - cluster_name_id = var.is_vpc_cluster ? ibm_container_vpc_cluster.cluster[0].id : ibm_container_cluster.cluster[0].id + cluster_name_id = local.cluster_name_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 = "5s" + create_duration = "45s" } ############################################################################## -# Observability Agents +# Observability Instance ############################################################################## +module "observability_instances" { + source = "terraform-ibm-modules/observability-instances/ibm" + version = "2.19.1" + providers = { + logdna.at = logdna.at + logdna.ld = logdna.ld + } + resource_group_id = module.resource_group.resource_group_id + region = var.region + cloud_logs_plan = "standard" + cloud_monitoring_plan = "graduated-tier" + enable_platform_logs = false + enable_platform_metrics = false + cloud_logs_instance_name = "${var.prefix}-cloud-logs" + cloud_monitoring_instance_name = "${var.prefix}-cloud-monitoring" +} + +############################################################################## +# Observability Agents +############################################################################## module "observability_agents" { - source = "../.." - depends_on = [time_sleep.wait_operators] - is_vpc_cluster = var.is_vpc_cluster - cluster_id = var.is_vpc_cluster ? ibm_container_vpc_cluster.cluster[0].id : ibm_container_cluster.cluster[0].id - cluster_resource_group_id = module.resource_group.resource_group_id - log_analysis_instance_region = module.observability_instances.region - log_analysis_ingestion_key = module.observability_instances.log_analysis_ingestion_key - cloud_monitoring_access_key = module.observability_instances.cloud_monitoring_access_key - log_analysis_agent_tags = var.resource_tags - log_analysis_add_cluster_name = true - # 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 - cloud_monitoring_metrics_filter = [{ type = "exclude", name = "metricA.*" }, { type = "include", name = "metricB.*" }] - cloud_monitoring_agent_tags = var.resource_tags + source = "../.." + depends_on = [time_sleep.wait_operators] + cluster_id = local.cluster_name_id + is_vpc_cluster = var.is_vpc_cluster + cluster_resource_group_id = module.resource_group.resource_group_id + # Logs Agent + logs_agent_enabled = true + logs_agent_iam_mode = "IAMAPIKey" + logs_agent_iam_api_key = module.iam_service_id.service_id_apikey + cloud_logs_ingress_endpoint = module.observability_instances.cloud_logs_ingress_private_endpoint + cloud_logs_ingress_port = 3443 + logs_agent_enable_scc = false # only true for Openshift + # # Monitoring agent + cloud_monitoring_enabled = true + cloud_monitoring_access_key = module.observability_instances.cloud_monitoring_access_key cloud_monitoring_instance_region = module.observability_instances.region - # Log Analysis agent custom settings to setup Kubernetes metadata logs filtering by setting - # LOGDNA_K8S_METADATA_LINE_INCLUSION and LOGDNA_K8S_METADATA_LINE_EXCLUSION in the agent daemonset definition - # Ref https://github.com/logdna/logdna-agent-v2/blob/3.8/docs/KUBERNETES.md#configuration-for-kubernetes-metadata-filtering - log_analysis_agent_custom_line_exclusion = "label.app.kubernetes.io/name:sample-app\\, annotation.user:sample-user" - log_analysis_agent_custom_line_inclusion = "namespace:default" } diff --git a/examples/basic/outputs.tf b/examples/obs-agent-iks/outputs.tf similarity index 100% rename from examples/basic/outputs.tf rename to examples/obs-agent-iks/outputs.tf diff --git a/examples/basic/provider.tf b/examples/obs-agent-iks/provider.tf similarity index 67% rename from examples/basic/provider.tf rename to examples/obs-agent-iks/provider.tf index 656f3bf9..5c11f46f 100644 --- a/examples/basic/provider.tf +++ b/examples/obs-agent-iks/provider.tf @@ -3,6 +3,26 @@ provider "ibm" { 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 + } + # IBM Cloud credentials are required to authenticate to the helm repo + registry { + url = "oci://icr.io/ibm/observe/logs-agent-helm" + username = "iamapikey" + password = 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 +} + locals { at_endpoint = "https://api.${var.region}.logging.cloud.ibm.com" } @@ -18,16 +38,3 @@ provider "logdna" { servicekey = module.observability_instances.log_analysis_resource_key != null ? module.observability_instances.log_analysis_resource_key : "" url = local.at_endpoint } - -provider "kubernetes" { - host = data.ibm_container_cluster_config.cluster_config.host - token = data.ibm_container_cluster_config.cluster_config.token -} - -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 - } -} diff --git a/examples/basic/variables.tf b/examples/obs-agent-iks/variables.tf similarity index 63% rename from examples/basic/variables.tf rename to examples/obs-agent-iks/variables.tf index ae6e193a..0f42a3c5 100644 --- a/examples/basic/variables.tf +++ b/examples/obs-agent-iks/variables.tf @@ -4,40 +4,34 @@ variable "ibmcloud_api_key" { sensitive = true } -variable "is_openshift" { - type = bool - description = "Defines whether this is an OpenShift or Kubernetes cluster" - default = true -} - -variable "is_vpc_cluster" { - type = bool - description = "Specify true if the target cluster for the observability agents is a VPC cluster, false if it is classic cluster." - default = true -} - variable "prefix" { type = string - description = "Prefix for name of all resource created by this example" - default = "test-obs-agents" + 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 unset a new resource group will be created" + 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 = "Optional list of tags to be added to created resources" + description = "A list of tags to add to the resources that are created." default = [] } variable "region" { type = string - description = "Region where resources are created" - default = "ca-tor" + description = "The region where the resources are created." + default = "au-syd" +} + +variable "is_vpc_cluster" { + type = bool + description = "Specify true if the target cluster for the observability agents is a VPC cluster, false if it is classic cluster." + default = true } variable "datacenter" { diff --git a/examples/obs-agent-iks/version.tf b/examples/obs-agent-iks/version.tf new file mode 100644 index 00000000..a52dc79c --- /dev/null +++ b/examples/obs-agent-iks/version.tf @@ -0,0 +1,31 @@ +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 (obs-agent-ocp). + required_providers { + ibm = { + source = "ibm-cloud/ibm" + version = "1.69.2" + } + 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" + } + # The logdna provider is not actually required by the module itself, just this example, so OK to use ">=" here instead of locking into a version + logdna = { + source = "logdna/logdna" + version = ">= 1.14.2" + } + } +} diff --git a/examples/obs-agent-ocp/README.md b/examples/obs-agent-ocp/README.md new file mode 100644 index 00000000..cc466f2c --- /dev/null +++ b/examples/obs-agent-ocp/README.md @@ -0,0 +1,13 @@ +# Monitoring agent + Cloud Logs agent on OCP using VPE ingress endpoint with a Trusted Profile + +An example that shows how to deploy Logs Routing agents and Monitoring agent in an Red Hat OpenShift container platform cluster to send Logs directly to IBM Cloud Logs and Cloud Monitoring instance respectively. + +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. +- A Trusted Profile with `Sender` role to `logs` service. +- An IBM Cloud Logs and Cloud Monitoring instance. +- A Virtual Private Endpoint for Cloud Logs. +- Logs agents and Monitoring agent diff --git a/examples/obs-agent-ocp/main.tf b/examples/obs-agent-ocp/main.tf new file mode 100644 index 00000000..95c56b24 --- /dev/null +++ b/examples/obs-agent-ocp/main.tf @@ -0,0 +1,206 @@ +############################################################################## +# 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 +} + +############################################################################## +# Trusted Profile +############################################################################## + +locals { + logs_agent_namespace = "ibm-observe" + logs_agent_name = "logs-agent" +} + + +module "trusted_profile" { + source = "terraform-ibm-modules/trusted-profile/ibm" + version = "1.0.4" + trusted_profile_name = "${var.prefix}-profile" + trusted_profile_description = "Logs agent Trusted Profile" + # As a `Sender`, you can send logs to your IBM Cloud Logs service instance - but not query or tail logs. This role is meant to be used by agents and routers sending logs. + trusted_profile_policies = [{ + roles = ["Sender"] + resources = [{ + service = "logs" + }] + }] + # Set up fine-grained authorization for `logs-agent` running in ROKS cluster in `ibm-observe` namespace. + trusted_profile_links = [{ + cr_type = "ROKS_SA" + links = [{ + crn = module.ocp_base.cluster_crn + namespace = local.logs_agent_namespace + name = local.logs_agent_name + }] + } + ] +} + +######################################################################################################################## +# 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 + } + ] +} + +module "ocp_base" { + source = "terraform-ibm-modules/base-ocp-vpc/ibm" + version = "3.31.1" + 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 + import_default_worker_pool_on_create = false +} + +data "ibm_container_cluster_config" "cluster_config" { + cluster_name_id = module.ocp_base.cluster_id + resource_group_id = module.resource_group.resource_group_id +} + +############################################################################## +# Observability Instance +############################################################################## + +module "observability_instances" { + source = "terraform-ibm-modules/observability-instances/ibm" + version = "2.19.1" + providers = { + logdna.at = logdna.at + logdna.ld = logdna.ld + } + resource_group_id = module.resource_group.resource_group_id + region = var.region + cloud_logs_plan = "standard" + cloud_monitoring_plan = "graduated-tier" + enable_platform_logs = false + enable_platform_metrics = false + cloud_logs_instance_name = "${var.prefix}-cloud-logs" + cloud_monitoring_instance_name = "${var.prefix}-cloud-monitoring" +} + +data "ibm_is_security_groups" "vpc_security_groups" { + depends_on = [module.ocp_base] + vpc_id = ibm_is_vpc.vpc.id +} + +# The below code creates a VPE for Cloud logs in the provisioned VPC which allows the agents to access the private Cloud Logs Ingress endpoint. +module "vpe" { + source = "terraform-ibm-modules/vpe-gateway/ibm" + version = "4.3.0" + region = var.region + prefix = var.prefix + vpc_id = ibm_is_vpc.vpc.id + vpc_name = "${var.prefix}-vpc" + subnet_zone_list = [ + { + id = ibm_is_subnet.subnet_zone_1.id + name = ibm_is_subnet.subnet_zone_1.name + zone = ibm_is_subnet.subnet_zone_1.zone + } + ] + resource_group_id = module.resource_group.resource_group_id + security_group_ids = [for group in data.ibm_is_security_groups.vpc_security_groups.security_groups : group.id if group.name == "kube-${module.ocp_base.cluster_id}"] # Select only security group attached to the Cluster + cloud_service_by_crn = [ + { + crn = module.observability_instances.cloud_logs_crn + service_name = "logs" + } + ] + service_endpoints = "private" +} + +############################################################################## +# Observability Agents +############################################################################## + +module "observability_agents" { + source = "../.." + depends_on = [module.vpe] + cluster_id = module.ocp_base.cluster_id + cluster_resource_group_id = module.resource_group.resource_group_id + # Cloud Logs agent + logs_agent_trusted_profile = module.trusted_profile.trusted_profile.id + logs_agent_namespace = local.logs_agent_namespace + logs_agent_name = local.logs_agent_name + cloud_logs_ingress_endpoint = module.observability_instances.cloud_logs_ingress_private_endpoint + cloud_logs_ingress_port = 443 + # example of how to add additional metadata to the logs agents + logs_agent_additional_metadata = [{ + key = "cluster_id" + value = module.ocp_base.cluster_id + }] + # example of how to add additional log source path + logs_agent_additional_log_source_paths = ["/logs/*.log"] + # Monitoring agent + cloud_monitoring_access_key = module.observability_instances.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 + cloud_monitoring_metrics_filter = [{ type = "exclude", name = "metricA.*" }, { type = "include", name = "metricB.*" }] + cloud_monitoring_agent_tags = var.resource_tags + cloud_monitoring_instance_region = module.observability_instances.region +} diff --git a/examples/obs-agent-ocp/outputs.tf b/examples/obs-agent-ocp/outputs.tf new file mode 100644 index 00000000..135186b7 --- /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 00000000..5c11f46f --- /dev/null +++ b/examples/obs-agent-ocp/provider.tf @@ -0,0 +1,40 @@ +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 + } + # IBM Cloud credentials are required to authenticate to the helm repo + registry { + url = "oci://icr.io/ibm/observe/logs-agent-helm" + username = "iamapikey" + password = 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 +} + +locals { + at_endpoint = "https://api.${var.region}.logging.cloud.ibm.com" +} + +provider "logdna" { + alias = "at" + servicekey = module.observability_instances.activity_tracker_resource_key != null ? module.observability_instances.activity_tracker_resource_key : "" + url = local.at_endpoint +} + +provider "logdna" { + alias = "ld" + servicekey = module.observability_instances.log_analysis_resource_key != null ? module.observability_instances.log_analysis_resource_key : "" + url = local.at_endpoint +} diff --git a/examples/obs-agent-ocp/variables.tf b/examples/obs-agent-ocp/variables.tf new file mode 100644 index 00000000..9795d32e --- /dev/null +++ b/examples/obs-agent-ocp/variables.tf @@ -0,0 +1,47 @@ +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 +} diff --git a/examples/obs-agent-ocp/version.tf b/examples/obs-agent-ocp/version.tf new file mode 100644 index 00000000..aad29be6 --- /dev/null +++ b/examples/obs-agent-ocp/version.tf @@ -0,0 +1,24 @@ +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 (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.69.2" + } + helm = { + source = "hashicorp/helm" + version = ">= 2.15.0" + } + kubernetes = { + source = "hashicorp/kubernetes" + version = ">= 2.16.1" + } + logdna = { + source = "logdna/logdna" + version = ">= 1.14.2" + } + } +} diff --git a/main.tf b/main.tf index 23baebfd..43739164 100644 --- a/main.tf +++ b/main.tf @@ -40,6 +40,7 @@ locals { cloud_monitoring_agent_tags = var.cloud_monitoring_add_cluster_name ? concat(["ibm.containers-kubernetes.cluster.name:${local.cluster_name}"], var.cloud_monitoring_agent_tags) : var.cloud_monitoring_agent_tags cloud_monitoring_host = var.cloud_monitoring_enabled ? var.cloud_monitoring_endpoint_type == "private" ? "ingest.private.${var.cloud_monitoring_instance_region}.monitoring.cloud.ibm.com" : "logs.${var.cloud_monitoring_instance_region}.monitoring.cloud.ibm.com" : null + # TODO: Move this into variable.tf since module requires 1.9 now # VARIABLE VALIDATION log_analysis_key_validate_condition = var.log_analysis_enabled == true && var.log_analysis_instance_region == null && var.log_analysis_ingestion_key == null log_analysis_key_validate_msg = "Values for 'log_analysis_ingestion_key' and 'log_analysis_instance_region' variables must be passed when 'log_analysis_enabled = true'" @@ -209,3 +210,30 @@ resource "helm_release" "cloud_monitoring_agent" { } } /** Cloud Monitoring Configuration End **/ + + +/** Logs Agent Configuration Start **/ +module "logs_agent" { + count = var.logs_agent_enabled ? 1 : 0 + source = "./modules/logs-agent" + cluster_id = var.cluster_id + cluster_resource_group_id = var.cluster_resource_group_id + cluster_config_endpoint_type = var.cluster_config_endpoint_type + logs_agent_name = var.logs_agent_name + logs_agent_namespace = var.logs_agent_namespace + logs_agent_trusted_profile = var.logs_agent_trusted_profile + logs_agent_iam_api_key = var.logs_agent_iam_api_key + logs_agent_tolerations = var.logs_agent_tolerations + logs_agent_additional_log_source_paths = var.logs_agent_additional_log_source_paths + logs_agent_exclude_log_source_paths = var.logs_agent_exclude_log_source_paths + logs_agent_selected_log_source_paths = var.logs_agent_selected_log_source_paths + logs_agent_log_source_namespaces = var.logs_agent_log_source_namespaces + logs_agent_iam_mode = var.logs_agent_iam_mode + logs_agent_iam_environment = var.logs_agent_iam_environment + logs_agent_additional_metadata = var.logs_agent_additional_metadata + logs_agent_enable_scc = var.logs_agent_enable_scc + cloud_logs_ingress_endpoint = var.cloud_logs_ingress_endpoint + cloud_logs_ingress_port = var.cloud_logs_ingress_port + is_vpc_cluster = var.is_vpc_cluster +} +/** Logs Agent Configuration End **/ diff --git a/modules/logs-agent/README.md b/modules/logs-agent/README.md new file mode 100644 index 00000000..44ed0d8e --- /dev/null +++ b/modules/logs-agent/README.md @@ -0,0 +1,106 @@ +# Logs Agents module + +You can use this module to deploy Logs Agent in your cluster. The agent can collect and route application logs from a Red Hat OpenShift or Kubernetes cluster to an IBM Cloud Logs of your choice. + +## Usage + +```hcl +# ############################################################################ +# Init cluster config for helm +# ############################################################################ + +data "ibm_container_cluster_config" "cluster_config" { + # update this value with the Id of the cluster where these agents will be provisioned + cluster_name_id = "cluster_id" +} + +# ############################################################################ +# Config providers +# ############################################################################ + +provider "ibm" { + # update this value with your IBM Cloud API key value + ibmcloud_api_key = "api key value" # pragma: allowlist secret +} + +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 + } + # IBM Cloud credentials are required to authenticate to the helm repo + registry { + url = "oci://icr.io/ibm/observe/logs-agent-helm" + username = "iamapikey" + password = "XXXXXXXXXXXXXXXXX" # replace with an IBM cloud apikey + } +} + +# ############################################################################ +# Install observability agents +# ############################################################################ + +module "logs_agent_module" { + source = "terraform-ibm-modules/observability-agents/ibm//modules/logs-agent" + # update this with your cluster id where the agents will be installed + cluster_id = "cluster id" + # update this with the Id of your IBM Cloud resource group + cluster_resource_group_id = "resource group id" + # Logs Agent variables + logs_agent_trusted_profile = "XXXXXXXX" + cloud_logs_ingress_endpoint = ".ingress.us-south.logs.cloud.ibm.com" + cloud_logs_ingress_port = 443 +} +``` + + +### Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.9.0 | +| [helm](#requirement\_helm) | >= 2.11.0, <3.0.0 | +| [ibm](#requirement\_ibm) | >= 1.59.0, <2.0.0 | + +### Modules + +No modules. + +### Resources + +| Name | Type | +|------|------| +| [helm_release.logs_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 | +|------|-------------|------|---------|:--------:| +| [cloud\_logs\_ingress\_endpoint](#input\_cloud\_logs\_ingress\_endpoint) | The host for IBM Cloud Logs ingestion. Ensure you use the ingress endpoint. See https://cloud.ibm.com/docs/cloud-logs?topic=cloud-logs-endpoints_ingress. | `string` | `null` | no | +| [cloud\_logs\_ingress\_port](#input\_cloud\_logs\_ingress\_port) | The target port for the IBM Cloud Logs ingestion endpoint. The port must be 443 if you connect by using a VPE gateway, or port 3443 when you connect by using CSEs. | `number` | `3443` | no | +| [cluster\_config\_endpoint\_type](#input\_cluster\_config\_endpoint\_type) | The type of endpoint to use for the cluster config access: `default`, `private`, `vpe`, or `link`. The `default` value uses the default endpoint of the cluster. | `string` | `"default"` | no | +| [cluster\_id](#input\_cluster\_id) | The ID of the cluster to deploy the agents. | `string` | n/a | yes | +| [cluster\_resource\_group\_id](#input\_cluster\_resource\_group\_id) | The resource group ID of the cluster. | `string` | n/a | yes | +| [is\_vpc\_cluster](#input\_is\_vpc\_cluster) | Specify true if the target cluster for the agents is a VPC cluster, false if it is a classic cluster. | `bool` | `true` | no | +| [logs\_agent\_additional\_log\_source\_paths](#input\_logs\_agent\_additional\_log\_source\_paths) | The list of additional log sources. By default, the Logs agent collects logs from a single source at `/var/log/containers/*.log`. | `list(string)` | `[]` | no | +| [logs\_agent\_additional\_metadata](#input\_logs\_agent\_additional\_metadata) | The list of additional metadata fields to add to the routed logs. |
list(object({
key = optional(string)
value = optional(string)
}))
| `[]` | no | +| [logs\_agent\_enable\_scc](#input\_logs\_agent\_enable\_scc) | Whether to enable creation of Security Context Constraints in Openshift. When installing on an OpenShift cluster, this setting is mandatory to configure permissions for pods within your cluster. | `bool` | `true` | no | +| [logs\_agent\_exclude\_log\_source\_paths](#input\_logs\_agent\_exclude\_log\_source\_paths) | The list of log sources to exclude. Specify the paths that the Logs agent ignores. | `list(string)` | `[]` | no | +| [logs\_agent\_iam\_api\_key](#input\_logs\_agent\_iam\_api\_key) | The IBM Cloud API key for the Logs agent to authenticate and communicate with the IBM Cloud Logs. It is required if `logs_agent_iam_mode` is set to `IAMAPIKey`. | `string` | `null` | no | +| [logs\_agent\_iam\_environment](#input\_logs\_agent\_iam\_environment) | IAM authentication Environment: `Production` or `PrivateProduction` or `Staging` or `PrivateStaging`. `Production` specifies the public endpoint & `PrivateProduction` specifies the private endpoint. | `string` | `"PrivateProduction"` | no | +| [logs\_agent\_iam\_mode](#input\_logs\_agent\_iam\_mode) | IAM authentication mode: `TrustedProfile` or `IAMAPIKey`. | `string` | `"TrustedProfile"` | no | +| [logs\_agent\_log\_source\_namespaces](#input\_logs\_agent\_log\_source\_namespaces) | The list of namespaces from which logs should be forwarded by agent. If namespaces are not listed, logs from all namespaces will be sent. | `list(string)` | `[]` | no | +| [logs\_agent\_name](#input\_logs\_agent\_name) | The name of the Logs agent. The name is used in all Kubernetes and Helm resources in the cluster. | `string` | `"logs-agent"` | no | +| [logs\_agent\_namespace](#input\_logs\_agent\_namespace) | The namespace where the Logs agent is deployed. The default value is `ibm-observe`. | `string` | `"ibm-observe"` | no | +| [logs\_agent\_selected\_log\_source\_paths](#input\_logs\_agent\_selected\_log\_source\_paths) | The list of specific log sources paths. Logs will only be collected from the specified log source paths. If no paths are specified, it will send logs from `/var/log/containers`. | `list(string)` | `[]` | no | +| [logs\_agent\_tolerations](#input\_logs\_agent\_tolerations) | List of tolerations to apply to Logs agent. The default value means a pod will run on every node. |
list(object({
key = optional(string)
operator = optional(string)
value = optional(string)
effect = optional(string)
tolerationSeconds = optional(number)
}))
|
[
{
"operator": "Exists"
}
]
| no | +| [logs\_agent\_trusted\_profile](#input\_logs\_agent\_trusted\_profile) | The IBM Cloud trusted profile ID. Used only when `logs_agent_iam_mode` is set to `TrustedProfile`. The trusted profile must have an IBM Cloud Logs `Sender` role. | `string` | `null` | no | + +### Outputs + +No outputs. + diff --git a/modules/logs-agent/kubeconfig/.gitignore b/modules/logs-agent/kubeconfig/.gitignore new file mode 100644 index 00000000..632a28fb --- /dev/null +++ b/modules/logs-agent/kubeconfig/.gitignore @@ -0,0 +1,6 @@ +# Ignore everything +* + +# But not these files... +!.gitignore +!README.md diff --git a/modules/logs-agent/kubeconfig/README.md b/modules/logs-agent/kubeconfig/README.md new file mode 100644 index 00000000..dff9dd4a --- /dev/null +++ b/modules/logs-agent/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 (See https://github.ibm.com/GoldenEye/issues/issues/552). diff --git a/modules/logs-agent/main.tf b/modules/logs-agent/main.tf new file mode 100644 index 00000000..315505ed --- /dev/null +++ b/modules/logs-agent/main.tf @@ -0,0 +1,128 @@ +# 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 +} + +data "ibm_container_cluster" "cluster" { + count = var.is_vpc_cluster ? 0 : 1 + name = var.cluster_id + resource_group_id = var.cluster_resource_group_id +} + +# Download cluster config which is required to connect to cluster +data "ibm_container_cluster_config" "cluster_config" { + cluster_name_id = var.cluster_id + 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 { + logs_agent_chart_location = "oci://icr.io/ibm/observe/logs-agent-helm" + logs_agent_version = "1.3.0" # datasource: icr.io/ibm/observe/logs-agent-helm + logs_agent_selected_log_source_paths = distinct(concat([for namespace in var.logs_agent_log_source_namespaces : "/var/log/containers/*_${namespace}_*.log"], var.logs_agent_selected_log_source_paths)) + logs_agent_iam_api_key = var.logs_agent_iam_api_key != null ? var.logs_agent_iam_api_key : "" + logs_agent_trusted_profile = var.logs_agent_trusted_profile != null ? var.logs_agent_trusted_profile : "" + cloud_logs_ingress_endpoint = var.cloud_logs_ingress_endpoint != null ? var.cloud_logs_ingress_endpoint : "" + logs_agent_additional_metadata = length(var.logs_agent_additional_metadata) > 0 ? merge([ + for metadata in var.logs_agent_additional_metadata : { + (metadata.key) = metadata.value + }]...) : {} # DO NOT REMOVE "...", it is used to convert list of objects into a single object + 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 +} + +resource "helm_release" "logs_agent" { + name = var.logs_agent_name + chart = local.logs_agent_chart_location + version = local.logs_agent_version + namespace = var.logs_agent_namespace + create_namespace = true + timeout = 1200 + wait = true + recreate_pods = true + force_update = true + + set { + name = "metadata.name" + type = "string" + value = var.logs_agent_name + } + set { + name = "image.version" + type = "string" + value = local.logs_agent_version + } + set { + name = "env.ingestionHost" + type = "string" + value = local.cloud_logs_ingress_endpoint + } + set { + name = "env.ingestionPort" + value = var.cloud_logs_ingress_port + } + set_sensitive { + name = "secret.iamAPIKey" + type = "string" + value = local.logs_agent_iam_api_key + } + set { + name = "env.trustedProfileID" + type = "string" + value = local.logs_agent_trusted_profile + } + set { + name = "env.iamMode" + type = "string" + value = var.logs_agent_iam_mode + } + set { + name = "env.iamEnvironment" + type = "string" + value = var.logs_agent_iam_environment + } + set { + name = "additionalLogSourcePaths" + type = "string" + value = join("\\,", var.logs_agent_additional_log_source_paths) + } + set { + name = "excludeLogSourcePaths" + type = "string" + value = join("\\,", var.logs_agent_exclude_log_source_paths) + } + set { + name = "selectedLogSourcePaths" + type = "string" + value = join("\\,", local.logs_agent_selected_log_source_paths) + } + set { + name = "clusterName" + type = "string" + value = local.cluster_name + } + set { + name = "scc.create" + value = var.logs_agent_enable_scc + } + + # dummy value hack to force update https://github.com/hashicorp/terraform-provider-helm/issues/515#issuecomment-813088122 + values = [ + yamlencode({ + tolerations = var.logs_agent_tolerations + additionalMetadata = local.logs_agent_additional_metadata + dummy = uuid() + }) + ] + + + provisioner "local-exec" { + command = "${path.module}/scripts/confirm-rollout-status.sh ${var.logs_agent_name} ${var.logs_agent_namespace}" + interpreter = ["/bin/bash", "-c"] + environment = { + KUBECONFIG = data.ibm_container_cluster_config.cluster_config.config_file_path + } + } +} diff --git a/modules/logs-agent/outputs.tf b/modules/logs-agent/outputs.tf new file mode 100644 index 00000000..135186b7 --- /dev/null +++ b/modules/logs-agent/outputs.tf @@ -0,0 +1,11 @@ +############################################################################## +# Outputs +############################################################################## + +#output "myoutput" { +# description = "Description of my output" +# value = "value" +# depends_on = [] +#} + +############################################################################## diff --git a/modules/logs-agent/scripts/confirm-rollout-status.sh b/modules/logs-agent/scripts/confirm-rollout-status.sh new file mode 100755 index 00000000..4197143d --- /dev/null +++ b/modules/logs-agent/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/modules/logs-agent/variables.tf b/modules/logs-agent/variables.tf new file mode 100644 index 00000000..cc76d9ba --- /dev/null +++ b/modules/logs-agent/variables.tf @@ -0,0 +1,176 @@ +############################################################################## +# Cluster variables +############################################################################## + +variable "cluster_id" { + type = string + description = "The ID of the cluster to deploy the agents." +} + +variable "cluster_resource_group_id" { + type = string + description = "The resource group ID of the cluster." +} + +variable "cluster_config_endpoint_type" { + description = "The type of endpoint to use for the cluster config access: `default`, `private`, `vpe`, or `link`. The `default` value uses 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 agents is a VPC cluster, false if it is a classic cluster." + type = bool + default = true +} + +############################################################################## +# Logs Agents variables +############################################################################## + +variable "logs_agent_name" { + description = "The name of the Logs agent. The name is used in all Kubernetes and Helm resources in the cluster." + type = string + default = "logs-agent" + nullable = false +} + +variable "logs_agent_namespace" { + type = string + description = "The namespace where the Logs agent is deployed. The default value is `ibm-observe`." + default = "ibm-observe" + nullable = false +} + +variable "logs_agent_trusted_profile" { + type = string + description = "The IBM Cloud trusted profile ID. Used only when `logs_agent_iam_mode` is set to `TrustedProfile`. The trusted profile must have an IBM Cloud Logs `Sender` role." + default = null + + validation { + condition = ( + var.logs_agent_iam_mode != "TrustedProfile" || + (var.logs_agent_trusted_profile != null && var.logs_agent_trusted_profile != "") + ) + error_message = "When 'logs_agent_iam_mode' is set to 'TrustedProfile', 'logs_agent_trusted_profile' cannot be null or an empty string." + } +} + + +variable "logs_agent_iam_api_key" { + type = string + description = "The IBM Cloud API key for the Logs agent to authenticate and communicate with the IBM Cloud Logs. It is required if `logs_agent_iam_mode` is set to `IAMAPIKey`." + sensitive = true + default = null + + validation { + condition = ( + var.logs_agent_iam_mode != "IAMAPIKey" || + (var.logs_agent_iam_api_key != null && var.logs_agent_iam_api_key != "") + ) + error_message = "When 'logs_agent_iam_mode' is set to 'IAMAPIKey', 'logs_agent_iam_api_key' cannot be null or an empty string." + } +} + +variable "logs_agent_tolerations" { + description = "List of tolerations to apply to Logs agent. The default value means a pod will run on every node." + type = list(object({ + key = optional(string) + operator = optional(string) + value = optional(string) + effect = optional(string) + tolerationSeconds = optional(number) + })) + default = [{ + operator = "Exists" + }] +} + +variable "logs_agent_additional_log_source_paths" { + type = list(string) + description = "The list of additional log sources. By default, the Logs agent collects logs from a single source at `/var/log/containers/*.log`." + default = [] + nullable = false +} + +variable "logs_agent_exclude_log_source_paths" { + type = list(string) + description = "The list of log sources to exclude. Specify the paths that the Logs agent ignores." + default = [] + nullable = false +} + +variable "logs_agent_selected_log_source_paths" { + type = list(string) + description = "The list of specific log sources paths. Logs will only be collected from the specified log source paths. If no paths are specified, it will send logs from `/var/log/containers`." + default = [] + nullable = false +} + +variable "logs_agent_log_source_namespaces" { + type = list(string) + description = "The list of namespaces from which logs should be forwarded by agent. If namespaces are not listed, logs from all namespaces will be sent." + default = [] + nullable = false +} + +variable "logs_agent_iam_mode" { + type = string + default = "TrustedProfile" + description = "IAM authentication mode: `TrustedProfile` or `IAMAPIKey`." + validation { + error_message = "The IAM mode can only be `TrustedProfile` or `IAMAPIKey`." + condition = contains(["TrustedProfile", "IAMAPIKey"], var.logs_agent_iam_mode) + } +} + +variable "logs_agent_iam_environment" { + type = string + default = "PrivateProduction" + description = "IAM authentication Environment: `Production` or `PrivateProduction` or `Staging` or `PrivateStaging`. `Production` specifies the public endpoint & `PrivateProduction` specifies the private endpoint." + validation { + error_message = "The IAM environment can only be `Production` or `PrivateProduction` or `Staging` or `PrivateStaging`." + condition = contains(["Production", "PrivateProduction", "Staging", "PrivateStaging"], var.logs_agent_iam_environment) + } +} + +variable "logs_agent_additional_metadata" { + description = "The list of additional metadata fields to add to the routed logs." + type = list(object({ + key = optional(string) + value = optional(string) + })) + default = [] +} + +variable "logs_agent_enable_scc" { + description = "Whether to enable creation of Security Context Constraints in Openshift. When installing on an OpenShift cluster, this setting is mandatory to configure permissions for pods within your cluster." + type = bool + default = true +} + +variable "cloud_logs_ingress_endpoint" { + description = "The host for IBM Cloud Logs ingestion. Ensure you use the ingress endpoint. See https://cloud.ibm.com/docs/cloud-logs?topic=cloud-logs-endpoints_ingress." + type = string + default = null + + validation { + condition = (var.cloud_logs_ingress_endpoint != null && var.cloud_logs_ingress_endpoint != "") + error_message = "When 'logs_agent_enabled' is enabled, you cannot set 'cloud_logs_ingress_endpoint' as null or empty string." + } +} + +variable "cloud_logs_ingress_port" { + type = number + default = 3443 + description = "The target port for the IBM Cloud Logs ingestion endpoint. The port must be 443 if you connect by using a VPE gateway, or port 3443 when you connect by using CSEs." + validation { + error_message = "The Logs Routing supertenant ingestion port can only be `3443` or `443`." + condition = contains([3443, 443], var.cloud_logs_ingress_port) + } +} diff --git a/modules/logs-agent/version.tf b/modules/logs-agent/version.tf new file mode 100644 index 00000000..42854b02 --- /dev/null +++ b/modules/logs-agent/version.tf @@ -0,0 +1,15 @@ +terraform { + required_version = ">= 1.9.0" + + # Each required provider's version should be a flexible range to future proof the module's usage with upcoming minor and patch versions. + required_providers { + ibm = { + source = "ibm-cloud/ibm" + version = ">= 1.59.0, <2.0.0" + } + helm = { + source = "hashicorp/helm" + version = ">= 2.11.0, <3.0.0" + } + } +} diff --git a/tests/other_test.go b/tests/other_test.go new file mode 100644 index 00000000..87e1a6fc --- /dev/null +++ b/tests/other_test.go @@ -0,0 +1,18 @@ +// 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 + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestRunAgentClassicKubernetes(t *testing.T) { + t.Parallel() + + options := setupOptions(t, "obs-agent-iks", terraformDirLogsAgentIKS) + options.TerraformVars["is_vpc_cluster"] = false + output, err := options.RunTestConsistency() + assert.Nil(t, err, "This should not have errored") + assert.NotNil(t, output, "Expected some output") +} diff --git a/tests/pr_test.go b/tests/pr_test.go index f89efaeb..2dd6d52c 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -11,19 +11,8 @@ import ( ) const resourceGroup = "geretain-test-observability-agents" -const terraformDirOther = "examples/basic" - -var ignoreUpdates = []string{ - "module.observability_agents.helm_release.sysdig_agent[0]", - "module.observability_agents.helm_release.logdna_agent[0]", - "module.observability_agents.helm_release.logdna_agent_activity_tracker[0]", - "module.observability_agents.helm_release.log_analysis_agent[0]", - "module.observability_agents.helm_release.cloud_monitoring_agent[0]", - "ibm_is_subnet.testacc_subnet", - "module.observability_agents.helm_release.log_analysis_agent_activity_tracker[0]", -} - -var extTerraformVars = map[string]interface{}{} +const terraformDirLogsAgentIKS = "examples/obs-agent-iks" +const terraformDirLogsAgentROKS = "examples/obs-agent-ocp" var sharedInfoSvc *cloudinfo.CloudInfoService @@ -35,63 +24,55 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } -func setupOptions(t *testing.T, prefix string, terraformDir string, terraformVars map[string]interface{}) *testhelper.TestOptions { +func setupOptions(t *testing.T, prefix string, terraformDir string) *testhelper.TestOptions { + options := testhelper.TestOptionsDefaultWithVars(&testhelper.TestOptions{ Testing: t, TerraformDir: terraformDir, Prefix: prefix, ResourceGroup: resourceGroup, - IgnoreUpdates: testhelper.Exemptions{ - List: ignoreUpdates, + IgnoreUpdates: testhelper.Exemptions{ // Ignore for consistency check + List: []string{ + "module.observability_agents.module.logs_agent[0].helm_release.logs_agent", + }, }, - CloudInfoService: sharedInfoSvc, - ExcludeActivityTrackerRegions: true, - TerraformVars: terraformVars, + CloudInfoService: sharedInfoSvc, }) + // add ocp entitlement to keep costs down for tests + if terraformDir == terraformDirLogsAgentROKS { + options.TerraformVars["ocp_entitlement"] = "cloud_pak" + } + return options } -func TestRunBasicAgents(t *testing.T) { +func TestRunAgentVpcKubernetes(t *testing.T) { t.Parallel() - options := setupOptions(t, "basic-obs-agents", terraformDirOther, extTerraformVars) - + options := setupOptions(t, "obs-agent-iks", terraformDirLogsAgentIKS) output, err := options.RunTestConsistency() assert.Nil(t, err, "This should not have errored") assert.NotNil(t, output, "Expected some output") } -func TestRunUpgrade(t *testing.T) { +func TestRunAgentVpcOcp(t *testing.T) { t.Parallel() - options := setupOptions(t, "observ-agents-upg", terraformDirOther, extTerraformVars) - - output, err := options.RunTestUpgrade() - if !options.UpgradeTestSkipped { - assert.Nil(t, err, "This should not have errored") - assert.NotNil(t, output, "Expected some output") - } -} - -func TestRunBasicAgentsKubernetes(t *testing.T) { - t.Parallel() - - options := setupOptions(t, "basic-obs-agents-k8s", terraformDirOther, extTerraformVars) - options.TerraformVars["is_openshift"] = false - + options := setupOptions(t, "obs-agent-roks", terraformDirLogsAgentROKS) output, err := options.RunTestConsistency() assert.Nil(t, err, "This should not have errored") assert.NotNil(t, output, "Expected some output") } -func TestRunBasicAgentsClassic(t *testing.T) { +func TestRunAgentVpcOcpUpgrade(t *testing.T) { t.Parallel() - options := setupOptions(t, "basic-obs-agents-classic", terraformDirOther, extTerraformVars) - options.TerraformVars["is_vpc_cluster"] = false + options := setupOptions(t, "log-agent-upg", terraformDirLogsAgentROKS) - output, err := options.RunTestConsistency() - assert.Nil(t, err, "This should not have errored") - assert.NotNil(t, output, "Expected some output") + output, err := options.RunTestUpgrade() + if !options.UpgradeTestSkipped { + assert.Nil(t, err, "This should not have errored") + assert.NotNil(t, output, "Expected some output") + } } diff --git a/variables.tf b/variables.tf index ee2b9f79..7d47b03a 100644 --- a/variables.tf +++ b/variables.tf @@ -35,47 +35,47 @@ variable "is_vpc_cluster" { variable "log_analysis_enabled" { type = bool - description = "Deploy IBM Cloud Logging agent" - default = true + description = "DEPRECATED: Deploy IBM Cloud Log Analysis agent" + default = false } variable "log_analysis_agent_tags" { type = list(string) - description = "List of tags to associate to all log records that the agent collects so that you can identify the agent's data quicker in the logging UI. NOTE: Use the 'log_analysis_add_cluster_name' variable to add the cluster name as a tag." + description = "DEPRECATED: List of tags to associate to all log records that the agent collects so that you can identify the agent's data quicker in the logging UI. NOTE: Use the 'log_analysis_add_cluster_name' variable to add the cluster name as a tag." default = [] nullable = false } variable "log_analysis_add_cluster_name" { type = bool - description = "If true, configure the log analysis agent to attach a tag containing the cluster name to all log messages." + description = "DEPRECATED: If true, configure the Log Analysis agent to attach a tag containing the cluster name to all log messages." default = true } variable "log_analysis_ingestion_key" { type = string - description = "Ingestion key for the IBM Cloud Logging agent to communicate with the instance" + description = "DEPRECATED: Ingestion key for the Log Analysis agent to communicate with the instance" sensitive = true default = null } variable "log_analysis_secret_name" { type = string - description = "The name of the secret which will store the ingestion key." + description = "DEPRECATED: The name of the secret which will store the Log Analysis ingestion key." default = "logdna-agent" nullable = false } variable "log_analysis_instance_region" { type = string - description = "The IBM Log Analysis instance region. Used to construct the ingestion endpoint." + description = "DEPRECATED: The IBM Log Analysis instance region. Used to construct the ingestion endpoint." default = null } variable "log_analysis_endpoint_type" { type = string - description = "Specify the IBM Log Analysis instance endpoint type (public or private) to use. Used to construct the ingestion endpoint." + description = "DEPRECATED: Specify the IBM Log Analysis 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." @@ -84,19 +84,19 @@ variable "log_analysis_endpoint_type" { } variable "log_analysis_agent_custom_line_inclusion" { - description = "Log Analysis agent custom configuration for line inclusion setting LOGDNA_K8S_METADATA_LINE_INCLUSION. See https://github.com/logdna/logdna-agent-v2/blob/master/docs/KUBERNETES.md#configuration-for-kubernetes-metadata-filtering for more info." + description = "DEPRECATED: Log Analysis agent custom configuration for line inclusion setting LOGDNA_K8S_METADATA_LINE_INCLUSION. See https://github.com/logdna/logdna-agent-v2/blob/master/docs/KUBERNETES.md#configuration-for-kubernetes-metadata-filtering for more info." type = string default = null } variable "log_analysis_agent_custom_line_exclusion" { - description = "Log Analysis agent custom configuration for line exclusion setting LOGDNA_K8S_METADATA_LINE_EXCLUSION. See https://github.com/logdna/logdna-agent-v2/blob/master/docs/KUBERNETES.md#configuration-for-kubernetes-metadata-filtering for more info." + description = "DEPRECATED: Log Analysis agent custom configuration for line exclusion setting LOGDNA_K8S_METADATA_LINE_EXCLUSION. See https://github.com/logdna/logdna-agent-v2/blob/master/docs/KUBERNETES.md#configuration-for-kubernetes-metadata-filtering for more info." type = string default = null } variable "log_analysis_agent_name" { - description = "Log Analysis agent name. Used for naming all kubernetes and helm resources on the cluster." + description = "DEPRECATED: Log Analysis agent name. Used for naming all kubernetes and helm resources on the cluster." type = string default = "logdna-agent" nullable = false @@ -104,13 +104,13 @@ variable "log_analysis_agent_name" { variable "log_analysis_agent_namespace" { type = string - description = "Namespace where to deploy the Log Analysis agent. Default value is 'ibm-observe'" + description = "DEPRECATED: Namespace where to deploy the Log Analysis agent. Default value is 'ibm-observe'" default = "ibm-observe" nullable = false } variable "log_analysis_agent_tolerations" { - description = "List of tolerations to apply to Log Analysis agent." + description = "DEPRECATED: List of tolerations to apply to Log Analysis agent." type = list(object({ key = optional(string) operator = optional(string) @@ -220,3 +220,121 @@ variable "cloud_monitoring_agent_tolerations" { key : "node-role.kubernetes.io/master" }] } + +############################################################################## +# Logs Agents variables +############################################################################## + +variable "logs_agent_enabled" { + type = bool + description = "Whether to deploy the Logs agent." + default = true +} + +variable "logs_agent_name" { + description = "The name of the Logs agent. The name is used in all Kubernetes and Helm resources in the cluster." + type = string + default = "logs-agent" + nullable = false +} + +variable "logs_agent_namespace" { + type = string + description = "The namespace where the Logs agent is deployed. The default value is `ibm-observe`." + default = "ibm-observe" + nullable = false +} + +variable "logs_agent_trusted_profile" { + type = string + description = "The IBM Cloud trusted profile ID. Used only when `logs_agent_iam_mode` is set to `TrustedProfile`. The trusted profile must have an IBM Cloud Logs `Sender` role." + default = null +} + +variable "logs_agent_iam_api_key" { + type = string + description = "The IBM Cloud API key for the Logs agent to authenticate and communicate with the IBM Cloud Logs. It is required if `logs_agent_iam_mode` is set to `IAMAPIKey`." + sensitive = true + default = null +} + +variable "logs_agent_tolerations" { + description = "List of tolerations to apply to Logs agent. The default value means a pod will run on every node." + type = list(object({ + key = optional(string) + operator = optional(string) + value = optional(string) + effect = optional(string) + tolerationSeconds = optional(number) + })) + default = [{ + operator = "Exists" + }] +} + +variable "logs_agent_additional_log_source_paths" { + type = list(string) + description = "The list of additional log sources. By default, the Logs agent collects logs from a single source at `/var/log/containers/*.log`." + default = [] + nullable = false +} + +variable "logs_agent_exclude_log_source_paths" { + type = list(string) + description = "The list of log sources to exclude. Specify the paths that the Logs agent ignores." + default = [] + nullable = false +} + +variable "logs_agent_selected_log_source_paths" { + type = list(string) + description = "The list of specific log sources paths. Logs will only be collected from the specified log source paths. If no paths are specified, it will send logs from `/var/log/containers`." + default = [] + nullable = false +} + +variable "logs_agent_log_source_namespaces" { + type = list(string) + description = "The list of namespaces from which logs should be forwarded by agent. If namespaces are not listed, logs from all namespaces will be sent." + default = [] + nullable = false +} + +variable "logs_agent_iam_mode" { + type = string + default = "TrustedProfile" + description = "IAM authentication mode: `TrustedProfile` or `IAMAPIKey`." +} + +variable "logs_agent_iam_environment" { + type = string + default = "PrivateProduction" + description = "IAM authentication Environment: `Production` or `PrivateProduction` or `Staging` or `PrivateStaging`. `Production` specifies the public endpoint & `PrivateProduction` specifies the private endpoint." +} + +variable "logs_agent_additional_metadata" { + description = "The list of additional metadata fields to add to the routed logs." + type = list(object({ + key = optional(string) + value = optional(string) + })) + default = [] +} + +variable "logs_agent_enable_scc" { + description = "Whether to enable creation of Security Context Constraints in Openshift. When installing on an OpenShift cluster, this setting is mandatory to configure permissions for pods within your cluster." + type = bool + default = true +} + +variable "cloud_logs_ingress_endpoint" { + description = "The host for IBM Cloud Logs ingestion. Ensure you use the ingress endpoint. See https://cloud.ibm.com/docs/cloud-logs?topic=cloud-logs-endpoints_ingress." + type = string + default = null +} + +variable "cloud_logs_ingress_port" { + type = number + default = 3443 + description = "The target port for the IBM Cloud Logs ingestion endpoint. The port must be 443 if you connect by using a VPE gateway, or port 3443 when you connect by using CSEs." +} diff --git a/version.tf b/version.tf index fd664465..6121ddb9 100644 --- a/version.tf +++ b/version.tf @@ -1,16 +1,15 @@ terraform { - # module uses nullable feature which is only available in versions >= 1.1.0 - required_version = ">= 1.1.0" + required_version = ">= 1.9.0" # Each required provider's version should be a flexible range to future proof the module's usage with upcoming minor and patch versions. required_providers { ibm = { source = "ibm-cloud/ibm" - version = ">= 1.59.0, <2.0.0" + version = ">= 1.69.2, <2.0.0" } helm = { source = "hashicorp/helm" - version = ">= 2.8.0, <3.0.0" + version = ">= 2.15.0, <3.0.0" } } }