- Introduced Aggregator.sol for Chainlink-compatible oracle functionality, including round-based updates and access control. - Added OracleWithCCIP.sol to extend Aggregator with CCIP cross-chain messaging capabilities. - Created .gitmodules to include OpenZeppelin contracts as a submodule. - Developed a comprehensive deployment guide in NEXT_STEPS_COMPLETE_GUIDE.md for Phase 2 and smart contract deployment. - Implemented Vite configuration for the orchestration portal, supporting both Vue and React frameworks. - Added server-side logic for the Multi-Cloud Orchestration Portal, including API endpoints for environment management and monitoring. - Created scripts for resource import and usage validation across non-US regions. - Added tests for CCIP error handling and integration to ensure robust functionality. - Included various new files and directories for the orchestration portal and deployment scripts.
182 lines
6.1 KiB
HCL
182 lines
6.1 KiB
HCL
# Phase 2: Docker Compose Deployment - 5 US Commercial Azure Regions
|
|
# DeFi Oracle Meta Mainnet (ChainID 138)
|
|
#
|
|
# Architecture:
|
|
# - Deploys multi-service docker-compose stacks to Phase 1 VMs
|
|
# - Each region gets a region-specific docker-compose file
|
|
# - Services: Besu + FireFly + Cacti + Chainlink + Databases + Monitoring
|
|
#
|
|
# NOTE: Phase 1 must be deployed first. Phase 2 deploys docker-compose files to existing VMs.
|
|
|
|
terraform {
|
|
required_version = ">= 1.0"
|
|
|
|
required_providers {
|
|
azurerm = {
|
|
source = "hashicorp/azurerm"
|
|
version = "~> 3.0"
|
|
}
|
|
null = {
|
|
source = "hashicorp/null"
|
|
version = "~> 3.0"
|
|
}
|
|
local = {
|
|
source = "hashicorp/local"
|
|
version = "~> 2.0"
|
|
}
|
|
}
|
|
}
|
|
|
|
provider "azurerm" {
|
|
features {
|
|
resource_group {
|
|
prevent_deletion_if_contains_resources = var.environment == "prod" ? true : false
|
|
}
|
|
}
|
|
}
|
|
|
|
# Local values for configuration
|
|
locals {
|
|
cloud_provider = "az"
|
|
|
|
env_codes = {
|
|
prod = "p"
|
|
dev = "d"
|
|
test = "t"
|
|
staging = "s"
|
|
}
|
|
|
|
env_code = local.env_codes[var.environment]
|
|
|
|
# Region to docker-compose file mapping
|
|
region_compose_map = {
|
|
centralus = "docker-compose.cus.yml"
|
|
eastus = "docker-compose.eus.yml"
|
|
eastus2 = "docker-compose.eus2.yml"
|
|
westus = "docker-compose.wus.yml"
|
|
westus2 = "docker-compose.wus2.yml"
|
|
}
|
|
|
|
# Extract region from phase1_vm_info keys
|
|
regions = keys(var.phase1_vm_info)
|
|
|
|
# Common tags
|
|
common_tags = merge(var.tags, {
|
|
Environment = var.environment
|
|
CostCenter = "Blockchain"
|
|
Owner = "DevOps Team"
|
|
NamingConvention = "az-env-region-resource-instance"
|
|
DeploymentPhase = "phase2"
|
|
Project = "DeFi Oracle Meta Mainnet"
|
|
ChainID = "138"
|
|
})
|
|
}
|
|
|
|
# Create deployment directory structure on VMs and copy docker-compose files
|
|
resource "null_resource" "deploy_docker_compose" {
|
|
for_each = var.phase1_vm_info
|
|
|
|
triggers = {
|
|
# Trigger when compose file changes or VM info changes
|
|
compose_file_hash = filemd5("${var.docker_compose_source_path}/${local.region_compose_map[each.value.region]}")
|
|
# Use VM name, resource group, and IPs to create unique trigger
|
|
vm_identifier = "${each.value.resource_group}/${each.value.vm_names[0]}/${join(",", each.value.private_ips)}/${join(",", each.value.public_ips)}"
|
|
}
|
|
|
|
# Determine connection IP (prefer private IP, fallback to public IP)
|
|
# NOTE: This Terraform should be run from the Nginx proxy host (20.160.58.99)
|
|
# where direct access to private IPs is available
|
|
connection {
|
|
type = "ssh"
|
|
user = var.vm_admin_username
|
|
private_key = file(var.ssh_private_key_path)
|
|
host = length(each.value.private_ips) > 0 ? each.value.private_ips[0] : (length(each.value.public_ips) > 0 ? each.value.public_ips[0] : null)
|
|
timeout = "5m"
|
|
}
|
|
|
|
# Step 1: Create directories for docker-compose and volume mounts
|
|
provisioner "remote-exec" {
|
|
inline = [
|
|
"sudo mkdir -p /opt/docker-compose",
|
|
"sudo mkdir -p /opt/besu/{data,config,keys,logs}",
|
|
"sudo mkdir -p /opt/firefly/{postgres,postgres-primary,postgres-replica}",
|
|
"sudo mkdir -p /opt/cacti/{postgres,postgres-primary}",
|
|
"sudo mkdir -p /opt/prometheus",
|
|
"sudo mkdir -p /opt/grafana",
|
|
"sudo mkdir -p /opt/grafana-logs",
|
|
"sudo mkdir -p /opt/alertmanager",
|
|
"sudo mkdir -p /opt/loki/{data,config}",
|
|
"sudo mkdir -p /opt/ipfs/data",
|
|
"sudo mkdir -p /opt/promtail",
|
|
"sudo chown -R ${var.vm_admin_username}:${var.vm_admin_username} /opt/docker-compose",
|
|
"sudo chown -R ${var.vm_admin_username}:${var.vm_admin_username} /opt/besu",
|
|
"sudo chown -R ${var.vm_admin_username}:${var.vm_admin_username} /opt/firefly",
|
|
"sudo chown -R ${var.vm_admin_username}:${var.vm_admin_username} /opt/cacti",
|
|
"sudo chown -R ${var.vm_admin_username}:${var.vm_admin_username} /opt/prometheus",
|
|
"sudo chown -R ${var.vm_admin_username}:${var.vm_admin_username} /opt/grafana",
|
|
"sudo chown -R ${var.vm_admin_username}:${var.vm_admin_username} /opt/grafana-logs",
|
|
"sudo chown -R ${var.vm_admin_username}:${var.vm_admin_username} /opt/alertmanager",
|
|
"sudo chown -R ${var.vm_admin_username}:${var.vm_admin_username} /opt/loki",
|
|
"sudo chown -R ${var.vm_admin_username}:${var.vm_admin_username} /opt/ipfs",
|
|
"sudo chown -R ${var.vm_admin_username}:${var.vm_admin_username} /opt/promtail",
|
|
]
|
|
}
|
|
|
|
# Step 2: Copy docker-compose file to VM
|
|
provisioner "file" {
|
|
source = "${var.docker_compose_source_path}/${local.region_compose_map[each.value.region]}"
|
|
destination = "/tmp/docker-compose.yml"
|
|
}
|
|
|
|
# Step 3: Move file to final location and set permissions
|
|
provisioner "remote-exec" {
|
|
inline = [
|
|
"mv /tmp/docker-compose.yml /opt/docker-compose/docker-compose.yml",
|
|
"chmod 644 /opt/docker-compose/docker-compose.yml",
|
|
"chown ${var.vm_admin_username}:${var.vm_admin_username} /opt/docker-compose/docker-compose.yml",
|
|
]
|
|
}
|
|
|
|
}
|
|
|
|
# Create systemd service file for docker-compose stack
|
|
resource "null_resource" "create_systemd_service" {
|
|
for_each = var.phase1_vm_info
|
|
|
|
triggers = {
|
|
compose_deployed = null_resource.deploy_docker_compose[each.key].id
|
|
}
|
|
|
|
connection {
|
|
type = "ssh"
|
|
user = var.vm_admin_username
|
|
private_key = file(var.ssh_private_key_path)
|
|
host = length(each.value.private_ips) > 0 ? each.value.private_ips[0] : (length(each.value.public_ips) > 0 ? each.value.public_ips[0] : null)
|
|
timeout = "5m"
|
|
}
|
|
|
|
# Create systemd service file
|
|
provisioner "file" {
|
|
content = templatefile("${path.module}/templates/phase2-stack.service.tpl", {
|
|
admin_username = var.vm_admin_username
|
|
})
|
|
destination = "/tmp/phase2-stack.service"
|
|
}
|
|
|
|
# Install systemd service
|
|
provisioner "remote-exec" {
|
|
inline = [
|
|
"sudo mv /tmp/phase2-stack.service /etc/systemd/system/phase2-stack.service",
|
|
"sudo chmod 644 /etc/systemd/system/phase2-stack.service",
|
|
"sudo systemctl daemon-reload",
|
|
"sudo systemctl enable phase2-stack.service",
|
|
"# Service will be started manually or via separate apply"
|
|
]
|
|
}
|
|
|
|
depends_on = [
|
|
null_resource.deploy_docker_compose
|
|
]
|
|
}
|
|
|