diff --git a/oci.compute.tf b/oci.compute.tf index b9b7918..131160f 100644 --- a/oci.compute.tf +++ b/oci.compute.tf @@ -1,5 +1,66 @@ -resource "tls_private_key" "ssh_key" { - count = var.compute_ssh_key == null ? 1 : 0 +resource "tls_private_key" "compute_ssh_key" { + count = var.supplied_compute_ssh_public_key == null ? 1 : 0 - algorithm = var.created_ssh_key_algorithm + algorithm = var.created_compute_ssh_key_algorithm +} + +resource "oci_core_instance" "compute" { + for_each = local.compute_for_each_value + + compartment_id = oci_identity_compartment.compartment.id + availability_domain = local.compute_availability_domains[each.value.key][0] + display_name = join("", [var.prefix, each.value.key, each.value.index]) + shape = local.compute_shapes[each.value.key] + dynamic "shape_config" { + for_each = each.value.key == "flex" ? [1] : [] + content { + memory_in_gbs = 24 + ocpus = 4 + } + } + create_vnic_details { + assign_ipv6ip = var.enable_ipv6 + display_name = join("", [var.prefix, each.value.key, each.value.index]) + hostname_label = join("", [local.compute_dns_labels[each.value.key], each.value.index]) + subnet_id = oci_core_subnet.public.id + nsg_ids = [oci_core_network_security_group.default.id] + freeform_tags = merge(local.freeform_tags, { type = each.value.key }) + } + is_pv_encryption_in_transit_enabled = true # only used on creation + launch_options { + is_pv_encryption_in_transit_enabled = true # only used on update + is_consistent_volume_naming_enabled = true + network_type = "PARAVIRTUALIZED" + } + source_details { + source_type = "image" + source_id = data.oci_core_images.selected[each.value.key].images[0].id + boot_volume_size_in_gbs = each.value.key == "flex" ? 100 : 50 + boot_volume_vpus_per_gb = 120 + is_preserve_boot_volume_enabled = false + } + metadata = { + ssh_authorized_keys = local.compute_ssh_key + user_data = try(file("${path.module}/files/user_data.${each.value.key}.sh"), null) + } + availability_config { + is_live_migration_preferred = true + recovery_action = "RESTORE_INSTANCE" + } + freeform_tags = merge(local.freeform_tags, { type = each.value.key }) + + lifecycle { + ignore_changes = [ + # don't replace running instances when latest available image changes + source_details.0.source_id + ] + } +} + +resource "oci_core_public_ip" "static" { + count = var.create_static_ip ? 1 : 0 + compartment_id = oci_identity_compartment.compartment.id + lifetime = "RESERVED" + display_name = join("", [var.prefix, "static-ip"]) + # private_ip_id = var.attach_static_ip_to_flex ? data.oci_core_private_ips.flex.private_ips[0].id : null } diff --git a/oci.data.tf b/oci.data.tf index e878766..cda3d9e 100644 --- a/oci.data.tf +++ b/oci.data.tf @@ -1,3 +1,37 @@ data "oci_identity_tenancy" "tenancy" { tenancy_id = var.tenancy_id } + +data "oci_identity_availability_domains" "available" { + compartment_id = oci_identity_compartment.compartment.id +} + +data "oci_core_shapes" "available" { + for_each = { + for item in data.oci_identity_availability_domains.available.availability_domains : + item.name => item + } + + availability_domain = each.key + compartment_id = oci_identity_compartment.compartment.id +} + +data "oci_core_images" "selected" { + for_each = try(local.compute_shapes, {}) + compartment_id = oci_identity_compartment.compartment.id + operating_system = "Canonical Ubuntu" + shape = each.value + state = "available" + filter { + name = "display_name" + values = ["^Canonical-Ubuntu-\\d{1,2}\\.\\d{1,2}-(aarch64-)?[\\.0-9-]+$"] + regex = true + } +} + +# data "oci_core_private_ips" "flex" { +# count = (var.create_static_ip && var.attach_static_ip_to_flex) ? 1 : 0 +# +# ip_address = oci_core_instance.compute["flex_1"].private_ip +# subnet_id = oci_core_subnet.public.id +# } diff --git a/oci.locals.tf b/oci.locals.tf index bd437fb..3114b99 100644 --- a/oci.locals.tf +++ b/oci.locals.tf @@ -5,7 +5,48 @@ locals { "iac/source" = var.iac_project_source "iac/component" = var.iac_project_name } - # vcn dns label must be only alphanumeric and max 15 chars - vcn_dns_label = substr(replace(join("", [var.prefix, "vcn"]), "/(?i)[^0-9a-z]/", ""), 0, 15) - compute_ssh_key = coalesce(var.compute_ssh_key, trimspace(tls_private_key.ssh_key[0].public_key_openssh)) + # dns label must be only alphanumeric and max 15 chars + vcn_dns_label = substr(replace(join("", [var.prefix, "vcn"]), "/(?i)[^0-9a-z]/", ""), 0, 15) + compute_dns_labels = { + # reduce 1 from max length because an index suffix gets added later + micro = substr(replace(join("", [var.prefix, "micro"]), "/(?i)[^0-9a-z]/", ""), 0, 14) + flex = substr(replace(join("", [var.prefix, "flex"]), "/(?i)[^0-9a-z]/", ""), 0, 14) + } + compute_ssh_key = coalesce( + var.supplied_compute_ssh_public_key, + trimspace(tls_private_key.compute_ssh_key[0].public_key_openssh) + ) + + compute_shapes = { + micro = "VM.Standard.E2.1.Micro" + flex = "VM.Standard.A1.Flex" + } + + compute_counts = { + micro = var.create_instances.micro ? 2 : 0 + flex = var.create_instances.flex ? 1 : 0 + } + + compute_availability_domains = { + micro = !var.create_instances.micro ? [] : [ + for domain, value in data.oci_core_shapes.available : + domain if contains(value.shapes.*.name, local.compute_shapes.micro) + ] + flex = !var.create_instances.flex ? [] : [ + for domain, value in data.oci_core_shapes.available : + domain if contains(value.shapes.*.name, local.compute_shapes.flex) + ] + } + + # { micro_1 = micro, micro_2 = micro, flex_1 = flex } + compute_for_each_value = { + for item in toset(flatten([ + for shape in keys(local.compute_shapes) : [ + for n in range(local.compute_counts[shape]) : "${shape}_${n + 1}" + ]])) : + item => { + key = split("_", item)[0] + index = split("_", item)[1] + } + } } diff --git a/terraform.outputs.tf b/terraform.outputs.tf index 23ecc51..3eb543d 100644 --- a/terraform.outputs.tf +++ b/terraform.outputs.tf @@ -89,6 +89,26 @@ output "ssh_key_public" { output "ssh_key_private" { description = "The created SSH private key for the compute instances" - value = try(tls_private_key.ssh_key[0].private_key_pem, null) + value = try(trimspace(tls_private_key.compute_ssh_key[0].private_key_pem), null) sensitive = true } + +output "reserved_ip" { + description = "The reserved public IP address" + value = oci_core_public_ip.static[0].ip_address +} + +output "instance_ips" { + description = "The public IP addresses of the instances" + value = { for k, v in oci_core_instance.compute : k => v.public_ip } +} + +output "instance_availability_domains" { + description = "The availability domains of the instances" + value = { for k, v in oci_core_instance.compute : k => v.availability_domain } +} + +output "instance_selected_images" { + description = "The selected images for each instance shape" + value = { for k, v in data.oci_core_images.selected : k => v.images[0].display_name } +} diff --git a/terraform.variables.tf b/terraform.variables.tf index 977820d..82d416a 100644 --- a/terraform.variables.tf +++ b/terraform.variables.tf @@ -81,13 +81,13 @@ variable "use_vault" { } } -variable "compute_ssh_key" { +variable "supplied_compute_ssh_public_key" { description = "A pre-created public SSH key for the compute instances" type = string default = null } -variable "created_ssh_key_algorithm" { +variable "created_compute_ssh_key_algorithm" { description = "The algorithm for the created SSH key if no key is provided" type = string default = "ED25519"