Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

terraform-vsphere-resource-pool

Terraform Provider: vmware/vsphere Resource: vsphere_resource_pool Type: standalone Lifecycle: plan--only

A standalone module that manages a single vsphere_resource_pool — a CPU/memory allocation container nested under a compute cluster's root pool, a standalone host's root pool, or another resource pool.


Overview

Why it matters: A resource pool is how you carve a slice of an existing cluster or host into a governed, named allocation — reservations that guarantee capacity, limits that cap it, and shares that set scheduling priority under contention. This module wraps exactly one pool as the keystone resource (this), exposes the provider's flat cpu_* / memory_* arguments as two typed object inputs, and enforces the share-level/share-count invariant before terraform validate ever reaches vCenter. The parent pool is consumed by MOID — the module never looks up or creates the cluster, host, or parent it hangs from.


❤️ Support this project

If these Terraform modules have been helpful to you or your organization, I'd appreciate your support in any of the following ways:

Whether it's a star, a professional connection, or a coffee, every gesture helps keep these modules actively maintained and continually improving. Thank you for being part of the community!


Family DAG — where this fits

Render the source below via the Mermaid Chart MCP (validated flowchart). This module is highlighted in #607078. It hangs from a parent_resource_pool_id (the root pool of a terraform-vsphere-compute-cluster, or another pool) and takes tags from terraform-vsphere-tag; its id flows out as the resource_pool_id a VM runs in, the parent of a nested child pool, or a vApp's parent.

graph LR
 cc["terraform-vsphere-compute-cluster<br/>parent_resource_pool_id"]
 parent["parent resource pool (another pool)<br/>parent_resource_pool_id"]
 tag["terraform-vsphere-tag<br/>tags"]
 rp["terraform-vsphere-resource-pool"]
 child["terraform-vsphere-resource-pool<br/>(nested child pool)"]
 vm["terraform-vsphere-virtual-machine<br/>resource_pool_id"]
 vapp["terraform-vsphere-vapp<br/>parent_resource_pool_id"]

 cc -->|parent_resource_pool_id| rp
 parent -->|parent_resource_pool_id| rp
 tag -->|tags| rp
 rp -->|id| child
 rp -->|id| vm
 rp -->|id| vapp

 style rp fill:#607078,color:#fff,stroke:#333,stroke-width:2px
Loading

Resource shape — what this builds

Keystone node in #00A1E0; the universal tail in #607078. This module wraps exactly one resource — vsphere_resource_pool.this — hung from a parent pool (consumed by ID) and carrying CPU + memory reservations, limits, and shares.

graph TD
 parent["parent_resource_pool_id (MOID)<br/>cluster root pool or another pool<br/>consumed by ID"]
 this["vsphere_resource_pool.this<br/>(keystone — one resource pool)<br/>CPU + memory reservations / limits / shares"]
 tail["universal tail<br/>tags (list) + custom_attributes (map)"]

 parent -->|parent_resource_pool_id| this
 this --> tail

 style this fill:#00A1E0,color:#fff,stroke:#333,stroke-width:2px
 style tail fill:#607078,color:#fff
Loading

🔑 Required vCenter Privileges

Grant the Terraform integration account the least-privilege set below — never the built-in Administrator role. Privileges are granted on the parent object referenced by parent_resource_pool_id (the cluster, host, or parent pool) and must propagate to children so the created pool can later be modified, renamed, or removed. Validate the final set with vCenter's Check Privileges feature before handing the account to a pipeline.

Core — always required (create / update settings / destroy):

Privilege ID vCenter display name Why this module needs it
Resource.CreatePool Resource → Create resource pool Create the pool under the parent.
Resource.EditPool Resource → Modify resource pool Change CPU/memory allocation (share_level, shares, reservation, expandable, limit) and scale_descendants_shares.
Resource.DeletePool Resource → Remove resource pool Destroy the pool on terraform destroy / removal.

Conditional — required only when the corresponding input changes:

Privilege ID vCenter display name Required when
Resource.RenamePool Resource → Rename resource pool name is changed after creation (rename in place).
Resource.MovePool Resource → Move resource pool parent_resource_pool_id is changed (the pool is re-parented / moved).
InventoryService.Tagging.AttachTag vSphere Tagging → Assign or Unassign vSphere Tag tags is non-empty.
Global.SetCustomField Global → Set custom attribute custom_attributes is non-empty (sets values on existing attributes — defining attributes is the caller's job and is out of scope).

vSphere Prerequisites

  • Provider: vmware/vsphere ~> 2.0 (VMware by Broadcom). Do not use hashicorp/vsphere.
  • Terraform: >= 1.12.0.
  • vCenter Server: any version supported by the ~> 2.0 provider (7.0 / 8.0). A non-default scale_descendants_shares (i.e. scaleCpuAndMemoryShares) requires vCenter 7.0 or higher — it fails on older endpoints.
  • Licensing / DRS: a resource pool on a cluster requires that cluster to have DRS enabled, which requires vSphere Enterprise Plus licensing. A pool on a standalone host's root pool does not require DRS.
  • Pre-existing parent: the MOID passed as parent_resource_pool_id must already exist and be resolvable by the caller (a cluster/host root pool, or another pool). The module performs no lookups of its own.
  • Connectivity & auth: the caller configures the provider "vsphere" block; credentials are supplied out of band (prefer VSPHERE_SERVER / VSPHERE_USER / VSPHERE_PASSWORD environment variables). This module defines no connection variables.

Quick Start

Source is pinned to a release tag (?ref=v1.0.0) — never a branch. The provider is configured by the caller; no credentials appear in module inputs. Plan-only — a human reviews the plan and runs apply.

# Provider is caller-configured; credentials come from the environment
# (VSPHERE_SERVER / VSPHERE_USER / VSPHERE_PASSWORD).
provider "vsphere" {}

# Resolve the parent by ID — the module never looks this up.
data "vsphere_datacenter" "dc" {
  name = "dc-01"
}

data "vsphere_compute_cluster" "cluster" {
  name          = "cluster-01"
  datacenter_id = data.vsphere_datacenter.dc.id
}

# Minimal pool: an empty cpu/memory config produces a neutral, non-disruptive pool
# (normal shares, zero reservation, expandable, unlimited limit).
module "team_pool" {
  source = "git::https://github.com/microsoftexpert/terraform-vsphere-resource-pool?ref=v1.0.0"

  name                    = "team-apps"
  parent_resource_pool_id = data.vsphere_compute_cluster.cluster.resource_pool_id
}

A fuller example — custom CPU shares, reservations, a high memory priority, and a tag:

module "team_pool_custom" {
  source = "git::https://github.com/microsoftexpert/terraform-vsphere-resource-pool?ref=v1.0.0"

  name                    = "team-bravo"
  parent_resource_pool_id = data.vsphere_compute_cluster.cluster.resource_pool_id

  cpu = {
    share_level = "custom" # shares are honored ONLY when level is "custom"
    shares      = 8000
    reservation = 4000  # MHz guaranteed to the pool
    limit       = 16000 # MHz ceiling
    expandable  = false # do not borrow beyond the reservation
  }

  memory = {
    share_level = "high"
    reservation = 8192 # MB guaranteed
    limit       = -1   # unlimited
  }

  # tags is a LIST of vsphere_tag MOIDs (not a key/value map).
  tags = [module.tf_mod_vsphere_tag.tag_ids["environment"]]
}

See examples/main.tf for a complete, runnable example that also nests a child pool under another pool.

📚 Example Library

1 · Minimal — no CPU or memory constraints (unlimited)
module "resource_pool_prod" {
  source = "git::https://github.com/microsoftexpert/terraform-vsphere-resource-pool?ref=v1.0.0"

  name                    = "rp-prod-workloads"
  parent_resource_pool_id = data.vsphere_compute_cluster.prod.resource_pool_id
}
2 · CPU reservation with expandable default
module "resource_pool_reserved" {
  source = "git::https://github.com/microsoftexpert/terraform-vsphere-resource-pool?ref=v1.0.0"

  name                    = "rp-prod-reserved"
  parent_resource_pool_id = data.vsphere_compute_cluster.prod.resource_pool_id

  cpu = {
    reservation = 4000 # 4 GHz reserved for this pool
    expandable  = true # may borrow additional unreserved parent capacity
  }
}
3 · Memory reservation for latency-sensitive workloads
module "resource_pool_db" {
  source = "git::https://github.com/microsoftexpert/terraform-vsphere-resource-pool?ref=v1.0.0"

  name                    = "rp-prod-databases"
  parent_resource_pool_id = data.vsphere_compute_cluster.prod.resource_pool_id

  memory = {
    reservation = 65536 # 64 GB guaranteed to database VMs
    expandable  = false # strict reservation — no balloon
    share_level = "high"
  }
}
4 · Fixed CPU limit (cap at specific MHz)
module "resource_pool_dev" {
  source = "git::https://github.com/microsoftexpert/terraform-vsphere-resource-pool?ref=v1.0.0"

  name                    = "rp-dev-capped"
  parent_resource_pool_id = data.vsphere_compute_cluster.dev.resource_pool_id

  cpu = {
    limit = 8000 # dev pool capped at 8 GHz total
  }
}
5 · Fixed memory limit
module "resource_pool_sandbox" {
  source = "git::https://github.com/microsoftexpert/terraform-vsphere-resource-pool?ref=v1.0.0"

  name                    = "rp-sandbox"
  parent_resource_pool_id = data.vsphere_compute_cluster.dev.resource_pool_id

  memory = {
    limit = 131072 # 128 GB memory ceiling for sandbox
  }
}
6 · High-priority pool with custom shares
module "resource_pool_priority" {
  source = "git::https://github.com/microsoftexpert/terraform-vsphere-resource-pool?ref=v1.0.0"

  name                    = "rp-prod-high-priority"
  parent_resource_pool_id = data.vsphere_compute_cluster.prod.resource_pool_id

  cpu = {
    share_level = "high"
  }
  memory = {
    share_level = "high"
  }
}
7 · Custom shares (explicit share count)
module "resource_pool_custom_shares" {
  source = "git::https://github.com/microsoftexpert/terraform-vsphere-resource-pool?ref=v1.0.0"

  name                    = "rp-custom-shares"
  parent_resource_pool_id = data.vsphere_compute_cluster.prod.resource_pool_id

  cpu = {
    share_level = "custom"
    shares      = 8000 # valid only when share_level = "custom"
  }
  memory = {
    share_level = "custom"
    shares      = 163840 # explicit memory share count
  }
}
8 · Strict (non-expandable) CPU + memory reservation
module "resource_pool_strict" {
  source = "git::https://github.com/microsoftexpert/terraform-vsphere-resource-pool?ref=v1.0.0"

  name                    = "rp-prod-strict"
  parent_resource_pool_id = data.vsphere_compute_cluster.prod.resource_pool_id

  cpu = {
    reservation = 8000
    expandable  = false # hard reservation — never borrow from parent
  }
  memory = {
    reservation = 32768 # 32 GB
    expandable  = false
  }
}
9 · Low-priority dev/test pool
module "resource_pool_dev_low" {
  source = "git::https://github.com/microsoftexpert/terraform-vsphere-resource-pool?ref=v1.0.0"

  name                    = "rp-dev-low-priority"
  parent_resource_pool_id = data.vsphere_compute_cluster.dev.resource_pool_id

  cpu    = { share_level = "low" }
  memory = { share_level = "low" }
}
10 · Nested child pool (inside another resource pool)
module "resource_pool_parent" {
  source                  = "git::https://github.com/microsoftexpert/terraform-vsphere-resource-pool?ref=v1.0.0"
  name                    = "rp-prod-tier1"
  parent_resource_pool_id = data.vsphere_compute_cluster.prod.resource_pool_id
  cpu                     = { reservation = 16000 }
  memory                  = { reservation = 131072 }
}

module "resource_pool_child" {
  source                  = "git::https://github.com/microsoftexpert/terraform-vsphere-resource-pool?ref=v1.0.0"
  name                    = "rp-prod-tier1-web"
  parent_resource_pool_id = module.resource_pool_parent.id # ← child of above
  cpu                     = { reservation = 4000 }
  memory                  = { reservation = 32768 }
}
11 · Multiple pools with for_each
locals {
  resource_pools = {
    web = { share = "high", cpu_limit = -1, mem_limit = -1 }
    app = { share = "normal", cpu_limit = -1, mem_limit = -1 }
    dev = { share = "low", cpu_limit = 4000, mem_limit = 16384 }
  }
}

module "resource_pools" {
  source   = "git::https://github.com/microsoftexpert/terraform-vsphere-resource-pool?ref=v1.0.0"
  for_each = local.resource_pools

  name                    = "rp-${each.key}"
  parent_resource_pool_id = data.vsphere_compute_cluster.prod.resource_pool_id

  cpu    = { share_level = each.value.share, limit = each.value.cpu_limit }
  memory = { share_level = each.value.share, limit = each.value.mem_limit }
}
12 · With tags and custom attributes
module "resource_pool_tagged" {
  source = "git::https://github.com/microsoftexpert/terraform-vsphere-resource-pool?ref=v1.0.0"

  name                    = "rp-prod-tagged"
  parent_resource_pool_id = data.vsphere_compute_cluster.prod.resource_pool_id

  cpu    = { share_level = "high" }
  memory = { share_level = "high" }

  tags = [
    module.tf_mod_vsphere_tag.tag_ids["environment"], # "production"
    module.tf_mod_vsphere_tag.tag_ids["tier"],        # "tier-1"
  ]
  custom_attributes = {
    (data.vsphere_custom_attribute.cost_center.id) = "PROD-OPS"
    (data.vsphere_custom_attribute.owner.id)       = "platform-team"
  }
}
13 · Scale descendants shares (vSphere 7.0+)
module "resource_pool_scale" {
  source = "git::https://github.com/microsoftexpert/terraform-vsphere-resource-pool?ref=v1.0.0"

  name                    = "rp-prod-scalable"
  parent_resource_pool_id = data.vsphere_compute_cluster.prod.resource_pool_id

  cpu    = { share_level = "high" }
  memory = { share_level = "high" }

  scale_descendants_shares = "scaleCpuAndMemoryShares"
  # Requires vSphere 7.0+; child pool shares scale proportionally when this pool's shares change
}
14 · Import an existing resource pool
import {
  to = module.resource_pool_existing.vsphere_resource_pool.this
  id = "resgroup-123" # MOID — obtain from vCenter or `terraform show`
}

module "resource_pool_existing" {
  source = "git::https://github.com/microsoftexpert/terraform-vsphere-resource-pool?ref=v1.0.0"

  name                    = "rp-prod-existing"
  parent_resource_pool_id = data.vsphere_compute_cluster.prod.resource_pool_id
}
15 · End-to-end: compute cluster → resource pool → VM placement
# The cluster root pool is resolved by the caller
data "vsphere_compute_cluster" "prod" {
  name          = "Cluster-Prod-01"
  datacenter_id = module.datacenter.id
}

module "resource_pool_web" {
  source = "git::https://github.com/microsoftexpert/terraform-vsphere-resource-pool?ref=v1.0.0"

  name                    = "rp-prod-web"
  parent_resource_pool_id = data.vsphere_compute_cluster.prod.resource_pool_id

  cpu    = { share_level = "high" }
  memory = { reservation = 16384 }
}

output "resource_pool_id" {
  value = module.resource_pool_web.id # wire into terraform-vsphere-virtual-machine
}


Inputs

Name Type Required Default Description
name string yes Display name of the pool in vCenter. Validated non-empty. Mutable — a change renames the pool in place.
parent_resource_pool_id string yes MOID of the parent pool: a cluster root pool (data.vsphere_compute_cluster.*.resource_pool_id), a host root pool, or another pool's id. A change re-parents (moves) the pool — see gotchas.
cpu object (below) no {} CPU allocation. Empty object → provider defaults.
memory object (below) no {} Memory allocation. Empty object → provider defaults.
scale_descendants_shares string no "disabled" disabled or scaleCpuAndMemoryShares. Non-default requires vCenter 7.0+.
tags list(string) no [] List of vsphere_tag MOIDs to attach (e.g. from terraform-vsphere-tag.tag_ids). A list, not a map.
custom_attributes map(string) no {} Map of custom-attribute MOID → value string. Attributes must already exist.

cpu / memory object schema

Both inputs share the same shape (units differ: CPU in MHz, memory in MB):

cpu = {
  share_level = optional(string, "normal") # low | normal | high | custom
  shares      = optional(number, null)     # explicit share count; valid ONLY when share_level = "custom"
  reservation = optional(number, 0)        # guaranteed capacity (MHz for cpu, MB for memory); must be >= 0
  expandable  = optional(bool, true)       # allow the reservation to borrow unreserved parent capacity
  limit       = optional(number, -1)       # ceiling (MHz/MB); -1 = unlimited
}
Field Type Default Notes
share_level string "normal" One of low / normal / high / custom. With low/normal/high, vCenter derives the share count and any supplied shares is ignored.
shares number null Must be set when share_level = "custom" and must be null otherwise (validated). When set, must be > 0.
reservation number 0 Capacity guaranteed to the pool. Must be >= 0.
expandable bool true When true, the reservation may grow into the parent's unreserved capacity.
limit number -1 Hard ceiling. -1 = unlimited; otherwise must be >= -1.

Validations enforced by the module (fail at terraform validate, not at apply):

  • name and parent_resource_pool_id must be non-empty.
  • cpu/memory share_level ∈ {low,normal,high,custom}.
  • shares is set iff share_level = "custom" (loud failure instead of a silently-ignored value).
  • reservation >= 0, limit >= -1, and shares (when set) > 0.
  • scale_descendants_shares ∈ {disabled,scaleCpuAndMemoryShares}.

Outputs

Output Type Description
id string MOID of the resource pool. Wire to parent_resource_pool_id of a child pool, or to resource_pool_id on a vsphere_virtual_machine.
name string Display name of the pool.
cpu_shares number Effective CPU shares. Derived by vCenter from share_level when it is low/normal/high; the supplied value when custom. Computed — appears as known after apply on first create and whenever share_level is non-custom.
memory_shares number Effective memory shares, same semantics as cpu_shares.

Design Principles

The empty call produces the safe, neutral pool: it guarantees itself nothing, caps nothing, skews no scheduling priority, and carries no governance metadata. Every risky or opinionated choice is an explicit opt-out the caller must type.

Principle Secure / neutral default Explicit opt-out
Reserve nothing by default cpu.reservation / memory.reservation = 0 — creating the pool cannot starve sibling pools or trip admission control. Set a positive reservation to guarantee capacity.
No artificial ceiling cpu.limit / memory.limit = -1 (unlimited) — the pool never throttles its own workloads. Set a positive limit (MHz / MB) to cap consumption.
Neutral priority share_level = "normal" — no scheduling advantage under contention. low / high, or custom with an explicit shares count.
Fail loud on ignored shares shares must be null unless share_level = "custom" (validated). Set share_level = "custom" together with a shares value.
Elastic but bounded expandable = true — a reservation may borrow unused parent capacity rather than fail. expandable = false to hard-bound the pool at its reservation.
No implicit cascade scale_descendants_shares = "disabled" — resizing this pool does not silently re-scale child pools; also keeps the module working on pre-7.0 vCenter. scaleCpuAndMemoryShares (requires vCenter 7.0+).
Explicit placement parent_resource_pool_id is required — the module never guesses where the pool hangs. — (always caller-supplied).
Opt-in governance metadata tags = [], custom_attributes = {}. Supply tag MOIDs / attribute values.

Runbook

Plan-only. This module system never runs terraform apply — a human reviews the plan and applies it after review. From the module or example directory:

# 1. Initialize without a backend (validation/formatting only — no state, no apply).
terraform init -backend=false

# 2. Validate types, schema, and the module's validation {} rules.
terraform validate

# 3. Confirm canonical formatting (use `terraform fmt` to fix, then review the diff).
terraform fmt -check

# A human reviews the resulting plan and runs `terraform apply` against vCenter.
# Never run `terraform apply` from this module system.

Pin the module source to the release tag (?ref=v1.0.0) — never a branch.


Troubleshooting

Symptom Cause Resolution
cpu.shares must be set when cpu.share_level is "custom"... at validate You set shares without share_level = "custom", or selected custom without a shares value. Either set share_level = "custom" and a shares count, or remove shares and use low/normal/high.
cpu_shares / memory_shares show known after apply on a no-op plan share_level is low/normal/high, so the share count is computed by vCenter, not by you. Expected — it is a computed attribute, not drift. It stabilizes after apply; use custom if you need a fixed, plan-visible value.
Re-parent fails when parent_resource_pool_id changes The old and new parents do not share a common root resource pool, or the account lacks Resource.MovePool. A pool can only move within the same root pool tree. To relocate across clusters/hosts, recreate the pool. Grant Resource.MovePool if the move is legitimate.
scaleCpuAndMemoryShares rejected by vCenter scale_descendants_shares other than disabled requires vCenter 7.0+. Set scale_descendants_shares = "disabled", or target a 7.0+ vCenter.
Permission to perform this operation was denied on create The integration account is missing Resource.CreatePool on the parent object, or the privilege does not propagate. Grant the privileges in 🔑 Required vCenter Privileges on the parent with propagation; confirm via vCenter Check Privileges.
Insufficient resources / admission-control failure on apply The requested reservation exceeds the parent's unreserved capacity, especially with expandable = false. Lower the reservation, set expandable = true, or free capacity in the parent pool/cluster.

Related Docs

  • SCOPE.md — design contract: in-scope vs consumed-by-ID, privileges, prerequisites, emits, gotchas.
  • examples/main.tf — runnable example (minimal pool, custom pool, nested child pool).
  • Provider docs — vmware/vsphere · vsphere_resource_pool.
  • Sibling modules — terraform-vsphere-compute-cluster (emits the cluster root resource_pool_id), terraform-vsphere-tag (emits tag_ids for tags), terraform-vsphere-virtual-machine (consumes id as resource_pool_id).

Releases

Packages

Contributors

Languages