Authoring desired state

This guide explains how to author the desired state in MechCloud Stateless IaC for AWS. You define your infrastructure using a clean, hierarchical YAML format that is inspired by CloudFormation but significantly simpler — no logical IDs, no !Ref, no state files, and no PascalCase. Instead, you use nesting for relationships, snake_case for properties, and ref: syntax for cross-resource references.

Key Principles

Principle
Description

Hierarchy = Relationship

Nest resources to define parent-child relationships (e.g., subnet inside VPC).

Unique Relative Paths

Every resource must have a unique path (e.g., vpc1/subnet1/instance1). You are responsible for ensuring uniqueness.

snake_case Properties

All keys use lowercase with underscores (e.g., cidr_block, not CidrBlock).

No Parent IDs

Do not include vpc_id, subnet_id, etc. — MechCloud infers them from nesting.

Sibling References

Use ref:<name> only if both resources are in the same resources: block.

Non-Sibling References

Use ref:<full_path> to reference resources outside the current parent.

Step-by-Step: From CloudFormation to MechCloud

Let’s convert a simple CloudFormation stack into a MechCloud desired state.

CloudFormation (Original)

Resources:
  VPC1:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: "10.2.0.0/16"

  SGWeb:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: !Ref VPC1
      GroupDescription: "Allow HTTP from internet"
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: "0.0.0.0/0"

  SGService:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: !Ref VPC1
      GroupDescription: "Allow app traffic only from web1 SG"
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 8080
          ToPort: 8080
          SourceSecurityGroupId: !Ref SGWeb

  Subnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC1
      CidrBlock: "10.2.1.0/24"

  Service1:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: "ami-0bc691261a82b32bc"
      InstanceType: "t3.small"
      SubnetId: !Ref Subnet1
      SecurityGroupIds:
        - !Ref SGService

  Web1:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: "ami-0bc691261a82b32bc"
      InstanceType: "t3.small"
      SubnetId: !Ref Subnet1
      SecurityGroupIds:
        - !Ref SGWeb

MechCloud Desired State (Converted)

resources:
  - type: aws_ec2_vpc
    name: vpc1
    props:
      cidr_block: "10.2.0.0/16"
    resources:
      - type: aws_ec2_security_group
        name: sg_web
        props:
          group_description: "Allow HTTP from internet"
          security_group_ingress:
            - ip_protocol: tcp
              from_port: 80
              to_port: 80
              cidr_ip: "0.0.0.0/0"
      - type: aws_ec2_security_group
        name: sg_service
        props:
          group_description: "Allow app traffic only from web1 SG"
          security_group_ingress:
            - ip_protocol: tcp
              from_port: 8080
              to_port: 8080
              source_security_group_id: "ref:sg_web"
      - type: aws_ec2_subnet
        name: subnet1
        props:
          cidr_block: "10.2.1.0/24"
        resources:
          - type: aws_ec2_instance
            name: web1
            props:
              image_id: "ami-0bc691261a82b32bc"
              instance_type: "t3.micro"
              security_group_ids:
                - "ref:vpc1/sg_web"
          - type: aws_ec2_instance
            name: service1
            props:
              image_id: "ami-0bc691261a82b32bc"
              instance_type: "t3.small"
              security_group_ids:
                - "ref:vpc1/sg_service"

This template contains two security groups (sg_web and sg_service) that are declared together under the same parent resource (vpc1). sg_service needs to refer to the ID of sg_web in its ingress rule (AWS expects an actual security-group ID like sg-0123456789). Because that ID is only known once the security group is created, MechCloud lets you refer to the other resource by name using the special ref:<name> syntax.

The EC2 instances (web1 and service1) are nested under subnet1, which is a different resources: block (a different parent) than the security groups. They therefore cannot use the short ref:sg_name form (which resolves only among siblings in the same resources: block). Instead they must use the full relative path to the security group so MechCloud can uniquely locate it across the hierarchy:

  • source_security_group_id: "ref:sg_web" — used inside sg_service because sg_web and sg_service are siblings under vpc1; this references sg_web’s ID for the security-group ingress rule.

  • security_group_ids: ["ref:vpc1/sg_web"] and ["ref:vpc1/sg_service"] — used on the EC2 instances because the instances live under vpc1/subnet1. The full path (vpc1/sg_web) tells MechCloud exactly which security-group resource to resolve and then substitute its actual ID into the instance’s SecurityGroupIds property.

In short: ref:<name> (short form) points to a sibling resource in the same resources: block; ref:<full_path> (path form) is required when the target resource lives under a different parent. MechCloud resolves either form at plan/apply time to the underlying AWS ID that CloudFormation/AWS expects.

Conversion Rules

Tip: Use hyphens in names for readability (e.g., my-vpc), but avoid spaces or special characters.

CloudFormation
MechCloud

Type: AWS::EC2::VPC

type: aws_ec2_vpc

CidrBlock

cidr_block

VpcId: !Ref MyVPC

Remove — use nesting

Logical ID MyVPC

name: my-vpc

SecurityGroupIds: [!Ref MySG]

security_group_ids: ["ref:my-sg"]

SecurityGroupIngress SourceSecurityGroupId

security_group_ingress source_security_group_id

SecurityGroupIngress SourceSecurityGroupOwnerId

security_group_ingress source_security_group_owner_id

Notes and clarifications for the example template

  • snake_case is mandatory in MechCloud YAML. MechCloud translates these property names to the AWS/CloudFormation property names when making provider calls (for example source_security_group_idSourceSecurityGroupId).

  • There are two kinds of ref: forms used in the example:

    • Short name (sibling) form: ref:<name> — used when one resource needs the ID of another resource that is declared together under the same parent. In the example both sg_web and sg_service are siblings under vpc1, so sg_service uses:

      source_security_group_id: "ref:sg_web"

      MechCloud resolves ref:sg_web at plan/apply time to the actual security-group ID (for AWS).

    • Full-path (non-sibling) form: ref:<relative_path> — used when the referencing resource is in a different part of the hierarchy (different parent). In the example EC2 instances live under vpc1/subnet1, so they must reference the security groups by full relative path:

      security_group_ids:
        - "ref:vpc1/sg_web"
        - "ref:vpc1/sg_service"

      The full path disambiguates the target resource for MechCloud so it can resolve it to the AWS GroupId.

  • Use source_security_group_owner_id when referencing a security group that belongs to a different AWS account (this maps to CloudFormation SourceSecurityGroupOwnerId).

  • Always ensure the ref: target resolves to a security-group resource (so MechCloud can substitute the runtime GroupId). If a ref: points to a non-existent path/name, plan will fail with an unresolved reference error.

Resource Paths (Must Be Unique)

Each resource gets a unique relative path based on its nesting within the hierarchy. This path allows MechCloud to resolve references (ref:) precisely at plan and apply time.

Resource
Path

VPC

vpc1

Security Group — Web

vpc1/sg_web

Security Group — Service

vpc1/sg_service

Subnet

vpc1/subnet1

Instance — Web

vpc1/subnet1/web1

Instance — Service

vpc1/subnet1/service1

Each resource’s path must be unique across the entire desired state file.

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)

    • AWS Account — e.g., Test1 (User 2)

    • Region — e.g., Europe (Ireland)

    • Context — e.g., app1-dev1

  2. Generate the Plan Click Plan to generate an execution plan. MechCloud compares the desired state (defined in YAML) with the actual AWS 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 AWS 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

Was this helpful?