Skip to content

Heat examples

You will find below different examples to achieve several usecases you've read in the documentation.

List of heat resource types you might find in this page
OS::Nova::ResourceGroup
OS::Nova::ServerGroup
OS::Neutron::SecurityGroup
OS::Neutron::SecurityGroupRule

Example 1 : VMs Affinity - Anti-affinity. 3 VMs physically in different datacenter zones

VMs Affinity - Anti-affinity documentation and manual creation

How to create 3 VMs, each one in a different zone (meaning physically in different datacenter zones)

You need resources of type OS::Heat::ResourceGroup in combination with OS::Nova::ServerGroup and define an additional template for the VMs themselves called in this example node.yaml

The example below will create

  • a group of server called group_nodes with the policy anti-affinity
  • 3 VMs of type node.yaml in the same group group_nodes therefore using the anti-affinity policy
group_nodes
group_nodes:
  type: OS::Nova::ServerGroup
  properties:
    name: {list_join: ['-', [{get_param: "OS::stack_name"}, 'group-nodes']]}
    policies: ["anti-affinity"]

nodes:
  type: OS::Heat::ResourceGroup
  properties:
    count: 3
    resource_def:
      type: node.yaml
      properties:
        flavorname: a1-ram2-disk20-perf1
        image: Debian 11 bullseye
        private_network: mynetwork
        name: {list_join: ['-', [{get_param: "OS::stack_name"}, 'node', '%index%']]}
        servergroup: {get_resource: group_nodes}
        key_name: my_keypair
        security_groups:
          - default
node.yaml
---
heat_template_version: 2018-08-31

parameters:
  private_network:
    type: string
  key_name:
    type: string
    label: Key Name
    description: Name of key-pair to be used for compute instance
    default: my_keypair
  flavorname:
    type: string
    default: a1-ram2-disk20-perf1
  image:
    type: string
    default: Debian 11 bullseye
  name:
    type: string
  servergroup:
    type: string
  security_groups:
    type: comma_delimited_list
    default: "default"

resources:
  port:
    type: OS::Neutron::Port
    properties:
      network: {get_param: private_network}
      security_groups: {get_param: security_groups}

  instance:
    type: OS::Nova::Server
    properties:
      name: {get_param: name}
      flavor: {get_param: flavorname}
      image: {get_param: image}
      key_name: {get_param: key_name}
      networks: [port: {get_resource: port}]
      scheduler_hints:
        group: {get_param: servergroup}

outputs:
  internal_ip:
    description: Internal IP of the host
    value: {get_attr: [instance, first_address]}
  server_id:
    description: ID of instance
    value: {get_attr: [instance, name]}

Example 2 : Security groups & Remote security groups

Security groups documentation

In this example :

  1. allow ping from anywhere (ipv4 and ipv6)
  2. allow ssh tcp port 22 from IPs 10.8.0.2 and 2001:1600:10:100::7a only
  3. Allow tcp traffic from anywhere except tcp port 22 ipv4 and ipv6
  4. Allow VMs using securityGroupRuleA only to SSH VMs using securityGroupRuleB

You need resources of type OS::Neutron::SecurityGroup and OS::Neutron::SecurityGroupRule

Info

you can't mix IPv4 and IPv6 rules in the same security group Heat resource, you must create 2 different security groups like we did below : bastion_security_group_ipv4 and bastion_security_group_ipv6

Info

There are 2 syntaxes possible, one has been used for IPv4 and the other one for IPv6.

bastion_security_group.yaml
---
heat_template_version: 2015-04-30

resources:
  # ---------------------------------- CLASSIC AND PREFIX SECURITY GROUP EXAMPLE -----------------------------
  bastion_security_group_ipv4:
    type: OS::Neutron::SecurityGroup
    properties:
      description: Security group for bastion
      name: {list_join: ['-', [{get_param: OS::stack_name}, 'bastion-ipv4']]}
      rules:
        - protocol: "icmp"
          direction: "ingress"
          remote_ip_prefix: 0.0.0.0/0
        - protocol: "tcp"
          direction: "ingress"
          remote_ip_prefix: 0.0.0.0/0
          port_range_min: 1
          port_range_max: 21
        - protocol: "tcp"
          direction: "ingress"
          remote_ip_prefix: 10.8.0.0/32
          port_range_min: 22
          port_range_max: 22
        - protocol: "tcp"
          direction: "ingress"
          remote_ip_prefix: 0.0.0.0/0
          port_range_min: 23
          port_range_max: 65535

  bastion_security_group_ipv6:
    type: OS::Neutron::SecurityGroup
    properties:
      description: Security group for bastion
      name: {list_join: ['-', [{get_param: OS::stack_name}, 'bastion-ipv6']]}
      rules:
        -  {"direction": ingress, "ethertype": IPv6, "protocol": icmpv6, "remote_ip_prefix": "::/0"}
        -  {"direction": ingress, "ethertype": IPv6, "port_range_min": 1, "port_range_max": 21, "protocol": tcp, "remote_ip_prefix": "::/0"}
        -  {"direction": ingress, "ethertype": IPv6, "port_range_min": 22, "port_range_max": 22, "protocol": tcp, "remote_ip_prefix": "2001:1600:10:100::7a/32"}
        -  {"direction": ingress, "ethertype": IPv6, "port_range_min": 23, "port_range_max": 65535, "protocol": tcp, "remote_ip_prefix": "::/0"}

  # ---------------------------------- REMOTE SECURITY GROUP EXAMPLE  ---------------------------------------
  securityGroupA:
    type: OS::Neutron::SecurityGroup
    properties:
      description: Security group allowing icmp from anywhere
      name: "securityGroupA"
      rules:
        -  {"direction": ingress, "ethertype": IPv4, "protocol": icmp, "remote_ip_prefix": "0.0.0.0/0"}
  securityGroupB:
    type: OS::Neutron::SecurityGroup
    properties:
      description: Security group where will be added a rule allowing tcp port 22 from VMs using securityGroupA only (securityGroupRuleB)
      name: "securityGroupB"

  securityGroupRuleB:
    type: OS::Neutron::SecurityGroupRule
    depends_on: securityGroupB
    properties:
      description: Security group allowing tcp port 22 from VMs using securityGroupA only
      direction: ingress
      ethertype: IPv4
      port_range_min: 22
      port_range_max: 22
      protocol: tcp
      remote_group: {get_resource: securityGroupA}
      security_group: {get_resource: securityGroupB}
Apply and check rules have been created

openstack stack create -t bastion_security_group.yaml bastion_security_group
$ openstack security group rule list bastion_security_group-bastion-ipv4 --long
+--------------------------------------+-------------+-----------+-------------+------------+-----------+-----------------------+
| ID                                   | IP Protocol | Ethertype | IP Range    | Port Range | Direction | Remote Security Group |
+--------------------------------------+-------------+-----------+-------------+------------+-----------+-----------------------+
| 07b4e3ac-cd2e-4ad9-8ae4-633749e56397 | tcp         | IPv4      | 0.0.0.0/0   | 23:65535   | ingress   | None                  |
| 8bfdcb54-53d7-47aa-a9ae-e53998465b42 | None        | IPv4      | 0.0.0.0/0   |            | egress    | None                  |
| 8c88e43d-356b-4ac2-839f-2d1841ee9733 | icmp        | IPv4      | 0.0.0.0/0   |            | ingress   | None                  |
| ad73629e-9570-4182-aee0-a6e0a49242da | tcp         | IPv4      | 0.0.0.0/0   | 1:21       | ingress   | None                  |
| b05e111b-fc58-46ab-b374-ce1f1e81dd38 | tcp         | IPv4      | 10.8.0.0/24 | 22:22      | ingress   | None                  |
| c645c0da-f0fd-4aa4-ae5a-857ac51e2232 | None        | IPv6      | ::/0        |            | egress    | None                  |
+--------------------------------------+-------------+-----------+-------------+------------+-----------+-----------------------+
$ openstack security group rule list bastion_security_group-bastion-ipv6 --long
+--------------------------------------+-------------+-----------+-------------------------+------------+-----------+-----------------------+
| ID                                   | IP Protocol | Ethertype | IP Range                | Port Range | Direction | Remote Security Group |
+--------------------------------------+-------------+-----------+-------------------------+------------+-----------+-----------------------+
| 04cdee6f-7469-426d-8df6-98736105a8c0 | tcp         | IPv6      | ::/0                    | 23:65535   | ingress   | None                  |
| 2ac7f77e-7598-4864-84c3-a51c019ad9de | None        | IPv6      | ::/0                    |            | egress    | None                  |
| 3c00cdb8-8e4b-4184-ac8b-182df7b35c44 | ipv6-icmp   | IPv6      | ::/0                    |            | ingress   | None                  |
| 92255a66-53d4-428f-87ce-61df98580e99 | tcp         | IPv6      | ::/0                    | 1:21       | ingress   | None                  |
| d5799100-b7e5-442e-a74b-7a72f99b22b4 | tcp         | IPv6      | 2001:1600:10:100::7a/32 | 22:22      | ingress   | None                  |
| dddf71fd-d570-451b-b4d7-850de9bc54e2 | None        | IPv4      | 0.0.0.0/0               |            | egress    | None                  |
+--------------------------------------+-------------+-----------+-------------------------+------------+-----------+-----------------------+

$ openstack security group rule list securityGroupA
+--------------------------------------+-------------+-----------+-----------+------------+-----------------------+
| ID                                   | IP Protocol | Ethertype | IP Range  | Port Range | Remote Security Group |
+--------------------------------------+-------------+-----------+-----------+------------+-----------------------+
| 1e79830f-c1ca-4046-b2e3-b300f05ea7af | None        | IPv4      | 0.0.0.0/0 |            | None                  |
| d1c400d8-33ae-4d8e-bbcb-3e739e034e14 | icmp        | IPv4      | 0.0.0.0/0 |            | None                  |
| e82709ed-2307-4db8-9438-98b629623e0e | None        | IPv6      | ::/0      |            | None                  |
+--------------------------------------+-------------+-----------+-----------+------------+-----------------------+
$ openstack security group rule list securityGroupB
+--------------------------------------+-------------+-----------+-----------+------------+--------------------------------------+
| ID                                   | IP Protocol | Ethertype | IP Range  | Port Range | Remote Security Group                |
+--------------------------------------+-------------+-----------+-----------+------------+--------------------------------------+
| 3981cc09-532b-49de-9c65-40f4107ffb55 | None        | IPv6      | ::/0      |            | None                                 |
| 9c8f04a8-2779-4cde-9413-b4203c62955c | tcp         | IPv4      | 0.0.0.0/0 | 22:22      | 4cfe556b-39d7-4cd5-8d59-42ccd654c6a7 |
| b4782f10-1738-4797-bc89-a3c43c488d2c | None        | IPv4      | 0.0.0.0/0 |            | None                                 |
+--------------------------------------+-------------+-----------+-----------+------------+--------------------------------------+

To apply these security groups to a server add these lines to your instance resource definition, for example :

security_groups:
  - {get_resource: bastion_security_group_ipv4 }
  - {get_resource: bastion_security_group_ipv6 }