Skip to content

microsoftexpert/tf-mod-vsphere-folder

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

tf-mod-vsphere-folder

Terraform Provider vSphere Module type Resources Lifecycle

Standalone vSphere module — manages a single vCenter inventory folder (vsphere_folder) of any of the five folder types, with secure-by-default tagging and fail-fast placement validation.


Overview

Why it matters: Inventory folders are how vCenter keeps a growing estate legible. They group VMs, hosts, datastores, and networks into a navigable hierarchy and — just as importantly — they are the natural anchor points for permissions and tag-based policy. A flat inventory is unmanageable and unauditable; a folder tree lets you delegate access at the branch level and apply governance consistently. This module creates exactly one folder of any of the five vCenter types. The empty, valid call places the folder correctly or fails at plan time with an actionable message — it never guesses a datacenter, and it never silently applies tags.


❤️ 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. The folder consumes a datacenter_id (MOID) resolved by the caller and tags from tf-mod-vsphere-tag; its id / path flows out to sibling modules that place inventory objects (VMs and other folders) inside it.

graph LR
 dc["caller data vsphere_datacenter<br/>datacenter_id"]
 tag["tf-mod-vsphere-tag<br/>tags"]
 fold["tf-mod-vsphere-folder"]
 vm["tf-mod-vsphere-virtual-machine<br/>folder placement"]
 sib["sibling inventory objects placed<br/>in this folder (host / datastore /<br/>network / datacenter folders)"]

 dc -->|datacenter_id| fold
 tag -->|tags| fold
 fold -->|id / path| vm
 fold -->|id / path| sib

 style fold 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_folder.this — with tags and custom_attributes applied to it. path and type are immutable (force-new).

graph TD
 this["vsphere_folder.this<br/>(keystone — one folder)<br/>path + type immutable (force-new)"]
 tail["universal tail<br/>tags (list) + custom_attributes (map)"]

 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 minimum set below on the target datacenter (or on the parent folder you are building under — Folder.Create is checked on the parent). Do not use the built-in Administrator account; validate the set with vCenter's Check Privileges feature.

Privilege ID vCenter UI name Why this module needs it
Folder.Create Create folder Create the folder.
Folder.Delete Delete folder Remove the folder on destroy.
Folder.Move Move folder Re-parent the folder when the leading portion of path changes.
Folder.Rename Rename folder Rename the folder when the final segment of path changes.
InventoryService.Tagging.AttachTag Assign or Unassign vSphere Tag Only if tags is non-empty — attach vsphere_tag MOIDs.
Global.SetCustomField Set custom attribute Only if custom_attributes is non-empty — set attribute values.

All operations also require baseline read access (the built-in Read-only role: System.Anonymous, System.View, System.Read) on the inventory path so Terraform can refresh state.

The last two rows are conditional — omit them from the role if the caller never sets tags or custom_attributes. Defining a custom attribute (as opposed to setting its value) additionally requires Global.ManageCustomFields, which is out of scope for this module.


vSphere Prerequisites

Requirement Detail
vCenter Server ≥ 7.0. Folders are a vCenter inventory construct — a direct ESXi connection cannot manage them, and custom_attributes is unsupported outside vCenter.
License Any vSphere edition that includes vCenter Server. Inventory folders are not a separately licensed feature.
Datacenter exists For types host, vm, datastore, and network, the target datacenter must already exist and be resolved by the caller to a MOID (datacenter_id).
Parent folder exists For nested paths (foo/bar), the parent foo must already exist — the provider does not create intermediate folders.
Tags / attributes exist Any vsphere_tag MOID (from tf-mod-vsphere-tag) or custom-attribute definition must already exist before it is referenced.
Provider vmware/vsphere ~> 2.0, Terraform ≥ 1.12.0. The provider is configured by the caller (see Quick Start).

Quick Start

# ---- caller's root module ----

# The provider is configured by the CALLER — never inside the module.
# Prefer environment variables: VSPHERE_SERVER, VSPHERE_USER, VSPHERE_PASSWORD.
provider "vsphere" {
  allow_unverified_ssl = false # true is acceptable only for lab/self-signed certs — never in production
}

# Resolve the pre-existing datacenter MOID (consumed by ID — this module never looks it up).
data "vsphere_datacenter" "dc" {
  name = "dc-01"
}

# Create the VM inventory folder /dc-01/vm/Production
module "production_vm_folder" {
  source = "git::https://github.com/microsoftexpert/tf-mod-vsphere-folder?ref=v1.0.0"

  path          = "Production"
  type          = "vm"
  datacenter_id = data.vsphere_datacenter.dc.id
}

output "production_vm_folder_id" {
  value = module.production_vm_folder.id
}

Nested folder (parent must already exist):

module "webtier_vm_folder" {
  source = "git::https://github.com/microsoftexpert/tf-mod-vsphere-folder?ref=v1.0.0"

  path          = "Production/WebTier" # nests under the existing "Production" folder
  type          = "vm"
  datacenter_id = data.vsphere_datacenter.dc.id

  tags = [module.tf_mod_vsphere_tag.tag_ids["environment"]] # vsphere_tag MOIDs, not names
}

Datacenter-type folder (no datacenter_id):

module "research_dc_folder" {
  source = "git::https://github.com/microsoftexpert/tf-mod-vsphere-folder?ref=v1.0.0"

  path = "Research"
  type = "datacenter" # datacenter_id is omitted only for this type
}

Plan-only. Validate with terraform init -backend=false && terraform validate. This module system never runs terraform apply — a human reviews the plan and applies it in the controlled pipeline. See the Runbook.

📚 Example Library

1 · Minimal VM folder
module "vm_folder_prod" {
  source = "git::https://github.com/microsoftexpert/tf-mod-vsphere-folder?ref=v1.0.0"

  path          = "Production"
  type          = "vm"
  datacenter_id = data.vsphere_datacenter.dc.id
}
2 · Nested VM folder (two levels)
module "vm_folder_webtier" {
  source = "git::https://github.com/microsoftexpert/tf-mod-vsphere-folder?ref=v1.0.0"

  path          = "Production/WebTier" # "Production" must already exist
  type          = "vm"
  datacenter_id = module.datacenter.id
}
3 · Host / cluster folder
module "host_folder_prod" {
  source = "git::https://github.com/microsoftexpert/tf-mod-vsphere-folder?ref=v1.0.0"

  path          = "ProdClusters"
  type          = "host"
  datacenter_id = module.datacenter.id
}
4 · Datastore folder
module "ds_folder_prod" {
  source = "git::https://github.com/microsoftexpert/tf-mod-vsphere-folder?ref=v1.0.0"

  path          = "prod/nfs"
  type          = "datastore"
  datacenter_id = module.datacenter.id
}
5 · Network folder
module "net_folder" {
  source = "git::https://github.com/microsoftexpert/tf-mod-vsphere-folder?ref=v1.0.0"

  path          = "DVS-PortGroups"
  type          = "network"
  datacenter_id = module.datacenter.id
}
6 · Datacenter-type folder (no datacenter_id required)
module "dc_folder_regions" {
  source = "git::https://github.com/microsoftexpert/tf-mod-vsphere-folder?ref=v1.0.0"

  path = "regions"
  type = "datacenter"
  # datacenter_id is NOT required for type = "datacenter"
}
7 · With environment tags
module "vm_folder_staging" {
  source = "git::https://github.com/microsoftexpert/tf-mod-vsphere-folder?ref=v1.0.0"

  path          = "Staging"
  type          = "vm"
  datacenter_id = module.datacenter.id

  tags = [
    module.tf_mod_vsphere_tag.tag_ids["environment"], # "staging"
    module.tf_mod_vsphere_tag.tag_ids["managed-by"],  # "terraform"
  ]
}
8 · With custom attributes for ownership
module "vm_folder_platform" {
  source = "git::https://github.com/microsoftexpert/tf-mod-vsphere-folder?ref=v1.0.0"

  path          = "Platform"
  type          = "vm"
  datacenter_id = module.datacenter.id

  custom_attributes = {
    (data.vsphere_custom_attribute.owner.id)       = "platform-team"
    (data.vsphere_custom_attribute.cost_center.id) = "INFRA-PLAT"
  }
}
9 · Multiple VM folders with for_each
locals {
  vm_folders = {
    production = "Production"
    staging    = "Staging"
    dev        = "Development"
    lab        = "Lab"
  }
}

module "vm_folders" {
  source   = "git::https://github.com/microsoftexpert/tf-mod-vsphere-folder?ref=v1.0.0"
  for_each = local.vm_folders

  path          = each.value
  type          = "vm"
  datacenter_id = module.datacenter.id
  tags          = [module.tf_mod_vsphere_tag.tag_ids[each.key]]
}
10 · Three-tier app folder structure
# Creates Production/WebTier, Production/AppTier, Production/DbTier
locals {
  app_folders = {
    web = "Production/WebTier"
    app = "Production/AppTier"
    db  = "Production/DbTier"
  }
}

module "app_vm_folders" {
  source   = "git::https://github.com/microsoftexpert/tf-mod-vsphere-folder?ref=v1.0.0"
  for_each = local.app_folders

  path          = each.value # "Production" must already exist
  type          = "vm"
  datacenter_id = module.datacenter.id
}
11 · Moving a folder (rename path segment)
# Before: path = "OldName" → After: path = "NewName"
# The provider moves the folder in place; no destroy/recreate needed.
module "vm_folder_renamed" {
  source = "git::https://github.com/microsoftexpert/tf-mod-vsphere-folder?ref=v1.0.0"

  path          = "NewName" # was "OldName" — this rename is safe (mutable)
  type          = "vm"
  datacenter_id = module.datacenter.id
}
12 · Import an existing folder into Terraform state
import {
  to = module.vm_folder_existing.vsphere_folder.this
  id = "tf-dc-01/vm/Existing" # format: <datacenter_name>/<type>/<path>
}

module "vm_folder_existing" {
  source        = "git::https://github.com/microsoftexpert/tf-mod-vsphere-folder?ref=v1.0.0"
  path          = "Existing"
  type          = "vm"
  datacenter_id = module.datacenter.id
}
13 · Tags + custom attributes — full governance metadata
module "vm_folder_regulated" {
  source = "git::https://github.com/microsoftexpert/tf-mod-vsphere-folder?ref=v1.0.0"

  path          = "Regulated/PII"
  type          = "vm"
  datacenter_id = module.datacenter.id

  tags = [
    module.tf_mod_vsphere_tag.tag_ids["data-class"], # "npi"
    module.tf_mod_vsphere_tag.tag_ids["compliance"], # "fca-regulated"
  ]
  custom_attributes = {
    (data.vsphere_custom_attribute.owner.id)       = "cloud-platform"
    (data.vsphere_custom_attribute.data_class.id)  = "PII"
    (data.vsphere_custom_attribute.review_date.id) = "2027-01-01"
  }
}
14 · All folder types for a complete datacenter org structure
# One module call per folder type, all in the same datacenter
module "vm_folder" { source = "git::https://github.com/microsoftexpert/tf-mod-vsphere-folder?ref=v1.0.0"; path = "Production"; type = "vm"; datacenter_id = module.datacenter.id }
module "host_folder" { source = "git::https://github.com/microsoftexpert/tf-mod-vsphere-folder?ref=v1.0.0"; path = "ProdHosts"; type = "host"; datacenter_id = module.datacenter.id }
module "datastore_folder" { source = "git::https://github.com/microsoftexpert/tf-mod-vsphere-folder?ref=v1.0.0"; path = "ProdDS"; type = "datastore"; datacenter_id = module.datacenter.id }
module "network_folder" { source = "git::https://github.com/microsoftexpert/tf-mod-vsphere-folder?ref=v1.0.0"; path = "DVS"; type = "network"; datacenter_id = module.datacenter.id }
15 · End-to-end: datacenter → folder → VM placement
module "datacenter" {
  source = "git::https://github.com/microsoftexpert/tf-mod-vsphere-datacenter?ref=v1.0.0"
  name   = "dc-prod-01"
}

module "vm_folder_prod" {
  source        = "git::https://github.com/microsoftexpert/tf-mod-vsphere-folder?ref=v1.0.0"
  path          = "Production/WebTier"
  type          = "vm"
  datacenter_id = module.datacenter.id # ← from datacenter module
}

# A downstream VM module consumes the folder path:
# folder = "${module.vm_folder_prod.path}"
output "prod_webtier_folder_path" {
  value = module.vm_folder_prod.path
}


Inputs

Name Type Required Default Description
path string ✅ Yes Inventory path relative to the chosen type root in the datacenter. Do not prefix with the datacenter or type segment. "Production"/dc-01/vm/Production; "Production/WebTier" nests under the existing Production. Mutable — changing the leading portion moves the folder; changing the final segment renames it. Validated non-empty after trimming whitespace.
type string ✅ Yes Folder hierarchy. One of datacenter, host, vm, datastore, network. Immutable — changing forces destroy/recreate.
datacenter_id string ⚠️ Conditional null MOID of the containing datacenter (consumed by ID; the caller resolves it via data "vsphere_datacenter"). Required for types host/vm/datastore/network; omit only when type = "datacenter". Immutable — changing forces destroy/recreate.
tags list(string) No [] List of vsphere_tag MOIDs (not display names) to attach. Wire from tf-mod-vsphere-tag, e.g. [module.tf_mod_vsphere_tag.tag_ids["environment"]]. The provider argument is a set; a list is converted automatically.
custom_attributes map(string) No {} Map of custom-attribute MOID → value string. Requires vCenter (unsupported on direct ESXi).

Validation rules enforced in variables.tf:

  • path must be non-empty after trimming whitespace.
  • type must be one of: datacenter, host, vm, datastore, network.
  • datacenter_id must be set (non-null, non-empty) for every type except datacenter.

Outputs

Output Type Description
id string (MOID) Primary identifier. Managed object ID of the folder. Wire into sibling modules' folder-placement inputs (e.g. tf-mod-vsphere-virtual-machine's folder placement).
name string Display name — the final segment of the inventory path.
path string The folder's inventory path, relative to the datacenter/type root.
type string The folder type: datacenter, host, vm, datastore, or network.

Design Principles

The empty call produces the safe, correct resource; the caller types extra characters to opt into anything broader. Folders carry no network or encryption attack surface, so the posture here is correctness guards plus the secure tagging tail.

Principle Secure default Opt-out / override Why
Tags off by default tags = [] Pass a list of vsphere_tag MOIDs Governance tags are applied deliberately by the caller, never silently inherited.
Custom attributes off by default custom_attributes = {} Pass a MOID→value map No surprise metadata written to the inventory.
Placement is explicit datacenter_id = null + validation {} Set datacenter_id A folder cannot land in the wrong (or a default) datacenter by accident — non-datacenter types fail fast without it.
Type is a closed set validation {} on type A typo ("vms") is a plan-time error, not a misplaced folder.
Path cannot be empty validation {} on path Prevents accidentally targeting the type root.
No credentials in the module provider configured by caller Auth (vsphere_server/user/password/allow_unverified_ssl) lives in the caller's provider block. Use a least-privilege role — never Administrator.
Immutable fields documented type, datacenter_id flagged force-new Operators are warned before a config edit silently turns into a destroy/recreate.

Runbook

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

terraform init -backend=false # no remote state during validation
terraform validate # type-checks variables and the resource graph
terraform fmt -check # style gate (run `terraform fmt` to fix)
  • Pin the module by tag (?ref=v1.0.0), never a branch.
  • The controlled pipeline runs terraform plan for human review; terraform apply is performed by an operator after approval — never by this module system.

Troubleshooting

Symptom Cause Fix
Error: datacenter_id is required for folder types host, vm, datastore, and network… at plan time type is not datacenter but datacenter_id was left null. Resolve the datacenter MOID in the caller (data "vsphere_datacenter") and pass it as datacenter_id.
Apply fails: parent/ancestor folder not found Nested path (foo/bar) where the parent foo does not exist — the provider does not create intermediate folders. Create the parent first (a separate module call), and reference its output so Terraform orders creation.
Folder is destroyed and recreated unexpectedly type or datacenter_id changed — both are immutable / force-new. Treat both as fixed at creation. To re-home a folder, plan the recreate deliberately (it yields a new MOID, breaking existing references).
Tag not applied, or 404 / "managed object not found" on a tag tags was given a tag name instead of a vsphere_tag MOID, or the tag/category does not exist yet. Pass MOIDs from tf-mod-vsphere-tag.tag_ids[...]; create the tag and its category first.
custom_attributes rejected / unsupported Connected directly to an ESXi host rather than vCenter. Connect to vCenter Server — custom attributes (and folder inventory generally) are a vCenter feature.
Folder unexpectedly moved after editing path You changed the leading portion of path, which re-parents the folder (a move, not a recreate). Expected behaviour. Change only the final segment to rename in place; change the leading portion only when you intend to move it.

Related Docs

  • SCOPE.md — design contract for this module (in-scope vs. consumed-by-ID boundary, privileges, gotchas).
  • vsphere_folder resource — provider documentation.
  • tf-mod-vsphere-tag — source of the vsphere_tag MOIDs consumed by tags.
  • tf-mod-vsphere-datacenter — produces the datacenter_id MOID consumed here (or resolve a pre-existing one via data "vsphere_datacenter").

vSphere module library · No terraform apply is ever performed by this module system — plan-only until a human reviews and applies.

About

No description or website provided.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors

Languages