summaryrefslogtreecommitdiffstats
path: root/roles
diff options
context:
space:
mode:
authorTomas Sedovic <tomas@sedovic.cz>2017-11-07 14:17:27 +1100
committerTomas Sedovic <tomas@sedovic.cz>2017-11-07 14:17:27 +1100
commit6f4d509817f200ec2a273a097f4f048da5997925 (patch)
treeebddc919d850ec5c4d308613661063b01ae89784 /roles
parent0cf8cf65a89ad7cac8c1cef1f743426b610adae0 (diff)
parent332f131e8e6457a03a4f1ab19abc8e4ceb897307 (diff)
downloadopenshift-6f4d509817f200ec2a273a097f4f048da5997925.tar.gz
openshift-6f4d509817f200ec2a273a097f4f048da5997925.tar.bz2
openshift-6f4d509817f200ec2a273a097f4f048da5997925.tar.xz
openshift-6f4d509817f200ec2a273a097f4f048da5997925.zip
Merge ../openshift-ansible-contrib into openstack-provider-githist
This moves all the OpenStack-related code from the -contrib[1] repo including its git history to openshift-ansible. It will then be moved around and updated to fit the rest of the project's structure. [1]: https://github.com/openshift/openshift-ansible-contrib
Diffstat (limited to 'roles')
-rw-r--r--roles/common/defaults/main.yml6
-rw-r--r--roles/dns-records/defaults/main.yml2
-rw-r--r--roles/dns-records/tasks/main.yml121
-rw-r--r--roles/dns-server-detect/defaults/main.yml3
-rw-r--r--roles/dns-server-detect/tasks/main.yml36
-rw-r--r--roles/dns-views/defaults/main.yml4
-rw-r--r--roles/dns-views/tasks/main.yml30
-rw-r--r--roles/docker-storage-setup/defaults/main.yaml7
-rw-r--r--roles/docker-storage-setup/tasks/main.yaml46
-rw-r--r--roles/docker-storage-setup/templates/docker-storage-setup-dm.j24
-rw-r--r--roles/docker-storage-setup/templates/docker-storage-setup-overlayfs.j27
-rw-r--r--roles/hostnames/tasks/main.yaml26
-rw-r--r--roles/hostnames/test/inv12
l---------roles/hostnames/test/roles1
-rw-r--r--roles/hostnames/test/test.retry3
-rw-r--r--roles/hostnames/test/test.yaml4
-rw-r--r--roles/hostnames/vars/main.yaml2
-rw-r--r--roles/hostnames/vars/records.yaml28
-rw-r--r--roles/node-network-manager/tasks/main.yml22
-rw-r--r--roles/openshift-prep/defaults/main.yml13
-rw-r--r--roles/openshift-prep/tasks/main.yml4
-rw-r--r--roles/openshift-prep/tasks/prerequisites.yml37
-rw-r--r--roles/openstack-create-cinder-registry/tasks/main.yaml5
-rw-r--r--roles/openstack-stack/README.md9
-rw-r--r--roles/openstack-stack/defaults/main.yml21
-rw-r--r--roles/openstack-stack/meta/main.yml3
-rw-r--r--roles/openstack-stack/tasks/cleanup.yml6
-rw-r--r--roles/openstack-stack/tasks/generate-templates.yml26
-rw-r--r--roles/openstack-stack/tasks/main.yml27
-rw-r--r--roles/openstack-stack/tasks/subnet_update_dns_servers.yaml9
-rw-r--r--roles/openstack-stack/templates/heat_stack.yaml.j2888
-rw-r--r--roles/openstack-stack/templates/heat_stack_server.yaml.j2270
-rw-r--r--roles/openstack-stack/templates/user_data.j213
l---------roles/openstack-stack/test/roles1
-rw-r--r--roles/openstack-stack/test/stack-create-test.yml18
-rw-r--r--roles/static_inventory/defaults/main.yml29
-rw-r--r--roles/static_inventory/meta/main.yml3
-rw-r--r--roles/static_inventory/tasks/checkpoint.yml17
-rw-r--r--roles/static_inventory/tasks/filter_out_new_app_nodes.yaml15
-rw-r--r--roles/static_inventory/tasks/main.yml25
-rw-r--r--roles/static_inventory/tasks/openstack.yml120
-rw-r--r--roles/static_inventory/tasks/sshconfig.yml13
-rw-r--r--roles/static_inventory/tasks/sshtun.yml15
-rw-r--r--roles/static_inventory/templates/inventory.j2104
-rw-r--r--roles/static_inventory/templates/openstack_ssh_config.j221
-rw-r--r--roles/static_inventory/templates/ssh-tunnel.service.j220
-rw-r--r--roles/subscription-manager/README.md156
-rw-r--r--roles/subscription-manager/pre_tasks/pre_tasks.yml45
-rw-r--r--roles/subscription-manager/tasks/main.yml150
49 files changed, 2447 insertions, 0 deletions
diff --git a/roles/common/defaults/main.yml b/roles/common/defaults/main.yml
new file mode 100644
index 000000000..8db591374
--- /dev/null
+++ b/roles/common/defaults/main.yml
@@ -0,0 +1,6 @@
+---
+openshift_cluster_node_labels:
+ app:
+ region: primary
+ infra:
+ region: infra
diff --git a/roles/dns-records/defaults/main.yml b/roles/dns-records/defaults/main.yml
new file mode 100644
index 000000000..3f7fa783f
--- /dev/null
+++ b/roles/dns-records/defaults/main.yml
@@ -0,0 +1,2 @@
+---
+use_bastion: False
diff --git a/roles/dns-records/tasks/main.yml b/roles/dns-records/tasks/main.yml
new file mode 100644
index 000000000..7148b016a
--- /dev/null
+++ b/roles/dns-records/tasks/main.yml
@@ -0,0 +1,121 @@
+---
+- name: "Generate list of private A records"
+ set_fact:
+ private_records: "{{ private_records | default([]) + [ { 'type': 'A', 'hostname': hostvars[item]['ansible_hostname'], 'ip': hostvars[item]['private_v4'] } ] }}"
+ with_items: "{{ groups['cluster_hosts'] }}"
+
+- name: "Add wildcard records to the private A records for infrahosts"
+ set_fact:
+ private_records: "{{ private_records | default([]) + [ { 'type': 'A', 'hostname': '*.' + openshift_app_domain, 'ip': hostvars[item]['private_v4'] } ] }}"
+ with_items: "{{ groups['infra_hosts'] }}"
+
+- name: "Add public master cluster hostname records to the private A records (single master)"
+ set_fact:
+ private_records: "{{ private_records | default([]) + [ { 'type': 'A', 'hostname': (hostvars[groups.masters[0]].openshift_master_cluster_public_hostname | replace(full_dns_domain, ''))[:-1], 'ip': hostvars[groups.masters[0]].private_v4 } ] }}"
+ when:
+ - hostvars[groups.masters[0]].openshift_master_cluster_public_hostname is defined
+ - openstack_num_masters == 1
+
+- name: "Add public master cluster hostname records to the private A records (multi-master)"
+ set_fact:
+ private_records: "{{ private_records | default([]) + [ { 'type': 'A', 'hostname': (hostvars[groups.masters[0]].openshift_master_cluster_public_hostname | replace(full_dns_domain, ''))[:-1], 'ip': hostvars[groups.lb[0]].private_v4 } ] }}"
+ when:
+ - hostvars[groups.masters[0]].openshift_master_cluster_public_hostname is defined
+ - openstack_num_masters > 1
+
+- name: "Set the private DNS server to use the external value (if provided)"
+ set_fact:
+ nsupdate_server_private: "{{ external_nsupdate_keys['private']['server'] }}"
+ nsupdate_key_secret_private: "{{ external_nsupdate_keys['private']['key_secret'] }}"
+ nsupdate_key_algorithm_private: "{{ external_nsupdate_keys['private']['key_algorithm'] }}"
+ nsupdate_private_key_name: "{{ external_nsupdate_keys['private']['key_name']|default('private-' + full_dns_domain) }}"
+ when:
+ - external_nsupdate_keys is defined
+ - external_nsupdate_keys['private'] is defined
+
+- name: "Set the private DNS server to use the provisioned value"
+ set_fact:
+ nsupdate_server_private: "{{ hostvars[groups['dns'][0]].public_v4 }}"
+ nsupdate_key_secret_private: "{{ hostvars[groups['dns'][0]].nsupdate_keys['private-' + full_dns_domain].key_secret }}"
+ nsupdate_key_algorithm_private: "{{ hostvars[groups['dns'][0]].nsupdate_keys['private-' + full_dns_domain].key_algorithm }}"
+ when:
+ - nsupdate_server_private is undefined
+
+- name: "Generate the private Add section for DNS"
+ set_fact:
+ private_named_records:
+ - view: "private"
+ zone: "{{ full_dns_domain }}"
+ server: "{{ nsupdate_server_private }}"
+ key_name: "{{ nsupdate_private_key_name|default('private-' + full_dns_domain) }}"
+ key_secret: "{{ nsupdate_key_secret_private }}"
+ key_algorithm: "{{ nsupdate_key_algorithm_private | lower }}"
+ entries: "{{ private_records }}"
+
+- name: "Generate list of public A records"
+ set_fact:
+ public_records: "{{ public_records | default([]) + [ { 'type': 'A', 'hostname': hostvars[item]['ansible_hostname'], 'ip': hostvars[item]['public_v4'] } ] }}"
+ with_items: "{{ groups['cluster_hosts'] }}"
+ when: hostvars[item]['public_v4'] is defined
+
+- name: "Add wildcard records to the public A records"
+ set_fact:
+ public_records: "{{ public_records | default([]) + [ { 'type': 'A', 'hostname': '*.' + openshift_app_domain, 'ip': hostvars[item]['public_v4'] } ] }}"
+ with_items: "{{ groups['infra_hosts'] }}"
+ when: hostvars[item]['public_v4'] is defined
+
+- name: "Add public master cluster hostname records to the public A records (single master)"
+ set_fact:
+ public_records: "{{ public_records | default([]) + [ { 'type': 'A', 'hostname': (hostvars[groups.masters[0]].openshift_master_cluster_public_hostname | replace(full_dns_domain, ''))[:-1], 'ip': hostvars[groups.masters[0]].public_v4 } ] }}"
+ when:
+ - hostvars[groups.masters[0]].openshift_master_cluster_public_hostname is defined
+ - openstack_num_masters == 1
+ - not use_bastion|bool
+
+- name: "Add public master cluster hostname records to the public A records (single master behind a bastion)"
+ set_fact:
+ public_records: "{{ public_records | default([]) + [ { 'type': 'A', 'hostname': (hostvars[groups.masters[0]].openshift_master_cluster_public_hostname | replace(full_dns_domain, ''))[:-1], 'ip': hostvars[groups.bastions[0]].public_v4 } ] }}"
+ when:
+ - hostvars[groups.masters[0]].openshift_master_cluster_public_hostname is defined
+ - openstack_num_masters == 1
+ - use_bastion|bool
+
+- name: "Add public master cluster hostname records to the public A records (multi-master)"
+ set_fact:
+ public_records: "{{ public_records | default([]) + [ { 'type': 'A', 'hostname': (hostvars[groups.masters[0]].openshift_master_cluster_public_hostname | replace(full_dns_domain, ''))[:-1], 'ip': hostvars[groups.lb[0]].public_v4 } ] }}"
+ when:
+ - hostvars[groups.masters[0]].openshift_master_cluster_public_hostname is defined
+ - openstack_num_masters > 1
+
+- name: "Set the public DNS server details to use the external value (if provided)"
+ set_fact:
+ nsupdate_server_public: "{{ external_nsupdate_keys['public']['server'] }}"
+ nsupdate_key_secret_public: "{{ external_nsupdate_keys['public']['key_secret'] }}"
+ nsupdate_key_algorithm_public: "{{ external_nsupdate_keys['public']['key_algorithm'] }}"
+ nsupdate_public_key_name: "{{ external_nsupdate_keys['public']['key_name']|default('public-' + full_dns_domain) }}"
+ when:
+ - external_nsupdate_keys is defined
+ - external_nsupdate_keys['public'] is defined
+
+- name: "Set the public DNS server details to use the provisioned value"
+ set_fact:
+ nsupdate_server_public: "{{ hostvars[groups['dns'][0]].public_v4 }}"
+ nsupdate_key_secret_public: "{{ hostvars[groups['dns'][0]].nsupdate_keys['public-' + full_dns_domain].key_secret }}"
+ nsupdate_key_algorithm_public: "{{ hostvars[groups['dns'][0]].nsupdate_keys['public-' + full_dns_domain].key_algorithm }}"
+ when:
+ - nsupdate_server_public is undefined
+
+- name: "Generate the public Add section for DNS"
+ set_fact:
+ public_named_records:
+ - view: "public"
+ zone: "{{ full_dns_domain }}"
+ server: "{{ nsupdate_server_public }}"
+ key_name: "{{ nsupdate_public_key_name|default('public-' + full_dns_domain) }}"
+ key_secret: "{{ nsupdate_key_secret_public }}"
+ key_algorithm: "{{ nsupdate_key_algorithm_public | lower }}"
+ entries: "{{ public_records }}"
+
+- name: "Generate the final dns_records_add"
+ set_fact:
+ dns_records_add: "{{ private_named_records + public_named_records }}"
diff --git a/roles/dns-server-detect/defaults/main.yml b/roles/dns-server-detect/defaults/main.yml
new file mode 100644
index 000000000..58bd861cd
--- /dev/null
+++ b/roles/dns-server-detect/defaults/main.yml
@@ -0,0 +1,3 @@
+---
+
+external_nsupdate_keys: {}
diff --git a/roles/dns-server-detect/tasks/main.yml b/roles/dns-server-detect/tasks/main.yml
new file mode 100644
index 000000000..cd775814f
--- /dev/null
+++ b/roles/dns-server-detect/tasks/main.yml
@@ -0,0 +1,36 @@
+---
+- fail:
+ msg: 'Missing required private DNS server(s)'
+ when:
+ - external_nsupdate_keys['private'] is undefined
+ - hostvars[groups['dns'][0]] is undefined
+
+- fail:
+ msg: 'Missing required public DNS server(s)'
+ when:
+ - external_nsupdate_keys['public'] is undefined
+ - hostvars[groups['dns'][0]] is undefined
+
+- name: "Set the private DNS server to use the external value (if provided)"
+ set_fact:
+ private_dns_server: "{{ external_nsupdate_keys['private']['server'] }}"
+ when:
+ - external_nsupdate_keys['private'] is defined
+
+- name: "Set the private DNS server to use the provisioned value"
+ set_fact:
+ private_dns_server: "{{ hostvars[groups['dns'][0]].private_v4 }}"
+ when:
+ - private_dns_server is undefined
+
+- name: "Set the public DNS server to use the external value (if provided)"
+ set_fact:
+ public_dns_server: "{{ external_nsupdate_keys['public']['server'] }}"
+ when:
+ - external_nsupdate_keys['public'] is defined
+
+- name: "Set the public DNS server to use the provisioned value"
+ set_fact:
+ public_dns_server: "{{ hostvars[groups['dns'][0]].public_v4 }}"
+ when:
+ - public_dns_server is undefined
diff --git a/roles/dns-views/defaults/main.yml b/roles/dns-views/defaults/main.yml
new file mode 100644
index 000000000..c9f8248af
--- /dev/null
+++ b/roles/dns-views/defaults/main.yml
@@ -0,0 +1,4 @@
+---
+external_nsupdate_keys: {}
+named_private_recursion: 'yes'
+named_public_recursion: 'no'
diff --git a/roles/dns-views/tasks/main.yml b/roles/dns-views/tasks/main.yml
new file mode 100644
index 000000000..ffbad2e3f
--- /dev/null
+++ b/roles/dns-views/tasks/main.yml
@@ -0,0 +1,30 @@
+---
+- name: "Generate ACL list for DNS server"
+ set_fact:
+ acl_list: "{{ acl_list | default([]) + [ (hostvars[item]['private_v4'] + '/32') ] }}"
+ with_items: "{{ groups['cluster_hosts'] }}"
+
+- name: "Generate the private view"
+ set_fact:
+ private_named_view:
+ - name: "private"
+ recursion: "{{ named_private_recursion }}"
+ acl_entry: "{{ acl_list }}"
+ zone:
+ - dns_domain: "{{ full_dns_domain }}"
+ forwarder: "{{ public_dns_nameservers }}"
+ when: external_nsupdate_keys['private'] is undefined
+
+- name: "Generate the public view"
+ set_fact:
+ public_named_view:
+ - name: "public"
+ recursion: "{{ named_public_recursion }}"
+ zone:
+ - dns_domain: "{{ full_dns_domain }}"
+ forwarder: "{{ public_dns_nameservers }}"
+ when: external_nsupdate_keys['public'] is undefined
+
+- name: "Generate the final named_config_views"
+ set_fact:
+ named_config_views: "{{ private_named_view|default([]) + public_named_view|default([]) }}"
diff --git a/roles/docker-storage-setup/defaults/main.yaml b/roles/docker-storage-setup/defaults/main.yaml
new file mode 100644
index 000000000..062f543ad
--- /dev/null
+++ b/roles/docker-storage-setup/defaults/main.yaml
@@ -0,0 +1,7 @@
+---
+docker_dev: "/dev/sdb"
+docker_vg: "docker-vol"
+docker_data_size: "95%VG"
+docker_dm_basesize: "3G"
+container_root_lv_name: "dockerlv"
+container_root_lv_mount_path: "/var/lib/docker"
diff --git a/roles/docker-storage-setup/tasks/main.yaml b/roles/docker-storage-setup/tasks/main.yaml
new file mode 100644
index 000000000..8606eeba4
--- /dev/null
+++ b/roles/docker-storage-setup/tasks/main.yaml
@@ -0,0 +1,46 @@
+---
+- name: stop docker
+ service: name=docker state=stopped
+
+- block:
+ - name: create the docker-storage config file
+ template:
+ src: "{{ role_path }}/templates/docker-storage-setup-overlayfs.j2"
+ dest: /etc/sysconfig/docker-storage-setup
+ owner: root
+ group: root
+ mode: 0644
+ when:
+ - ansible_distribution_version | version_compare('7.4', '>=')
+ - ansible_distribution == "RedHat"
+
+- block:
+ - name: create the docker-storage-setup config file
+ template:
+ src: "{{ role_path }}/templates/docker-storage-setup-dm.j2"
+ dest: /etc/sysconfig/docker-storage-setup
+ owner: root
+ group: root
+ mode: 0644
+ when:
+ - ansible_distribution_version | version_compare('7.4', '<')
+ - ansible_distribution == "RedHat"
+
+- block:
+ - name: create the docker-storage-setup config file for CentOS
+ template:
+ src: "{{ role_path }}/templates/docker-storage-setup-dm.j2"
+ dest: /etc/sysconfig/docker-storage-setup
+ owner: root
+ group: root
+ mode: 0644
+
+ # TODO(shadower): Find out which CentOS version supports overlayfs2
+ when:
+ - ansible_distribution == "CentOS"
+
+- name: Install Docker
+ package: name=docker state=present
+
+- name: start docker
+ service: name=docker state=restarted enabled=true
diff --git a/roles/docker-storage-setup/templates/docker-storage-setup-dm.j2 b/roles/docker-storage-setup/templates/docker-storage-setup-dm.j2
new file mode 100644
index 000000000..b5869feff
--- /dev/null
+++ b/roles/docker-storage-setup/templates/docker-storage-setup-dm.j2
@@ -0,0 +1,4 @@
+DEVS="{{ docker_dev }}"
+VG="{{ docker_vg }}"
+DATA_SIZE="{{ docker_data_size }}"
+EXTRA_DOCKER_STORAGE_OPTIONS="--storage-opt dm.basesize={{ docker_dm_basesize }}"
diff --git a/roles/docker-storage-setup/templates/docker-storage-setup-overlayfs.j2 b/roles/docker-storage-setup/templates/docker-storage-setup-overlayfs.j2
new file mode 100644
index 000000000..d8b4a0276
--- /dev/null
+++ b/roles/docker-storage-setup/templates/docker-storage-setup-overlayfs.j2
@@ -0,0 +1,7 @@
+DEVS="{{ docker_dev }}"
+VG="{{ docker_vg }}"
+DATA_SIZE="{{ docker_data_size }}"
+STORAGE_DRIVER=overlay2
+CONTAINER_ROOT_LV_NAME="{{ container_root_lv_name }}"
+CONTAINER_ROOT_LV_MOUNT_PATH="{{ container_root_lv_mount_path }}"
+CONTAINER_ROOT_LV_SIZE=100%FREE
diff --git a/roles/hostnames/tasks/main.yaml b/roles/hostnames/tasks/main.yaml
new file mode 100644
index 000000000..c49852210
--- /dev/null
+++ b/roles/hostnames/tasks/main.yaml
@@ -0,0 +1,26 @@
+---
+- name: Setting Hostname Fact
+ set_fact:
+ new_hostname: "{{ custom_hostname | default(inventory_hostname_short) }}"
+
+- name: Setting FQDN Fact
+ set_fact:
+ new_fqdn: "{{ new_hostname }}.{{ full_dns_domain }}"
+
+- name: Setting hostname and DNS domain
+ hostname: name="{{ new_fqdn }}"
+
+- name: Check for cloud.cfg
+ stat: path=/etc/cloud/cloud.cfg
+ register: cloud_cfg
+
+- name: Prevent cloud-init updates of hostname/fqdn (if applicable)
+ lineinfile:
+ dest: /etc/cloud/cloud.cfg
+ state: present
+ regexp: "{{ item.regexp }}"
+ line: "{{ item.line }}"
+ with_items:
+ - { regexp: '^ - set_hostname', line: '# - set_hostname' }
+ - { regexp: '^ - update_hostname', line: '# - update_hostname' }
+ when: cloud_cfg.stat.exists == True
diff --git a/roles/hostnames/test/inv b/roles/hostnames/test/inv
new file mode 100644
index 000000000..ffbe6e03d
--- /dev/null
+++ b/roles/hostnames/test/inv
@@ -0,0 +1,12 @@
+[all:vars]
+dns_domain=example.com
+
+[openshift_masters]
+192.168.124.41 dns_private_ip=1.1.1.41 dns_public_ip=192.168.124.41
+192.168.124.117 dns_private_ip=1.1.1.117 dns_public_ip=192.168.124.117
+
+[openshift_nodes]
+192.168.124.40 dns_private_ip=1.1.1.40 dns_public_ip=192.168.124.40
+
+#[dns]
+#192.168.124.117 dns_private_ip=1.1.1.117
diff --git a/roles/hostnames/test/roles b/roles/hostnames/test/roles
new file mode 120000
index 000000000..e2b799b9d
--- /dev/null
+++ b/roles/hostnames/test/roles
@@ -0,0 +1 @@
+../../../roles/ \ No newline at end of file
diff --git a/roles/hostnames/test/test.retry b/roles/hostnames/test/test.retry
new file mode 100644
index 000000000..63fc08e4c
--- /dev/null
+++ b/roles/hostnames/test/test.retry
@@ -0,0 +1,3 @@
+192.168.124.117
+192.168.124.40
+192.168.124.41
diff --git a/roles/hostnames/test/test.yaml b/roles/hostnames/test/test.yaml
new file mode 100644
index 000000000..0c56aea51
--- /dev/null
+++ b/roles/hostnames/test/test.yaml
@@ -0,0 +1,4 @@
+---
+- hosts: all
+ roles:
+ - role: hostnames
diff --git a/roles/hostnames/vars/main.yaml b/roles/hostnames/vars/main.yaml
new file mode 100644
index 000000000..3eecb8dc4
--- /dev/null
+++ b/roles/hostnames/vars/main.yaml
@@ -0,0 +1,2 @@
+---
+counter: 1
diff --git a/roles/hostnames/vars/records.yaml b/roles/hostnames/vars/records.yaml
new file mode 100644
index 000000000..0cadc8181
--- /dev/null
+++ b/roles/hostnames/vars/records.yaml
@@ -0,0 +1,28 @@
+---
+- name: "Building Records"
+ set_fact:
+ dns_records_add:
+ - view: private
+ zone: example.com
+ entries:
+ - type: A
+ hostname: master1.example.com
+ ip: 172.16.15.94
+ - type: A
+ hostname: node1.example.com
+ ip: 172.16.15.86
+ - type: A
+ hostname: node2.example.com
+ ip: 172.16.15.87
+ - view: public
+ zone: example.com
+ entries:
+ - type: A
+ hostname: master1.example.com
+ ip: 10.3.10.116
+ - type: A
+ hostname: node1.example.com
+ ip: 10.3.11.46
+ - type: A
+ hostname: node2.example.com
+ ip: 10.3.12.6
diff --git a/roles/node-network-manager/tasks/main.yml b/roles/node-network-manager/tasks/main.yml
new file mode 100644
index 000000000..6a17855e7
--- /dev/null
+++ b/roles/node-network-manager/tasks/main.yml
@@ -0,0 +1,22 @@
+---
+- name: install NetworkManager
+ package:
+ name: NetworkManager
+ state: present
+
+- name: configure NetworkManager
+ lineinfile:
+ dest: "/etc/sysconfig/network-scripts/ifcfg-{{ ansible_default_ipv4['interface'] }}"
+ regexp: '^{{ item }}='
+ line: '{{ item }}=yes'
+ state: present
+ create: yes
+ with_items:
+ - 'USE_PEERDNS'
+ - 'NM_CONTROLLED'
+
+- name: enable and start NetworkManager
+ service:
+ name: NetworkManager
+ state: restarted
+ enabled: yes
diff --git a/roles/openshift-prep/defaults/main.yml b/roles/openshift-prep/defaults/main.yml
new file mode 100644
index 000000000..c8c9a00c0
--- /dev/null
+++ b/roles/openshift-prep/defaults/main.yml
@@ -0,0 +1,13 @@
+---
+# Defines either to install required packages and update all
+manage_packages: true
+install_debug_packages: false
+required_packages:
+ - wget
+ - git
+ - net-tools
+ - bind-utils
+ - bridge-utils
+debug_packages:
+ - bash-completion
+ - vim-enhanced
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..b7601aa48
--- /dev/null
+++ b/roles/openshift-prep/tasks/prerequisites.yml
@@ -0,0 +1,37 @@
+---
+- name: "Cleaning yum repositories"
+ command: "yum clean all"
+
+- name: "Install required packages"
+ yum:
+ name: "{{ item }}"
+ state: latest
+ with_items: "{{ required_packages }}"
+ when: manage_packages|bool
+
+- name: "Install debug packages (optional)"
+ yum:
+ name: "{{ item }}"
+ state: latest
+ with_items: "{{ debug_packages }}"
+ when: install_debug_packages|bool
+
+- name: "Update all packages (this can take a very long time)"
+ yum:
+ name: '*'
+ state: latest
+ when: manage_packages|bool
+
+- 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-create-cinder-registry/tasks/main.yaml b/roles/openstack-create-cinder-registry/tasks/main.yaml
new file mode 100644
index 000000000..6e9d1c2e7
--- /dev/null
+++ b/roles/openstack-create-cinder-registry/tasks/main.yaml
@@ -0,0 +1,5 @@
+---
+- os_volume:
+ display_name: "{{ cinder_hosted_registry_name }}"
+ size: "{{ cinder_hosted_registry_size_gb }}"
+ register: cinder_registry_volume
diff --git a/roles/openstack-stack/README.md b/roles/openstack-stack/README.md
new file mode 100644
index 000000000..32a2b49f1
--- /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 openshift-ansible-contrib/roles/openstack-stack/test/stack-create-test.yml
+```
diff --git a/roles/openstack-stack/defaults/main.yml b/roles/openstack-stack/defaults/main.yml
new file mode 100644
index 000000000..a24e684cc
--- /dev/null
+++ b/roles/openstack-stack/defaults/main.yml
@@ -0,0 +1,21 @@
+---
+
+stack_state: 'present'
+
+ssh_ingress_cidr: 0.0.0.0/0
+node_ingress_cidr: 0.0.0.0/0
+master_ingress_cidr: 0.0.0.0/0
+lb_ingress_cidr: 0.0.0.0/0
+bastion_ingress_cidr: 0.0.0.0/0
+num_etcd: 0
+num_masters: 1
+num_nodes: 1
+num_dns: 1
+num_infra: 1
+nodes_to_remove: []
+etcd_volume_size: 2
+dns_volume_size: 1
+lb_volume_size: 5
+use_bastion: False
+ui_ssh_tunnel: False
+provider_network: False
diff --git a/roles/openstack-stack/meta/main.yml b/roles/openstack-stack/meta/main.yml
new file mode 100644
index 000000000..fdda41bb3
--- /dev/null
+++ b/roles/openstack-stack/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - role: common
diff --git a/roles/openstack-stack/tasks/cleanup.yml b/roles/openstack-stack/tasks/cleanup.yml
new file mode 100644
index 000000000..258334a6b
--- /dev/null
+++ b/roles/openstack-stack/tasks/cleanup.yml
@@ -0,0 +1,6 @@
+---
+
+- name: cleanup temp files
+ file:
+ path: "{{ stack_template_pre.path }}"
+ state: absent
diff --git a/roles/openstack-stack/tasks/generate-templates.yml b/roles/openstack-stack/tasks/generate-templates.yml
new file mode 100644
index 000000000..0ff50a095
--- /dev/null
+++ b/roles/openstack-stack/tasks/generate-templates.yml
@@ -0,0 +1,26 @@
+---
+- name: create HOT stack template prefix
+ register: stack_template_pre
+ tempfile:
+ state: directory
+ prefix: openshift-ansible
+
+- name: set template paths
+ set_fact:
+ stack_template_path: "{{ stack_template_pre.path }}/stack.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: "{{ stack_template_pre.path }}/server.yaml"
+
+- name: generate user_data from jinja2 template
+ template:
+ src: user_data.j2
+ dest: "{{ user_data_template_path }}"
diff --git a/roles/openstack-stack/tasks/main.yml b/roles/openstack-stack/tasks/main.yml
new file mode 100644
index 000000000..983567026
--- /dev/null
+++ b/roles/openstack-stack/tasks/main.yml
@@ -0,0 +1,27 @@
+---
+
+- name: Generate the templates
+ include: generate-templates.yml
+ when:
+ - stack_state == 'present'
+
+- name: Handle the Stack (create/delete)
+ ignore_errors: False
+ register: stack_create
+ os_stack:
+ name: "{{ stack_name }}"
+ state: "{{ stack_state }}"
+ template: "{{ stack_template_path | default(omit) }}"
+ wait: yes
+
+# NOTE(bogdando) OS::Neutron::Subnet doesn't support live updates for
+# dns_nameservers, so we can't do that for the "create stack" task.
+- include: subnet_update_dns_servers.yaml
+ when:
+ - private_dns_server is defined
+ - stack_state == 'present'
+
+- name: CleanUp
+ include: cleanup.yml
+ when:
+ - stack_state == 'present'
diff --git a/roles/openstack-stack/tasks/subnet_update_dns_servers.yaml b/roles/openstack-stack/tasks/subnet_update_dns_servers.yaml
new file mode 100644
index 000000000..af28fc98f
--- /dev/null
+++ b/roles/openstack-stack/tasks/subnet_update_dns_servers.yaml
@@ -0,0 +1,9 @@
+---
+- name: Live update the subnet's DNS servers
+ os_subnet:
+ name: openshift-ansible-{{ stack_name }}-subnet
+ network_name: openshift-ansible-{{ stack_name }}-net
+ state: present
+ use_default_subnetpool: yes
+ dns_nameservers: "{{ [private_dns_server|default(public_dns_nameservers[0])]|union(public_dns_nameservers)|unique }}"
+ when: not provider_network
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..2359842a5
--- /dev/null
+++ b/roles/openstack-stack/templates/heat_stack.yaml.j2
@@ -0,0 +1,888 @@
+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 ] }
+
+{% if num_dns|int > 0 %}
+ dns_name:
+ description: Name of the DNS
+ value:
+ get_attr:
+ - dns
+ - name
+
+ dns_floating_ips:
+ description: Floating IPs of the DNS
+ value: { get_attr: [ dns, floating_ip ] }
+
+ dns_private_ips:
+ description: Private IPs of the DNS
+ value: { get_attr: [ dns, private_ip ] }
+{% endif %}
+
+conditions:
+ no_floating: {% if provider_network or use_bastion|bool %}true{% else %}false{% endif %}
+
+resources:
+
+{% if not provider_network %}
+ 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 %}
+
+{% if openshift_use_flannel|default(False)|bool %}
+ data_net:
+ type: OS::Neutron::Net
+ properties:
+ name: openshift-ansible-{{ stack_name }}-data-net
+ port_security_enabled: false
+
+ data_subnet:
+ type: OS::Neutron::Subnet
+ properties:
+ name: openshift-ansible-{{ stack_name }}-data-subnet
+ network: { get_resource: data_net }
+ cidr: {{ osm_cluster_network_cidr|default('10.128.0.0/14') }}
+ gateway_ip: null
+{% endif %}
+
+ 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 }
+
+{% endif %}
+
+# 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 }}
+
+ common-secgrp:
+ type: OS::Neutron::SecurityGroup
+ properties:
+ name:
+ str_replace:
+ template: openshift-ansible-cluster_id-common-secgrp
+ params:
+ cluster_id: {{ stack_name }}
+ description:
+ str_replace:
+ template: Basic ssh/icmp security group for cluster_id OpenShift 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 }}
+{% if use_bastion|bool %}
+ - direction: ingress
+ protocol: tcp
+ port_range_min: 22
+ port_range_max: 22
+ remote_ip_prefix: {{ bastion_ingress_cidr }}
+{% endif %}
+ - direction: ingress
+ protocol: icmp
+ remote_ip_prefix: {{ ssh_ingress_cidr }}
+
+{% if openstack_flat_secgrp|default(False)|bool %}
+ flat-secgrp:
+ type: OS::Neutron::SecurityGroup
+ properties:
+ name:
+ str_replace:
+ template: openshift-ansible-cluster_id-flat-secgrp
+ params:
+ cluster_id: {{ stack_name }}
+ description:
+ str_replace:
+ template: Security group for cluster_id OpenShift cluster
+ params:
+ cluster_id: {{ stack_name }}
+ rules:
+ - direction: ingress
+ protocol: tcp
+ port_range_min: 4001
+ port_range_max: 4001
+ - direction: ingress
+ protocol: tcp
+ port_range_min: {{ openshift_master_api_port|default(8443) }}
+ port_range_max: {{ openshift_master_api_port|default(8443) }}
+ - direction: ingress
+ protocol: tcp
+ port_range_min: {{ openshift_master_console_port|default(8443) }}
+ port_range_max: {{ openshift_master_console_port|default(8443) }}
+ - 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: 5405
+ - direction: ingress
+ protocol: tcp
+ port_range_min: 9090
+ port_range_max: 9090
+ - direction: ingress
+ protocol: tcp
+ port_range_min: 2379
+ port_range_max: 2380
+ remote_mode: remote_group_id
+ - direction: ingress
+ protocol: tcp
+ port_range_min: 10250
+ port_range_max: 10250
+ remote_mode: remote_group_id
+ - direction: ingress
+ protocol: udp
+ 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 }}
+ - direction: ingress
+ protocol: tcp
+ port_range_min: 30000
+ port_range_max: 32767
+ remote_ip_prefix: "{{ openstack_subnet_prefix }}.0/24"
+{% else %}
+ 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: 4001
+ port_range_max: 4001
+ - direction: ingress
+ protocol: tcp
+ port_range_min: {{ openshift_master_api_port|default(8443) }}
+ port_range_max: {{ openshift_master_api_port|default(8443) }}
+ - direction: ingress
+ protocol: tcp
+ port_range_min: {{ openshift_master_console_port|default(8443) }}
+ port_range_max: {{ openshift_master_console_port|default(8443) }}
+ - 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: 5405
+ - direction: ingress
+ protocol: tcp
+ port_range_min: 9090
+ port_range_max: 9090
+{% if openshift_use_flannel|default(False)|bool %}
+ - direction: ingress
+ protocol: tcp
+ port_range_min: 2379
+ port_range_max: 2379
+{% endif %}
+
+ 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: 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: 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 }}
+ - direction: ingress
+ protocol: tcp
+ port_range_min: 30000
+ port_range_max: 32767
+ remote_ip_prefix: "{{ openstack_subnet_prefix }}.0/24"
+{% endif %}
+
+ 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
+
+{% if num_dns|int > 0 %}
+ 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: udp
+ port_range_min: 53
+ port_range_max: 53
+ remote_ip_prefix: {{ node_ingress_cidr }}
+ - direction: ingress
+ protocol: udp
+ port_range_min: 53
+ port_range_max: 53
+ remote_ip_prefix: "{{ openstack_subnet_prefix }}.0/24"
+ - direction: ingress
+ protocol: tcp
+ 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: "{{ openstack_subnet_prefix }}.0/24"
+{% endif %}
+
+{% if num_masters|int > 1 or ui_ssh_tunnel|bool %}
+ lb-secgrp:
+ type: OS::Neutron::SecurityGroup
+ properties:
+ name: openshift-ansible-{{ stack_name }}-lb-secgrp
+ description: Security group for {{ stack_name }} cluster Load Balancer
+ rules:
+ - direction: ingress
+ protocol: tcp
+ port_range_min: {{ openshift_master_api_port | default(8443) }}
+ port_range_max: {{ openshift_master_api_port | default(8443) }}
+ remote_ip_prefix: {{ lb_ingress_cidr | default(bastion_ingress_cidr) }}
+{% if ui_ssh_tunnel|bool %}
+ - direction: ingress
+ protocol: tcp
+ port_range_min: {{ openshift_master_api_port | default(8443) }}
+ port_range_max: {{ openshift_master_api_port | default(8443) }}
+ remote_ip_prefix: {{ ssh_ingress_cidr }}
+{% endif %}
+{% if openshift_master_console_port is defined and openshift_master_console_port != openshift_master_api_port %}
+ - direction: ingress
+ protocol: tcp
+ port_range_min: {{ openshift_master_console_port | default(8443) }}
+ port_range_max: {{ openshift_master_console_port | default(8443) }}
+ remote_ip_prefix: {{ lb_ingress_cidr | default(bastion_ingress_cidr) }}
+{% endif %}
+{% endif %}
+
+ 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_hostname | default('etcd') }}
+ cluster_env: {{ public_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_etcd_image | default(openstack_image) }}
+ flavor: {{ etcd_flavor }}
+ key_name: {{ ssh_public_key }}
+{% if provider_network %}
+ net: {{ provider_network }}
+ net_name: {{ provider_network }}
+{% else %}
+ net: { get_resource: net }
+ subnet: { get_resource: subnet }
+ net_name:
+ str_replace:
+ template: openshift-ansible-cluster_id-net
+ params:
+ cluster_id: {{ stack_name }}
+{% endif %}
+ secgrp:
+ - { get_resource: {% if openstack_flat_secgrp|default(False)|bool %}flat-secgrp{% else %}etcd-secgrp{% endif %} }
+ - { get_resource: common-secgrp }
+ floating_network:
+ if:
+ - no_floating
+ - null
+ - {{ external_network }}
+{% if use_bastion|bool or provider_network %}
+ attach_float_net: false
+{% endif %}
+ volume_size: {{ etcd_volume_size }}
+{% if not provider_network %}
+ depends_on:
+ - interface
+{% endif %}
+
+{% if master_server_group_policies|length > 0 %}
+ master_server_group:
+ type: OS::Nova::ServerGroup
+ properties:
+ name: master_server_group
+ policies: {{ master_server_group_policies }}
+{% endif %}
+{% if infra_server_group_policies|length > 0 %}
+ infra_server_group:
+ type: OS::Nova::ServerGroup
+ properties:
+ name: infra_server_group
+ policies: {{ infra_server_group_policies }}
+{% endif %}
+{% if num_masters|int > 1 %}
+ loadbalancer:
+ type: OS::Heat::ResourceGroup
+ properties:
+ count: 1
+ resource_def:
+ type: server.yaml
+ properties:
+ name:
+ str_replace:
+ template: k8s_type-%index%.cluster_id
+ params:
+ cluster_id: {{ stack_name }}
+ k8s_type: {{ lb_hostname | default('lb') }}
+ cluster_env: {{ public_dns_domain }}
+ cluster_id: {{ stack_name }}
+ group:
+ str_replace:
+ template: k8s_type.cluster_id
+ params:
+ k8s_type: lb
+ cluster_id: {{ stack_name }}
+ type: lb
+ image: {{ openstack_lb_image | default(openstack_image) }}
+ flavor: {{ lb_flavor }}
+ key_name: {{ ssh_public_key }}
+{% if provider_network %}
+ net: {{ provider_network }}
+ net_name: {{ provider_network }}
+{% else %}
+ net: { get_resource: net }
+ subnet: { get_resource: subnet }
+ net_name:
+ str_replace:
+ template: openshift-ansible-cluster_id-net
+ params:
+ cluster_id: {{ stack_name }}
+{% endif %}
+ secgrp:
+ - { get_resource: lb-secgrp }
+ - { get_resource: common-secgrp }
+{% if not provider_network %}
+ floating_network: {{ external_network }}
+{% endif %}
+ volume_size: {{ lb_volume_size }}
+{% if not provider_network %}
+ depends_on:
+ - interface
+{% endif %}
+{% endif %}
+
+ 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_hostname | default('master')}}
+ cluster_env: {{ public_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_master_image | default(openstack_image) }}
+ flavor: {{ master_flavor }}
+ key_name: {{ ssh_public_key }}
+{% if provider_network %}
+ net: {{ provider_network }}
+ net_name: {{ provider_network }}
+{% else %}
+ net: { get_resource: net }
+ subnet: { get_resource: subnet }
+ net_name:
+ str_replace:
+ template: openshift-ansible-cluster_id-net
+ params:
+ cluster_id: {{ stack_name }}
+{% if openshift_use_flannel|default(False)|bool %}
+ attach_data_net: true
+ data_net: { get_resource: data_net }
+ data_subnet: { get_resource: data_subnet }
+{% endif %}
+{% endif %}
+ secgrp:
+{% if openstack_flat_secgrp|default(False)|bool %}
+ - { get_resource: flat-secgrp }
+{% else %}
+ - { get_resource: master-secgrp }
+ - { get_resource: node-secgrp }
+{% if num_etcd|int == 0 %}
+ - { get_resource: etcd-secgrp }
+{% endif %}
+{% endif %}
+ - { get_resource: common-secgrp }
+ floating_network:
+ if:
+ - no_floating
+ - null
+ - {{ external_network }}
+{% if use_bastion|bool or provider_network %}
+ attach_float_net: false
+{% endif %}
+ volume_size: {{ master_volume_size }}
+{% if master_server_group_policies|length > 0 %}
+ scheduler_hints:
+ group: { get_resource: master_server_group }
+{% endif %}
+{% if not provider_network %}
+ depends_on:
+ - interface
+{% endif %}
+
+ compute_nodes:
+ type: OS::Heat::ResourceGroup
+ properties:
+ count: {{ num_nodes }}
+ removal_policies:
+ - resource_list: {{ nodes_to_remove }}
+ resource_def:
+ type: server.yaml
+ properties:
+ name:
+ str_replace:
+ template: sub_type_k8s_type-%index%.cluster_id
+ params:
+ cluster_id: {{ stack_name }}
+ sub_type_k8s_type: {{ node_hostname | default('app-node') }}
+ cluster_env: {{ public_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:
+{% for k, v in openshift_cluster_node_labels.app.iteritems() %}
+ {{ k|e }}: {{ v|e }}
+{% endfor %}
+ image: {{ openstack_node_image | default(openstack_image) }}
+ flavor: {{ node_flavor }}
+ key_name: {{ ssh_public_key }}
+{% if provider_network %}
+ net: {{ provider_network }}
+ net_name: {{ provider_network }}
+{% else %}
+ net: { get_resource: net }
+ subnet: { get_resource: subnet }
+ net_name:
+ str_replace:
+ template: openshift-ansible-cluster_id-net
+ params:
+ cluster_id: {{ stack_name }}
+{% if openshift_use_flannel|default(False)|bool %}
+ attach_data_net: true
+ data_net: { get_resource: data_net }
+ data_subnet: { get_resource: data_subnet }
+{% endif %}
+{% endif %}
+ secgrp:
+ - { get_resource: {% if openstack_flat_secgrp|default(False)|bool %}flat-secgrp{% else %}node-secgrp{% endif %} }
+ - { get_resource: common-secgrp }
+ floating_network:
+ if:
+ - no_floating
+ - null
+ - {{ external_network }}
+{% if use_bastion|bool or provider_network %}
+ attach_float_net: false
+{% endif %}
+ volume_size: {{ node_volume_size }}
+{% if not provider_network %}
+ depends_on:
+ - interface
+{% endif %}
+
+ infra_nodes:
+ type: OS::Heat::ResourceGroup
+ properties:
+ count: {{ num_infra }}
+ resource_def:
+ type: server.yaml
+ properties:
+ name:
+ str_replace:
+ template: sub_type_k8s_type-%index%.cluster_id
+ params:
+ cluster_id: {{ stack_name }}
+ sub_type_k8s_type: {{ infra_hostname | default('infranode') }}
+ cluster_env: {{ public_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:
+{% for k, v in openshift_cluster_node_labels.infra.iteritems() %}
+ {{ k|e }}: {{ v|e }}
+{% endfor %}
+ image: {{ openstack_infra_image | default(openstack_image) }}
+ flavor: {{ infra_flavor }}
+ key_name: {{ ssh_public_key }}
+{% if provider_network %}
+ net: {{ provider_network }}
+ net_name: {{ provider_network }}
+{% else %}
+ net: { get_resource: net }
+ subnet: { get_resource: subnet }
+ net_name:
+ str_replace:
+ template: openshift-ansible-cluster_id-net
+ params:
+ cluster_id: {{ stack_name }}
+{% if openshift_use_flannel|default(False)|bool %}
+ attach_data_net: true
+ data_net: { get_resource: data_net }
+ data_subnet: { get_resource: data_subnet }
+{% endif %}
+{% endif %}
+ secgrp:
+# TODO(bogdando) filter only required node rules into infra-secgrp
+{% if openstack_flat_secgrp|default(False)|bool %}
+ - { get_resource: flat-secgrp }
+{% else %}
+ - { get_resource: node-secgrp }
+{% endif %}
+{% if ui_ssh_tunnel|bool and num_masters|int < 2 %}
+ - { get_resource: lb-secgrp }
+{% endif %}
+ - { get_resource: infra-secgrp }
+ - { get_resource: common-secgrp }
+{% if not provider_network %}
+ floating_network: {{ external_network }}
+{% endif %}
+ volume_size: {{ infra_volume_size }}
+{% if infra_server_group_policies|length > 0 %}
+ scheduler_hints:
+ group: { get_resource: infra_server_group }
+{% endif %}
+{% if not provider_network %}
+ depends_on:
+ - interface
+{% endif %}
+
+{% if num_dns|int > 0 %}
+ 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_hostname | default('dns') }}
+ cluster_env: {{ public_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_dns_image | default(openstack_image) }}
+ flavor: {{ dns_flavor }}
+ key_name: {{ ssh_public_key }}
+{% if provider_network %}
+ net: {{ provider_network }}
+ net_name: {{ provider_network }}
+{% else %}
+ net: { get_resource: net }
+ subnet: { get_resource: subnet }
+ net_name:
+ str_replace:
+ template: openshift-ansible-cluster_id-net
+ params:
+ cluster_id: {{ stack_name }}
+{% endif %}
+ secgrp:
+ - { get_resource: dns-secgrp }
+ - { get_resource: common-secgrp }
+{% if not provider_network %}
+ floating_network: {{ external_network }}
+{% endif %}
+ volume_size: {{ dns_volume_size }}
+{% if not provider_network %}
+ depends_on:
+ - interface
+{% endif %}
+{% endif %}
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..9ffe721a5
--- /dev/null
+++ b/roles/openstack-stack/templates/heat_stack_server.yaml.j2
@@ -0,0 +1,270 @@
+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
+
+{% if not provider_network %}
+ subnet:
+ type: string
+ label: Subnet ID
+ description: Subnet resource
+{% endif %}
+
+{% if openshift_use_flannel|default(False)|bool %}
+ attach_data_net:
+ type: boolean
+ default: false
+ label: Attach-data-net
+ description: A switch for data port connection
+
+ data_net:
+ type: string
+ default: ''
+ label: Net ID
+ description: Net resource
+
+{% if not provider_network %}
+ data_subnet:
+ type: string
+ default: ''
+ label: Subnet ID
+ description: Subnet resource
+{% endif %}
+{% endif %}
+
+ secgrp:
+ type: comma_delimited_list
+ label: Security groups
+ description: Security group resources
+
+ attach_float_net:
+ type: boolean
+ default: true
+
+ label: Attach-float-net
+ description: A switch for floating network port connection
+
+{% if not provider_network %}
+ floating_network:
+ type: string
+ default: ''
+ label: Floating network
+ description: Network to allocate floating IP from
+{% endif %}
+
+ 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" }
+
+ scheduler_hints:
+ type: json
+ description: Server scheduler hints.
+ 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 }
+{% if provider_network %}
+ - 0
+{% else %}
+ - 1
+{% endif %}
+ - addr
+
+conditions:
+ no_floating: {not: { get_param: attach_float_net} }
+{% if openshift_use_flannel|default(False)|bool %}
+ no_data_subnet: {not: { get_param: attach_data_net} }
+{% endif %}
+
+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:
+{% if openshift_use_flannel|default(False)|bool %}
+ if:
+ - no_data_subnet
+{% if use_trunk_ports|default(false)|bool %}
+ - - port: { get_attr: [trunk-port, port_id] }
+{% else %}
+ - - port: { get_resource: port }
+{% endif %}
+{% if use_trunk_ports|default(false)|bool %}
+ - - port: { get_attr: [trunk-port, port_id] }
+{% else %}
+ - - port: { get_resource: port }
+ - port: { get_resource: data_port }
+{% endif %}
+
+{% else %}
+{% if use_trunk_ports|default(false)|bool %}
+ - port: { get_attr: [trunk-port, port_id] }
+{% else %}
+ - port: { get_resource: port }
+{% endif %}
+{% endif %}
+ user_data:
+ get_file: user-data
+ user_data_format: RAW
+ user_data_update_policy: IGNORE
+ 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 }
+ scheduler_hints: { get_param: scheduler_hints }
+
+{% if use_trunk_ports|default(false)|bool %}
+ trunk-port:
+ type: OS::Neutron::Trunk
+ properties:
+ name: { get_param: name }
+ port: { get_resource: port }
+{% endif %}
+
+ port:
+ type: OS::Neutron::Port
+ properties:
+ network: { get_param: net }
+{% if not provider_network %}
+ fixed_ips:
+ - subnet: { get_param: subnet }
+{% endif %}
+ security_groups: { get_param: secgrp }
+
+{% if openshift_use_flannel|default(False)|bool %}
+ data_port:
+ type: OS::Neutron::Port
+ condition: { not: no_data_subnet }
+ properties:
+ network: { get_param: data_net }
+ port_security_enabled: false
+{% if not provider_network %}
+ fixed_ips:
+ - subnet: { get_param: data_subnet }
+{% endif %}
+{% endif %}
+
+{% if not provider_network %}
+ floating-ip:
+ condition: { not: no_floating }
+ type: OS::Neutron::FloatingIP
+ properties:
+ floating_network: { get_param: floating_network }
+ port_id: { get_resource: port }
+{% endif %}
+
+{% if not ephemeral_volumes|default(false)|bool %}
+ 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
+{% endif %}
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
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..d80472193
--- /dev/null
+++ b/roles/openstack-stack/test/stack-create-test.yml
@@ -0,0 +1,18 @@
+---
+- hosts: localhost
+ gather_facts: True
+ become: False
+ roles:
+ - role: openstack-stack
+ stack_name: test-stack
+ dns_domain: "{{ public_dns_domain }}"
+ dns_nameservers: "{{ public_dns_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 }}"
diff --git a/roles/static_inventory/defaults/main.yml b/roles/static_inventory/defaults/main.yml
new file mode 100644
index 000000000..871700f8c
--- /dev/null
+++ b/roles/static_inventory/defaults/main.yml
@@ -0,0 +1,29 @@
+---
+# Either to checkpoint the dynamic inventory into a static one
+refresh_inventory: True
+inventory: static
+inventory_path: ~/openstack-inventory
+
+# Either to configure bastion
+use_bastion: true
+
+# SSH user/key/options to access hosts via bastion
+ssh_user: openshift
+ssh_options: >-
+ -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no
+ -o ConnectTimeout=90 -o ControlMaster=auto -o ControlPersist=270s
+ -o ServerAliveInterval=30 -o GSSAPIAuthentication=no
+
+# SSH key to access nodes
+private_ssh_key: ~/.ssh/openshift
+
+# The patch to store the generated config to access bastion/hosts
+ssh_config_path: /tmp/ssh.config.ansible
+
+# The IP:port to make an SSH tunnel to access UI on the 1st master
+# via bastion node (requires sudo on the ansible control node)
+ui_ssh_tunnel: False
+ui_port: "{{ openshift_master_api_port | default(8443) }}"
+target_ip: "{{ hostvars[groups['masters.' + stack_name|quote][0]].private_v4 }}"
+
+openstack_private_network: private
diff --git a/roles/static_inventory/meta/main.yml b/roles/static_inventory/meta/main.yml
new file mode 100644
index 000000000..fdda41bb3
--- /dev/null
+++ b/roles/static_inventory/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - role: common
diff --git a/roles/static_inventory/tasks/checkpoint.yml b/roles/static_inventory/tasks/checkpoint.yml
new file mode 100644
index 000000000..c0365bd3d
--- /dev/null
+++ b/roles/static_inventory/tasks/checkpoint.yml
@@ -0,0 +1,17 @@
+---
+- name: check for static inventory dir
+ stat:
+ path: "{{ inventory_path }}"
+ register: stat_inventory_path
+
+- name: create static inventory dir
+ file:
+ path: "{{ inventory_path }}"
+ state: directory
+ mode: 0750
+ when: not stat_inventory_path.stat.exists
+
+- name: create inventory from template
+ template:
+ src: inventory.j2
+ dest: "{{ inventory_path }}/hosts"
diff --git a/roles/static_inventory/tasks/filter_out_new_app_nodes.yaml b/roles/static_inventory/tasks/filter_out_new_app_nodes.yaml
new file mode 100644
index 000000000..826efe78d
--- /dev/null
+++ b/roles/static_inventory/tasks/filter_out_new_app_nodes.yaml
@@ -0,0 +1,15 @@
+---
+- name: Add all new app nodes to new_app_nodes
+ when:
+ - 'oc_old_app_nodes is defined'
+ - 'oc_old_app_nodes | list'
+ - 'node.name not in oc_old_app_nodes'
+ - 'node["metadata"]["sub-host-type"] == "app"'
+ register: result
+ set_fact:
+ new_app_nodes: '{{ new_app_nodes }} + [ {{ node }} ]'
+
+- name: If the node was added to new_nodes, remove it from registered nodes
+ set_fact:
+ registered_nodes: '{{ registered_nodes | difference([ node ]) }}'
+ when: 'not result | skipped'
diff --git a/roles/static_inventory/tasks/main.yml b/roles/static_inventory/tasks/main.yml
new file mode 100644
index 000000000..3dab62df2
--- /dev/null
+++ b/roles/static_inventory/tasks/main.yml
@@ -0,0 +1,25 @@
+---
+- name: Remove any existing inventory
+ file:
+ path: "{{ inventory_path }}/hosts"
+ state: absent
+
+- name: Refresh the inventory
+ meta: refresh_inventory
+
+- name: Generate in-memory inventory
+ include: openstack.yml
+
+- name: Checkpoint in-memory data into a static inventory
+ include: checkpoint.yml
+
+- name: Generate SSH config for accessing hosts via bastion
+ include: sshconfig.yml
+ when: use_bastion|bool
+
+- name: Configure SSH tunneling to access UI
+ include: sshtun.yml
+ become: true
+ when:
+ - use_bastion|bool
+ - ui_ssh_tunnel|bool
diff --git a/roles/static_inventory/tasks/openstack.yml b/roles/static_inventory/tasks/openstack.yml
new file mode 100644
index 000000000..adf78c966
--- /dev/null
+++ b/roles/static_inventory/tasks/openstack.yml
@@ -0,0 +1,120 @@
+---
+- no_log: true
+ block:
+ - name: fetch all nodes from openstack shade dynamic inventory
+ command: shade-inventory --list
+ register: registered_nodes_output
+ when: refresh_inventory|bool
+
+ - name: set fact for openstack inventory cluster nodes
+ set_fact:
+ registered_nodes: "{{ (registered_nodes_output.stdout | from_json) | json_query(q) }}"
+ vars:
+ q: "[] | [?metadata.clusterid=='{{stack_name}}']"
+ when:
+ - refresh_inventory|bool
+
+ - name: set_fact for openstack inventory nodes
+ set_fact:
+ registered_bastion_nodes: "{{ (registered_nodes_output.stdout | from_json) | json_query(q) }}"
+ registered_nodes_floating: "{{ (registered_nodes_output.stdout | from_json) | json_query(q2) }}"
+ vars:
+ q: "[] | [?metadata.group=='infra.{{stack_name}}']"
+ q2: "[] | [?metadata.clusterid=='{{stack_name}}'] | [?public_v4!='']"
+ when:
+ - refresh_inventory|bool
+
+ - name: set_fact for openstack inventory nodes with provider network
+ set_fact:
+ registered_nodes_floating: "{{ (registered_nodes_output.stdout | from_json) | json_query(q) }}"
+ vars:
+ q: "[] | [?metadata.clusterid=='{{stack_name}}'] | [?public_v4=='']"
+ when:
+ - refresh_inventory|bool
+ - openstack_provider_network_name|default(None)
+
+ - name: Add cluster nodes w/o floating IPs to inventory
+ with_items: "{{ registered_nodes|difference(registered_nodes_floating) }}"
+ add_host:
+ name: '{{ item.name }}'
+ ansible_host: >-
+ {% if use_bastion|bool -%}
+ {{ item.name }}
+ {%- else -%}
+ {%- set node = registered_nodes | json_query("[?name=='" + item.name + "']") -%}
+ {{ node[0].addresses[openstack_private_network|quote][0].addr }}
+ {%- endif %}
+ ansible_fqdn: '{{ item.name }}'
+ ansible_user: '{{ ssh_user }}'
+ ansible_private_key_file: '{{ private_ssh_key }}'
+ ansible_ssh_extra_args: '-F {{ ssh_config_path }}'
+ private_v4: >-
+ {% set node = registered_nodes | json_query("[?name=='" + item.name + "']") -%}
+ {{ node[0].addresses[openstack_private_network|quote][0].addr }}
+
+ - name: Add cluster nodes with floating IPs to inventory
+ with_items: "{{ registered_nodes_floating }}"
+ add_host:
+ name: '{{ item.name }}'
+ ansible_host: >-
+ {% if use_bastion|bool -%}
+ {{ item.name }}
+ {%- elif openstack_provider_network_name|default(None) -%}
+ {{ item.private_v4 }}
+ {%- else -%}
+ {{ item.public_v4 }}
+ {%- endif %}
+ ansible_fqdn: '{{ item.name }}'
+ ansible_user: '{{ ssh_user }}'
+ ansible_private_key_file: '{{ private_ssh_key }}'
+ ansible_ssh_extra_args: '-F {{ ssh_config_path }}'
+ private_v4: >-
+ {% set node = registered_nodes | json_query("[?name=='" + item.name + "']") -%}
+ {{ node[0].addresses[openstack_private_network|quote][0].addr }}
+ public_v4: >-
+ {% if openstack_provider_network_name|default(None) -%}
+ {{ item.private_v4 }}
+ {%- else -%}
+ {{ item.public_v4 }}
+ {%- endif %}
+
+ # Split registered_nodes into old nodes and new app nodes
+ # Add new app nodes to new_nodes host group for upscaling
+ - name: Create new_app_nodes variable
+ set_fact:
+ new_app_nodes: []
+
+ - name: Filter new app nodes out of registered_nodes
+ include: filter_out_new_app_nodes.yaml
+ with_items: "{{ registered_nodes }}"
+ loop_control:
+ loop_var: node
+
+ - name: Add new app nodes to the new_nodes section (if a deployment already exists)
+ with_items: "{{ new_app_nodes }}"
+ add_host:
+ name: "{{ item.name }}"
+ groups: new_nodes, app
+
+ - name: Add the rest of cluster nodes to their corresponding groups
+ with_items: "{{ registered_nodes }}"
+ add_host:
+ name: '{{ item.name }}'
+ groups: '{{ item.metadata.group }}'
+
+ - name: Add bastion node to inventory
+ add_host:
+ name: bastion
+ groups: bastions
+ ansible_host: '{{ registered_bastion_nodes[0].public_v4 }}'
+ ansible_fqdn: '{{ registered_bastion_nodes[0].name }}'
+ ansible_user: '{{ ssh_user }}'
+ ansible_private_key_file: '{{ private_ssh_key }}'
+ ansible_ssh_extra_args: '-F {{ ssh_config_path }}'
+ private_v4: >-
+ {% set node = registered_nodes | json_query("[?name=='" + registered_bastion_nodes[0].name + "']") -%}
+ {{ node[0].addresses[openstack_private_network|quote][0].addr }}
+ public_v4: '{{ registered_bastion_nodes[0].public_v4 }}'
+ when:
+ - registered_bastion_nodes is defined
+ - use_bastion|bool
diff --git a/roles/static_inventory/tasks/sshconfig.yml b/roles/static_inventory/tasks/sshconfig.yml
new file mode 100644
index 000000000..7119fe6ff
--- /dev/null
+++ b/roles/static_inventory/tasks/sshconfig.yml
@@ -0,0 +1,13 @@
+---
+- name: set ssh proxy command prefix for accessing nodes via bastion
+ set_fact:
+ ssh_proxy_command: >-
+ ssh {{ ssh_options }}
+ -i {{ private_ssh_key }}
+ {{ ssh_user }}@{{ hostvars['bastion'].ansible_host }}
+
+- name: regenerate ssh config
+ template:
+ src: openstack_ssh_config.j2
+ dest: "{{ ssh_config_path }}"
+ mode: 0644
diff --git a/roles/static_inventory/tasks/sshtun.yml b/roles/static_inventory/tasks/sshtun.yml
new file mode 100644
index 000000000..b0e4c832c
--- /dev/null
+++ b/roles/static_inventory/tasks/sshtun.yml
@@ -0,0 +1,15 @@
+---
+- name: Create ssh tunnel systemd service
+ template:
+ src: ssh-tunnel.service.j2
+ dest: /etc/systemd/system/ssh-tunnel.service
+ mode: 0644
+
+- name: reload the systemctl daemon after file update
+ command: systemctl daemon-reload
+
+- name: Enable ssh tunnel service
+ service:
+ name: ssh-tunnel
+ enabled: true
+ state: restarted
diff --git a/roles/static_inventory/templates/inventory.j2 b/roles/static_inventory/templates/inventory.j2
new file mode 100644
index 000000000..9dfbe3a5b
--- /dev/null
+++ b/roles/static_inventory/templates/inventory.j2
@@ -0,0 +1,104 @@
+# BEGIN Autogenerated hosts
+{% for host in groups['all'] %}
+{% if hostvars[host].get('ansible_connection', '') == 'local' %}
+{{ host }} ansible_connection=local
+{% else %}
+
+{{ host }}{% if 'ansible_host' in hostvars[host]
+%} ansible_host={{ hostvars[host]['ansible_host'] }}{% endif %}
+{% if 'private_v4' in hostvars[host]
+%} private_v4={{ hostvars[host]['private_v4'] }}{% endif %}
+{% if 'public_v4' in hostvars[host]
+%} public_v4={{ hostvars[host]['public_v4'] }}{% endif %}
+{% if 'ansible_user' in hostvars[host]
+%} ansible_user={{ hostvars[host]['ansible_user'] }}{% endif %}
+{% if 'ansible_private_key_file' in hostvars[host] and hostvars[host]['ansible_private_key_file']
+%} ansible_private_key_file={{ hostvars[host]['ansible_private_key_file'] }}{% endif %}
+{% if use_bastion|bool and 'ansible_ssh_extra_args' in hostvars[host]
+%} ansible_ssh_extra_args={{ hostvars[host]['ansible_ssh_extra_args']|quote }}{% endif %} openshift_hostname={{ host }}
+
+{% endif %}
+{% endfor %}
+# END autogenerated hosts
+
+#[all:vars]
+# For all group_vars, see ./group_vars/all.yml
+[infra_hosts:vars]
+openshift_node_labels={{ openshift_cluster_node_labels.infra | to_json | quote }}
+
+[app:vars]
+openshift_node_labels={{ openshift_cluster_node_labels.app | to_json | quote }}
+
+# Create an OSEv3 group that contains the master, nodes, etcd, and lb groups.
+# The lb group lets Ansible configure HAProxy as the load balancing solution.
+# Comment lb out if your load balancer is pre-configured.
+[cluster_hosts:children]
+OSEv3
+dns
+
+[OSEv3:children]
+nodes
+etcd
+lb
+new_nodes
+
+# Set variables common for all OSEv3 hosts
+[OSEv3:vars]
+
+# For OSEv3 normal group vars, see ./group_vars/OSEv3.yml
+
+{% if cinder_registry_volume is defined and 'volume' in cinder_registry_volume %}
+openshift_hosted_registry_storage_openstack_volumeID="{{ cinder_registry_volume.id }}"
+openshift_hosted_registry_storage_volume_size="{{ cinder_registry_volume.volume.size }}Gi"
+{% endif %}
+
+
+# Host Groups
+
+[masters:children]
+masters.{{ stack_name }}
+
+[etcd:children]
+etcd.{{ stack_name }}
+{% if 'etcd' not in groups or groups['etcd']|length == 0 %}masters.{{ stack_name }}{% endif %}
+
+[nodes:children]
+masters
+infra.{{ stack_name }}
+nodes.{{ stack_name }}
+
+[infra_hosts:children]
+infra.{{ stack_name }}
+
+[app:children]
+nodes.{{ stack_name }}
+
+[dns:children]
+dns.{{ stack_name }}
+
+[lb:children]
+lb.{{ stack_name }}
+
+[new_nodes:children]
+
+# Empty placeholders for all groups of the cluster nodes
+[masters.{{ stack_name }}]
+[etcd.{{ stack_name }}]
+[infra.{{ stack_name }}]
+[nodes.{{ stack_name }}]
+[app.{{ stack_name }}]
+[dns.{{ stack_name }}]
+[lb.{{ stack_name }}]
+[new_nodes.{{ stack_name }}]
+
+# BEGIN Autogenerated groups
+{% for group in groups %}
+{% if group not in ['ungrouped', 'all'] %}
+[{{ group }}]
+{% for host in groups[group] %}
+{{ host }}
+{% endfor %}
+
+{% endif %}
+{% endfor %}
+# END Autogenerated groups
diff --git a/roles/static_inventory/templates/openstack_ssh_config.j2 b/roles/static_inventory/templates/openstack_ssh_config.j2
new file mode 100644
index 000000000..ad5d1253a
--- /dev/null
+++ b/roles/static_inventory/templates/openstack_ssh_config.j2
@@ -0,0 +1,21 @@
+Host *
+ IdentitiesOnly yes
+
+Host bastion
+ Hostname {{ hostvars['bastion'].ansible_host }}
+ IdentityFile {{ hostvars['bastion'].ansible_private_key_file }}
+ User {{ ssh_user }}
+ StrictHostKeyChecking no
+ UserKnownHostsFile=/dev/null
+
+{% for host in groups['all'] | difference(groups['bastions'][0]) %}
+
+Host {{ host }}
+ Hostname {{ hostvars[host].ansible_host }}
+ ProxyCommand {{ ssh_proxy_command }} -W {{ hostvars[host].private_v4 }}:22
+ IdentityFile {{ hostvars[host].ansible_private_key_file }}
+ User {{ ssh_user }}
+ StrictHostKeyChecking no
+ UserKnownHostsFile=/dev/null
+
+{% endfor %}
diff --git a/roles/static_inventory/templates/ssh-tunnel.service.j2 b/roles/static_inventory/templates/ssh-tunnel.service.j2
new file mode 100644
index 000000000..0d1cf8f79
--- /dev/null
+++ b/roles/static_inventory/templates/ssh-tunnel.service.j2
@@ -0,0 +1,20 @@
+[Unit]
+Description=Set up ssh tunneling for OpenShift cluster UI
+After=network.target
+
+[Service]
+ExecStart=/usr/bin/ssh -NT -o \
+ ServerAliveInterval=60 -o \
+ UserKnownHostsFile=/dev/null -o \
+ StrictHostKeyChecking=no -o \
+ ExitOnForwardFailure=no -i \
+ {{ private_ssh_key }} {{ ssh_user }}@{{ hostvars['bastion'].ansible_host }} \
+ -L 0.0.0.0:{{ ui_port }}:{{ target_ip }}:{{ ui_port }}
+
+
+# Restart every >2 seconds to avoid StartLimitInterval failure
+RestartSec=5
+Restart=always
+
+[Install]
+WantedBy=multi-user.target
diff --git a/roles/subscription-manager/README.md b/roles/subscription-manager/README.md
new file mode 100644
index 000000000..748de282c
--- /dev/null
+++ b/roles/subscription-manager/README.md
@@ -0,0 +1,156 @@
+# Red Hat Subscription Manager Ansible Role
+
+## Parameters
+
+This role depends on user specified variables. These can be set in the inventory file, group_vars or passed to the playbook from the CLI. No values are set by default which disables this role. The variables are:
+
+### rhsm_satellite
+
+Subscription Manager server hostname. If using a Satellite server set the FQDN here. If using RHSM Hosted this value must be left blank, none or false.
+
+Default: none
+
+### rhsm_username
+
+Subscription Manager username. Required for RHSM Hosted. Can be optionally used for Satellite, but it may be better to use **rhsm_activationkey** for this.
+
+Default: none
+
+### rhsm_password
+
+Subscription Manager password. Required for RHSM Hosted. Can be optionally used for Satellite, but it may be better to use **rhsm_activationkey** for this.
+
+NOTE: If this variable is specified on the command-line or set in a variable file it may leave your password exposed. For this reason you may perfer to use an Activation Key if using Satellite. For RHSM Hosted, your password must be specified. There are two ways to provide the password to the Ansible playbook without exposing it to prying eyes.
+
+1. The first method is to use a **vars_prompt** to collect the password up front one time for the playbook. Ansible will not display the password if the prompt is configured as **private** and the task will not display the password on the CLI. This is the a good method as it supports automating the task to every host with only one password entry. To enable **vars_prompt** add the following to the very top of your playbook after the **hosts** declaration and before any **pre_tasks** section:
+
+ ```
+ - hosts: localhost
+ # Add the following lines after a -hosts: declaration and before pre_tasks:
+ # Start of vars_prompt code block
+ vars_prompt:
+ - name: "rhsm_password"
+ prompt: "Subscription Manager password"
+ confirm: yes
+ private: yes
+ # End of vars_prompt code block
+ pre_tasks:
+ ```
+
+2. A second method is to use an encrypted file via **ansible-vault**. This does does not require modifying any code as the previous method, but does require more work to create and encrypt the file. To accomplish this, first create a file containing at least the **rhsm_password** variable (it is also possible to specify additional variables to encrypt them all as well):
+ 1. Create a file to contain the variable such as **secrets.yml**:
+
+ ```
+ ---
+ rhsm_password: "my_secret_password"
+ # other variables can optionally be placed here as well
+ ```
+
+ 2. Encrypt the file with **ansible-vault**:
+
+ ```
+ $ ansible-vault encrypt secrets.yml
+ Vault password:
+ Confirm Vault password:
+ Encryption successful
+ ```
+
+ 3. When executing **ansible-playbook** specify **--ask-vault-pass** to be prompted for the decryption password, and also specify the location of the **secrets.yml** as such:
+
+ ```
+ $ ansible-playbook --ask-vault-pass --extra-vars=@secrets.yml --extra-vars="rhsm_username=myusername" <other playbook options>
+ ```
+
+ NOTE: Optionally the file containing the encrypted variables can be decrypted with **ansible-vault** and the **--ask-vault-pass** option omitted to prevent any password prompting (for automated runs) and the file can be encrypted after the run. This can be used if an external system such as Jenkins would handle the decryption/encryption outside of Ansible.
+
+Default: none
+
+### rhsm_org
+
+Optional Subscription Manager Satellite Organization. Required for Satellite, ignored if using RHSM Hosted.
+
+Default: none
+
+### rhsm_activationkey
+
+Optional Subscription Manager Satellite Activation Key, use this instead of **rhsm_username** and **rhsm_password** if using Satellite to provide repositories and authentication in a key instead.
+
+Default: none
+
+### rhsm_pool
+
+Optional Subscription Manager pool, determine this by running **subscription-manager list --available** on a registered system. Valid for RHSM Hosted or Satellite. Specifying **rhsm_activationkey** will ignore this option.
+
+Default: none
+
+### rhsm_repos
+
+Optional list of repositories to enable. If left blank it is expected that the **rhsm_activationkey** will specify repos instead. If populated, a **subscription-manager repos --disable=\*** will be run and each of the specified repos explicitly enabled. Valid for RHSM Hosted or Satellite
+
+NOTE: If specifying this value in an inventory file as opposed to group_vars, be sure to define it as a proper list as such:
+
+rhsm_repos='["rhel-7-server-rpms", "rhel-7-server-ose-3.1-rpms", "rhel-7-server-extras-rpms"]'
+
+Default: none
+
+## Calling This Role
+Calling this role is done at both **pre_tasks** and **roles** sections of a playbook and optionally a **vars_prompt**.
+
+### vars_prompt
+Unfortunately **vars_prompt** can only be used at the play level before role tasks are executed, so this is the only place it can go. It also cannot be shown conditionally. For this reason it is not included in this role by default. A better method may be using a file containing the password variable encrypted with **ansible-vault**. See the **rhsm_password** section for more details.
+
+To Add a prompt to capture **rhsm_password**:
+
+```
+- hosts: localhost
+ # Add the following lines after a -hosts: declaration and before pre_tasks:
+ # Start of vars_prompt code block
+ vars_prompt:
+ - name: "rhsm_password"
+ prompt: "Subscription Manager password"
+ confirm: yes
+ private: yes
+ # End of vars_prompt code block
+ pre_tasks:
+```
+
+### pre-tasks
+
+A number of variable checks are performed before any tasks to ensure the proper parameters are set. To include these checks call the pre_task yaml before any roles:
+
+```
+pre_tasks:
+- include: roles/subscription-manager/pre_tasks/pre_tasks.yml
+```
+
+### roles
+
+The bulk of the work is performed in the main.yml for this role. The pre-task play will set a variable which can be checked to contitionally include this role as such:
+
+```
+roles:
+ - { role: subscription-manager, when: hostvars.localhost.rhsm_register, tags: 'subscription-manager' }
+```
+
+## Running Playbooks with this Role
+
+- To register to RHSM Hosted or Satellite with a username and plain text password (NOTE: This may retain your password in your CLI history):
+
+ ```
+ $ ansible-playbook --extra-vars="rhsm_username=vvaldez rhsm_password=my_secret_password <other playbook otions>"
+ ```
+
+- To register to RHSM Hosted or Satellite with username and an encrypted file containing the password:
+
+ ```
+ $ ansible-playbook --ask-vault-pass --extra-vars=@secrets.yml --extra-vars="rhsm_username=myusername" <other playbook options>
+
+ ```
+
+- To register to a Satellite server with an activation key:
+
+ ```
+ $ ansible-playbook --extra-vars="rhsm_satellite=satellite.example.com rhsm_org=example_org rhsm_activationkey=rhel-7-ose-3-1 <other playbook options>"
+
+ ```
+- To ignore any Subscription Manager activities, simply do not set any parameters.
diff --git a/roles/subscription-manager/pre_tasks/pre_tasks.yml b/roles/subscription-manager/pre_tasks/pre_tasks.yml
new file mode 100644
index 000000000..464670fc0
--- /dev/null
+++ b/roles/subscription-manager/pre_tasks/pre_tasks.yml
@@ -0,0 +1,45 @@
+---
+- name: "Set password fact"
+ set_fact:
+ rhsm_password: "{{ rhsm_password | default(None) }}"
+ no_log: true
+
+- name: "Initialize Subscription Manager fact"
+ set_fact:
+ rhsm_register: true
+
+- name: "Determine if Subscription Manager should be used"
+ set_fact:
+ rhsm_register: false
+ when:
+ - rhsm_satellite is undefined or rhsm_satellite is none or rhsm_satellite|trim == ''
+ - rhsm_username is undefined or rhsm_username is none or rhsm_username|trim == ''
+ - rhsm_password is undefined or rhsm_password is none or rhsm_password|trim == ''
+ - rhsm_org is undefined or rhsm_org is none or rhsm_org|trim == ''
+ - rhsm_activationkey is undefined or rhsm_activationkey is none or rhsm_activationkey|trim == ''
+ - rhsm_pool is undefined or rhsm_pool is none or rhsm_pool|trim == ''
+
+- name: "Validate Subscription Manager organization is set"
+ fail: msg="Cannot register to a Satellite server without a value for the Organization via 'rhsm_org'"
+ when:
+ - rhsm_org is undefined or rhsm_org is none or rhsm_org|trim == ''
+ - rhsm_satellite is defined
+ - rhsm_satellite is not none
+ - rhsm_satellite|trim != ''
+ - rhsm_register
+
+- name: "Validate Subscription Manager authentication is defined"
+ fail: msg="Cannot register without ('rhsm_username' and 'rhsm_password') or 'rhsm_activationkey' variables set. See the README.md for details on securely prompting for a password"
+ when:
+ - (rhsm_username is undefined or rhsm_username is none or rhsm_username|trim == '') or (rhsm_password is undefined or rhsm_password is none or rhsm_password|trim == '')
+ - rhsm_activationkey is undefined or rhsm_activationkey is none or rhsm_activationkey|trim == ''
+ - rhsm_register
+
+- name: "Validate activation key and Hosted are not requested together"
+ fail: msg="Cannot register to RHSM Hosted with 'rhsm_activationkey'"
+ when:
+ - rhsm_satellite is undefined or rhsm_satellite is none or rhsm_satellite|trim == ''
+ - rhsm_activationkey is defined
+ - rhsm_activationkey is not none
+ - rhsm_activationkey|trim != ''
+ - rhsm_register
diff --git a/roles/subscription-manager/tasks/main.yml b/roles/subscription-manager/tasks/main.yml
new file mode 100644
index 000000000..e4c9fdffb
--- /dev/null
+++ b/roles/subscription-manager/tasks/main.yml
@@ -0,0 +1,150 @@
+---
+- name: "Initialize rhsm_password variable if vars_prompt was used"
+ set_fact:
+ rhsm_password: "{{ hostvars.localhost.rhsm_password }}"
+ when:
+ - rhsm_password is not defined or rhsm_password is none or rhsm_password|trim == ''
+
+- name: "Initializing Subscription Manager authentication method"
+ set_fact:
+ rhsm_authentication: false
+
+# 'rhsm_activationkey' will take precedence even if 'rhsm_username' and 'rhsm_password' are also set
+- name: "Setting Subscription Manager Activation Key Fact"
+ set_fact:
+ rhsm_authentication: "key"
+ when:
+ - rhsm_activationkey is defined
+ - rhsm_activationkey is not none
+ - rhsm_activationkey|trim != ''
+ - not rhsm_authentication
+
+# If 'rhsm_username' and 'rhsm_password' are set but not 'rhsm_activationkey', set 'rhsm_authentication' to password
+- name: "Setting Subscription Manager Username and Password Fact"
+ set_fact:
+ rhsm_authentication: "password"
+ when:
+ - rhsm_username is defined
+ - rhsm_username is not none
+ - rhsm_username|trim != ''
+ - rhsm_password is defined
+ - rhsm_password is not none
+ - rhsm_password|trim != ''
+ - not rhsm_authentication
+
+- name: "Initializing registration status"
+ set_fact:
+ registered: false
+
+- name: "Checking subscription status (a failure means it is not registered and will be)"
+ command: "/usr/bin/subscription-manager status"
+ ignore_errors: yes
+ changed_when: no
+ register: check_if_registered
+
+- name: "Set registration fact if system is already registered"
+ set_fact:
+ registered: true
+ when: check_if_registered.rc == 0
+
+- name: "Cleaning any old subscriptions"
+ command: "/usr/bin/subscription-manager clean"
+ when:
+ - not registered
+ - rhsm_authentication is defined
+ register: cleaningsubs_result
+ until: cleaningsubs_result.rc == 0
+ retries: 10
+ delay: 1
+
+- name: "Install Satellite certificate"
+ command: "rpm -Uvh --force http://{{ rhsm_satellite }}/pub/katello-ca-consumer-latest.noarch.rpm"
+ when:
+ - not registered
+ - rhsm_satellite is defined
+ - rhsm_satellite is not none
+ - rhsm_satellite|trim != ''
+
+- name: "Register to Satellite using activation key"
+ command: "/usr/bin/subscription-manager register --activationkey={{ rhsm_activationkey }} --org='{{ rhsm_org }}'"
+ when:
+ - not registered
+ - rhsm_authentication == 'key'
+ - rhsm_satellite is defined
+ - rhsm_satellite is not none
+ - rhsm_satellite|trim != ''
+ register: register_key_result
+ until: register_key_result.rc == 0
+ retries: 10
+ delay: 1
+
+# This can apply to either Hosted or Satellite
+- name: "Register using username and password"
+ command: "/usr/bin/subscription-manager register --username={{ rhsm_username }} --password={{ rhsm_password }}"
+ no_log: true
+ when:
+ - not registered
+ - rhsm_authentication == "password"
+ - rhsm_org is not defined or rhsm_org is none or rhsm_org|trim == ''
+ register: register_userpw_result
+ until: register_userpw_result.rc == 0
+ retries: 10
+ delay: 1
+
+# This can apply to either Hosted or Satellite
+- name: "Register using username, password and organization"
+ command: "/usr/bin/subscription-manager register --username={{ rhsm_username }} --password={{ rhsm_password }} --org={{ rhsm_org }}"
+ no_log: true
+ when:
+ - not registered
+ - rhsm_authentication == "password"
+ - rhsm_org is defined
+ - rhsm_org is not none
+ - rhsm_org|trim != ''
+ register: register_userpworg_result
+ until: register_userpworg_result.rc == 0
+ retries: 10
+ delay: 1
+
+- name: "Auto-attach to Subscription Manager Pool"
+ command: "/usr/bin/subscription-manager attach --auto"
+ when:
+ - not registered
+ - rhsm_pool is undefined or rhsm_pool is none or rhsm_pool|trim == ''
+ register: autoattach_result
+ until: autoattach_result.rc == 0
+ retries: 10
+ delay: 1
+
+- name: "Attach to a specific pool"
+ command: "/usr/bin/subscription-manager attach --pool={{ rhsm_pool }}"
+ when:
+ - rhsm_pool is defined
+ - rhsm_pool is not none
+ - rhsm_pool|trim != ''
+ - not registered
+ register: attachpool_result
+ until: attachpool_result.rc == 0
+ retries: 10
+ delay: 1
+
+- name: "Disable all repositories"
+ command: "/usr/bin/subscription-manager repos --disable=*"
+ when:
+ - not registered
+ - rhsm_repos is defined
+ - rhsm_repos is not none
+ - rhsm_repos|trim != ''
+
+- name: "Enable specified repositories"
+ command: "/usr/bin/subscription-manager repos --enable={{ item }}"
+ with_items: "{{ rhsm_repos }}"
+ when:
+ - not registered
+ - rhsm_repos is defined
+ - rhsm_repos is not none
+ - rhsm_repos|trim != ''
+ register: enablerepos_result
+ until: enablerepos_result.rc == 0
+ retries: 10
+ delay: 1