Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions .github/workflows/validate-config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# =============================================================================
# validate-config.yml — Validate config/variables.example.yml against schema
# =============================================================================
# Triggered on PRs and pushes that touch config/ or this workflow.
# Validates YAML syntax and JSON Schema compliance.
# =============================================================================

name: Validate Configuration

on:
push:
branches: [main]
paths:
- 'config/**'
- '.github/workflows/validate-config.yml'
pull_request:
branches: [main]
paths:
- 'config/**'
workflow_dispatch:
Comment on lines +4 to +20

permissions:
contents: read

jobs:
validate:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Install dependencies
run: pip install pyyaml jsonschema

- name: Validate variables.example.yml against schema
run: |
python3 -c "
import yaml, json, sys
from jsonschema import validate, ValidationError

Comment on lines +41 to +46
with open('config/variables.example.yml') as f:
data = yaml.safe_load(f)

with open('config/schema/variables.schema.json') as f:
schema = json.load(f)

try:
validate(instance=data, schema=schema)
print('✅ config/variables.example.yml passes schema validation')
except ValidationError as e:
print(f'❌ Schema validation failed: {e.message}')
print(f' Path: {\" > \".join(str(p) for p in e.absolute_path)}')
sys.exit(1)
"
149 changes: 149 additions & 0 deletions config/schema/variables.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://github.com/AzureLocal/azurelocal-sofs-fslogix/config/schema/variables.schema.json",
"title": "SOFS FSLogix Variables",
"description": "Schema for config/variables.example.yml — validates required sections and key structure.",
"type": "object",
"required": ["azure", "keyvault", "azure_local", "vm", "data_disks", "domain", "dns_servers", "sofs", "s2d", "cloud_witness", "guest_config_engine", "tags"],
"properties": {
"azure": {
"type": "object",
"required": ["subscription_id", "resource_group", "location"],
"properties": {
"subscription_id": { "type": "string" },
"resource_group": { "type": "string" },
"location": { "type": "string" }
}
},
Comment on lines +8 to +17
"keyvault": {
"type": "object",
"required": ["name"],
"properties": {
"name": { "type": "string" }
}
},
"azure_local": {
"type": "object",
"required": ["cluster_name", "custom_location_id", "logical_network_id", "gallery_image_name"],
"properties": {
"cluster_name": { "type": "string" },
"custom_location_id": { "type": "string" },
"logical_network_id": { "type": "string" },
"gallery_image_name": { "type": "string" },
"storage_path_id": { "type": "string" },
"storage_path_ids": { "type": "object", "additionalProperties": { "type": "string" } }
}
},
"vm": {
"type": "object",
"required": ["prefix", "count", "processors", "memory_mb", "admin_username", "admin_password", "ips"],
"properties": {
"prefix": { "type": "string" },
"count": { "type": "integer", "minimum": 1 },
"processors": { "type": "integer", "minimum": 1 },
"memory_mb": { "type": "integer", "minimum": 1024 },
"admin_username": { "type": "string" },
"admin_password": { "type": "string" },
"ips": { "type": "object", "additionalProperties": { "type": "string" } }
}
},
"data_disks": {
"type": "object",
"required": ["count", "size_gb"],
"properties": {
"count": { "type": "integer", "minimum": 1 },
"size_gb": { "type": "integer", "minimum": 1 }
}
},
"domain": {
"type": "object",
"required": ["fqdn", "netbios", "join_username", "join_password"],
"properties": {
"fqdn": { "type": "string" },
"netbios": { "type": "string" },
"join_username": { "type": "string" },
"join_password": { "type": "string" },
"cluster_ou_path": { "type": "string" },
"nodes_ou_path": { "type": "string" }
}
},
"dns_servers": {
"type": "array",
"items": { "type": "string" },
"minItems": 1
},
"sofs": {
"type": "object",
"required": ["name", "cluster_name", "cluster_ip"],
"properties": {
"name": { "type": "string" },
"cluster_name": { "type": "string" },
"cluster_ip": { "type": "string" },
"role_enabled": { "type": "boolean" },
"anti_affinity_rule_name": { "type": "string" },
"share_name": { "type": "string" },
"shares": {
"type": "array",
"items": {
"type": "object",
"required": ["name", "volume"],
"properties": {
"name": { "type": "string" },
"volume": { "type": "string" }
}
}
}
}
},
"s2d": {
"type": "object",
"properties": {
"volume_name": { "type": "string" },
"volume_size_gb": { "type": "integer" },
"data_copies": { "type": "integer", "enum": [2, 3] },
"volumes": {
"type": "array",
"items": {
"type": "object",
"required": ["name", "size_gb", "data_copies"],
"properties": {
"name": { "type": "string" },
"size_gb": { "type": "integer" },
"data_copies": { "type": "integer", "enum": [2, 3] }
}
}
}
}
},
"cloud_witness": {
"type": "object",
"required": ["name"],
"properties": {
"name": { "type": "string" },
"key_uri": { "type": "string" },
"key_secret": { "type": "string" }
}
},
"guest_config_engine": {
"type": "string",
"enum": ["ansible_create", "ansible_existing", "manual"]
},
"ansible_controller": {
"type": "object",
"properties": {
"name": { "type": "string" },
"size": { "type": "string" },
"admin_username": { "type": "string" },
"hub_subnet_id": { "type": "string" },
"hub_rg": { "type": "string" },
"existing_controller_ip": { "type": "string" },
"existing_controller_user": { "type": "string" }
}
},
"tags": {
"type": "object",
"additionalProperties": { "type": "string" }
}
},
"additionalProperties": false
}
24 changes: 24 additions & 0 deletions docs/reference/variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,30 @@ All deployment tools read from a single central configuration file: `config/vari

---

## Naming Rules

| Scope | Convention | Example |
|-------|-----------|---------|
| Top-level sections | `snake_case` | `azure_local`, `data_disks` |
| Keys within sections | `snake_case` | `subscription_id`, `volume_size_gb` |
| Per-VM maps | Zero-padded string keys | `"01"`, `"02"`, `"03"` |
| Booleans | Descriptive name | `role_enabled: true` |
| Secrets | `keyvault://` URI | `keyvault://kv-name/secret-name` |
| Example values | IIC fictional identity | `iic.local`, `rg-iic-sofs-01`, `kv-iic-platform` |

---

## Compatibility

The PowerShell scripts include a **compatibility shim** that maps the new sectioned config into the legacy `compute_wsfc` / `wsfc_sofs_*` flat key format. This means:

- New `config/variables.yml` → works with all scripts
- Legacy `solution-sofs.yml` → also works (auto-detected)

The shim is transparent — downstream script logic is unchanged.

---

## Azure

```yaml
Expand Down
93 changes: 8 additions & 85 deletions docs/standards/variables.md
Original file line number Diff line number Diff line change
@@ -1,89 +1,12 @@
# Variable Standards

Conventions for the central configuration file and all variable naming across the repository.
!!! info "This page has moved"
Variable standards, naming conventions, and the complete configuration reference are now consolidated at **[Variable Reference](../reference/variables.md)**.

---
See [Variable Reference](../reference/variables.md) for:

## Central Config

The single source of truth is `config/variables.yml`. Copy from `config/variables.example.yml`.

### Format

- **YAML** with sectioned structure
- Clean, human-readable keys (no prefixes like `wsfc_sofs_`)
- 2-space indentation

### Sections

```yaml
azure: # Azure subscription, resource group, location
keyvault: # Key Vault name for secret resolution
azure_local: # Azure Local cluster, custom location, networks, images, storage paths
vm: # VM prefix, count, specs, admin creds, IPs
data_disks: # Disk count and size for S2D pool
domain: # AD domain config, join credentials, OU paths
dns_servers: # DNS server list
sofs: # SOFS role name, cluster name/IP, share name
s2d: # Storage Spaces Direct volume config
cloud_witness: # Cloud witness storage account
guest_config_engine: # How to configure guests (ansible_create, ansible_existing, manual)
ansible_controller: # Ansible controller VM details
tags: # Resource tags
```

### Naming Rules

| Scope | Convention | Example |
|-------|-----------|---------|
| Top-level sections | `snake_case` | `azure_local`, `data_disks` |
| Keys within sections | `snake_case` | `subscription_id`, `volume_size_gb` |
| Per-VM maps | Zero-padded string keys | `"01"`, `"02"`, `"03"` |
| Booleans | Descriptive name | `role_enabled: true` |
| Secrets | `keyvault://` URI | `keyvault://kv-name/secret-name` |
| Example values | IIC fictional identity | `iic.local`, `rg-iic-sofs-01`, `kv-iic-platform` |

---

## Key Vault References

Secrets are **never** stored as plain text in config files. Use the `keyvault://` URI format:

```yaml
vm:
admin_password: "keyvault://kv-platform-prod/sofs-vm-admin-password"
domain:
join_password: "keyvault://kv-platform-prod/domain-join-password"
```

At runtime, scripts resolve these via `Resolve-KeyVaultRef`:

1. Try `Az.KeyVault` PowerShell module (preferred)
2. Fallback to `az keyvault secret show` CLI
3. Hard fail if neither works (no interactive prompts)

---

## Compatibility

The PowerShell scripts include a **compatibility shim** that maps the new sectioned config into the legacy `compute_wsfc` / `wsfc_sofs_*` flat key format. This means:

- New `config/variables.yml` → works with all scripts
- Legacy `solution-sofs.yml` → also works (auto-detected)

The shim is transparent — downstream script logic is unchanged.

---

## Tool-Specific Parameter Files

| Tool | File | Location |
|------|------|----------|
| PowerShell | `variables.yml` | `config/` |
| Bicep | `main.bicepparam` | `src/bicep/` |
| Terraform | `terraform.tfvars` | `src/terraform/` |
| ARM | `azuredeploy.parameters.json` | `src/arm/` |
| Ansible | `inventory.yml` | `src/ansible/inventory/` |
| Azure CLI | `.env` | `scripts/` |

All tool-specific parameter files should derive their values from the central `config/variables.yml`.
- Naming rules and conventions
- Compatibility notes
- Every configuration section with types, defaults, and deployment phase mapping
- Key Vault secret resolution
- Tool-specific parameter mapping
Loading