From 560200bb3c2ffee388257986d8088861b7ffac6d Mon Sep 17 00:00:00 2001 From: Patrick de Ruiter Date: Sat, 1 Nov 2025 06:18:59 +0100 Subject: [PATCH] Initial commit: Terraform vSphere resource groups module - Add vSphere resource pool management - Configure CPU and memory allocation controls - Implement tagging system for organization - Add comprehensive documentation --- .gitignore | 58 +++++++++++++++++++++++++++++++++ README.md | 70 ++++++++++++++++++++++++++++++++++++++++ backend.tf | 20 ++++++++++++ data.tf | 17 ++++++++++ main.tf | 63 ++++++++++++++++++++++++++++++++++++ outputs.tf | 25 +++++++++++++++ provider.tf | 31 ++++++++++++++++++ variables.tf | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 374 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 backend.tf create mode 100644 data.tf create mode 100644 main.tf create mode 100644 outputs.tf create mode 100644 provider.tf create mode 100644 variables.tf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..46562e3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,58 @@ +# Local .terraform directories +**/.terraform/* + +# .tfstate files +*.tfstate +*.tfstate.* + +# Crash log files +crash.log +crash.*.log + +# Exclude all .tfvars files, which are likely to contain sensitive data +*.tfvars +*.tfvars.json + +# Ignore override files as they are usually used to override resources locally +override.tf +override.tf.json +*_override.tf +*_override.tf.json + +# Include override files you do wish to add to version control using negated pattern +# !example_override.tf + +# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan +*tfplan* + +# Ignore CLI configuration files +.terraformrc +terraform.rc + +# Ignore lock files (optional, some prefer to commit these) +.terraform.lock.hcl + +# Ansible directories +ansible/ +**/ansible/ + +# SSH keys and sensitive files +*.pem +*.key +**/files/kubernetes_key* +**/files/*_key + +# OS files +.DS_Store +Thumbs.db + +# IDE files +.idea/ +.vscode/ +*.swp +*.swo +*~ + +# Backup files +*.backup +*.bak diff --git a/README.md b/README.md new file mode 100644 index 0000000..9511fc8 --- /dev/null +++ b/README.md @@ -0,0 +1,70 @@ +# Terraform vSphere Resource Groups Module + +This Terraform module manages vSphere resource pools (resource groups) with CPU/memory allocation controls and integrated tagging for organization and management. + +## Purpose + +Creates and manages vSphere resource pools with configurable resource allocation policies, reservations, limits, and shares. Includes automated tagging for environment and resource group classification. + +## What It Does + +1. Creates resource pools under vSphere cluster +2. Configures CPU reservations, limits, and shares +3. Configures memory reservations, limits, and shares +4. Creates tag categories for Environment and ResourceGroupType +5. Applies tags to resource pools for organization + +## Usage + +```hcl +module "vsphere_resource_groups" { + source = "./terraform-vsphere-resourcegroups" + + datacenter = "DC1" + cluster_name = "Cluster01" + environment = "prod" + + role_id = var.vault_role_id + secret_id = var.vault_secret_id + + resource_groups = { + kubernetes = { + name = "Kubernetes" + cpu_reservation = 4000 + cpu_shares = "high" + memory_reservation = 8192 + memory_shares = "high" + } + docker = { + name = "Docker" + cpu_shares = "normal" + memory_shares = "normal" + } + infra = { + name = "Infrastructure" + cpu_shares = "low" + memory_shares = "low" + } + } +} +``` + +## Key Features + +- **Resource Allocation**: CPU and memory reservations, limits, shares +- **Shares Mapping**: Automatic conversion of low/normal/high to vSphere values (500/1000/2000) +- **Tagging System**: Environment and resource group type tags +- **Flexible Configuration**: Optional parameters with sensible defaults +- **Expandable Resources**: Allow resources to grow beyond reservations + +## Default Resource Groups + +- **Kubernetes**: For Kubernetes infrastructure +- **Docker**: For Docker containers +- **Infra**: For infrastructure services + +## Prerequisites + +- VMware vSphere with compute cluster +- Vault with vSphere credentials +- Terraform >= 0.13 diff --git a/backend.tf b/backend.tf new file mode 100644 index 0000000..a02f2f4 --- /dev/null +++ b/backend.tf @@ -0,0 +1,20 @@ +terraform { + backend "s3" { + endpoints = { + s3 = "https://minio.bsdserver.nl:443" + } + + bucket = "home-terraform" + key = "home/vsphere/network/vsphere-resourcegroup-config.tfstate" + + access_key = "R9lCycfEO8qJ2dxlQT1S" + secret_key = "6rtVLjDIjx7U9ecNRkdbS3idSBNWsfNhN6wB20sJ" + + region = "main" + skip_credentials_validation = true + skip_metadata_api_check = true + skip_requesting_account_id = true + skip_region_validation = true + use_path_style = true + } +} diff --git a/data.tf b/data.tf new file mode 100644 index 0000000..29d2011 --- /dev/null +++ b/data.tf @@ -0,0 +1,17 @@ +data "vault_generic_secret" "vmware" { + path = "secret/vmware" +} + +data "vsphere_datacenter" "dc" { + name = var.datacenter +} + +data "vsphere_compute_cluster" "cluster" { + name = var.cluster_name + datacenter_id = data.vsphere_datacenter.dc.id +} + +data "vsphere_host" "host" { + name = "esxi101.bsdserver.lan" + datacenter_id = data.vsphere_datacenter.dc.id +} diff --git a/main.tf b/main.tf new file mode 100644 index 0000000..4c760f4 --- /dev/null +++ b/main.tf @@ -0,0 +1,63 @@ +locals { + shares_mapping = { + "low" = 500 + "normal" = 1000 + "high" = 2000 + } +} + +resource "vsphere_resource_pool" "resource_groups" { + for_each = var.resource_groups + + name = each.value.name + parent_resource_pool_id = data.vsphere_compute_cluster.cluster.resource_pool_id + + cpu_reservation = each.value.cpu_reservation + cpu_expandable = each.value.cpu_expandable + cpu_limit = each.value.cpu_limit + cpu_shares = lookup(local.shares_mapping, each.value.cpu_shares, 1000) + + memory_reservation = each.value.memory_reservation + memory_expandable = each.value.memory_expandable + memory_limit = each.value.memory_limit + memory_shares = lookup(local.shares_mapping, each.value.memory_shares, 1000) + + tags = [ + vsphere_tag.environment.id, + vsphere_tag.resource_group[each.key].id + ] +} + +resource "vsphere_tag_category" "environment" { + name = "Environment" + description = "Environment category for resource groups" + cardinality = "SINGLE" + + associable_types = [ + "ResourcePool", + ] +} + +resource "vsphere_tag" "environment" { + name = var.environment + category_id = vsphere_tag_category.environment.id + description = "Environment tag for ${var.environment}" +} + +resource "vsphere_tag_category" "resource_group_type" { + name = "ResourceGroupType" + description = "Resource group type category" + cardinality = "SINGLE" + + associable_types = [ + "ResourcePool", + ] +} + +resource "vsphere_tag" "resource_group" { + for_each = var.resource_groups + + name = each.key + category_id = vsphere_tag_category.resource_group_type.id + description = "Resource group tag for ${each.value.name}" +} diff --git a/outputs.tf b/outputs.tf new file mode 100644 index 0000000..6c10a5a --- /dev/null +++ b/outputs.tf @@ -0,0 +1,25 @@ +output "resource_pool_ids" { + description = "Map of resource group names to their resource pool IDs" + value = { + for k, v in vsphere_resource_pool.resource_groups : k => v.id + } +} + +output "resource_pool_names" { + description = "Map of resource group keys to their display names" + value = { + for k, v in var.resource_groups : k => v.name + } +} + +output "environment_tag_id" { + description = "ID of the environment tag" + value = vsphere_tag.environment.id +} + +output "resource_group_tag_ids" { + description = "Map of resource group tag IDs" + value = { + for k, v in vsphere_tag.resource_group : k => v.id + } +} \ No newline at end of file diff --git a/provider.tf b/provider.tf new file mode 100644 index 0000000..6442cb3 --- /dev/null +++ b/provider.tf @@ -0,0 +1,31 @@ +terraform { + required_providers { + vsphere = { + source = "vmware/vsphere" + } + vault = { + source = "hashicorp/vault" + } + } +} + +# Configure the Vault provider +provider "vault" { + address = "https://wbyc-srv-docker01.bsdserver.lan:8200" + auth_login { + path = "auth/approle/login" + parameters = { + role_id = var.role_id + secret_id = var.secret_id + } + } +} + +# vSphere Provider +provider "vsphere" { + vsphere_server = data.vault_generic_secret.vmware.data["vcenter_server"] + user = data.vault_generic_secret.vmware.data["vcenter_username"] + password = data.vault_generic_secret.vmware.data["vcenter_password"] + + allow_unverified_ssl = true +} diff --git a/variables.tf b/variables.tf new file mode 100644 index 0000000..f8c79fb --- /dev/null +++ b/variables.tf @@ -0,0 +1,90 @@ + +variable "datacenter" { + description = "vSphere data center" + type = string +} + +variable "cluster_name" { + description = "vSphere Cluster Name" + type = string +} + + +# Environment +variable "environment" { + description = "Environment name can be: dev, tst, acc, uat, prod, shared or tools" + type = string +} + +# Resource Groups +variable "resource_groups" { + type = map(object({ + name = string + cpu_reservation = optional(number, 0) + cpu_expandable = optional(bool, true) + cpu_limit = optional(number, -1) + cpu_shares = optional(string, "normal") + memory_reservation = optional(number, 0) + memory_expandable = optional(bool, true) + memory_limit = optional(number, -1) + memory_shares = optional(string, "normal") + })) + description = "Map of resource groups to create" + default = { + kubernetes = { + name = "Kubernetes" + } + docker = { + name = "Docker" + } + infra = { + name = "Infra" + } + } +} + +# Vault approle +variable "role_id" { + description = "Role ID for Vault AppRole authentication" + type = string + sensitive = true +} + +variable "secret_id" { + description = "Secret ID for Vault AppRole authentication" + type = string + sensitive = true +} + +# Domain +variable "domain" { + description = "Domain name" + type = string + default = "" +} + +# ESXi Hosts +variable "esxi_hosts" { + description = "Map of ESXi hosts configuration" + type = map(object({ + name = string + ip_address = string + tags = optional(map(string), {}) + })) + default = {} +} + +# Port Groups +variable "port_groups" { + description = "Map of port groups configuration" + type = map(object({ + vlan_id = number + allow_promiscuous = optional(bool, false) + subnet_address = string + subnet_mask = number + gateway_ip = string + nameserver_id = number + hosts = list(string) + })) + default = {} +}