Dom C
Dom C

Reputation: 56

What is the OpenStack HEAT syntax for multiple fixed_ips as a parameter

I am trying to create a HEAT template that will use 'allowed_address_pairs' and neutron ports to support the concept of a virtual IP address shared between instances for an application similar to VRRP.

I've followed the examples from http://superuser.openstack.org/articles/implementing-high-availability-instances-with-neutron-using-vrrp and from https://github.com/nvpnathan/heat/blob/master/allowed-address-pairs.yaml to come up with my own template to achieve this, and it works great for a single virtual IP address.

Here is what that template looks like:

heat_template_version: 2013-05-23

description: Simple template using allowed_address_pairs for a virtual IP

parameters:
  image:
    type: string
    label: Image name or ID
    description: Image to be used for compute instance
    default: "cirros"
  flavor:
    type: string
    label: Flavor
    description: Type of instance (flavor) to be used
    default: "t1.small"
  key:
    type: string
    label: Key name
    description: Name of key-pair to be used for compute instance
    default: "mykey"
  ext_network:
    type: string
    label: External network name or ID
    description: External network that can assign a floating IP
    default: "provider"
  test_virtual_ip:
    type: string
    label: Virtual IP address 
    description: Virtual IP address that can be used on different instances
    default: "192.168.10.101"


resources:
  # Create the internal test network
  test_net:
    type: OS::Neutron::Net
    properties:
      admin_state_up: true
      name: test_net

  # Create a subnet on the test network
  test_subnet:
    type: OS::Neutron::Subnet
    properties:
      name: test_subnet
      cidr: 192.168.10.2/24
      enable_dhcp: true
      allocation_pools: [{end: 192.168.10.99, start: 192.168.10.10}]
      gateway_ip: 192.168.10.1
      network_id: { get_resource: test_net }

  # Create router for the test network
  test_router:
    type: OS::Neutron::Router
    properties:
      admin_state_up: true
      name: test_router
      external_gateway_info: { "network": { get_param: ext_network }}

  # Create router interface and attach to subnet
  test_router_itf:
    type: OS::Neutron::RouterInterface
    properties:
      router_id: { get_resource: test_router }
      subnet_id: { get_resource: test_subnet }


  # Create extra port for a virtual IP address
  test_vip_port:
    type: OS::Neutron::Port
    properties:
      network_id: { get_resource: test_net }
      fixed_ips:
        - ip_address: { get_param: test_virtual_ip }


  # Create instance ports that have an internal IP and the virtual IP
  instance1_test_vip_port:
    type: OS::Neutron::Port
    properties:
      admin_state_up: true
      network_id: { get_resource: test_net }
      allowed_address_pairs:
        - ip_address: { get_param: test_virtual_ip}
      security_groups:
        - default

  # Create instances
  test_instance_1:
    type: OS::Nova::Server
    properties:
      name: instance1
      image: { get_param: image }
      flavor: { get_param: flavor }
      key_name: { get_param: key }
      networks:
        - port: { get_resource: instance1_test_vip_port }
      user_data_format: RAW
      user_data: |
        #cloud-config
        password: mysecret
        chpasswd: { expire: False }
        ssh_pwauth: True
        final_message: "The system is up after $UPTIME sec"

outputs:
  instance1_ip:
    description: IP address of the first instance
    value: { get_attr: [test_instance_1, first_address] }

So far so good. Now I need to take this to the next level and assign multiple IP addresses that can be used as virtual IPs within an instance. The problem is that it is not known in advance how many will be needed when the instance is launched, so it needs to be a parameter and cannot simply be hard-coded as

- ip_address: {get_param: ip1}
- ip_address: {get_param: ip2}
and so on

In other words, the parameter test_virtual_ip needs to be a list of IP addresses rather than a single IP address, e.g. "191.168.10.101, 192.168.10.102, 192.168.10.103"

This impacts the definitions for test_vip_port and instance1_test_vip_port, but I can't figure out the correct syntax.

I tried this:

# Create extra port for a virtual IP address
  test_vip_port:
    type: OS::Neutron::Port
    properties:
      network_id: { get_resource: test_net }
      fixed_ips: [{ get_param: test_virtual_ip }]

  # Create instance ports that have an internal IP and the virtual IP
  instance1_test_vip_port:
    type: OS::Neutron::Port
    properties:
      admin_state_up: true
      network_id: { get_resource: test_net }
      allowed_address_pairs: [{ get_param: test_virtual_ip}]
      security_groups:
        - default

But get error "unicode object has no attribute get" when I try to launch the stack.

What is the proper syntax for providing a list of IP addresses as a parameter to the OS::Neutron::Port::fixed_ips and OS::Neutron::Port::allowed_address_pairs ?

Upvotes: 0

Views: 3400

Answers (2)

hakkican
hakkican

Reputation: 436

      firewall_rules:
    - { get_resource: heat_firewall_tcp_22 }
    - { get_resource: heat_firewall_tcp_43 }
    - { get_resource: heat_firewall_tcp_53 }
    - { get_resource: heat_firewall_tcp_80 }
    - { get_resource: heat_firewall_tcp_443 } 

This works fine for multiple entries type: OS::Neutron::FirewallPolicy

    - { get_resource: heat_firewall_pol_web_1 }
    - { get_resource: heat_firewall_pol_dns_1 }
    - { get_resource: fw_pol_ssh_1 }

This does not work throwing expecting some sort of string value error for type: OS::Neutron::Firewall I am guessing there is not any general standard for formatting multiple entries in yaml?

Upvotes: 0

Dom C
Dom C

Reputation: 56

The only solution I was able to get to work was to use the repeat/for_each construct and define the parameter as a comma_delimited_list as follows:

  test_virtual_ip:
    type: comma_delimited_list
    label: Virtual IP address
    description: Virtual IP address that can be used on different instances
    default: "192.168.10.101,192.168.10.102"

  test_vip_port:
    type: OS::Neutron::Port
    properties:
      network_id: { get_resource: test_net }
      fixed_ips:
        repeat:
          for_each:
            <%ipaddr%>: {get_param: test_virtual_ip}
          template:
            ip_address: <%ipaddr%>

A couple of details for this to work:

  • Your heat template version must support the repeat/for_each construct, I used heat_template_version: 2016-04-08
  • Don't include any spaces in the list of IP addresses or you will get validation errors.

Upvotes: 1

Related Questions