summaryrefslogtreecommitdiffstats
path: root/roles
diff options
context:
space:
mode:
authorEric Sauer <etsauer@gmail.com>2016-12-21 10:37:40 -0500
committerØystein Bedin <oybed@users.noreply.github.com>2016-12-21 08:37:40 -0700
commit11b48fe4e237950f9d9e9a0e66d8b15f48be1ea0 (patch)
tree37465841228605d501ef1761578856df90e45a22 /roles
parent953e8a7403f49640c04175386eadda329e9fd4b0 (diff)
downloadopenshift-11b48fe4e237950f9d9e9a0e66d8b15f48be1ea0.tar.gz
openshift-11b48fe4e237950f9d9e9a0e66d8b15f48be1ea0.tar.bz2
openshift-11b48fe4e237950f9d9e9a0e66d8b15f48be1ea0.tar.xz
openshift-11b48fe4e237950f9d9e9a0e66d8b15f48be1ea0.zip
Openstack heat (#2)
* Adding a role to invoke openstack heat * Adding readme * Pulling parameters out to inventory file * start of end-to-end playbook * More enhancements and refactoring to make dynamic inventory the driver for an openshift install * Switching to variable substituted path to config.yaml playbook * Changes to allow defining of number of nodes/infranodes. * Added labels to inventory * Start of end-to-end functionality * Enhancements to support openstack heat provisioning * Updating inventory sample to remove some deprecation warnings * Working towards making the secure-registry role 'become' aware * Fixing node labels and removing secure-registry as it's no longer needed * No longer need insecure registry line, as installer will secure our registry * Adjusted dynamic inventory to filter by clusterid * Minor updates to dynamic inventory bug * Adding a refactored sample inventory directory * Refactoring playbooks for better directory structure, and to narrow down host groups * Adding volume mounts to heat template * Moving dns playbooks back to original location * Fixing incorrect file path * Cleaning up inventory samples * One more hostname to clean up * Changing var name * changed openshift-provision to openshift-prep * Adjusting current provision script to avoid breakage by new openstack-heat code
Diffstat (limited to 'roles')
-rw-r--r--roles/common/pre_tasks/pre_tasks.yml5
-rw-r--r--roles/openshift-prep/tasks/main.yml4
-rw-r--r--roles/openshift-prep/tasks/prerequisites.yml36
-rw-r--r--roles/openstack-stack/README.md9
-rw-r--r--roles/openstack-stack/files/heat_stack.yaml684
-rw-r--r--roles/openstack-stack/files/heat_stack_server.yaml156
-rw-r--r--roles/openstack-stack/files/user-data13
-rw-r--r--roles/openstack-stack/tasks/main.yml31
l---------roles/openstack-stack/test/roles1
-rw-r--r--roles/openstack-stack/test/stack-create-test.yml17
10 files changed, 956 insertions, 0 deletions
diff --git a/roles/common/pre_tasks/pre_tasks.yml b/roles/common/pre_tasks/pre_tasks.yml
index 1ba1ea55d..71a989b30 100644
--- a/roles/common/pre_tasks/pre_tasks.yml
+++ b/roles/common/pre_tasks/pre_tasks.yml
@@ -15,6 +15,11 @@
env_id: "{{ env_id | default(default_env_id) }}"
delegate_to: localhost
+- name: Set Dynamic Inventory Filters
+ shell: >
+ export OS_INV_FILTER_KEY=clusterid && OS_INV_FILTER_VALUE={{ env_id }}
+ delegate_to: localhost
+
- name: Updating DNS domain to include env_id (if not empty)
set_fact:
full_dns_domain: "{{ (env_id|trim == '') | ternary(dns_domain, env_id + '.' + dns_domain) }}"
diff --git a/roles/openshift-prep/tasks/main.yml b/roles/openshift-prep/tasks/main.yml
new file mode 100644
index 000000000..5e484e75f
--- /dev/null
+++ b/roles/openshift-prep/tasks/main.yml
@@ -0,0 +1,4 @@
+---
+# Starting Point for OpenShift Installation and Configuration
+- include: prerequisites.yml
+ tags: [prerequisites]
diff --git a/roles/openshift-prep/tasks/prerequisites.yml b/roles/openshift-prep/tasks/prerequisites.yml
new file mode 100644
index 000000000..1286905f4
--- /dev/null
+++ b/roles/openshift-prep/tasks/prerequisites.yml
@@ -0,0 +1,36 @@
+---
+- name: "Cleaning yum repositories"
+ command: "yum clean all"
+
+- name: "Install required packages"
+ yum:
+ name: "{{ item }}"
+ state: latest
+ with_items:
+ - wget
+ - git
+ - net-tools
+ - bind-utils
+ - bridge-utils
+ - bash-completion
+ - atomic-openshift-utils
+ - vim-enhanced
+
+- name: "Update all packages (this can take a very long time)"
+ yum:
+ name: "*"
+ state: latest
+
+- name: "Verify hostname"
+ shell: hostnamectl status | awk "/Static hostname/"'{ print $3 }'
+ register: hostname_fqdn
+
+- name: "Set hostname if required"
+ hostname:
+ name: "{{ ansible_fqdn }}"
+ when: hostname_fqdn.stdout != ansible_fqdn
+
+- name: "Verify SELinux is enforcing"
+ fail:
+ msg: "SELinux is required for OpenShift and has been detected as '{{ ansible_selinux.config_mode }}'"
+ when: ansible_selinux.config_mode != "enforcing"
diff --git a/roles/openstack-stack/README.md b/roles/openstack-stack/README.md
new file mode 100644
index 000000000..509c9de6c
--- /dev/null
+++ b/roles/openstack-stack/README.md
@@ -0,0 +1,9 @@
+# Role openstack-stack
+
+Role for spinning up instances using OpenStack Heat.
+
+## To Test
+
+```
+ansible-playbook casl-ansible/roles/openstack-stack/test/stack-create-test.yml
+```
diff --git a/roles/openstack-stack/files/heat_stack.yaml b/roles/openstack-stack/files/heat_stack.yaml
new file mode 100644
index 000000000..058f7a7ad
--- /dev/null
+++ b/roles/openstack-stack/files/heat_stack.yaml
@@ -0,0 +1,684 @@
+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
new file mode 100644
index 000000000..978da4f0b
--- /dev/null
+++ b/roles/openstack-stack/files/heat_stack_server.yaml
@@ -0,0 +1,156 @@
+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
new file mode 100644
index 000000000..eb65f7cec
--- /dev/null
+++ b/roles/openstack-stack/files/user-data
@@ -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
diff --git a/roles/openstack-stack/tasks/main.yml b/roles/openstack-stack/tasks/main.yml
new file mode 100644
index 000000000..c953cb603
--- /dev/null
+++ b/roles/openstack-stack/tasks/main.yml
@@ -0,0 +1,31 @@
+---
+- name: create stack
+ ignore_errors: False
+ register: stack_create
+ os_stack:
+ name: "{{ stack_name }}"
+ state: present
+ template: 'roles/openstack-stack/files/heat_stack.yaml'
+ 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 }}"
diff --git a/roles/openstack-stack/test/roles b/roles/openstack-stack/test/roles
new file mode 120000
index 000000000..e2b799b9d
--- /dev/null
+++ b/roles/openstack-stack/test/roles
@@ -0,0 +1 @@
+../../../roles/ \ No newline at end of file
diff --git a/roles/openstack-stack/test/stack-create-test.yml b/roles/openstack-stack/test/stack-create-test.yml
new file mode 100644
index 000000000..94e312ee3
--- /dev/null
+++ b/roles/openstack-stack/test/stack-create-test.yml
@@ -0,0 +1,17 @@
+---
+- hosts: localhost
+ roles:
+ - role: openstack-stack
+ stack_name: test-stack
+ dns_domain: "{{ openstack_dns_domain }}"
+ dns_nameservers: "{{ openstack_nameservers }}"
+ subnet_prefix: "{{ openstack_subnet_prefix }}"
+ ssh_public_key: "{{ openstack_ssh_public_key }}"
+ openstack_image: "{{ openstack_default_image_name }}"
+ etcd_flavor: "{{ openstack_default_flavor }}"
+ master_flavor: "{{ openstack_default_flavor }}"
+ node_flavor: "{{ openstack_default_flavor }}"
+ infra_flavor: "{{ openstack_default_flavor }}"
+ dns_flavor: "{{ openstack_default_flavor }}"
+ external_network: "{{ openstack_external_network_name }}"
+