diff --git a/examples/oci-apm-export-data/main.tf b/examples/oci-apm-export-data/main.tf index 3071296..9204191 100644 --- a/examples/oci-apm-export-data/main.tf +++ b/examples/oci-apm-export-data/main.tf @@ -50,7 +50,7 @@ resource "oci_identity_policy" "gtw_policy" { name = "apm-data-exporter-gtway-policy" description = "Policy needed to allow ApiGateway to call the function." statements = [ - "ALLOW any-user to use functions-family in compartment ApmTestbed where ALL {request.principal.type= 'ApiGateway'} ", + "ALLOW any-user to use functions-family in compartment ${local.compartment_name} where ALL {request.principal.type= 'ApiGateway'} ", ] } diff --git a/examples/oci-apm-service-monitoring/.DS_Store b/examples/oci-apm-service-monitoring/.DS_Store new file mode 100644 index 0000000..8def3bf Binary files /dev/null and b/examples/oci-apm-service-monitoring/.DS_Store differ diff --git a/examples/oci-apm-service-monitoring/README.md b/examples/oci-apm-service-monitoring/README.md new file mode 100644 index 0000000..e5858d2 --- /dev/null +++ b/examples/oci-apm-service-monitoring/README.md @@ -0,0 +1,81 @@ +# OCI APM service monitoring using the APM Log Sender function + +This project provides a Terraform-based setup for monitoring Oracle Cloud Infrastructure (OCI) services using Oracle Application Performance Monitoring (APM). It provisions all necessary OCI resources, including: + +- Log and log group creation (unless a log is provided) +- OCI Functions application and function +- API Gateway +- Virtual Cloud Network (VCN) and networking components +- Service Connector Hub connection +- Required IAM policies + +The solution uses the Log Sender PBF and the OCI Logging service to enable monitoring of your target service. + +## Resources Created + +When deployed, the following resources will be created (unless existing ones are provided): + +- **1 x Log Group and Log** – to enable logging for the monitored service +- **1 x Virtual Cloud Network (VCN)** – named `apm-service-monitoring-vcn` with required networking +- **1 x OCI Application** – named `apm-service-monitoring-app` +- **1 x OCI Function** – named `apm-service-monitoring-function` +- **1 x Service Connector** – named `service-monitoring-connector` +- **IAM Policies** – for the Function and Service Connector to operate properly + +> **Note:** If `log_id` is provided, the log and log group will **not** be created, and the specified log will be used instead. Ensure the provided log exists in the correct compartment. (More details below.) + +--- + +## How to Use the Script + +This Terraform script uses input variables to determine whether to create a new log resource or use an existing one. + +- If `log_id` is **specified**, the script will use the existing log and **skip creating** a new log and log group. +- If `log_id` is **not specified**, then the following variables **must** be provided to create a new log: + - `resource_id`: The OCID of the resource to monitor. + - `log_service`: The service name. *(Default: Oracle Integration Cloud service)* + - `log_category`: The log category. *(Default: Activity Stream)* + +Ensure all required variables are provided based on your use case. + +--- + +## Terraform Deployment + +### Deploy to OCI with One Click + +Click the button below to deploy the function directly to OCI using the Resource Manager. Some values will be prepopulated: + +[![Deploy to Oracle Cloud](https://oci-resourcemanager-plugin.plugins.oci.oraclecloud.com/latest/deploy-to-oracle-cloud.svg)](https://cloud.oracle.com/resourcemanager/stacks/create?zipUrl=https://github.com/M-Iliass/oci-observability-and-management/releases/download/v1.0.1/oci-apm-service-monitoring.zip) + +--- + +### Deploy Using Local Development Environment + +#### 1. Prepare Your Variable File + +Create a file named `terraform.tfvars` and populate it with the required values. + +```hcl +tenancy_ocid = "your-tenancy-ocid" +region = "your-region" +apm_domain_id = "your-apm-domain-id" +compartment_ocid = "your-compartment-ocid" +resource_id = "your-resource-id" +log_id = "your-log-id" # Optional +log_service = "your-log-service" # Required if log_id is not provided +log_category = "your-log-category" # Required if log_id is not provided +``` + +Refer to the How to Use the Script section to determine which variables are required in your scenario. + + +## Deploying the function: + +Apply the changes using the following commands: + +``` + terraform init + terraform plan + terraform apply +``` diff --git a/examples/oci-apm-service-monitoring/main.tf b/examples/oci-apm-service-monitoring/main.tf new file mode 100644 index 0000000..4921e69 --- /dev/null +++ b/examples/oci-apm-service-monitoring/main.tf @@ -0,0 +1,113 @@ +data "oci_functions_pbf_listings" "log_sender_pbf_listings" { + name = "APM Log Sender" +} + +data "oci_logging_log_groups" "test_log_groups" { + #Required + compartment_id = var.compartment_ocid +} + +locals { + pbflisting_ocid = data.oci_functions_pbf_listings.log_sender_pbf_listings.pbf_listings_collection[0]["items"][0].id + function_config = { "APM_DOMAIN_ID" : var.apm_domain_id } + log_source_map = { + for log in data.oci_logging_log_groups.test_log_groups.log_groups : log.display_name => log + } +} + +data "oci_logging_log" "logs" { + for_each = local.log_source_map + + log_group_id = each.value.id + log_id = var.log_id +} + +locals { + log_group_id = [ + for name, d in data.oci_logging_log.logs : d.log_group_id if d.log_group_id != null + ] +} + +### Enable logging for the resource if the log_id isn't set +resource "oci_logging_log_group" "service_monitoring_log_group" { + count = var.log_id == "Don't change to enable logging" ? 1 : 0 + + compartment_id = var.compartment_ocid + display_name = "apm-service-monitoring-log-group" + description = "Log group for service monitoring by APM" +} + +resource "oci_logging_log" "service_monitoring_log" { + count = var.log_id == "Don't change to enable logging" ? 1 : 0 + + display_name = "service-monitoring-log" + log_group_id = oci_logging_log_group.service_monitoring_log_group[count.index].id + log_type = "SERVICE" + + configuration { + source { + category = var.log_category + service = var.log_service + resource = var.resource_id + source_type = "OCISERVICE" + } + } +} + +### Creates the application that should contain the function +resource "oci_functions_application" "service_monitoring_application" { + compartment_id = var.compartment_ocid + display_name = "apm-service-monitoring-app" + subnet_ids = [module.oci_subnets.subnets.public.id] + shape = "GENERIC_ARM" +} + +### Creates the PBF function that sends the logs to the APM collector +resource "oci_functions_function" "service_monitoring_function" { + application_id = oci_functions_application.service_monitoring_application.id + display_name = "apm-service-monitoring-function" + memory_in_mbs = "1024" + + timeout_in_seconds = 120 + source_details { + pbf_listing_id = local.pbflisting_ocid + source_type = "PRE_BUILT_FUNCTIONS" + } + config = local.function_config +} + +### Creates the policies for the connector and PBF +resource "oci_identity_policy" "function_policies" { + provider = oci.home + compartment_id = var.compartment_ocid + description = "Policies for the function for the service monitoring integration" + name = "service-monitoring-integration-policies" + statements = [ + "ALLOW any-user TO {APM_DOMAIN_DATA_UPLOAD} in compartment id ${var.compartment_ocid} WHERE ALL { request.principal.id='${oci_functions_function.service_monitoring_function.id}' }", + "ALLOW any-user TO read apm-domains in compartment id ${var.compartment_ocid} WHERE ALL { request.principal.id='${oci_functions_function.service_monitoring_function.id}' }", + "allow any-user to use fn-function in compartment id ${var.compartment_ocid} where all {request.principal.type='serviceconnector', request.principal.compartment.id='${var.compartment_ocid}'}", + "allow any-user to use fn-invocation in compartment id ${var.compartment_ocid} where all {request.principal.type='serviceconnector', request.principal.compartment.id='${var.compartment_ocid}'}" + ] +} + +### Creates the connector which connects the log and PBF +resource "oci_sch_service_connector" "service_monitoring_connector" { + compartment_id = var.compartment_ocid + display_name = "Service-monitoring-connector" + description = "Connects the Log Sender PBF with the log resource to enable the monitoring." + + source { + kind = "logging" + + log_sources { + compartment_id = var.compartment_ocid + log_group_id = var.log_id == "Don't change to enable logging" ? oci_logging_log_group.service_monitoring_log_group[0].id : local.log_group_id[0] + log_id = var.log_id == "Don't change to enable logging" ? oci_logging_log.service_monitoring_log[0].id : var.log_id + } + } + target { + kind = "functions" + + function_id = oci_functions_function.service_monitoring_function.id + } +} diff --git a/examples/oci-apm-service-monitoring/network.tf b/examples/oci-apm-service-monitoring/network.tf new file mode 100644 index 0000000..b48cb55 --- /dev/null +++ b/examples/oci-apm-service-monitoring/network.tf @@ -0,0 +1,88 @@ +# Copyright (c) 2025 Oracle and/or its affiliates. +# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. + +locals { + next_hop_ids = { + "igw" = module.oci_network.igw.id + } + anywhere = "0.0.0.0/0" + vcn_cidr = "10.0.0.0/24" + subnet_public_cidr = cidrsubnet(local.vcn_cidr, 2, 0) + subnet_private_cidr = cidrsubnet(local.vcn_cidr, 2, 1) +} + +module "oci_network" { + source = "../../oci-core-modules/oci_network" + default_compartment_id = var.compartment_ocid + + vcn_options = { + display_name = "apm-service-monitoring-vcn" + cidr = local.vcn_cidr + enable_dns = true + dns_label = "apmmonitor" + compartment_id = null + defined_tags = null + freeform_tags = null + } + + svcgw_options = { + display_name = null + compartment_id = null + defined_tags = null + freeform_tags = null + services = [ + module.oci_network.svcgw_services.1.id + ] + } + + create_igw = true + create_svcgw = false + create_natgw = false + create_drg = false + + route_tables = { + + igw = { + compartment_id = null + defined_tags = null + freeform_tags = null + route_rules = [ + { + dst = "0.0.0.0/0" + dst_type = "CIDR_BLOCK" + next_hop_id = local.next_hop_ids["igw"] + } + ] + } + } + +} + +module "oci_subnets" { + source = "../../oci-core-modules/oci_subnets" + + default_compartment_id = var.compartment_ocid + vcn_id = module.oci_network.vcn.id + vcn_cidr = module.oci_network.vcn.cidr_block + + + subnets = { + public = { + compartment_id = null + defined_tags = null + freeform_tags = null + dynamic_cidr = false + cidr = local.subnet_public_cidr + cidr_len = null + cidr_num = null + enable_dns = null + dns_label = "public" + private = false + ad = null + dhcp_options_id = null + route_table_id = module.oci_network.route_tables.igw.id + security_list_ids = null + } + } +} + diff --git a/examples/oci-apm-service-monitoring/providers.tf b/examples/oci-apm-service-monitoring/providers.tf new file mode 100644 index 0000000..0fac280 --- /dev/null +++ b/examples/oci-apm-service-monitoring/providers.tf @@ -0,0 +1,20 @@ +# Copyright (c) 2025, Oracle and/or its affiliates. +# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. + + +provider "oci" { + tenancy_ocid = var.tenancy_ocid + region = var.region + # config_file_profile = "" # Add this for local runs with your profile name +} + +provider "oci" { + alias = "home" + tenancy_ocid = var.tenancy_ocid + region = [for i in data.oci_identity_region_subscriptions.this.region_subscriptions : i.region_name if i.is_home_region == true][0] + # config_file_profile = "" # Add this for local runs with your profile name +} + +data "oci_identity_region_subscriptions" "this" { + tenancy_id = var.tenancy_ocid +} \ No newline at end of file diff --git a/examples/oci-apm-service-monitoring/variables.tf b/examples/oci-apm-service-monitoring/variables.tf new file mode 100644 index 0000000..38b110a --- /dev/null +++ b/examples/oci-apm-service-monitoring/variables.tf @@ -0,0 +1,23 @@ +variable "tenancy_ocid" {} + +variable "region" {} + +variable "apm_domain_id" {} + +variable "compartment_ocid" {} + +variable "resource_id" { + default = "Add this to create a new log for the resource" +} + +variable "log_id" { + default = "Don't change to enable logging" +} + +variable "log_service" { + default = "integration" +} + +variable "log_category" { + default = "activitystream" +} \ No newline at end of file