diff --git a/main.tf b/main.tf index def01b8d..fd7eaadc 100644 --- a/main.tf +++ b/main.tf @@ -65,6 +65,7 @@ module "landing_zone_vsi" { existing_resource_group = var.existing_resource_group prefix = var.prefix vpc_id = local.vpc_id + zones = var.zones bastion_security_group_id = var.bastion_security_group_id bastion_public_key_content = local.bastion_public_key_content client_subnets = local.client_subnets @@ -89,6 +90,7 @@ module "landing_zone_vsi" { ldap_vsi_profile = var.ldap_vsi_profile ldap_vsi_osimage_name = var.ldap_vsi_osimage_name ldap_server = var.ldap_server + enable_dedicated_host = var.enable_dedicated_host } module "prepare_tf_input" { @@ -123,6 +125,7 @@ module "prepare_tf_input" { deployer_hostname = local.deployer_hostname enable_hyperthreading = var.enable_hyperthreading enable_ldap = var.enable_ldap + enable_dedicated_host = var.enable_dedicated_host ldap_vsi_profile = var.ldap_vsi_profile ldap_vsi_osimage_name = var.ldap_vsi_osimage_name ldap_basedns = var.ldap_basedns diff --git a/modules/dedicated_host/README.md b/modules/dedicated_host/README.md new file mode 100644 index 00000000..c194c91f --- /dev/null +++ b/modules/dedicated_host/README.md @@ -0,0 +1,5 @@ +# Basic example + +An end-to-end basic example that will provision the following: +- A new dedicated host will be created. +- A new dedicated host group will be created and add the created dedicated host to the group. diff --git a/modules/dedicated_host/main.tf b/modules/dedicated_host/main.tf new file mode 100644 index 00000000..cd3b945b --- /dev/null +++ b/modules/dedicated_host/main.tf @@ -0,0 +1,25 @@ +######################################################################################################################## +# Dedicated Host Module +######################################################################################################################## + +module "dedicated_host" { + source = "terraform-ibm-modules/dedicated-host/ibm" + version = "1.1.0" + dedicated_hosts = [ + { + host_group_name = "${var.prefix}-dhgroup" + existing_host_group = var.existing_host_group + resource_group_id = var.resource_group_id + class = var.class + family = var.family + zone = var.zone[0] + resource_tags = var.resource_tags + dedicated_host = [ + { + name = "${var.prefix}-dhhost" + profile = var.profile + } + ] + } + ] +} diff --git a/modules/dedicated_host/outputs.tf b/modules/dedicated_host/outputs.tf new file mode 100644 index 00000000..2a99e37c --- /dev/null +++ b/modules/dedicated_host/outputs.tf @@ -0,0 +1,13 @@ +############################################################################## +# Outputs +############################################################################## + +output "dedicated_host_id" { + value = module.dedicated_host.dedicated_host_ids + description = "List the Dedicated Host ID's" +} + +output "dedicated_host_group_id" { + value = module.dedicated_host.dedicated_host_group_ids + description = "List the Dedicated Host Group ID's" +} diff --git a/modules/dedicated_host/variables.tf b/modules/dedicated_host/variables.tf new file mode 100644 index 00000000..839a96be --- /dev/null +++ b/modules/dedicated_host/variables.tf @@ -0,0 +1,46 @@ +######################################################################################################################## +# Dedicated Host Input Variables +######################################################################################################################## + +variable "prefix" { + type = string + description = "Name of the resources" +} + +variable "resource_tags" { + type = list(string) + description = "A list of access tags to apply to the resources created by the module." + default = [] +} + +variable "resource_group_id" { + type = string + description = "The name of the resource group where you want to create the service." +} + +variable "existing_host_group" { + type = bool + description = "Allows users to use an existing dedicated host group when set to true. Checks for the host_group_name and validates if exists, if not creates new one." + default = false +} + +variable "zone" { + type = list(string) + description = "Particular zone selection for creating the dedicated host." + default = null +} + +variable "family" { + description = "Family defines the purpose of the dedicated host, The dedicated host family can be defined from balanced,compute or memory. Refer [Understanding DH Profile family](https://cloud.ibm.com/docs/vpc?topic=vpc-dh-profiles&interface=ui) for more details" + type = string +} + +variable "class" { + description = "Profile class of the dedicated host, this has to be defined based on the VSI usage. Refer [Understanding DH Class](https://cloud.ibm.com/docs/vpc?topic=vpc-dh-profiles&interface=ui) for more details" + type = string +} + +variable "profile" { + description = "Profile for the dedicated hosts(size and resources). Refer [Understanding DH Profile](https://cloud.ibm.com/docs/vpc?topic=vpc-dh-profiles&interface=ui) for more details" + type = string +} diff --git a/modules/dedicated_host/version.tf b/modules/dedicated_host/version.tf new file mode 100644 index 00000000..bfb98ab9 --- /dev/null +++ b/modules/dedicated_host/version.tf @@ -0,0 +1,3 @@ +terraform { + required_version = ">= 1.9.0" +} diff --git a/modules/landing_zone_vsi/datasource.tf b/modules/landing_zone_vsi/datasource.tf index f923e0ad..76af4000 100644 --- a/modules/landing_zone_vsi/datasource.tf +++ b/modules/landing_zone_vsi/datasource.tf @@ -66,3 +66,7 @@ data "ibm_is_image" "ldap_vsi_image" { name = var.ldap_vsi_osimage_name count = var.ldap_server == "null" ? 1 : 0 } + +data "ibm_is_dedicated_host_profiles" "profiles" { + count = var.enable_dedicated_host ? 1 : 0 +} diff --git a/modules/landing_zone_vsi/locals.tf b/modules/landing_zone_vsi/locals.tf index 37d24f3a..5c37eee7 100644 --- a/modules/landing_zone_vsi/locals.tf +++ b/modules/landing_zone_vsi/locals.tf @@ -281,3 +281,91 @@ locals { ldap_instance_image_id = var.enable_ldap == true && var.ldap_server == "null" ? data.ibm_is_image.ldap_vsi_image[0].id : "null" } + +locals { + + # Getting current/available dedicated host profiles + current_dh_profiles = var.enable_dedicated_host ? [for p in data.ibm_is_dedicated_host_profiles.profiles[0].profiles : p if p.status == "current"] : [] + + # Get valid instance profiles from available dedicated hosts + valid_instance_profiles = toset(distinct(flatten([ + for p in local.current_dh_profiles : p.supported_instance_profiles[*].name + ]))) + + # Extract profile family prefix (e.g., "bx2" from "bx2-16x64") + instance_profile_prefixes = distinct([ + for inst in var.static_compute_instances : + regex("^([a-z]+[0-9]+)", inst.profile)[0] + ]) + + # Map instance profile prefixes to available dedicated host profiles + profile_mappings = { + for prefix in local.instance_profile_prefixes : + prefix => { + dh_profiles = [ + for p in local.current_dh_profiles : + p if startswith(p.name, "${prefix}-host") + ] + } + } + + # Validate each instance configuration + validation_results = [ + for inst in var.static_compute_instances : { + profile = inst.profile + profile_prefix = regex("^([a-z]+[0-9]+)", inst.profile)[0] + count = inst.count + instance_valid = contains(local.valid_instance_profiles, inst.profile) + dh_profile_available = length(local.profile_mappings[regex("^([a-z]+[0-9]+)", inst.profile)[0]].dh_profiles) > 0 + } if inst.count > 0 + ] + + # Error messages for invalid configurations + errors = concat( + [ + for vr in local.validation_results : + "ERROR: Instance profile '${vr.profile}' is not available in this region" + if !vr.instance_valid + ], + [ + for vr in local.validation_results : + "ERROR: No CURRENT dedicated host profile available for '${vr.profile_prefix}-host-*' (required for '${vr.profile}')" + if vr.instance_valid && !vr.dh_profile_available + ] + ) + + # Create one dedicated host config per instance profile (not per count) + dedicated_host_config = { + for vr in local.validation_results : + vr.profile => { + class = vr.profile_prefix + profile = local.profile_mappings[vr.profile_prefix].dh_profiles[0].name + family = local.profile_mappings[vr.profile_prefix].dh_profiles[0].family + count = vr.count + } + if vr.instance_valid && vr.dh_profile_available + } + + dedicated_host_ids = [ + for instance in var.static_compute_instances : { + profile = instance.profile + id = try(one(module.dedicated_host[instance.profile].dedicated_host_id), "") + } + ] + + dedicated_host_map = { for instance in local.dedicated_host_ids : instance.profile => instance.id } + +} + +# Validating profile configurations +check "profile_validation" { + assert { + condition = length(local.errors) == 0 + error_message = join("\n", concat( + ["Deployment configuration invalid:"], + local.errors, + ["", "Available CURRENT dedicated host profiles:"], + [for p in local.current_dh_profiles : " - ${p.name} (${p.family})"] + )) + } +} diff --git a/modules/landing_zone_vsi/main.tf b/modules/landing_zone_vsi/main.tf index b0fb008b..914c24b4 100644 --- a/modules/landing_zone_vsi/main.tf +++ b/modules/landing_zone_vsi/main.tf @@ -178,6 +178,8 @@ module "compute_vsi" { skip_iam_authorization_policy = local.skip_iam_authorization_policy boot_volume_encryption_key = var.boot_volume_encryption_key placement_group_id = var.placement_group_ids + enable_dedicated_host = var.enable_dedicated_host + dedicated_host_id = var.enable_dedicated_host ? local.dedicated_host_map[var.static_compute_instances[count.index]["profile"]] : null #placement_group_id = var.placement_group_ids[(var.static_compute_instances[count.index]["count"])%(length(var.placement_group_ids))] } @@ -236,3 +238,18 @@ module "protocol_vsi" { placement_group_id = var.placement_group_ids #placement_group_id = var.placement_group_ids[(var.protocol_instances[count.index]["count"])%(length(var.placement_group_ids))] } + +######################################################################## +### Dedicated Host ### +######################################################################## +module "dedicated_host" { + for_each = var.enable_dedicated_host ? local.dedicated_host_config : {} + source = "../dedicated_host" + prefix = var.prefix + zone = var.zones + existing_host_group = false + class = each.value.class + profile = each.value.profile + family = each.value.family + resource_group_id = local.resource_group_id +} diff --git a/modules/landing_zone_vsi/variables.tf b/modules/landing_zone_vsi/variables.tf index 0d776ac7..6c9222e8 100644 --- a/modules/landing_zone_vsi/variables.tf +++ b/modules/landing_zone_vsi/variables.tf @@ -45,6 +45,11 @@ variable "vpc_id" { description = "ID of an existing VPC in which the cluster resources will be deployed." } +variable "zones" { + description = "Region where VPC will be created. To find your VPC region, use `ibmcloud is regions` command to find available regions." + type = list(string) +} + variable "placement_group_ids" { type = string default = null @@ -346,3 +351,13 @@ variable "ldap_vsi_osimage_name" { default = "ibm-ubuntu-22-04-4-minimal-amd64-3" description = "Image name to be used for provisioning the LDAP instances. By default ldap server are created on Ubuntu based OS flavour." } + +############################################################################## +# Dedicatedhost Variables +############################################################################## + +variable "enable_dedicated_host" { + type = bool + default = false + description = "Enables dedicated host to the compute instances" +} diff --git a/modules/prepare_tf_input/main.tf b/modules/prepare_tf_input/main.tf index dcf6b56a..79eb010e 100644 --- a/modules/prepare_tf_input/main.tf +++ b/modules/prepare_tf_input/main.tf @@ -59,7 +59,8 @@ resource "local_sensitive_file" "prepare_tf_input" { "observability_monitoring_on_compute_nodes_enable": ${var.observability_monitoring_on_compute_nodes_enable}, "observability_enable_metrics_routing": ${var.observability_enable_metrics_routing}, "observability_atracker_enable": ${var.observability_atracker_enable}, - "observability_atracker_target_type": "${var.observability_atracker_target_type}" + "observability_atracker_target_type": "${var.observability_atracker_target_type}", + "enable_dedicated_host": "${var.enable_dedicated_host}" } EOT filename = local.schematics_inputs_path diff --git a/modules/prepare_tf_input/variables.tf b/modules/prepare_tf_input/variables.tf index 01ad0f5a..712107f0 100644 --- a/modules/prepare_tf_input/variables.tf +++ b/modules/prepare_tf_input/variables.tf @@ -444,3 +444,13 @@ variable "ldap_vsi_osimage_name" { default = "ibm-ubuntu-22-04-4-minimal-amd64-3" description = "Image name to be used for provisioning the LDAP instances. By default ldap server are created on Ubuntu based OS flavour." } + +############################################################################## +# Dedicatedhost Variables +############################################################################## + +variable "enable_dedicated_host" { + type = bool + default = false + description = "Enables dedicated host to the compute instances" +} diff --git a/solutions/lsf/locals.tf b/solutions/lsf/locals.tf index d18b1eb6..ae31676c 100644 --- a/solutions/lsf/locals.tf +++ b/solutions/lsf/locals.tf @@ -93,6 +93,7 @@ locals { ldap_server = var.ldap_server ldap_server_cert = var.ldap_server_cert ldap_vsi_osimage_name = var.ldap_vsi_osimage_name + enable_dedicated_host = var.enable_dedicated_host # scc_profile_version = var.scc_profile_version } @@ -176,6 +177,7 @@ locals { ldap_server = lookup(local.override[local.override_type], "ldap_server", local.config.ldap_server) ldap_server_cert = lookup(local.override[local.override_type], "ldap_server_cert", local.config.ldap_server_cert) ldap_vsi_osimage_name = lookup(local.override[local.override_type], "ldap_vsi_osimage_name", local.config.ldap_vsi_osimage_name) + enable_dedicated_host = lookup(local.override[local.override_type], "enable_dedicated_host", local.config.enable_dedicated_host) # scc_profile_version = lookup(local.override[local.override_type], "scc_profile_version", local.config.scc_profile_version) } } diff --git a/solutions/lsf/main.tf b/solutions/lsf/main.tf index 0d508683..631fc659 100644 --- a/solutions/lsf/main.tf +++ b/solutions/lsf/main.tf @@ -72,6 +72,7 @@ module "lsf" { ldap_server = local.env.ldap_server ldap_server_cert = local.env.ldap_server_cert ldap_vsi_osimage_name = local.env.ldap_vsi_osimage_name + enable_dedicated_host = var.enable_dedicated_host # compute_gui_password = local.env.compute_gui_password # compute_gui_username = local.env.compute_gui_username diff --git a/solutions/lsf/variables.tf b/solutions/lsf/variables.tf index 268a2550..6897666c 100644 --- a/solutions/lsf/variables.tf +++ b/solutions/lsf/variables.tf @@ -706,3 +706,13 @@ variable "override_json_string" { default = null description = "Override default values with a JSON object. Any JSON other than an empty string overrides other configuration changes." } + +############################################################################## +# Dedicatedhost Variables +############################################################################## + +variable "enable_dedicated_host" { + type = bool + default = false + description = "Enables dedicated host to the compute instances" +} diff --git a/variables.tf b/variables.tf index f12cb6ba..85b03e6b 100644 --- a/variables.tf +++ b/variables.tf @@ -861,3 +861,13 @@ variable "scc_cos_instance_crn" { default = null description = "scc cos instance crn" } + +############################################################################## +# Dedicatedhost Variables +############################################################################## + +variable "enable_dedicated_host" { + type = bool + default = false + description = "Enables dedicated host to the compute instances" +}