Sunday, June 14, 2015

Orchestration with Heat

This time, I tried to get my hands dirty by writing a heat script - my first yaml file.
Oops!!!
I think I need to start off with a small intro.
OK, so what is openstack heat ?
Heat is one of the several services in Openstack. It is used for orchestration. This simply means that creating networks, instances, routers, security groups etc using a script(or rather a template in YAML format - called HOT - Heat Orchestration Template) instead of browsing the horizon or using nova/neutron etc commands to setup a tenant. It also means that if the same needs to be replicated, you just need to provide some parameters and its done. And if you want to delete the same, just do it by hitting the enter key with heat stack's delete command.
Ok, I used another jargon here... Heat stack. Heat stack can be simply defined as the collection of resources that are orchestrated with heat. So if you have spawned 5 networks, 100 VMs, 10 routers, a few security group rules through a heat yaml, then all of these form a heat stack.


In this post, I would describe a HOW-TO for writing a heat template. I have created a simple YAML file to spawn 2 VMs, a security group and a network to which these VMs are attached. Once a VM is spawned, it executes a script defined in the user_data section. This script prints "Scripts loaded on startup" in syslog. The purpose of this script is to illustrate that users can create VMs and spawn a configuration script or a start-up script once the VM boots up.

Sections:
A heat template has the below sections:
1. Heat template version
2. Parameters
3. Resources
4. Outputs - (Not describing in this post.)

Heat template version is simply a header that describes the template version that you

The parameters section is used to define the parameters. These parameters are like input variables with some default values.
For example, if you want to create two stacks for two different tenants using the below yaml file, then you can use the parameters to specify the values like vm name, subnet address etc for the tenant.

The resources section describes the resources of your stack - In this section, you define the VMs, networks, security groups, ports etc.

heat_template_version: 2013-05-23
description: Create a network and attach a VM. Run a script in the VM

parameters:
  p_my_vm_flavor:
    type: string
    label: Flavor
    description:
    default:ubuntu

  p_my_private_network:
    type: string
    description:
    default: tenantA_net

  p_my_private_subnet:
    type: string
    description:
    default: tenantA_subnet

  p_my_network_cidr:
    type: string
    description:
    default: 11.0.0.0/24

  p_my_network_gateway:
    type: string
    description:
    default: 11.0.0.1

resources:
  r_my_network:
    type: OS::Neutron::Net
    properties:
      name: { get_param: p_my_private_network }
  r_my_network_subnet:
    type: OS::Neutron::Subnet
    properties:
      name: {get_param: p_my_private_subnet }
      network_id: {get_resource: r_my_network}
      gateway_ip: {get_param: p_my_network_gateway}
      cidr: { get_param: p_my_network_cidr }
  r_my_port:
    type: OS::Neutron::Port
    properties:
      network_id: {get_resource: r_my_network}
  r_security_group:
    type: OS::Neutron::SecurityGroup
    properties:
      description:
      name:
      rules: [ { "direction": ingress, "protocol": ICMP }, { "direction": ingress, "protocol": TCP,"port_range_min": 1, "port_range_max": 65535 }, { "direction": ingress, "protocol": UDP,  "port_range_min": 1, "port_range_max": 65535 } ]

  r_my_vm:
    type: OS::Nova::Server
    properties:
      image: firewall
      flavor: m1.medium
      networks:
        - port: {get_resource: r_my_port}
      user_data: |
        #!/bin/sh -ex
        logger "Script loaded on startup"
  r_my_vm_port:
    type: OS::Neutron::Port
    properties:
      network_id: {get_resource: r_my_network}
      security_groups: [{get_resource: r_security_group}]


Parameters section: I have used 5 configurable parameters and specified  a default value (default: tag) for each of this. So if a user doesn't provides a parameter, its default value would be used.
  p_my_vm_flavor - To indicate the flavor of VM.
  p_my_private_network - Specify name of tenant's network.
  p_my_private_subnet - Specify the private subnet of the tenant.
  p_my_network_cidr - CIDR of tenant's network.
  p_my_network_gateway - Gateway of the tenant's network.

Resources Section: I have used 6 type of resources
r_my_network: It is defined as OS::Neutron::Net. This is an OpenStack resource type (see this).
Similarly  I have defined r_my_network_subnet, r_my_port, r_security_group, r_my_vm and r_my_vm_port. All these are self explanatory and define the subnet, port, security group, VM and VM's port.

The user_data in r_my_vm properties defines a script that would be loaded on start when the VM is instantiated.

You can run this YAML file(test.aml) with "heat stack-create" command and provide the below file as parameters.

parameters:
  p_my_private_network: TenantCNetwork
  p_my_private_subnet: TenantCSubnet
  p_my_network_cidr: 80.0.0.1/24
  p_my_network_gateway: 80.0.0.1