From f2cd99cf45c60283641ae1010c182da6e061de35 Mon Sep 17 00:00:00 2001 From: nikchern Date: Fri, 1 Dec 2023 09:00:42 -0800 Subject: [PATCH] PLT-834: MAAS cluster support in tf modules. (#79) * PLT-709: Support latest TF provider changes in 0.15.x. * fixed cluster_context in addon deployment * PLT-821: edge hosts attribute reference fix. // verified and correct commit. * PLT-834: MAAS cluster support in tf modules. --------- Co-authored-by: Sivaanand Murugesan --- .../maas/config/account/account-maas.yaml | 6 + .../maas/config/cluster/cluster-maas.yaml | 35 ++++ examples/maas/mod_spectro_org.tf | 31 +++ examples/maas/providers.tf | 28 +++ examples/maas/terraform.template.tfvars | 4 + .../tke/config/cluster/cluster-tke-dev.yaml | 31 --- spectro-account-maas.tf | 28 +++ spectro-accounts-common.tf | 2 + spectro-cluster-common.tf | 5 +- spectro-cluster-maas.tf | 184 ++++++++++++++++++ 10 files changed, 322 insertions(+), 32 deletions(-) create mode 100644 examples/maas/config/account/account-maas.yaml create mode 100644 examples/maas/config/cluster/cluster-maas.yaml create mode 100644 examples/maas/mod_spectro_org.tf create mode 100644 examples/maas/providers.tf create mode 100644 examples/maas/terraform.template.tfvars delete mode 100644 examples/tke/config/cluster/cluster-tke-dev.yaml create mode 100644 spectro-account-maas.tf create mode 100644 spectro-cluster-maas.tf diff --git a/examples/maas/config/account/account-maas.yaml b/examples/maas/config/account/account-maas.yaml new file mode 100644 index 0000000..fb61726 --- /dev/null +++ b/examples/maas/config/account/account-maas.yaml @@ -0,0 +1,6 @@ +name: "maas-account-tf" +cloudType: maas +maas_api_endpoint: "{Enter endpoint}" +maas_api_key: "{Enter key}" +private_cloud_gateway_id: "{Enter gateway id here}" + diff --git a/examples/maas/config/cluster/cluster-maas.yaml b/examples/maas/config/cluster/cluster-maas.yaml new file mode 100644 index 0000000..9b65d77 --- /dev/null +++ b/examples/maas/config/cluster/cluster-maas.yaml @@ -0,0 +1,35 @@ +name: maas-cl +cloudType: maas +context: "project" +cloud_account: "maas-1" +profiles: + infra: + name: DevMaas2 + version: 1.0.0 + context: project +apply_setting: "DownloadAndInstall" +tags: [] +cloud_config: + maas_domain: "maas.sc" +cluster_profiles: + - id: "ProfileID" + packs: + - name: "PackName" + tag: "1.0.0" + registry_uid: "RegistryUID" + type: "spectro" + values: "Values" + manifests: + - name: "ManifestName" + content: "ManifestContent" +node_groups: + - name: master-pool + count: 3 + disk_size_gb: 60 + control_plane_as_worker: true + control_plane: true + min_memory_mb: 8192 + min_cpu: 4 + azs: ["az2"] + placement: + - resource_pool: bm-generic diff --git a/examples/maas/mod_spectro_org.tf b/examples/maas/mod_spectro_org.tf new file mode 100644 index 0000000..a841ac4 --- /dev/null +++ b/examples/maas/mod_spectro_org.tf @@ -0,0 +1,31 @@ +locals { + accounts_params = {} + profile_params = {} + clusters_params = {} +} + +module "SpectroOrg" { + source = "../../" + + /*accounts = { + for k in fileset("config/account", "account-*.yaml") : + trimsuffix(k, ".yaml") => yamldecode(templatefile("config/account/${k}", local.accounts_params)) + }*/ + + profiles = { + for k in fileset("config/profile", "profile-*.yaml") : + trimsuffix(k, ".yaml") => yamldecode(templatefile("config/profile/${k}", local.profile_params)) + } + + +} + +module "SpectroProject" { + depends_on = [module.SpectroOrg] + source = "../../" + + clusters = { + for k in fileset("config/cluster", "cluster-*.yaml") : + trimsuffix(k, ".yaml") => yamldecode(templatefile("config/cluster/${k}", local.clusters_params)) + } +} diff --git a/examples/maas/providers.tf b/examples/maas/providers.tf new file mode 100644 index 0000000..3b0c88a --- /dev/null +++ b/examples/maas/providers.tf @@ -0,0 +1,28 @@ +terraform { + required_providers { + spectrocloud = { + version = ">= 0.17.0" + source = "spectrocloud/spectrocloud" + } + } +} + +variable "sc_host" { + description = "Spectro Cloud Endpoint" + default = "api.spectrocloud.com" +} + +variable "sc_api_key" { + description = "Spectro Cloud API key" +} + +variable "sc_project_name" { + description = "Spectro Cloud Project (e.g: Default)" + default = "Default" +} + +provider "spectrocloud" { + host = var.sc_host + api_key = var.sc_api_key + project_name = var.sc_project_name +} diff --git a/examples/maas/terraform.template.tfvars b/examples/maas/terraform.template.tfvars new file mode 100644 index 0000000..eeadb1b --- /dev/null +++ b/examples/maas/terraform.template.tfvars @@ -0,0 +1,4 @@ +# Spectro Cloud credentials +sc_host = "{enter Spectro Cloud API endpoint}" #e.g: api.spectrocloud.com (for SaaS) +sc_api_key = "{enter Spectro Cloud API Key}" #e.g: Q28GBs7ssdvNNkERWeWpqwSLfI1nnit6W +sc_project_name = "{enter Spectro Cloud project Name}" #e.g: Default \ No newline at end of file diff --git a/examples/tke/config/cluster/cluster-tke-dev.yaml b/examples/tke/config/cluster/cluster-tke-dev.yaml deleted file mode 100644 index 61b9a73..0000000 --- a/examples/tke/config/cluster/cluster-tke-dev.yaml +++ /dev/null @@ -1,31 +0,0 @@ -name: tke-dev -cloudType: tke -cloud_account: "tencent-account-tf-simyam" -profiles: - infra: - name: profile_infra_tke_simyam - addons: - - name: addon-profile-tke-tf1 -cloud_config: - tke_region: ap-mumbai - tke_vpc_id: vpc-hpzmtrp0 - endpoint_access: private - tke_subnets: - us-east-1a: subnet-0931c5e4f56d3,subnet-0c494a15916ac3c - us-east-1b: subnet-022297ad=0f29,subnet-0a75634ca45df8f -node_groups: - - name: worker-basic - count: 3 - disk_size_gb: 61 - instance_type: t3.large - worker_subnets: - us-east-1a: subnet-0dac5b9c4d0d5c - us-east-1b: subnet-0d710ba055568b -backup_policy: - schedule: "0 0 * * SUN" - backup_location: qa-sharma - prefix: weekly -scan_policy: - configuration_scan_schedule: "0 0 * * SUN" - penetration_scan_schedule: "0 0 * * SUN" - conformance_scan_schedule: "0 0 1 * *" \ No newline at end of file diff --git a/spectro-account-maas.tf b/spectro-account-maas.tf new file mode 100644 index 0000000..73a7205 --- /dev/null +++ b/spectro-account-maas.tf @@ -0,0 +1,28 @@ +locals { + maas_clusters_cloud_account_names = toset([for v in local.maas_clusters : v.cloud_account]) + maas_cloud_account_names_data_map = {for v in data.spectrocloud_cloudaccount_maas.this : v.name => v.id} + maas_cloud_account_names_resource_map = {for v in spectrocloud_cloudaccount_maas.account : v.name => v.id} + maas_cloud_account_names = merge(local.maas_cloud_account_names_data_map, local.maas_cloud_account_names_resource_map) +} + + +data "spectrocloud_cloudaccount_maas" "this" { + // TODO: Add depends on the resource once implemented. + for_each = local.maas_clusters_cloud_account_names + + name = each.key +} + +resource "spectrocloud_cloudaccount_maas" "account" { + for_each = { for x in local.maas_accounts : x.name => x } + + name = each.value.name + context = try(each.value.context, "project") + private_cloud_gateway_id = each.value.private_cloud_gateway_id + maas_api_endpoint = each.value.maas_api_endpoint + maas_api_key = each.value.maas_api_key +} + +output "debug_maas_accounts" { + value = local.maas_cloud_account_names +} \ No newline at end of file diff --git a/spectro-accounts-common.tf b/spectro-accounts-common.tf index afdabc2..90d4115 100644 --- a/spectro-accounts-common.tf +++ b/spectro-accounts-common.tf @@ -7,4 +7,6 @@ locals { tke_accounts = [for key in local.account_tke_keys : lookup(local.account_map, key)] account_vsphere_keys = compact([for i, account in local.account_map : account.cloudType == "vsphere" ? i : ""]) vsphere_accounts = [for key in local.account_vsphere_keys : lookup(local.account_map, key)] + account_maas_keys = compact([for i, account in local.account_map : account.cloudType == "maas" ? i : ""]) + maas_accounts = [for key in local.account_maas_keys : lookup(local.account_map, key)] } \ No newline at end of file diff --git a/spectro-cluster-common.tf b/spectro-cluster-common.tf index 976dcdf..726f586 100644 --- a/spectro-cluster-common.tf +++ b/spectro-cluster-common.tf @@ -8,6 +8,9 @@ locals { eks_clusters = [for key in local.eks_keys : lookup(local.cluster_map, key)] tke_keys = compact([for i, cluster in local.cluster_map : cluster.cloudType == "tke" ? i : ""]) tke_clusters = [for key in local.tke_keys : lookup(local.cluster_map, key)] + + maas_keys = compact([for i, cluster in local.cluster_map : cluster.cloudType == "maas" ? i : ""]) + maas_clusters = [for key in local.maas_keys : lookup(local.cluster_map, key)] vsphere_keys = compact([for i, cluster in local.cluster_map : cluster.cloudType == "vsphere" ? i : ""]) vsphere_clusters = [for key in local.vsphere_keys : lookup(local.cluster_map, key)] @@ -25,7 +28,7 @@ locals { data "spectrocloud_cluster" "clusters" { depends_on = [spectrocloud_cluster_tke.this, spectrocloud_cluster_edge_vsphere.this, - spectrocloud_cluster_eks.this, spectrocloud_cluster_libvirt.this] + spectrocloud_cluster_eks.this, spectrocloud_cluster_libvirt.this, spectrocloud_cluster_maas.this] for_each = local.cluster_map name = each.value.name diff --git a/spectro-cluster-maas.tf b/spectro-cluster-maas.tf new file mode 100644 index 0000000..eedad8e --- /dev/null +++ b/spectro-cluster-maas.tf @@ -0,0 +1,184 @@ +resource "spectrocloud_cluster_maas" "this" { + for_each = { for x in local.maas_clusters : x.name => x } + name = each.value.name + context = try(each.value.context, "project") + apply_setting = try(each.value.apply_setting, "DownloadAndInstall") + tags = try(each.value.tags, []) + + cloud_config { + domain = each.value.cloud_config.maas_domain # "maas.sc" + } + + os_patch_schedule = can(each.value.os_patch_schedule) ? each.value.os_patch_schedule : null + + dynamic "cluster_rbac_binding" { + for_each = try(each.value.cluster_rbac_binding, []) + content { + type = cluster_rbac_binding.value.type + namespace = try(cluster_rbac_binding.value.namespace, "") + + role = { + kind = cluster_rbac_binding.value.role.kind + name = cluster_rbac_binding.value.role.name + } + + dynamic "subjects" { + for_each = try(cluster_rbac_binding.value.subjects, []) + + content { + type = subjects.value.type + name = subjects.value.name + namespace = try(subjects.value.namespace, "") + } + } + } + } + + dynamic "namespaces" { + for_each = try(each.value.namespaces, []) + + content { + name = namespaces.value.name + resource_allocation = { + cpu_cores = try(namespaces.value.resource_allocation.cpu_cores, "") + memory_MiB = try(namespaces.value.resource_allocation.memory_MiB, "") + } + } + } + + cluster_profile { + id = (local.profile_map[format("%s%%%s%%%s", + each.value.profiles.infra.name, + try(each.value.profiles.infra.version, "1.0.0"), + try(each.value.profiles.infra.context, "project"))].id) + + dynamic "pack" { + for_each = try(each.value.profiles.infra.packs, []) + content { + name = pack.value.name + tag = try(pack.value.version, "") + registry_uid = try(local.all_registry_map[pack.value.registry][0], "") + type = (try(pack.value.is_manifest_pack, false)) ? "manifest" : "spectro" + values = "${(try(pack.value.is_manifest_pack, false)) ? + local.cluster-profile-pack-map[format("%s%%%s%%%s$%s", each.value.profiles.infra.name, try(each.value.profiles.infra.version, "1.0.0"), try(each.value.profiles.infra.context, "project"), pack.value.name)].values : + (pack.value.override_type == "values") ? + pack.value.values : + (pack.value.override_type == "params" ? + local.infra-pack-params-replaced[format("%s$%s%%%s%%%s$%s", each.value.name, each.value.profiles.infra.name, try(each.value.profiles.infra.version, "1.0.0"), try(each.value.profiles.infra.context, "project"), pack.value.name)] : + local.infra-pack-template-params-replaced[format("%s$%s%%%s%%%s$%s", each.value.name, each.value.profiles.infra.name, try(each.value.profiles.infra.version, "1.0.0"), try(each.value.profiles.infra.context, "project"), pack.value.name)]) + }" + + dynamic "manifest" { + for_each = try([local.infra_pack_manifests[format("%s$%s%%%s%%%s$%s", each.value.name, each.value.profiles.infra.name, try(each.value.profiles.infra.version, "1.0.0"), try(each.value.profile.infra.context, "project"), pack.value.name)]], []) + content { + name = manifest.value.name + content = manifest.value.content + } + } + } + } + } + + dynamic "cluster_profile" { + for_each = try(each.value.profiles.addons, []) + + content { + id = (local.profile_map[format("%s%%%s%%%s", + cluster_profile.value.name, + try(cluster_profile.value.version, "1.0.0"), + try(cluster_profile.value.context, "project"))].id) + + dynamic "pack" { + for_each = try(cluster_profile.value.packs, []) + content { + name = pack.value.name + tag = try(pack.value.version, "") + registry_uid = try(local.all_registry_map[pack.value.registry][0], "") + type = (try(pack.value.is_manifest_pack, false)) ? "manifest" : "spectro" + values = "${(try(pack.value.is_manifest_pack, false)) ? + local.cluster-profile-pack-map[format("%s%%%s%%%s$%s", cluster_profile.value.name, try(cluster_profile.value.version, "1.0.0"), try(cluster_profile.value.context, "project"), pack.value.name)].values : + (pack.value.override_type == "values") ? + pack.value.values : + (pack.value.override_type == "params" ? + local.addon_pack_params_replaced[format("%s$%s%%%s%%%s$%s", each.value.name, cluster_profile.value.name, try(cluster_profile.value.version, "1.0.0"), try(cluster_profile.value.context, "project"), pack.value.name)] : + local.addon_pack_template_params_replaced[format("%s$%s%%%s%%%s$%s", each.value.name, cluster_profile.value.name, try(cluster_profile.value.version, "1.0.0"), try(cluster_profile.value.context, "project"), pack.value.name)]) + }" + + dynamic "manifest" { + for_each = try(local.addon_pack_manifests[format("%s$%s%%%s%%%s$%s", each.value.name, cluster_profile.value.name, try(cluster_profile.value.version, "1.0.0"), try(cluster_profile.value.context, "project"), pack.value.name)], []) + content { + name = manifest.value.name + content = manifest.value.content + } + } + } + } + } + } + + cloud_account_id = lookup(local.maas_cloud_account_names, each.value.cloud_account, null) + + dynamic "machine_pool" { + for_each = each.value.node_groups + content { + name = machine_pool.value.name + control_plane = try(machine_pool.value.control_plane, false) + control_plane_as_worker = try(machine_pool.value.control_plane_as_worker, false) + count = machine_pool.value.count + min = try(machine_pool.value.min, machine_pool.value.count) # It is possible for the chosen max to be lesser than the min, or for the count to be out of bounds of min or max. Handle these conditions in the provider for this module or as input validation prior to using this module. + max = try(machine_pool.value.max, machine_pool.value.count) + node_repave_interval = can(machine_pool.value.node_repave_interval) ? machine_pool.value.node_repave_interval : null + update_strategy = try(machine_pool.value.update_strategy, "RollingUpdateScaleOut") + + dynamic "placement" { + for_each = machine_pool.value.placement + content { + resource_pool = placement.value.resource_pool + } + } + instance_type { + min_memory_mb = machine_pool.value.min_memory_mb + min_cpu = machine_pool.value.min_cpu + } + azs = machine_pool.value.azs + + additional_labels = try(machine_pool.value.additional_labels, tomap({})) + + dynamic "taints" { + for_each = try(machine_pool.value.taints, []) + + content { + key = taints.value.key + value = taints.value.value + effect = taints.value.effect + } + } + } + } + + dynamic "backup_policy" { + for_each = try(tolist([each.value.backup_policy]), []) + content { + schedule = backup_policy.value.schedule + backup_location_id = local.bsl_map[backup_policy.value.backup_location] + prefix = backup_policy.value.prefix + expiry_in_hour = 7200 + include_disks = true + include_cluster_resources = true + } + } + + dynamic "scan_policy" { + for_each = try(tolist([each.value.scan_policy]), []) + content { + configuration_scan_schedule = scan_policy.value.configuration_scan_schedule + penetration_scan_schedule = scan_policy.value.penetration_scan_schedule + conformance_scan_schedule = scan_policy.value.conformance_scan_schedule + } + } + + timeouts { + create = try(each.value.timeouts.create, "60m") + delete = try(each.value.timeouts.delete, "60m") + } +}