Authoring desired state

This guide explains how to author the desired state in MechCloud Stateless IaC for Azure. You define your infrastructure using a clean, flat YAML format that is inspired by ARM templates but significantly simpler — no complex nested JSON, no resourceId() functions, no deployment state files, and no camelCase. Instead, you use snake_case for properties, ref: syntax for cross-resource references, and defaults: to avoid repetition.

Key Principles

Principle
Description

Flat Resource List

All resources are declared in a single flat resources: list. Parent-child relationships are expressed via ref: syntax.

snake_case Properties

All keys use lowercase with underscores (e.g., address_prefixes, not addressPrefixes).

Defaults Block

Use defaults: to specify common values (like resource_group) once, avoiding repetition across all resources.

ref: for IDs

Use ref:<name> to reference another resource's ID. MechCloud resolves this to the full Azure resource ID at plan/apply time.

Nested Path References

Use ref:<parent>/<child_type>/<child_name> to reference nested resources (e.g., ref:vnet1/subnets/subnet1 for a subnet inside a VNet).

API Version Required

Each resource must specify its api_version to ensure compatibility with Azure Resource Manager.

Step-by-Step: From ARM Template to MechCloud

Let's convert a typical ARM template that creates a VM with networking into a MechCloud desired state.

ARM Template (Original)

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "resources": [
    {
      "type": "Microsoft.Network/virtualNetworks",
      "apiVersion": "2025-05-01",
      "name": "vnet1",
      "location": "[resourceGroup().location]",
      "properties": {
        "addressSpace": {
          "addressPrefixes": ["10.0.0.0/16"]
        },
        "subnets": [
          {
            "name": "subnet1",
            "properties": {
              "addressPrefixes": ["10.0.1.0/24"]
            }
          }
        ]
      }
    },
    {
      "type": "Microsoft.Network/networkSecurityGroups",
      "apiVersion": "2025-05-01",
      "name": "nsg1",
      "location": "[resourceGroup().location]",
      "properties": {
        "securityRules": [
          {
            "name": "allow-ssh",
            "properties": {
              "priority": 100,
              "direction": "Inbound",
              "access": "Allow",
              "protocol": "Tcp",
              "sourcePortRange": "*",
              "destinationPortRange": "22",
              "sourceAddressPrefix": "YOUR_IP/32",
              "destinationAddressPrefix": "*"
            }
          }
        ]
      }
    },
    {
      "type": "Microsoft.Network/networkInterfaces",
      "apiVersion": "2025-05-01",
      "name": "nic1",
      "location": "[resourceGroup().location]",
      "dependsOn": [
        "[resourceId('Microsoft.Network/virtualNetworks', 'vnet1')]",
        "[resourceId('Microsoft.Network/networkSecurityGroups', 'nsg1')]"
      ],
      "properties": {
        "networkSecurityGroup": {
          "id": "[resourceId('Microsoft.Network/networkSecurityGroups', 'nsg1')]"
        },
        "ipConfigurations": [
          {
            "name": "ipconfig1",
            "properties": {
              "subnet": {
                "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', 'vnet1', 'subnet1')]"
              },
              "privateIPAllocationMethod": "Dynamic"
            }
          }
        ]
      }
    },
    {
      "type": "Microsoft.Compute/virtualMachines",
      "apiVersion": "2025-04-01",
      "name": "vm1",
      "location": "[resourceGroup().location]",
      "dependsOn": [
        "[resourceId('Microsoft.Network/networkInterfaces', 'nic1')]"
      ],
      "properties": {
        "hardwareProfile": {
          "vmSize": "Standard_B2pts_v2"
        },
        "osProfile": {
          "computerName": "testvm",
          "adminUsername": "ubuntu",
          "adminPassword": "SecureP@ss2024!"
        },
        "networkProfile": {
          "networkInterfaces": [
            {
              "id": "[resourceId('Microsoft.Network/networkInterfaces', 'nic1')]"
            }
          ]
        },
        "storageProfile": {
          "imageReference": {
            "publisher": "Canonical",
            "offer": "ubuntu-24_04-lts",
            "sku": "server-arm64",
            "version": "latest"
          },
          "osDisk": {
            "createOption": "FromImage",
            "managedDisk": {
              "storageAccountType": "StandardSSD_LRS"
            }
          }
        }
      }
    }
  ]
}

MechCloud Desired State (Converted)

Key Simplifications

1. The defaults: Block — Eliminate Repetition

In ARM templates, you must specify location and often reference the resource group repeatedly using functions like [resourceGroup().location]. In MechCloud, the defaults: block lets you define common values once:

This value is automatically applied to all resources in the template. You don't need to repeat resource_group: rg1 for each resource.

Benefits:

  • Less repetition — Define once, apply everywhere

  • Fewer errors — No risk of typos or inconsistent values

  • Cleaner templates — Focus on what makes each resource unique

2. The ref: Syntax — Simple Resource References

ARM templates require verbose resourceId() function calls to reference other resources:

In MechCloud, you simply use:

MechCloud automatically resolves ref:nsg1 to the full Azure resource ID at plan/apply time:

3. Nested Resource References — Clean Path Syntax

For nested resources like subnets (which are children of VNets), ARM templates require complex expressions:

In MechCloud, you use a simple path notation:

The path follows the pattern: <parent_name>/<child_type>/<child_name>

MechCloud resolves this to:

4. No dependsOn Required

ARM templates require explicit dependsOn arrays to ensure resources are created in the correct order:

In MechCloud, dependencies are automatically inferred from ref: references. When you write:

MechCloud knows that nic1 depends on nsg1 and will create them in the correct order. No manual dependency management required.

Conversion Rules

ARM Template
MechCloud

"type": "Microsoft.Network/virtualNetworks"

type: "Microsoft.Network/virtualNetworks"

"apiVersion": "2025-05-01"

api_version: "2025-05-01"

"name": "vnet1"

name: vnet1

"properties": { ... }

props: ...

addressPrefixes

address_prefixes

privateIPAllocationMethod

private_ip_allocation_method

storageAccountType

storage_account_type

"[resourceGroup().location]"

Remove — derived from selected Region in UI

"[resourceId('...', 'name')]"

"ref:name"

"[resourceId('Type/SubType', 'parent', 'child')]"

"ref:parent/subtype/child"

"dependsOn": [...]

Remove — automatically inferred from ref: usage

Template Variables

MechCloud supports special template variables that are resolved at plan/apply time:

Variable
Description

{{CURRENT_IP}}

Replaced with the public IP address of the machine executing the plan. Useful for firewall rules and NSG rules.

Example usage in NSG rule:

This eliminates the need to manually look up and update your IP address every time it changes.

Reference Syntax Summary

Scenario
ARM Template
MechCloud

Reference a top-level resource

[resourceId('Microsoft.Network/networkSecurityGroups', 'nsg1')]

ref:nsg1

Reference a nested resource

[resourceId('Microsoft.Network/virtualNetworks/subnets', 'vnet1', 'subnet1')]

ref:vnet1/subnets/subnet1

Reference a NIC from a VM

[resourceId('Microsoft.Network/networkInterfaces', 'nic1')]

ref:nic1

Resource Paths

Each resource in MechCloud has a unique path based on its name and type. For nested resources, the path includes the parent:

Resource
Path

Virtual Network

vnet1

Subnet (nested in VNet)

vnet1/subnets/subnet1

Network Security Group

nsg1

Network Interface

nic1

Virtual Machine

vm1

Referencing Existing Resources

When you need to reference resources that already exist in Azure (not defined in your template), MechCloud supports shorthand formats that are automatically expanded to full Azure resource IDs.

Same Resource Group

For existing resources in the same resource group as your template's default, use the shorthand format starting with /providers:

MechCloud automatically expands this to the full Azure resource ID:

Different Resource Group (Same Subscription)

For existing resources in a different resource group (but same subscription), use the format starting with /resourceGroups:

MechCloud automatically expands this to the full Azure resource ID:

Note: All resources are provisioned in the same subscription (from the selected cloud account). The subscription ID is automatically obtained from the cloud account metadata — you never need to specify it.

Reference Format Summary

Scenario
Format

Resource in same template

ref:resource-name or ref:parent/child-type/child-name

Existing resource in same resource group

/providers/Microsoft.{RP}/{type}/{name}

Existing resource in different resource group

/resourceGroups/{rg}/providers/Microsoft.{RP}/{type}/{name}

Example: VM Using Existing VNet

This example creates a VM that uses an existing VNet and subnet:

Next Steps

  1. Select Execution Context At the top of the MechCloud console, select the execution context for your operation:

    • Team — e.g., Academy (User 2)

    • Cloud Provider — e.g., Azure

    • Cloud Account — e.g., Academy

    • Region — e.g., West US 2

    • Context — e.g., azure-random1

  2. Generate the Plan Click Plan to generate an execution plan. MechCloud compares the desired state (defined in YAML) with the actual Azure infrastructure and determines which resources require changes.

  3. Review Plan Actions Each resource in the plan shows an action indicating how MechCloud will reconcile it:

    • create — the resource does not exist and will be created.

    • update — the resource exists but properties differ and will be updated.

    • delete — the resource exists but is no longer in the desired state and will be removed.

    • recreate — the resource will be deleted and then created again (for non-updatable property changes).

    • none — the resource is already in the desired state; no action required.

  4. Apply the Plan (When Changes Exist)

    • The Apply button becomes visible only when the plan includes at least one resource whose action is not none.

    • Click Apply to provision or update resources as per the plan.

    • MechCloud will execute the required operations and bring your Azure environment to match the desired state.

  5. Verify Post-Apply State

    • Once the apply completes, click Plan again to re-run the comparison.

    • If all resources now display action: none, the desired and actual states are in sync.

    • In this case, the Apply button will not be visible because no further changes are required.

  6. Handle Errors (If Any)

    • If any errors occur during the apply step, re-run Plan to refresh dependencies and reconcile state.

    • Then click Apply again to retry provisioning with the updated plan.

Last updated