Skip to content

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

🔵 F5OS VLAN Terraform Module

Manages a single VLAN (f5os_vlan) on an F5OS platform — VELOS chassis partition or rSeries appliance — targeting the F5Networks/f5os provider ~> 1.10 (verified against v1.12.0).

Terraform Provider Module Type Resources Posture


🧩 Overview

  • 🏷️ Manages exactly one f5os_vlan resource — a numeric VLAN ID (0-4095) and an optional name.
  • 🧱 Standalone module: single keystone resource named this, no children, no for_each inside the module boundary.
  • 🌐 Applies identically to a VELOS chassis partition or an rSeries appliance — the f5os_vlan schema carries no platform-specific argument.
  • 🔗 Feeds vlan_id to sibling modules — terraform-f5os-tenant's vlans list, and VLAN-tagging arguments on terraform-f5os-interface / terraform-f5os-lag.
  • 🚫 No secrets, no nested blocks, no universal tail (tags/timeouts) — this is the smallest resource shape in the F5OS catalog.

💡 Why it matters: VLANs are a hard prerequisite for tenant networking and interface tagging across the whole F5OS catalog — get the VLAN ID and name right once, here, and every downstream module (tenant, interface, LAG) references it by ID instead of duplicating a literal.


❤️ 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!


🗺️ Where this fits

graph LR
 VLAN["terraform-f5os-vlan"]:::this
 IFACE["terraform-f5os-interface"]:::sibling
 LAG["terraform-f5os-lag"]:::sibling
 PARTITION["terraform-f5os-partition (VELOS only)"]:::sibling
 TENANT["terraform-f5os-tenant"]:::sibling
 PLATFORM["F5OS platform (VELOS chassis partition or rSeries appliance)"]:::target

 VLAN -->|"vlan_id consumed by"| TENANT
 VLAN -->|"vlan_id consumed by (VLAN tagging)"| IFACE
 VLAN -->|"vlan_id consumed by (VLAN tagging)"| LAG
 PARTITION -->|"hosts tenants that reference VLANs"| TENANT
 VLAN -->|"created directly against"| PLATFORM

 classDef this fill:#E4002B,color:#ffffff,stroke:#8f0016,stroke-width:1px;
 classDef target fill:#1B2A4A,color:#ffffff,stroke:#0d1626,stroke-width:1px;
 classDef sibling fill:#E8E8E8,color:#1a1a1a,stroke:#b5b5b5,stroke-width:1px;
Loading

terraform-f5os-vlan (red) sits in the networking domain alongside terraform-f5os-interface and terraform-f5os-lag. It has no upstream dependency of its own — it is a leaf module that other modules (terraform-f5os-tenant, and interface/LAG modules where their schema exposes a VLAN-tagging argument) consume by referencing its vlan_id output. terraform-f5os-partition is shown only to illustrate that a VELOS chassis partition hosting a tenant is a separate concern from the VLAN itself — this module does not consume or require a partition.


🧬 What this builds

graph LR
 subgraph Inputs["Inputs"]
 VAR["var.vlan { vlan_id, name }"]
 end

 RES["f5os_vlan.this"]:::this

 subgraph Outputs["Outputs"]
 OUT_ID["id"]
 OUT_NAME["name"]
 OUT_VLANID["vlan_id"]
 end

 VAR -->|"vlan_id, name"| RES
 RES -->|"exposes"| OUT_ID
 RES -->|"exposes"| OUT_NAME
 RES -->|"exposes"| OUT_VLANID

 classDef this fill:#E4002B,color:#ffffff,stroke:#8f0016,stroke-width:1px;
Loading

Resource inventory

Resource Terraform address Cardinality
f5os_vlan f5os_vlan.this Exactly 1 per module call

✅ Provider / Versions

Item Value
Terraform floor >= 1.12.0
Provider pin F5Networks/f5os ~> 1.10 — verified against the live Terraform Registry listing; terraform init resolved v1.12.0 during authoring, which satisfies this constraint
Provider block None in this module — the caller configures provider "f5os" {} once, in the root module, targeting a single already-authenticated VELOS chassis controller or rSeries appliance
Platform context Both — VELOS chassis partition and rSeries appliance. f5os_vlan's schema carries no partition-specific or appliance-specific argument; behavior is identical on either target

Schema notes that bite (verified against the live f5os_vlan Argument Reference):

  • name is marked Optional in the schema, but the provider's own documentation states "This parameter is required when creating a resource." Terraform's type system cannot catch this — it is a schema/docs mismatch, not a structural error — so omitting name will pass terraform validate and fail only at apply time against a real chassis/appliance.
  • vlan_id has a documented valid range of 0-4095, but the schema types it as a plain Number with no range constraint enforced by Terraform. Out-of-range values pass validate and fail at apply.
  • The fetched Argument Reference does not surface an explicit (Requires replacement) annotation on vlan_id, but since it is the VLAN's identifying value, treat changing it as likely to force recreation in practice — confirm against a real terraform plan before assuming safe in-place update.
  • Import uses the bare numeric VLAN ID as the resource ID (terraform import f5os_vlan.vlan-id-import 4), not a composite string.

🔑 Required F5OS User Role / Chassis Partition Access

Least-privilege role: operator, per the f5os_user resource's documented role set (role — "Specifies primary role assigned to the user (e.g., admin, operator, user)"). VLAN management privilege scoped to the target chassis partition (VELOS) or the appliance itself (rSeries) is sufficient for routine VLAN create/read/update/delete; admin is not required. No role name beyond operator / admin / user is asserted here — those are the only values the provider's own documentation shows as examples. Confirm the live RBAC role catalog on the target platform before granting access, since it may differ per F5OS release.

F5OS Prerequisites

  • F5OS provider F5Networks/f5os ~> 1.10; Terraform >= 1.12.0.
  • Applies to both platform contexts — no partition or appliance-specific prerequisite exists for f5os_vlan itself.
  • No image, chassis partition, or tenant needs to be staged before this module — a VLAN has no dependency on any other F5OS object in this catalog. It is instead a common prerequisite for terraform-f5os-tenant's vlans list and for VLAN-tagging arguments on terraform-f5os-interface / terraform-f5os-lag.
  • The single, already-authenticated f5os provider instance in scope must target the chassis partition or appliance where the VLAN should be visible.

📁 Module Structure

terraform-f5os-vlan/
├── providers.tf # required_version, F5Networks/f5os ~> 1.10 — no provider {} block
├── variables.tf # var.vlan { vlan_id, name } — 1:1 mapped to the real f5os_vlan schema
├── main.tf # f5os_vlan.this — the module's single keystone resource
├── outputs.tf # id, name, vlan_id
├── SCOPE.md # lightweight standalone contract — RBAC, prerequisites, emits, gotchas
└── README.md # this file — worked example configurations live in 📚 Example Library below

No separate examples/ directory ships with this module — every worked configuration is captured inline in the 📚 Example Library below, using the module's real variable names.


⚙️ Quick Start

# The caller configures the provider once, elsewhere in the root module:
# provider "f5os" {
# host = var.f5os_host
# username = var.f5os_username
# password = var.f5os_password
# }

module "vlan_100" {
  source = "git::https://github.com/microsoftexpert/terraform-f5os-vlan.git?ref=v1.0.0"

  vlan = {
    vlan_id = 100
    name    = "vlan100"
  }
}

🔌 Cross-Module Contract

Consumes

Input Type Source module
— — None. This is a leaf module in the F5OS catalog; it has no upstream dependency on another terraform-f5os-* module's output.

Emits

Output Description Consumed by
id Provider-internal synthetic identifier for the f5os_vlan resource Informational / import use — not typically referenced by sibling modules
name The configured VLAN name, if set (null otherwise) Informational; no documented sibling-module argument currently references it
vlan_id The numeric VLAN ID (0-4095) actually configured on the platform terraform-f5os-tenant (vlans list entries); terraform-f5os-interface / terraform-f5os-lag (VLAN tagging arguments — verify exact argument name per sibling module)

📚 Example Library

1 · Minimal VLAN

The smallest real call — both fields set, since name is required in practice.

module "vlan_minimal" {
  source = "git::https://github.com/microsoftexpert/terraform-f5os-vlan.git?ref=v1.0.0"

  vlan = {
    vlan_id = 10
    name    = "vlan10"
  }
}

💡 Always set name even though the schema marks it Optional — see "Schema notes that bite."

2 · Naming convention compliance

name must start with a letter, allow only alphanumerics/periods/commas/hyphens/underscores, and stay under 58 characters.

module "vlan_named" {
  source = "git::https://github.com/microsoftexpert/terraform-f5os-vlan.git?ref=v1.0.0"

  vlan = {
    vlan_id = 20
    name    = "corp-mgmt_vlan.20"
  }
}

ℹ️ This module does not enforce the naming pattern with a validation {} block (it is not a closed enum); the provider itself rejects a malformed name at apply time.

3 · Lower boundary VLAN ID (0)
module "vlan_zero" {
  source = "git::https://github.com/microsoftexpert/terraform-f5os-vlan.git?ref=v1.0.0"

  vlan = {
    vlan_id = 0
    name    = "vlan0"
  }
}

⚠️ VLAN 0 is within the documented schema range but may carry special meaning on some F5OS platform releases (e.g. default/native VLAN semantics) — confirm against the target platform's own documentation before relying on it in production.

4 · Upper boundary VLAN ID (4095)
module "vlan_max" {
  source = "git::https://github.com/microsoftexpert/terraform-f5os-vlan.git?ref=v1.0.0"

  vlan = {
    vlan_id = 4095
    name    = "vlan4095"
  }
}
5 · Omitting name (failure mode, documented deliberately)
module "vlan_no_name" {
  source = "git::https://github.com/microsoftexpert/terraform-f5os-vlan.git?ref=v1.0.0"

  vlan = {
    vlan_id = 30
    # name intentionally omitted
  }
}

⚠️ This passes terraform validate (the type is optional(string), matching the provider's own schema) but the provider's documentation states name is required when creating the resource — expect an apply-time failure against a real chassis/appliance. Set name explicitly instead.

6 · Multiple VLANs via root-module for_each

This module manages exactly one VLAN per call — fan-out across several VLANs is a root-module concern.

locals {
  vlans = {
    vlan_10  = { vlan_id = 10, name = "vlan10" }
    vlan_20  = { vlan_id = 20, name = "vlan20" }
    vlan_100 = { vlan_id = 100, name = "vlan100" }
  }
}

module "vlans" {
  source   = "git::https://github.com/microsoftexpert/terraform-f5os-vlan.git?ref=v1.0.0"
  for_each = local.vlans

  vlan = each.value
}
7 · Referencing vlan_id into a tenant's vlans list
module "vlan_tenant_data" {
  source = "git::https://github.com/microsoftexpert/terraform-f5os-vlan.git?ref=v1.0.0"

  vlan = {
    vlan_id = 50
    name    = "vlan50-tenant-data"
  }
}

module "tenant_app01" {
  source = "git::https://github.com/microsoftexpert/terraform-f5os-tenant.git?ref=v1.0.0"

  # Illustrative — consult terraform-f5os-tenant's own README for its full variable schema.
  # vlans = [module.vlan_tenant_data.vlan_id]
}

🔗 Reference vlan_id, not id — F5OS cross-references VLANs by numeric ID, and terraform-f5os-tenant's vlans argument is a flat list(number) of VLAN IDs.

8 · Referencing vlan_id into an interface's VLAN tagging
module "vlan_data" {
  source = "git::https://github.com/microsoftexpert/terraform-f5os-vlan.git?ref=v1.0.0"

  vlan = {
    vlan_id = 60
    name    = "vlan60-data"
  }
}

module "interface_1_0" {
  source = "git::https://github.com/microsoftexpert/terraform-f5os-interface.git?ref=v1.0.0"

  # Illustrative — consult terraform-f5os-interface's own README for its exact VLAN-tagging
  # argument name before wiring module.vlan_data.vlan_id into it.
}
9 · VELOS chassis partition target context

The module call itself is identical to the rSeries case — only the caller's provider "f5os" {} block (outside this module) changes to point at the VELOS chassis controller partition's management endpoint.

# provider "f5os" {
# host = var.velos_partition_mgmt_ip
# username = var.f5os_username
# password = var.f5os_password
# }

module "vlan_velos" {
  source = "git::https://github.com/microsoftexpert/terraform-f5os-vlan.git?ref=v1.0.0"

  vlan = {
    vlan_id = 70
    name    = "vlan70-velos"
  }
}
10 · rSeries appliance target context
# provider "f5os" {
# host = var.rseries_appliance_mgmt_ip
# username = var.f5os_username
# password = var.f5os_password
# }

module "vlan_rseries" {
  source = "git::https://github.com/microsoftexpert/terraform-f5os-vlan.git?ref=v1.0.0"

  vlan = {
    vlan_id = 80
    name    = "vlan80-rseries"
  }
}

💡 f5os_vlan behaves identically on VELOS and rSeries — there is no platform-context branch inside this module.

11 · Externalizing input via terraform.tfvars
# vlan.auto.tfvars
vlan = {
  vlan_id = 90
  name    = "vlan90-ext"
}
# main.tf (caller)
module "vlan_from_tfvars" {
  source = "git::https://github.com/microsoftexpert/terraform-f5os-vlan.git?ref=v1.0.0"

  vlan = var.vlan
}
12 · Computed VLAN name via a local value
locals {
  vlan_id_value = 200
}

module "vlan_computed_name" {
  source = "git::https://github.com/microsoftexpert/terraform-f5os-vlan.git?ref=v1.0.0"

  vlan = {
    vlan_id = local.vlan_id_value
    name    = "vlan${local.vlan_id_value}"
  }
}

ℹ️ Useful for a root module generating many VLANs from a numeric range without hand-typing each name.

13 · Importing an existing VLAN
module "vlan_existing" {
  source = "git::https://github.com/microsoftexpert/terraform-f5os-vlan.git?ref=v1.0.0"

  vlan = {
    vlan_id = 4
    name    = "vlan4"
  }
}
terraform import module.vlan_existing.f5os_vlan.this 4

🔒 Per the provider's documented import syntax, the bare numeric VLAN ID is the import key — not a composite string.

🏗️ 14 · End-to-end composition

VLAN provisioned once, then referenced by both an interface and a tenant deployed into a VELOS chassis partition — illustrating the full cross-module contract this module participates in.

module "vlan_app_data" {
  source = "git::https://github.com/microsoftexpert/terraform-f5os-vlan.git?ref=v1.0.0"

  vlan = {
    vlan_id = 500
    name    = "vlan500-app-data"
  }
}

module "partition_appA" {
  source = "git::https://github.com/microsoftexpert/terraform-f5os-partition.git?ref=v1.0.0"

  # Illustrative — consult terraform-f5os-partition's own README for its full variable schema.
}

module "interface_1_1" {
  source = "git::https://github.com/microsoftexpert/terraform-f5os-interface.git?ref=v1.0.0"

  # Illustrative — wires module.vlan_app_data.vlan_id into whichever VLAN-tagging
  # argument terraform-f5os-interface's own schema exposes.
}

module "tenant_appA" {
  source = "git::https://github.com/microsoftexpert/terraform-f5os-tenant.git?ref=v1.0.0"

  # Illustrative — consult terraform-f5os-tenant's own README.
  # vlans = [module.vlan_app_data.vlan_id]
  # partition_name = module.partition_appA.name # VELOS only
}

💡 Why it matters: this is the shape every real deployment takes — VLAN and chassis partition provisioned independently and in parallel, then referenced by ID/name from the interface and tenant modules that depend on them. Never hardcode a literal VLAN ID downstream; always pass module.vlan_app_data.vlan_id.


📥 Inputs

Name Type Required Description
vlan object({ vlan_id = number, name = optional(string) }) Yes VLAN configuration, 1:1 mapped to the f5os_vlan provider schema.
Full vlan object schema
variable "vlan" {
  type = object({
    vlan_id = number           # Required. 0-4095.
    name    = optional(string) # Optional per schema; required in practice per provider docs.
    # First char must be a letter; alphanumerics, periods, commas,
    # hyphens, underscores allowed; max 58 characters.
  })
}

No default is invented for name beyond the provider's own null/unset behavior — passing it unset mirrors the provider's schema exactly rather than papering over the docs/schema mismatch noted in "Schema notes that bite."


🧾 Outputs

Output Description Sensitive
id Provider-internal synthetic identifier for the f5os_vlan resource No
name The configured VLAN name, if set (null otherwise) No
vlan_id The numeric VLAN ID (0-4095) configured on the platform — the value sibling modules should reference No

🧠 Architecture Notes

  • Single keystone resource, no for_each. f5os_vlan's schema exposes no nested/child collection (just vlan_id and name), so this module has no genuine child to iterate over. Multiplicity (many VLANs) is a root-module concern — see Example 6.
  • try(var.vlan.name, null) in main.tf. Defensive around the one optional field this module's object wraps; functionally equivalent to referencing var.vlan.name directly given optional(string)'s own null-default behavior, but kept explicit per house style for optional nested-field references.
  • No VELOS-vs-rSeries branching. Unlike f5os_partition (VELOS-only) or f5os_tenant (platform-specific partition_name input), f5os_vlan behaves identically on both platform contexts — there is nothing in this module's main.tf that varies by target.
  • Ordering. A VLAN should exist before any sibling tenant/interface/LAG module references its vlan_id — always pass this module's vlan_id output into the consuming module's input via an implicit Terraform reference, never a hardcoded literal.
  • vlan_id treated as effectively immutable in practice. The fetched schema does not surface an explicit (Requires replacement) annotation, but since it is the VLAN's identifying value, verify actual in-place-update behavior against a real terraform plan before assuming it is safe to change post-creation.

🧱 Design Principles

Concern Secure default Opt-out (caller must type extra)
VLAN identification No default vlan_id — always an explicit, required input; matches the house-wide "no allow-all VLANs" rule N/A — hard rule, not a toggle
VLAN naming This module does not fabricate a default name even though the schema marks it Optional — passing it unset mirrors the provider's own optionality rather than papering over the documented schema/docs mismatch Caller explicitly supplies name (recommended for every real deployment per the provider's own documentation)
Credentials / secrets Not applicable — f5os_vlan carries no secret-shaped argument N/A

🚀 Runbook

cd C:\GitHubCode\newf5modules\f5os\terraform-f5os-vlan
terraform init -backend=false
terraform validate
terraform fmt -check
Remove-Item -Recurse -Force.terraform,.terraform.lock.hcl -ErrorAction SilentlyContinue

Pin every consumer to a specific release: ?ref=v1.0.0.


🧪 Testing

This is a plan-only proof gate — it never touches a real chassis or appliance.

Check Catches Does not catch
terraform validate Missing vlan_id, wrong type on either field, malformed HCL The name-required-in-practice mismatch; vlan_id out-of-range values; RBAC/permission failures
terraform fmt -check Formatting drift from canonical style Anything semantic
terraform plan (human-run, against real infra) The above two gaps — a real F5OS structured error surfaces at plan/apply time —

💬 Example Output

$ terraform output
id = "100"
name = "vlan100"
vlan_id = 100

🔍 Troubleshooting

Symptom Cause Fix
apply fails with a name-required error despite validate passing name omitted — schema marks it Optional but the provider requires it in practice at creation Set vlan.name explicitly (see Example 5)
apply fails with an out-of-range VLAN ID error vlan_id outside 0-4095 — not enforced by Terraform's type system Correct vlan_id to the documented range
Permission denied / RBAC error at apply The authenticated user's role lacks VLAN-management privilege on the target chassis partition or appliance Grant at least the operator role scoped to that partition/appliance
init cannot resolve provider version ~> 1.10 no longer matches the current Terraform Registry listing Re-verify the pin against the registry and update providers.tf
Plan shows unexpected diff on name/vlan_id with no caller change A previous out-of-band change was made directly on the F5OS platform Reconcile via terraform import or terraform plan -refresh-only before applying

🔗 Related Docs


💙 "Infrastructure as Code should be standardized, consistent, and secure."

Releases

Packages

Contributors

Languages