From c90d5323afc575246df2f50e9125069f3c12e81e Mon Sep 17 00:00:00 2001
From: Eric Sauer <etsauer@gmail.com>
Date: Tue, 25 Apr 2017 23:17:38 -0400
Subject: Stack refactor (#38)

* Refactored openstack-stack role to:

- Convert static heat template files to ansible templates
- Include native ansible groups via openstack metadata. This removes the need for a playbook to map host groups
- Some code cleanup

* Deleting commentd out code and irrelevant plays

* Refactored openstack-stack role to:

- Convert static heat template files to ansible templates
- Include native ansible groups via openstack metadata. This removes the need for a playbook to map host groups
- Some code cleanup

* Deleting commentd out code and irrelevant plays

* Replacing stack parameters with jinja expressions

* Updating sample inventory to work with latest dynamic inventory changes

* updating inventory with host group mapping. making sync keys optional

* Missing cluster_hosts group

* Updating to add infra_hosts

* Updating inventory per comments from oybed and sabre1041
---
 roles/openstack-stack/defaults/main.yml            |  10 +
 roles/openstack-stack/files/heat_stack.yaml        | 684 ---------------------
 roles/openstack-stack/files/heat_stack_server.yaml | 156 -----
 roles/openstack-stack/files/user-data              |  13 -
 roles/openstack-stack/tasks/main.yml               |  59 +-
 roles/openstack-stack/templates/heat_stack.yaml.j2 | 551 +++++++++++++++++
 .../templates/heat_stack_server.yaml.j2            | 170 +++++
 roles/openstack-stack/templates/user_data.j2       |  13 +
 8 files changed, 777 insertions(+), 879 deletions(-)
 create mode 100644 roles/openstack-stack/defaults/main.yml
 delete mode 100644 roles/openstack-stack/files/heat_stack.yaml
 delete mode 100644 roles/openstack-stack/files/heat_stack_server.yaml
 delete mode 100644 roles/openstack-stack/files/user-data
 create mode 100644 roles/openstack-stack/templates/heat_stack.yaml.j2
 create mode 100644 roles/openstack-stack/templates/heat_stack_server.yaml.j2
 create mode 100644 roles/openstack-stack/templates/user_data.j2

diff --git a/roles/openstack-stack/defaults/main.yml b/roles/openstack-stack/defaults/main.yml
new file mode 100644
index 000000000..8aefe039d
--- /dev/null
+++ b/roles/openstack-stack/defaults/main.yml
@@ -0,0 +1,10 @@
+---
+dns_volume_size: 1
+ssh_ingress_cidr: 0.0.0.0/0
+node_ingress_cidr: 0.0.0.0/0
+num_etcd: 0
+num_masters: 1
+num_nodes: 1
+num_dns: 1
+num_infra: 1
+etcd_volume_size: 2
diff --git a/roles/openstack-stack/files/heat_stack.yaml b/roles/openstack-stack/files/heat_stack.yaml
deleted file mode 100644
index 058f7a7ad..000000000
--- a/roles/openstack-stack/files/heat_stack.yaml
+++ /dev/null
@@ -1,684 +0,0 @@
-heat_template_version: 2014-10-16
-
-description: OpenShift cluster
-
-parameters:
-
-  cluster_env:
-    type: string
-    label: Cluster environment
-    description: Environment of the cluster
-
-  cluster_id:
-    type: string
-    label: Cluster ID
-    description: Identifier of the cluster
-
-  subnet_24_prefix:
-    type: string
-    label: subnet /24 prefix
-    description: /24 subnet prefix of the network of the cluster (dot separated number triplet)
-
-  dns_nameservers:
-    type: comma_delimited_list
-    label: DNS nameservers list
-    description: List of DNS nameservers
-
-  external_net:
-    type: string
-    label: External network
-    description: Name of the external network
-    default: external
-
-  ssh_public_key:
-    type: string
-    label: SSH public key
-    description: SSH public key
-    hidden: true
-
-  ssh_incoming:
-    type: string
-    label: Source of ssh connections
-    description: Source of legitimate ssh connections
-    default: 0.0.0.0/0
-
-  node_port_incoming:
-    type: string
-    label: Source of node port connections
-    description: Authorized sources targetting node ports
-    default: 0.0.0.0/0
-
-  num_etcd:
-    type: number
-    label: Number of etcd nodes
-    description: Number of etcd nodes
-
-  num_masters:
-    type: number
-    label: Number of masters
-    description: Number of masters
-
-  num_nodes:
-    type: number
-    label: Number of compute nodes
-    description: Number of compute nodes
-
-  num_infra:
-    type: number
-    label: Number of infrastructure nodes
-    description: Number of infrastructure nodes
-
-  num_dns:
-    type: number
-    label: Number of dns servers
-    description: Number of dns servers
-
-  etcd_image:
-    type: string
-    label: Etcd image
-    description: Name of the image for the etcd servers
-
-  master_image:
-    type: string
-    label: Master image
-    description: Name of the image for the master servers
-
-  node_image:
-    type: string
-    label: Node image
-    description: Name of the image for the compute node servers
-
-  infra_image:
-    type: string
-    label: Infra image
-    description: Name of the image for the infra node servers
-
-  dns_image:
-    type: string
-    label: DNS image
-    description: Name of the image for the DNS server
-
-  etcd_flavor:
-    type: string
-    label: Etcd flavor
-    description: Flavor of the etcd servers
-
-  master_flavor:
-    type: string
-    label: Master flavor
-    description: Flavor of the master servers
-
-  node_flavor:
-    type: string
-    label: Node flavor
-    description: Flavor of the compute node servers
-
-  infra_flavor:
-    type: string
-    label: Infra flavor
-    description: Flavor of the infra node servers
-
-  dns_flavor:
-    type: string
-    label: DNS flavor
-    description: Flavor of the DNS server
-
-  master_volume_size:
-    type: number
-    description: Size of the volume to be created.
-    default: 5
-    constraints:
-      - range: { min: 1, max: 1024 }
-        description: must be between 1 and 1024 Gb.
-
-  app_volume_size:
-    type: number
-    description: Size of the volume to be created.
-    default: 5
-    constraints:
-      - range: { min: 1, max: 1024 }
-        description: must be between 1 and 1024 Gb.
-
-  infra_volume_size:
-    type: number
-    description: Size of the volume to be created.
-    default: 5
-    constraints:
-      - range: { min: 1, max: 1024 }
-        description: must be between 1 and 1024 Gb.
-
-  dns_volume_size:
-    type: number
-    description: Size of the volume to be created.
-    default: 5
-    constraints:
-      - range: { min: 1, max: 1024 }
-        description: must be between 1 and 1024 Gb.
-
-  etcd_volume_size:
-    type: number
-    description: Size of the volume to be created.
-    default: 5
-    constraints:
-      - range: { min: 1, max: 1024 }
-        description: must be between 1 and 1024 Gb.
-
-outputs:
-
-  etcd_names:
-    description: Name of the etcds
-    value: { get_attr: [ etcd, name ] }
-
-  etcd_ips:
-    description: IPs of the etcds
-    value: { get_attr: [ etcd, private_ip ] }
-
-  etcd_floating_ips:
-    description: Floating IPs of the etcds
-    value: { get_attr: [ etcd, floating_ip ] }
-
-  master_names:
-    description: Name of the masters
-    value: { get_attr: [ masters, name ] }
-
-  master_ips:
-    description: IPs of the masters
-    value: { get_attr: [ masters, private_ip ] }
-
-  master_floating_ips:
-    description: Floating IPs of the masters
-    value: { get_attr: [ masters, floating_ip ] }
-
-  node_names:
-    description: Name of the nodes
-    value: { get_attr: [ compute_nodes, name ] }
-
-  node_ips:
-    description: IPs of the nodes
-    value: { get_attr: [ compute_nodes, private_ip ] }
-
-  node_floating_ips:
-    description: Floating IPs of the nodes
-    value: { get_attr: [ compute_nodes, floating_ip ] }
-
-  infra_names:
-    description: Name of the nodes
-    value: { get_attr: [ infra_nodes, name ] }
-
-  infra_ips:
-    description: IPs of the nodes
-    value: { get_attr: [ infra_nodes, private_ip ] }
-
-  infra_floating_ips:
-    description: Floating IPs of the nodes
-    value: { get_attr: [ infra_nodes, floating_ip ] }
-
-  dns_name:
-    description: Name of the DNS
-    value:
-      get_attr:
-        - dns
-        - name
-
-  dns_floating_ip:
-    description: Floating IP of the DNS
-    value:
-      get_attr:
-        - dns
-        - addresses
-        - str_replace:
-            template: openshift-ansible-cluster_id-net
-            params:
-              cluster_id: { get_param: cluster_id }
-        - 1
-        - addr
-
-resources:
-
-  net:
-    type: OS::Neutron::Net
-    properties:
-      name:
-        str_replace:
-          template: openshift-ansible-cluster_id-net
-          params:
-            cluster_id: { get_param: cluster_id }
-
-  subnet:
-    type: OS::Neutron::Subnet
-    properties:
-      name:
-        str_replace:
-          template: openshift-ansible-cluster_id-subnet
-          params:
-            cluster_id: { get_param: cluster_id }
-      network: { get_resource: net }
-      cidr:
-        str_replace:
-          template: subnet_24_prefix.0/24
-          params:
-            subnet_24_prefix: { get_param: subnet_24_prefix }
-      allocation_pools:
-        - start:
-            str_replace:
-              template: subnet_24_prefix.3
-              params:
-                subnet_24_prefix: { get_param: subnet_24_prefix }
-          end:
-            str_replace:
-              template: subnet_24_prefix.254
-              params:
-                subnet_24_prefix: { get_param: subnet_24_prefix }
-      dns_nameservers:
-        - 10.9.48.31
-#        - { get_param: dns_nameservers }
-#        repeat:
-#          for_each: 
-#            <%nameserver%>: { get_param: dns_nameservers }
-#          template: <%nameserver%>
-
-  router:
-    type: OS::Neutron::Router
-    properties:
-      name:
-        str_replace:
-          template: openshift-ansible-cluster_id-router
-          params:
-            cluster_id: { get_param: cluster_id }
-      external_gateway_info:
-        network: { get_param: external_net }
-
-  interface:
-    type: OS::Neutron::RouterInterface
-    properties:
-      router_id: { get_resource: router }
-      subnet_id: { get_resource: subnet }
-
-#  keypair:
-#    type: OS::Nova::KeyPair
-#    properties:
-#      name:
-#        str_replace:
-#          template: openshift-ansible-cluster_id-keypair
-#          params:
-#            cluster_id: { get_param: cluster_id }
-#      public_key: { get_param: ssh_public_key }
-
-  master-secgrp:
-    type: OS::Neutron::SecurityGroup
-    properties:
-      name:
-        str_replace:
-          template: openshift-ansible-cluster_id-master-secgrp
-          params:
-            cluster_id: { get_param: cluster_id }
-      description:
-        str_replace:
-          template: Security group for cluster_id OpenShift cluster master
-          params:
-            cluster_id: { get_param: cluster_id }
-      rules:
-        - direction: ingress
-          protocol: tcp
-          port_range_min: 22
-          port_range_max: 22
-          remote_ip_prefix: { get_param: ssh_incoming }
-        - direction: ingress
-          protocol: tcp
-          port_range_min: 4001
-          port_range_max: 4001
-        - direction: ingress
-          protocol: tcp
-          port_range_min: 8443
-          port_range_max: 8443
-        - direction: ingress
-          protocol: tcp
-          port_range_min: 8444
-          port_range_max: 8444
-        - direction: ingress
-          protocol: tcp
-          port_range_min: 53
-          port_range_max: 53
-        - direction: ingress
-          protocol: udp
-          port_range_min: 53
-          port_range_max: 53
-        - direction: ingress
-          protocol: tcp
-          port_range_min: 8053
-          port_range_max: 8053
-        - direction: ingress
-          protocol: udp
-          port_range_min: 8053
-          port_range_max: 8053
-        - direction: ingress
-          protocol: tcp
-          port_range_min: 24224
-          port_range_max: 24224
-        - direction: ingress
-          protocol: udp
-          port_range_min: 24224
-          port_range_max: 24224
-        - direction: ingress
-          protocol: tcp
-          port_range_min: 2224
-          port_range_max: 2224
-        - direction: ingress
-          protocol: udp
-          port_range_min: 5404
-          port_range_max: 5404
-        - direction: ingress
-          protocol: udp
-          port_range_min: 5405
-          port_range_max: 5405
-        - direction: ingress
-          protocol: tcp
-          port_range_min: 9090
-          port_range_max: 9090
-
-  etcd-secgrp:
-    type: OS::Neutron::SecurityGroup
-    properties:
-      name:
-        str_replace:
-          template: openshift-ansible-cluster_id-etcd-secgrp
-          params:
-            cluster_id: { get_param: cluster_id }
-      description:
-        str_replace:
-          template: Security group for cluster_id etcd cluster
-          params:
-            cluster_id: { get_param: cluster_id }
-      rules:
-        - direction: ingress
-          protocol: tcp
-          port_range_min: 22
-          port_range_max: 22
-          remote_ip_prefix: { get_param: ssh_incoming }
-        - direction: ingress
-          protocol: tcp
-          port_range_min: 2379
-          port_range_max: 2379
-          remote_mode: remote_group_id
-          remote_group_id: { get_resource: master-secgrp }
-        - direction: ingress
-          protocol: tcp
-          port_range_min: 2380
-          port_range_max: 2380
-          remote_mode: remote_group_id
-
-  node-secgrp:
-    type: OS::Neutron::SecurityGroup
-    properties:
-      name:
-        str_replace:
-          template: openshift-ansible-cluster_id-node-secgrp
-          params:
-            cluster_id: { get_param: cluster_id }
-      description:
-        str_replace:
-          template: Security group for cluster_id OpenShift cluster nodes
-          params:
-            cluster_id: { get_param: cluster_id }
-      rules:
-        - direction: ingress
-          protocol: tcp
-          port_range_min: 22
-          port_range_max: 22
-          remote_ip_prefix: { get_param: ssh_incoming }
-        - direction: ingress
-          protocol: tcp
-          port_range_min: 10250
-          port_range_max: 10250
-          remote_mode: remote_group_id
-        - direction: ingress
-          protocol: tcp
-          port_range_min: 10255
-          port_range_max: 10255
-          remote_mode: remote_group_id
-        - direction: ingress
-          protocol: udp
-          port_range_min: 10255
-          port_range_max: 10255
-          remote_mode: remote_group_id
-        - direction: ingress
-          protocol: udp
-          port_range_min: 4789
-          port_range_max: 4789
-          remote_mode: remote_group_id
-        - direction: ingress
-          protocol: tcp
-          port_range_min: 30000
-          port_range_max: 32767
-          remote_ip_prefix: { get_param: node_port_incoming }
-
-  infra-secgrp:
-    type: OS::Neutron::SecurityGroup
-    properties:
-      name:
-        str_replace:
-          template: openshift-ansible-cluster_id-infra-secgrp
-          params:
-            cluster_id: { get_param: cluster_id }
-      description:
-        str_replace:
-          template: Security group for cluster_id OpenShift infrastructure cluster nodes
-          params:
-            cluster_id: { get_param: cluster_id }
-      rules:
-        - direction: ingress
-          protocol: tcp
-          port_range_min: 80
-          port_range_max: 80
-        - direction: ingress
-          protocol: tcp
-          port_range_min: 443
-          port_range_max: 443
-
-  dns-secgrp:
-    type: OS::Neutron::SecurityGroup
-    properties:
-      name:
-        str_replace:
-          template: openshift-ansible-cluster_id-dns-secgrp
-          params:
-            cluster_id: { get_param: cluster_id }
-      description:
-        str_replace:
-          template: Security group for cluster_id cluster DNS
-          params:
-            cluster_id: { get_param: cluster_id }
-      rules:
-        - direction: ingress
-          protocol: tcp
-          port_range_min: 22
-          port_range_max: 22
-          remote_ip_prefix: { get_param: ssh_incoming }
-        - direction: ingress
-          protocol: udp
-          port_range_min: 53
-          port_range_max: 53
-          remote_ip_prefix: { get_param: node_port_incoming }
-        - direction: ingress
-          protocol: tcp
-          port_range_min: 53
-          port_range_max: 53
-          remote_ip_prefix: { get_param: node_port_incoming }
-
-  etcd:
-    type: OS::Heat::ResourceGroup
-    properties:
-      count: { get_param: num_etcd }
-      resource_def:
-        type: heat_stack_server.yaml
-        properties:
-          name:
-            str_replace:
-              template: k8s_type-%index%.cluster_id.cluster_env
-              params:
-                cluster_id: { get_param: cluster_id }
-                k8s_type: etcd
-                cluster_env: { get_param: cluster_env }
-          cluster_env: { get_param: cluster_env }
-          cluster_id:  { get_param: cluster_id }
-          type:        etcd
-          image:       { get_param: etcd_image }
-          flavor:      { get_param: etcd_flavor }
-          key_name:    { get_param: ssh_public_key }
-          net:         { get_resource: net }
-          subnet:      { get_resource: subnet }
-          secgrp:
-            - { get_resource: etcd-secgrp }
-          floating_network: { get_param: external_net }
-          net_name:
-            str_replace:
-              template: openshift-ansible-cluster_id-net
-              params:
-                cluster_id: { get_param: cluster_id }
-          volume_size: { get_param: etcd_volume_size }
-    depends_on:
-      - interface
-
-  masters:
-    type: OS::Heat::ResourceGroup
-    properties:
-      count: { get_param: num_masters }
-      resource_def:
-        type: heat_stack_server.yaml
-        properties:
-          name:
-            str_replace:
-              template: k8s_type-%index%.cluster_id.cluster_env
-              params:
-                cluster_id: { get_param: cluster_id }
-                k8s_type: master
-                cluster_env: { get_param: cluster_env }
-          cluster_env: { get_param: cluster_env }
-          cluster_id:  { get_param: cluster_id }
-          type:        master
-          image:       { get_param: master_image }
-          flavor:      { get_param: master_flavor }
-          key_name:    { get_param: ssh_public_key }
-          net:         { get_resource: net }
-          subnet:      { get_resource: subnet }
-          secgrp:
-            - { get_resource: master-secgrp }
-            - { get_resource: node-secgrp }
-          floating_network: { get_param: external_net }
-          net_name:
-            str_replace:
-              template: openshift-ansible-cluster_id-net
-              params:
-                cluster_id: { get_param: cluster_id }
-          volume_size: { get_param: master_volume_size }
-    depends_on:
-      - interface
-
-  compute_nodes:
-    type: OS::Heat::ResourceGroup
-    properties:
-      count: { get_param: num_nodes }
-      resource_def:
-        type: heat_stack_server.yaml
-        properties:
-          name:
-            str_replace:
-              template: subtype-k8s_type-%index%.cluster_id.cluster_env
-              params:
-                cluster_id: { get_param: cluster_id }
-                k8s_type: node
-                subtype: app
-                cluster_env: { get_param: cluster_env }
-          cluster_env: { get_param: cluster_env }
-          cluster_id:  { get_param: cluster_id }
-          type:        node
-          subtype:     app
-          image:       { get_param: node_image }
-          flavor:      { get_param: node_flavor }
-          key_name:    { get_param: ssh_public_key }
-          net:         { get_resource: net }
-          subnet:      { get_resource: subnet }
-          secgrp:
-            - { get_resource: node-secgrp }
-          floating_network: { get_param: external_net }
-          net_name:
-            str_replace:
-              template: openshift-ansible-cluster_id-net
-              params:
-                cluster_id: { get_param: cluster_id }
-          volume_size: { get_param: app_volume_size }
-    depends_on:
-      - interface
-
-  infra_nodes:
-    type: OS::Heat::ResourceGroup
-    properties:
-      count: { get_param: num_infra }
-      resource_def:
-        type: heat_stack_server.yaml
-        properties:
-          name:
-            str_replace:
-              template: subtypek8s_type-%index%.cluster_id.cluster_env
-              params:
-                cluster_id: { get_param: cluster_id }
-                k8s_type: node
-                subtype: infra
-                cluster_env: { get_param: cluster_env }
-          cluster_env: { get_param: cluster_env }
-          cluster_id:  { get_param: cluster_id }
-          type:        node
-          subtype:     infra
-          image:       { get_param: infra_image }
-          flavor:      { get_param: infra_flavor }
-          key_name:    { get_param: ssh_public_key }
-          net:         { get_resource: net }
-          subnet:      { get_resource: subnet }
-          secgrp:
-            - { get_resource: node-secgrp }
-            - { get_resource: infra-secgrp }
-          floating_network: { get_param: external_net }
-          net_name:
-            str_replace:
-              template: openshift-ansible-cluster_id-net
-              params:
-                cluster_id: { get_param: cluster_id }
-          volume_size: { get_param: infra_volume_size }
-    depends_on:
-      - interface
-
-  dns:
-    type: OS::Heat::ResourceGroup
-    properties:
-      count: { get_param: num_dns }
-      resource_def:
-        type: heat_stack_server.yaml
-        properties:
-          name:
-            str_replace:
-              template: k8s_type-%index%.cluster_id.cluster_env
-              params:
-                cluster_id: { get_param: cluster_id }
-                k8s_type: dns
-                cluster_env: { get_param: cluster_env }
-          cluster_env: { get_param: cluster_env }
-          cluster_id:  { get_param: cluster_id }
-          type:        dns
-          image:       { get_param: dns_image }
-          flavor:      { get_param: dns_flavor }
-          key_name:    { get_param: ssh_public_key }
-          net:         { get_resource: net }
-          subnet:      { get_resource: subnet }
-          secgrp:
-            - { get_resource: node-secgrp }
-            - { get_resource: dns-secgrp }
-          floating_network: { get_param: external_net }
-          net_name:
-            str_replace:
-              template: openshift-ansible-cluster_id-net
-              params:
-                cluster_id: { get_param: cluster_id }
-          volume_size: { get_param: dns_volume_size }
-    depends_on:
-      - interface
-
diff --git a/roles/openstack-stack/files/heat_stack_server.yaml b/roles/openstack-stack/files/heat_stack_server.yaml
deleted file mode 100644
index 978da4f0b..000000000
--- a/roles/openstack-stack/files/heat_stack_server.yaml
+++ /dev/null
@@ -1,156 +0,0 @@
-heat_template_version: 2014-10-16
-
-description: OpenShift cluster server
-
-parameters:
-
-  name:
-    type: string
-    label: Name
-    description: Name
-
-  cluster_env:
-    type: string
-    label: Cluster environment
-    description: Environment of the cluster
-
-  cluster_id:
-    type: string
-    label: Cluster ID
-    description: Identifier of the cluster
-
-  type:
-    type: string
-    label: Type
-    description: Type master or node
-
-  subtype:
-    type: string
-    label: Sub-type
-    description: Sub-type compute or infra for nodes, default otherwise
-    default: default
-
-  key_name:
-    type: string
-    label: Key name
-    description: Key name of keypair
-
-  image:
-    type: string
-    label: Image
-    description: Name of the image
-
-  flavor:
-    type: string
-    label: Flavor
-    description: Name of the flavor
-
-  net:
-    type: string
-    label: Net ID
-    description: Net resource
-
-  net_name:
-    type: string
-    label: Net name
-    description: Net name
-
-  subnet:
-    type: string
-    label: Subnet ID
-    description: Subnet resource
-
-  secgrp:
-    type: comma_delimited_list
-    label: Security groups
-    description: Security group resources
-
-  floating_network:
-    type: string
-    label: Floating network
-    description: Network to allocate floating IP from
-
-  availability_zone:
-    type: string
-    description: The Availability Zone to launch the instance.
-    default: nova
-
-  volume_size:
-    type: number
-    description: Size of the volume to be created.
-    default: 1
-    constraints:
-      - range: { min: 1, max: 1024 }
-        description: must be between 1 and 1024 Gb.
-
-outputs:
-
-  name:
-    description: Name of the server
-    value: { get_attr: [ server, name ] }
-
-  private_ip:
-    description: Private IP of the server
-    value:
-      get_attr:
-        - server
-        - addresses
-        - { get_param: net_name }
-        - 0
-        - addr
-
-  floating_ip:
-    description: Floating IP of the server
-    value:
-      get_attr:
-        - server
-        - addresses
-        - { get_param: net_name }
-        - 1
-        - addr
-
-resources:
-
-  server:
-    type: OS::Nova::Server
-    properties:
-      name:      { get_param: name }
-      key_name:  { get_param: key_name }
-      image:     { get_param: image }
-      flavor:    { get_param: flavor }
-      networks:
-        - port:  { get_resource: port }
-      user_data: { get_file: user-data }
-      user_data_format: RAW
-      metadata:
-        environment: { get_param: cluster_env }
-        clusterid: { get_param: cluster_id }
-        host-type: { get_param: type }
-        sub-host-type:    { get_param: subtype }
-
-  port:
-    type: OS::Neutron::Port
-    properties:
-      network: { get_param: net }
-      fixed_ips:
-        - subnet: { get_param: subnet }
-      security_groups: { get_param: secgrp }
-
-  floating-ip:
-    type: OS::Neutron::FloatingIP
-    properties:
-      floating_network: { get_param: floating_network }
-      port_id: { get_resource: port }
-
-  cinder_volume:
-    type: OS::Cinder::Volume
-    properties:
-      size: { get_param: volume_size }
-      availability_zone: { get_param: availability_zone }
-
-  volume_attachment:
-    type: OS::Cinder::VolumeAttachment
-    properties:
-      volume_id: { get_resource: cinder_volume }
-      instance_uuid: { get_resource: server }
-      mountpoint: /dev/sdb
diff --git a/roles/openstack-stack/files/user-data b/roles/openstack-stack/files/user-data
deleted file mode 100644
index eb65f7cec..000000000
--- a/roles/openstack-stack/files/user-data
+++ /dev/null
@@ -1,13 +0,0 @@
-#cloud-config
-disable_root: true
-
-system_info:
-  default_user:
-    name: openshift
-    sudo: ["ALL=(ALL) NOPASSWD: ALL"]
-
-write_files:
-  - path: /etc/sudoers.d/00-openshift-no-requiretty
-    permissions: 440
-    content: |
-      Defaults:openshift !requiretty
diff --git a/roles/openstack-stack/tasks/main.yml b/roles/openstack-stack/tasks/main.yml
index efee08c0e..71c7bbe0d 100644
--- a/roles/openstack-stack/tasks/main.yml
+++ b/roles/openstack-stack/tasks/main.yml
@@ -1,34 +1,41 @@
 ---
+- name: create HOT stack template prefix
+  register: stack_template_pre
+  tempfile:
+    state: directory
+    prefix: casl-ansible
+
+- name: set template paths
+  set_fact:
+    stack_template_path: "{{ stack_template_pre.path }}/stack.yaml"
+    server_template_path: "{{ stack_template_pre.path }}/server.yaml"
+    user_data_template_path: "{{ stack_template_pre.path }}/user-data"
+
+- name: generate HOT stack template from jinja2 template
+  template:
+    src: heat_stack.yaml.j2
+    dest: "{{ stack_template_path }}"
+
+- name: generate HOT server template from jinja2 template
+  template:
+    src: heat_stack_server.yaml.j2
+    dest: "{{ server_template_path }}"
+
+- name: generate user_data from jinja2 template
+  template:
+    src: user_data.j2
+    dest: "{{ user_data_template_path }}"
+
 - name: create stack
   ignore_errors: False
   register: stack_create
   os_stack:
     name: "{{ stack_name }}"
     state: present
-    template: 'roles/openstack-stack/files/heat_stack.yaml'
+    template: "{{ stack_template_path }}"
     wait: yes
-    parameters:
-      cluster_env: "{{ dns_domain }}"
-      cluster_id: "{{ stack_name }}"
-      subnet_24_prefix: "{{ subnet_prefix }}"
-      dns_nameservers: "{{ dns_nameservers }}"
-      external_net: "{{ external_network }}"
-      ssh_public_key: "{{ ssh_public_key }}"
-      num_etcd: "{{ num_etcd }}"
-      num_masters: "{{ num_masters }}"
-      num_nodes: "{{ num_nodes }}"
-      num_infra: "{{ num_infra }}"
-      num_dns: "{{ num_dns }}"
-      etcd_image: "{{ openstack_image }}"
-      master_image: "{{ openstack_image }}"
-      node_image: "{{ openstack_image }}"
-      infra_image: "{{ openstack_image }}"
-      dns_image: "{{ openstack_image }}"
-      etcd_flavor: "{{ etcd_flavor }}"
-      master_flavor: "{{ master_flavor }}"
-      node_flavor: "{{ node_flavor }}"
-      infra_flavor: "{{ infra_flavor }}"
-      dns_flavor: "{{ dns_flavor }}"
-      master_volume_size: "{{ master_volume_size }}"
-      app_volume_size: "{{ app_volume_size }}"
-      infra_volume_size: "{{ infra_volume_size }}"
+
+- name: cleanup temp files
+  file:
+    path: "{{ stack_template_pre.path }}"
+    state: absent
diff --git a/roles/openstack-stack/templates/heat_stack.yaml.j2 b/roles/openstack-stack/templates/heat_stack.yaml.j2
new file mode 100644
index 000000000..bc9547f66
--- /dev/null
+++ b/roles/openstack-stack/templates/heat_stack.yaml.j2
@@ -0,0 +1,551 @@
+heat_template_version: 2016-10-14
+
+description: OpenShift cluster
+
+parameters:
+
+outputs:
+
+  etcd_names:
+    description: Name of the etcds
+    value: { get_attr: [ etcd, name ] }
+
+  etcd_ips:
+    description: IPs of the etcds
+    value: { get_attr: [ etcd, private_ip ] }
+
+  etcd_floating_ips:
+    description: Floating IPs of the etcds
+    value: { get_attr: [ etcd, floating_ip ] }
+
+  master_names:
+    description: Name of the masters
+    value: { get_attr: [ masters, name ] }
+
+  master_ips:
+    description: IPs of the masters
+    value: { get_attr: [ masters, private_ip ] }
+
+  master_floating_ips:
+    description: Floating IPs of the masters
+    value: { get_attr: [ masters, floating_ip ] }
+
+  node_names:
+    description: Name of the nodes
+    value: { get_attr: [ compute_nodes, name ] }
+
+  node_ips:
+    description: IPs of the nodes
+    value: { get_attr: [ compute_nodes, private_ip ] }
+
+  node_floating_ips:
+    description: Floating IPs of the nodes
+    value: { get_attr: [ compute_nodes, floating_ip ] }
+
+  infra_names:
+    description: Name of the nodes
+    value: { get_attr: [ infra_nodes, name ] }
+
+  infra_ips:
+    description: IPs of the nodes
+    value: { get_attr: [ infra_nodes, private_ip ] }
+
+  infra_floating_ips:
+    description: Floating IPs of the nodes
+    value: { get_attr: [ infra_nodes, floating_ip ] }
+
+  dns_name:
+    description: Name of the DNS
+    value:
+      get_attr:
+        - dns
+        - name
+
+  dns_floating_ip:
+    description: Floating IP of the DNS
+    value:
+      get_attr:
+        - dns
+        - addresses
+        - str_replace:
+            template: openshift-ansible-cluster_id-net
+            params:
+              cluster_id: {{ stack_name }}
+        - 1
+        - addr
+
+resources:
+
+  net:
+    type: OS::Neutron::Net
+    properties:
+      name:
+        str_replace:
+          template: openshift-ansible-cluster_id-net
+          params:
+            cluster_id: {{ stack_name }}
+
+  subnet:
+    type: OS::Neutron::Subnet
+    properties:
+      name:
+        str_replace:
+          template: openshift-ansible-cluster_id-subnet
+          params:
+            cluster_id: {{ stack_name }}
+      network: { get_resource: net }
+      cidr:
+        str_replace:
+          template: subnet_24_prefix.0/24
+          params:
+            subnet_24_prefix: {{ subnet_prefix }}
+      allocation_pools:
+        - start:
+            str_replace:
+              template: subnet_24_prefix.3
+              params:
+                subnet_24_prefix: {{ subnet_prefix }}
+          end:
+            str_replace:
+              template: subnet_24_prefix.254
+              params:
+                subnet_24_prefix: {{ subnet_prefix }}
+      dns_nameservers:
+      {% for nameserver in dns_nameservers %}
+        - {{ nameserver }}
+      {% endfor %}
+
+  router:
+    type: OS::Neutron::Router
+    properties:
+      name:
+        str_replace:
+          template: openshift-ansible-cluster_id-router
+          params:
+            cluster_id: {{ stack_name }}
+      external_gateway_info:
+        network: {{ external_network }}
+
+  interface:
+    type: OS::Neutron::RouterInterface
+    properties:
+      router_id: { get_resource: router }
+      subnet_id: { get_resource: subnet }
+
+#  keypair:
+#    type: OS::Nova::KeyPair
+#    properties:
+#      name:
+#        str_replace:
+#          template: openshift-ansible-cluster_id-keypair
+#          params:
+#            cluster_id: {{ stack_name }}
+#      public_key: {{ ssh_public_key }}
+
+  master-secgrp:
+    type: OS::Neutron::SecurityGroup
+    properties:
+      name:
+        str_replace:
+          template: openshift-ansible-cluster_id-master-secgrp
+          params:
+            cluster_id: {{ stack_name }}
+      description:
+        str_replace:
+          template: Security group for cluster_id OpenShift cluster master
+          params:
+            cluster_id: {{ stack_name }}
+      rules:
+        - direction: ingress
+          protocol: tcp
+          port_range_min: 22
+          port_range_max: 22
+          remote_ip_prefix: {{ ssh_ingress_cidr }}
+        - direction: ingress
+          protocol: tcp
+          port_range_min: 4001
+          port_range_max: 4001
+        - direction: ingress
+          protocol: tcp
+          port_range_min: 8443
+          port_range_max: 8443
+        - direction: ingress
+          protocol: tcp
+          port_range_min: 8444
+          port_range_max: 8444
+        - direction: ingress
+          protocol: tcp
+          port_range_min: 53
+          port_range_max: 53
+        - direction: ingress
+          protocol: udp
+          port_range_min: 53
+          port_range_max: 53
+        - direction: ingress
+          protocol: tcp
+          port_range_min: 8053
+          port_range_max: 8053
+        - direction: ingress
+          protocol: udp
+          port_range_min: 8053
+          port_range_max: 8053
+        - direction: ingress
+          protocol: tcp
+          port_range_min: 24224
+          port_range_max: 24224
+        - direction: ingress
+          protocol: udp
+          port_range_min: 24224
+          port_range_max: 24224
+        - direction: ingress
+          protocol: tcp
+          port_range_min: 2224
+          port_range_max: 2224
+        - direction: ingress
+          protocol: udp
+          port_range_min: 5404
+          port_range_max: 5404
+        - direction: ingress
+          protocol: udp
+          port_range_min: 5405
+          port_range_max: 5405
+        - direction: ingress
+          protocol: tcp
+          port_range_min: 9090
+          port_range_max: 9090
+
+  etcd-secgrp:
+    type: OS::Neutron::SecurityGroup
+    properties:
+      name:
+        str_replace:
+          template: openshift-ansible-cluster_id-etcd-secgrp
+          params:
+            cluster_id: {{ stack_name }}
+      description:
+        str_replace:
+          template: Security group for cluster_id etcd cluster
+          params:
+            cluster_id: {{ stack_name }}
+      rules:
+        - direction: ingress
+          protocol: tcp
+          port_range_min: 22
+          port_range_max: 22
+          remote_ip_prefix: {{ ssh_ingress_cidr }}
+        - direction: ingress
+          protocol: tcp
+          port_range_min: 2379
+          port_range_max: 2379
+          remote_mode: remote_group_id
+          remote_group_id: { get_resource: master-secgrp }
+        - direction: ingress
+          protocol: tcp
+          port_range_min: 2380
+          port_range_max: 2380
+          remote_mode: remote_group_id
+
+  node-secgrp:
+    type: OS::Neutron::SecurityGroup
+    properties:
+      name:
+        str_replace:
+          template: openshift-ansible-cluster_id-node-secgrp
+          params:
+            cluster_id: {{ stack_name }}
+      description:
+        str_replace:
+          template: Security group for cluster_id OpenShift cluster nodes
+          params:
+            cluster_id: {{ stack_name }}
+      rules:
+        - direction: ingress
+          protocol: tcp
+          port_range_min: 22
+          port_range_max: 22
+          remote_ip_prefix: {{ ssh_ingress_cidr }}
+        - direction: ingress
+          protocol: tcp
+          port_range_min: 10250
+          port_range_max: 10250
+          remote_mode: remote_group_id
+        - direction: ingress
+          protocol: tcp
+          port_range_min: 10255
+          port_range_max: 10255
+          remote_mode: remote_group_id
+        - direction: ingress
+          protocol: udp
+          port_range_min: 10255
+          port_range_max: 10255
+          remote_mode: remote_group_id
+        - direction: ingress
+          protocol: udp
+          port_range_min: 4789
+          port_range_max: 4789
+          remote_mode: remote_group_id
+        - direction: ingress
+          protocol: tcp
+          port_range_min: 30000
+          port_range_max: 32767
+          remote_ip_prefix: {{ node_ingress_cidr }}
+
+  infra-secgrp:
+    type: OS::Neutron::SecurityGroup
+    properties:
+      name:
+        str_replace:
+          template: openshift-ansible-cluster_id-infra-secgrp
+          params:
+            cluster_id: {{ stack_name }}
+      description:
+        str_replace:
+          template: Security group for cluster_id OpenShift infrastructure cluster nodes
+          params:
+            cluster_id: {{ stack_name }}
+      rules:
+        - direction: ingress
+          protocol: tcp
+          port_range_min: 80
+          port_range_max: 80
+        - direction: ingress
+          protocol: tcp
+          port_range_min: 443
+          port_range_max: 443
+
+  dns-secgrp:
+    type: OS::Neutron::SecurityGroup
+    properties:
+      name:
+        str_replace:
+          template: openshift-ansible-cluster_id-dns-secgrp
+          params:
+            cluster_id: {{ stack_name }}
+      description:
+        str_replace:
+          template: Security group for cluster_id cluster DNS
+          params:
+            cluster_id: {{ stack_name }}
+      rules:
+        - direction: ingress
+          protocol: tcp
+          port_range_min: 22
+          port_range_max: 22
+          remote_ip_prefix: {{ ssh_ingress_cidr }}
+        - direction: ingress
+          protocol: udp
+          port_range_min: 53
+          port_range_max: 53
+          remote_ip_prefix: {{ node_ingress_cidr }}
+        - direction: ingress
+          protocol: tcp
+          port_range_min: 53
+          port_range_max: 53
+          remote_ip_prefix: {{ node_ingress_cidr }}
+
+  etcd:
+    type: OS::Heat::ResourceGroup
+    properties:
+      count: {{ num_etcd }}
+      resource_def:
+        type: server.yaml
+        properties:
+          name:
+            str_replace:
+              template: k8s_type-%index%.cluster_id
+              params:
+                cluster_id: {{ stack_name }}
+                k8s_type: etcd
+          cluster_env: {{ dns_domain }}
+          cluster_id:  {{ stack_name }}
+          group:
+            str_replace:
+              template: k8s_type.cluster_id
+              params:
+                k8s_type: etcds
+                cluster_id: {{ stack_name }}
+          type:        etcd
+          image:       {{ openstack_image }}
+          flavor:      {{ etcd_flavor }}
+          key_name:    {{ ssh_public_key }}
+          net:         { get_resource: net }
+          subnet:      { get_resource: subnet }
+          secgrp:
+            - { get_resource: etcd-secgrp }
+          floating_network: {{ external_network }}
+          net_name:
+            str_replace:
+              template: openshift-ansible-cluster_id-net
+              params:
+                cluster_id: {{ stack_name }}
+          volume_size: {{ etcd_volume_size }}
+    depends_on:
+      - interface
+
+  masters:
+    type: OS::Heat::ResourceGroup
+    properties:
+      count: {{ num_masters }}
+      resource_def:
+        type: server.yaml
+        properties:
+          name:
+            str_replace:
+              template: k8s_type-%index%.cluster_id
+              params:
+                cluster_id: {{ stack_name }}
+                k8s_type: master
+          cluster_env: {{ dns_domain }}
+          cluster_id:  {{ stack_name }}
+          group:
+            str_replace:
+              template: k8s_type.cluster_id
+              params:
+                k8s_type: masters
+                cluster_id: {{ stack_name }}
+          type:        master
+          image:       {{ openstack_image }}
+          flavor:      {{ master_flavor }}
+          key_name:    {{ ssh_public_key }}
+          net:         { get_resource: net }
+          subnet:      { get_resource: subnet }
+          secgrp:
+            - { get_resource: master-secgrp }
+            - { get_resource: node-secgrp }
+          floating_network: {{ external_network }}
+          net_name:
+            str_replace:
+              template: openshift-ansible-cluster_id-net
+              params:
+                cluster_id: {{ stack_name }}
+          volume_size: {{ master_volume_size }}
+    depends_on:
+      - interface
+
+  compute_nodes:
+    type: OS::Heat::ResourceGroup
+    properties:
+      count: {{ num_nodes }}
+      resource_def:
+        type: server.yaml
+        properties:
+          name:
+            str_replace:
+              template: subtype-k8s_type-%index%.cluster_id
+              params:
+                cluster_id: {{ stack_name }}
+                k8s_type: node
+                subtype: app
+          cluster_env: {{ dns_domain }}
+          cluster_id:  {{ stack_name }}
+          group:
+            str_replace:
+              template: k8s_type.cluster_id
+              params:
+                k8s_type: nodes
+                cluster_id: {{ stack_name }}
+          type:        node
+          subtype:     app
+          node_labels:
+            region: primary
+          image:       {{ openstack_image }}
+          flavor:      {{ node_flavor }}
+          key_name:    {{ ssh_public_key }}
+          net:         { get_resource: net }
+          subnet:      { get_resource: subnet }
+          secgrp:
+            - { get_resource: node-secgrp }
+          floating_network: {{ external_network }}
+          net_name:
+            str_replace:
+              template: openshift-ansible-cluster_id-net
+              params:
+                cluster_id: {{ stack_name }}
+          volume_size: {{ app_volume_size }}
+    depends_on:
+      - interface
+
+  infra_nodes:
+    type: OS::Heat::ResourceGroup
+    properties:
+      count: {{ num_infra }}
+      resource_def:
+        type: server.yaml
+        properties:
+          name:
+            str_replace:
+              template: subtypek8s_type-%index%.cluster_id
+              params:
+                cluster_id: {{ stack_name }}
+                k8s_type: node
+                subtype: infra
+          cluster_env: {{ dns_domain }}
+          cluster_id:  {{ stack_name }}
+          group:
+            str_replace:
+              template: k8s_type.cluster_id
+              params:
+                k8s_type: infra
+                cluster_id: {{ stack_name }}
+          type:        node
+          subtype:     infra
+          node_labels:
+            region: infra
+          image:       {{ openstack_image }}
+          flavor:      {{ infra_flavor }}
+          key_name:    {{ ssh_public_key }}
+          net:         { get_resource: net }
+          subnet:      { get_resource: subnet }
+          secgrp:
+            - { get_resource: node-secgrp }
+            - { get_resource: infra-secgrp }
+          floating_network: {{ external_network }}
+          net_name:
+            str_replace:
+              template: openshift-ansible-cluster_id-net
+              params:
+                cluster_id: {{ stack_name }}
+          volume_size: {{ infra_volume_size }}
+    depends_on:
+      - interface
+
+  dns:
+    type: OS::Heat::ResourceGroup
+    properties:
+      count: {{ num_dns }}
+      resource_def:
+        type: server.yaml
+        properties:
+          name:
+            str_replace:
+              template: k8s_type-%index%.cluster_id
+              params:
+                cluster_id: {{ stack_name }}
+                k8s_type: dns
+          cluster_env: {{ dns_domain }}
+          cluster_id:  {{ stack_name }}
+          group:
+            str_replace:
+              template: k8s_type.cluster_id
+              params:
+                k8s_type: dns
+                cluster_id: {{ stack_name }}
+          type:        dns
+          image:       {{ openstack_image }}
+          flavor:      {{ dns_flavor }}
+          key_name:    {{ ssh_public_key }}
+          net:         { get_resource: net }
+          subnet:      { get_resource: subnet }
+          secgrp:
+            - { get_resource: node-secgrp }
+            - { get_resource: dns-secgrp }
+          floating_network: {{ external_network }}
+          net_name:
+            str_replace:
+              template: openshift-ansible-cluster_id-net
+              params:
+                cluster_id: {{ stack_name }}
+          volume_size: {{ dns_volume_size }}
+    depends_on:
+      - interface
+
diff --git a/roles/openstack-stack/templates/heat_stack_server.yaml.j2 b/roles/openstack-stack/templates/heat_stack_server.yaml.j2
new file mode 100644
index 000000000..5851d3b9b
--- /dev/null
+++ b/roles/openstack-stack/templates/heat_stack_server.yaml.j2
@@ -0,0 +1,170 @@
+heat_template_version: 2016-10-14
+
+description: OpenShift cluster server
+
+parameters:
+
+  name:
+    type: string
+    label: Name
+    description: Name
+
+  group:
+    type: string
+    label: Host Group
+    description: The Primary Ansible Host Group
+    default: host
+
+  cluster_env:
+    type: string
+    label: Cluster environment
+    description: Environment of the cluster
+
+  cluster_id:
+    type: string
+    label: Cluster ID
+    description: Identifier of the cluster
+
+  type:
+    type: string
+    label: Type
+    description: Type master or node
+
+  subtype:
+    type: string
+    label: Sub-type
+    description: Sub-type compute or infra for nodes, default otherwise
+    default: default
+
+  key_name:
+    type: string
+    label: Key name
+    description: Key name of keypair
+
+  image:
+    type: string
+    label: Image
+    description: Name of the image
+
+  flavor:
+    type: string
+    label: Flavor
+    description: Name of the flavor
+
+  net:
+    type: string
+    label: Net ID
+    description: Net resource
+
+  net_name:
+    type: string
+    label: Net name
+    description: Net name
+
+  subnet:
+    type: string
+    label: Subnet ID
+    description: Subnet resource
+
+  secgrp:
+    type: comma_delimited_list
+    label: Security groups
+    description: Security group resources
+
+  floating_network:
+    type: string
+    label: Floating network
+    description: Network to allocate floating IP from
+
+  availability_zone:
+    type: string
+    description: The Availability Zone to launch the instance.
+    default: nova
+
+  volume_size:
+    type: number
+    description: Size of the volume to be created.
+    default: 1
+    constraints:
+      - range: { min: 1, max: 1024 }
+        description: must be between 1 and 1024 Gb.
+
+  node_labels:
+    type: json
+    description: OpenShift Node Labels
+    default: {"region": "default" }
+
+outputs:
+
+  name:
+    description: Name of the server
+    value: { get_attr: [ server, name ] }
+
+  private_ip:
+    description: Private IP of the server
+    value:
+      get_attr:
+        - server
+        - addresses
+        - { get_param: net_name }
+        - 0
+        - addr
+
+  floating_ip:
+    description: Floating IP of the server
+    value:
+      get_attr:
+        - server
+        - addresses
+        - { get_param: net_name }
+        - 1
+        - addr
+
+resources:
+
+  server:
+    type: OS::Nova::Server
+    properties:
+      name:      { get_param: name }
+      key_name:  { get_param: key_name }
+      image:     { get_param: image }
+      flavor:    { get_param: flavor }
+      networks:
+        - port:  { get_resource: port }
+      user_data:
+        get_file: user-data
+      user_data_format: RAW
+      metadata:
+        group: { get_param: group }
+        environment: { get_param: cluster_env }
+        clusterid: { get_param: cluster_id }
+        host-type: { get_param: type }
+        sub-host-type:    { get_param: subtype }
+        node_labels: { get_param: node_labels }
+
+  port:
+    type: OS::Neutron::Port
+    properties:
+      network: { get_param: net }
+      fixed_ips:
+        - subnet: { get_param: subnet }
+      security_groups: { get_param: secgrp }
+
+  floating-ip:
+    type: OS::Neutron::FloatingIP
+    properties:
+      floating_network: { get_param: floating_network }
+      port_id: { get_resource: port }
+
+  cinder_volume:
+    type: OS::Cinder::Volume
+    properties:
+      size: { get_param: volume_size }
+      availability_zone: { get_param: availability_zone }
+
+  volume_attachment:
+    type: OS::Cinder::VolumeAttachment
+    properties:
+      volume_id: { get_resource: cinder_volume }
+      instance_uuid: { get_resource: server }
+      mountpoint: /dev/sdb
diff --git a/roles/openstack-stack/templates/user_data.j2 b/roles/openstack-stack/templates/user_data.j2
new file mode 100644
index 000000000..eb65f7cec
--- /dev/null
+++ b/roles/openstack-stack/templates/user_data.j2
@@ -0,0 +1,13 @@
+#cloud-config
+disable_root: true
+
+system_info:
+  default_user:
+    name: openshift
+    sudo: ["ALL=(ALL) NOPASSWD: ALL"]
+
+write_files:
+  - path: /etc/sudoers.d/00-openshift-no-requiretty
+    permissions: 440
+    content: |
+      Defaults:openshift !requiretty
-- 
cgit v1.2.3