Files
Claude-Code-Monitor/deployments/terraform/providers/oci/main.tf
T
nntrivi2001 57dc91585d feat: Claude Code Monitor — lanes, pipelines and a merged workspace
Internal SmartGift build of a Claude Code monitoring dashboard.

Lanes: a durable unit of parallel agent work, one per working directory,
tracked across session restarts. Managed lanes are git worktrees the
dashboard provisions and can reset or remove behind a three-check destroy
guard and a counted preflight; adopted lanes are directories you already
own and are never destroyable.

Pipelines: a lane moves through pipeline stages. A stage the agent declares
with evidence renders green; a stage inferred from the tool-event stream
renders dashed amber and never counts as done. Detection is forward-only
within a 30-minute window, and never writes the declared stage.

Workspace: one page at /run with a lane grid, the selected lane's pipeline,
and a full Claude console behind a disclosure.
2026-07-30 14:39:03 +07:00

603 lines
19 KiB
Terraform
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ─────────────────────────────────────────────────────────────────────────────
# OCI Provider Full implementation for Claude Code Agent Monitor
#
# Architecture:
# VCN → Container Instances (blue/green) → File Storage Service
# → Flexible Load Balancer → OCI Monitoring & Notifications
#
# OCI Container Instances provide a serverless container runtime.
# File Storage Service (FSS) delivers NFS for SQLite persistence.
# Flexible Load Balancer supports WebSocket, SSL, and weighted backends.
# ─────────────────────────────────────────────────────────────────────────────
provider "oci" {
region = var.region
}
# ── Data sources ────────────────────────────────────────────────────────────
data "oci_identity_availability_domains" "ads" {
compartment_id = var.compartment_id
}
data "oci_identity_tenancy" "current" {
tenancy_id = var.tenancy_id
}
# ── Locals ──────────────────────────────────────────────────────────────────
locals {
name_prefix = lower(replace("${var.project_name}-${var.environment}", "_", "-"))
ad_name = data.oci_identity_availability_domains.ads.availability_domains[0].name
common_tags = {
"project" = var.project_name
"environment" = var.environment
"managed_by" = "terraform"
"cloud_provider" = "oci"
"repository" = "Claude-Code-Agent-Monitor"
}
}
# ─────────────────────────────────────────────────────────────────────────────
# VCN (Virtual Cloud Network)
# ─────────────────────────────────────────────────────────────────────────────
resource "oci_core_vcn" "main" {
compartment_id = var.compartment_id
cidr_blocks = [var.vpc_cidr]
display_name = "${local.name_prefix}-vcn"
dns_label = replace(substr(local.name_prefix, 0, 15), "-", "")
freeform_tags = local.common_tags
lifecycle {
prevent_destroy = false
}
}
# Internet Gateway
resource "oci_core_internet_gateway" "main" {
compartment_id = var.compartment_id
vcn_id = oci_core_vcn.main.id
display_name = "${local.name_prefix}-igw"
enabled = true
freeform_tags = local.common_tags
}
# NAT Gateway
resource "oci_core_nat_gateway" "main" {
compartment_id = var.compartment_id
vcn_id = oci_core_vcn.main.id
display_name = "${local.name_prefix}-nat"
freeform_tags = local.common_tags
}
# Service Gateway
resource "oci_core_service_gateway" "main" {
compartment_id = var.compartment_id
vcn_id = oci_core_vcn.main.id
display_name = "${local.name_prefix}-sgw"
services {
service_id = data.oci_core_services.all.services[0].id
}
freeform_tags = local.common_tags
}
data "oci_core_services" "all" {
filter {
name = "name"
values = ["All .* Services In Oracle Services Network"]
regex = true
}
}
# ── Route tables ────────────────────────────────────────────────────────────
resource "oci_core_route_table" "public" {
compartment_id = var.compartment_id
vcn_id = oci_core_vcn.main.id
display_name = "${local.name_prefix}-public-rt"
route_rules {
network_entity_id = oci_core_internet_gateway.main.id
destination = "0.0.0.0/0"
destination_type = "CIDR_BLOCK"
}
freeform_tags = local.common_tags
}
resource "oci_core_route_table" "private" {
compartment_id = var.compartment_id
vcn_id = oci_core_vcn.main.id
display_name = "${local.name_prefix}-private-rt"
route_rules {
network_entity_id = oci_core_nat_gateway.main.id
destination = "0.0.0.0/0"
destination_type = "CIDR_BLOCK"
}
route_rules {
network_entity_id = oci_core_service_gateway.main.id
destination = data.oci_core_services.all.services[0].cidr_block
destination_type = "SERVICE_CIDR_BLOCK"
}
freeform_tags = local.common_tags
}
# ── Security lists ──────────────────────────────────────────────────────────
resource "oci_core_security_list" "public" {
compartment_id = var.compartment_id
vcn_id = oci_core_vcn.main.id
display_name = "${local.name_prefix}-public-sl"
ingress_security_rules {
protocol = "6" # TCP
source = "0.0.0.0/0"
source_type = "CIDR_BLOCK"
tcp_options {
min = 443
max = 443
}
}
ingress_security_rules {
protocol = "6"
source = "0.0.0.0/0"
source_type = "CIDR_BLOCK"
tcp_options {
min = 80
max = 80
}
}
egress_security_rules {
protocol = "all"
destination = "0.0.0.0/0"
destination_type = "CIDR_BLOCK"
}
freeform_tags = local.common_tags
}
resource "oci_core_security_list" "private" {
compartment_id = var.compartment_id
vcn_id = oci_core_vcn.main.id
display_name = "${local.name_prefix}-private-sl"
ingress_security_rules {
protocol = "6"
source = var.vpc_cidr
source_type = "CIDR_BLOCK"
tcp_options {
min = var.app_port
max = var.app_port
}
}
ingress_security_rules {
protocol = "6"
source = var.vpc_cidr
source_type = "CIDR_BLOCK"
tcp_options {
min = var.mcp_port
max = var.mcp_port
}
}
# NFS (FSS)
ingress_security_rules {
protocol = "6"
source = var.vpc_cidr
source_type = "CIDR_BLOCK"
tcp_options {
min = 2048
max = 2050
}
}
ingress_security_rules {
protocol = "6"
source = var.vpc_cidr
source_type = "CIDR_BLOCK"
tcp_options {
min = 111
max = 111
}
}
ingress_security_rules {
protocol = "17" # UDP
source = var.vpc_cidr
source_type = "CIDR_BLOCK"
udp_options {
min = 111
max = 111
}
}
egress_security_rules {
protocol = "all"
destination = "0.0.0.0/0"
destination_type = "CIDR_BLOCK"
}
freeform_tags = local.common_tags
}
# ── Subnets ─────────────────────────────────────────────────────────────────
resource "oci_core_subnet" "public" {
compartment_id = var.compartment_id
vcn_id = oci_core_vcn.main.id
cidr_block = var.public_subnet_cidrs[0]
display_name = "${local.name_prefix}-public"
dns_label = "pub"
route_table_id = oci_core_route_table.public.id
security_list_ids = [oci_core_security_list.public.id]
freeform_tags = local.common_tags
}
resource "oci_core_subnet" "private" {
compartment_id = var.compartment_id
vcn_id = oci_core_vcn.main.id
cidr_block = var.private_subnet_cidrs[0]
display_name = "${local.name_prefix}-private"
dns_label = "priv"
route_table_id = oci_core_route_table.private.id
security_list_ids = [oci_core_security_list.private.id]
prohibit_public_ip_on_vnic = true
freeform_tags = local.common_tags
}
# ─────────────────────────────────────────────────────────────────────────────
# File Storage Service (FSS) NFS for SQLite
# ─────────────────────────────────────────────────────────────────────────────
resource "oci_file_storage_file_system" "main" {
compartment_id = var.compartment_id
availability_domain = local.ad_name
display_name = "${local.name_prefix}-data"
freeform_tags = local.common_tags
lifecycle {
prevent_destroy = true
}
}
resource "oci_file_storage_mount_target" "main" {
compartment_id = var.compartment_id
availability_domain = local.ad_name
subnet_id = oci_core_subnet.private.id
display_name = "${local.name_prefix}-mt"
freeform_tags = local.common_tags
}
resource "oci_file_storage_export_set" "main" {
mount_target_id = oci_file_storage_mount_target.main.id
display_name = "${local.name_prefix}-exports"
max_fs_stat_bytes = var.storage_size_gb * 1073741824 # GiB → bytes
}
resource "oci_file_storage_export" "main" {
export_set_id = oci_file_storage_export_set.main.id
file_system_id = oci_file_storage_file_system.main.id
path = "/appdata"
export_options {
source = var.private_subnet_cidrs[0]
access = "READ_WRITE"
identity_squash = "NONE"
require_privileged_source_port = false
}
}
# ─────────────────────────────────────────────────────────────────────────────
# Container Instances (Blue / Green)
# ─────────────────────────────────────────────────────────────────────────────
resource "oci_container_instances_container_instance" "blue" {
compartment_id = var.compartment_id
availability_domain = local.ad_name
display_name = "${local.name_prefix}-blue"
shape = "CI.Standard.E4.Flex"
shape_config {
ocpus = var.cpu / 1000.0
memory_in_gbs = var.memory / 1024.0
}
vnics {
subnet_id = oci_core_subnet.private.id
is_public_ip_assigned = false
}
containers {
display_name = "app"
image_url = var.app_container_image
environment_variables = var.environment_variables
health_checks {
health_check_type = "HTTP"
port = var.app_port
path = var.health_check_path
interval_in_seconds = 30
timeout_in_seconds = 5
}
resource_config {
vcpus_limit = var.cpu / 1000.0
memory_limit_in_gbs = var.memory / 1024.0
}
volume_mounts {
mount_path = "/app/data"
volume_name = "app-data"
is_read_only = false
}
}
dynamic "containers" {
for_each = var.mcp_container_image != "" ? [1] : []
content {
display_name = "mcp-sidecar"
image_url = var.mcp_container_image
environment_variables = {
NODE_ENV = "production"
MCP_PORT = tostring(var.mcp_port)
}
resource_config {
vcpus_limit = 0.25
memory_limit_in_gbs = 0.25
}
}
}
# NOTE: OCI Container Instances only support EMPTYDIR and CONFIGFILE volume
# types. For persistent NFS (FSS) storage, mount via the container entrypoint
# using the mount target IP from oci_file_storage_mount_target.main, or
# migrate to OCI Kubernetes Engine (OKE) which supports NFS PersistentVolumes.
volumes {
name = "app-data"
volume_type = "EMPTYDIR"
backing_store = "EPHEMERAL_STORAGE"
}
freeform_tags = merge(local.common_tags, {
deployment_slot = "blue"
})
lifecycle {
ignore_changes = [
freeform_tags["last_deployed"],
]
}
}
resource "oci_container_instances_container_instance" "green" {
count = var.active_deployment_slot == "green" || var.green_weight > 0 ? 1 : 0
compartment_id = var.compartment_id
availability_domain = local.ad_name
display_name = "${local.name_prefix}-green"
shape = "CI.Standard.E4.Flex"
shape_config {
ocpus = var.cpu / 1000.0
memory_in_gbs = var.memory / 1024.0
}
vnics {
subnet_id = oci_core_subnet.private.id
is_public_ip_assigned = false
}
containers {
display_name = "app"
image_url = var.app_container_image
environment_variables = var.environment_variables
health_checks {
health_check_type = "HTTP"
port = var.app_port
path = var.health_check_path
interval_in_seconds = 30
timeout_in_seconds = 5
}
resource_config {
vcpus_limit = var.cpu / 1000.0
memory_limit_in_gbs = var.memory / 1024.0
}
volume_mounts {
mount_path = "/app/data"
volume_name = "app-data"
is_read_only = false
}
}
# NOTE: OCI Container Instances only support EMPTYDIR and CONFIGFILE volume
# types. See blue instance comment for FSS mounting guidance.
volumes {
name = "app-data"
volume_type = "EMPTYDIR"
backing_store = "EPHEMERAL_STORAGE"
}
freeform_tags = merge(local.common_tags, {
deployment_slot = "green"
})
}
# ─────────────────────────────────────────────────────────────────────────────
# Flexible Load Balancer
# ─────────────────────────────────────────────────────────────────────────────
resource "oci_load_balancer_load_balancer" "main" {
compartment_id = var.compartment_id
display_name = "${local.name_prefix}-lb"
shape = "flexible"
shape_details {
minimum_bandwidth_in_mbps = var.environment == "production" ? 100 : 10
maximum_bandwidth_in_mbps = var.environment == "production" ? 1000 : 100
}
subnet_ids = [oci_core_subnet.public.id]
is_private = false
freeform_tags = local.common_tags
lifecycle {
prevent_destroy = false
}
}
# Backend set with health check
resource "oci_load_balancer_backend_set" "app" {
load_balancer_id = oci_load_balancer_load_balancer.main.id
name = "${local.name_prefix}-app-bs"
policy = "ROUND_ROBIN"
session_persistence_configuration {
cookie_name = "CCAM_SESSION"
is_secure = true
}
health_checker {
protocol = "HTTP"
port = var.app_port
url_path = var.health_check_path
return_code = 200
interval_ms = var.health_check_interval * 1000
timeout_in_millis = var.health_check_timeout * 1000
retries = var.health_check_unhealthy_threshold
}
}
# Blue backend
resource "oci_load_balancer_backend" "blue" {
load_balancer_id = oci_load_balancer_load_balancer.main.id
backendset_name = oci_load_balancer_backend_set.app.name
ip_address = oci_container_instances_container_instance.blue.vnics[0].private_ip
port = var.app_port
weight = var.blue_weight
}
# Green backend
resource "oci_load_balancer_backend" "green" {
count = length(oci_container_instances_container_instance.green) > 0 ? 1 : 0
load_balancer_id = oci_load_balancer_load_balancer.main.id
backendset_name = oci_load_balancer_backend_set.app.name
ip_address = oci_container_instances_container_instance.green[0].vnics[0].private_ip
port = var.app_port
weight = var.green_weight
}
# HTTP listener
resource "oci_load_balancer_listener" "http" {
load_balancer_id = oci_load_balancer_load_balancer.main.id
name = "${local.name_prefix}-http"
default_backend_set_name = oci_load_balancer_backend_set.app.name
port = 80
protocol = "HTTP"
connection_configuration {
idle_timeout_in_seconds = 300 # WebSocket support
}
}
# ─────────────────────────────────────────────────────────────────────────────
# OCI Monitoring Alarms and Notifications
# ─────────────────────────────────────────────────────────────────────────────
resource "oci_ons_notification_topic" "alerts" {
count = var.enable_monitoring ? 1 : 0
compartment_id = var.compartment_id
name = "${local.name_prefix}-alerts"
freeform_tags = local.common_tags
}
resource "oci_ons_subscription" "email" {
count = var.enable_monitoring && var.alert_email != "" ? 1 : 0
compartment_id = var.compartment_id
topic_id = oci_ons_notification_topic.alerts[0].id
protocol = "EMAIL"
endpoint = var.alert_email
freeform_tags = local.common_tags
}
resource "oci_monitoring_alarm" "lb_unhealthy" {
count = var.enable_monitoring ? 1 : 0
compartment_id = var.compartment_id
display_name = "${local.name_prefix}-unhealthy-backends"
namespace = "oci_lbaas"
query = "UnHealthyBackendCount[1m]{resourceId = \"${oci_load_balancer_load_balancer.main.id}\"}.max() > 0"
severity = "CRITICAL"
is_enabled = true
pending_duration = "PT5M"
destinations = var.alert_email != "" ? [oci_ons_notification_topic.alerts[0].id] : []
message_format = "ONS_OPTIMIZED"
body = "Unhealthy backends detected for ${local.name_prefix} load balancer"
freeform_tags = local.common_tags
}
resource "oci_monitoring_alarm" "lb_5xx" {
count = var.enable_monitoring ? 1 : 0
compartment_id = var.compartment_id
display_name = "${local.name_prefix}-high-5xx"
namespace = "oci_lbaas"
query = "HttpResponses5xx[1m]{resourceId = \"${oci_load_balancer_load_balancer.main.id}\"}.sum() > 10"
severity = "WARNING"
is_enabled = true
pending_duration = "PT5M"
destinations = var.alert_email != "" ? [oci_ons_notification_topic.alerts[0].id] : []
freeform_tags = local.common_tags
}
resource "oci_monitoring_alarm" "high_latency" {
count = var.enable_monitoring ? 1 : 0
compartment_id = var.compartment_id
display_name = "${local.name_prefix}-high-latency"
namespace = "oci_lbaas"
query = "BackendTimeFirstByte[1m]{resourceId = \"${oci_load_balancer_load_balancer.main.id}\"}.percentile(0.99) > 2000"
severity = "WARNING"
is_enabled = true
pending_duration = "PT5M"
destinations = var.alert_email != "" ? [oci_ons_notification_topic.alerts[0].id] : []
freeform_tags = local.common_tags
}