summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.tito/packages/openshift-ansible2
-rw-r--r--.tito/packages/openshift-ansible-bin1
-rw-r--r--.tito/packages/openshift-ansible-inventory1
-rw-r--r--.tito/releasers.conf13
-rw-r--r--bin/openshift-ansible-bin.spec5
-rw-r--r--inventory/byo/hosts.example7
-rwxr-xr-xinventory/multi_ec2.py27
-rw-r--r--inventory/openshift-ansible-inventory.spec5
-rw-r--r--openshift-ansible.spec56
-rwxr-xr-xplaybooks/adhoc/docker_loopback_to_lvm/ops-docker-loopback-to-direct-lvm.yml17
-rw-r--r--playbooks/adhoc/uninstall.yml13
-rw-r--r--playbooks/adhoc/upgrades/upgrade.yml10
-rw-r--r--playbooks/common/openshift-master/config.yml7
-rw-r--r--roles/lib_zabbix/library/zbx_item.py37
-rw-r--r--roles/lib_zabbix/tasks/create_template.yml2
-rw-r--r--roles/openshift_examples/files/examples/image-streams/image-streams-centos7.json18
-rw-r--r--roles/openshift_examples/files/examples/image-streams/image-streams-rhel7.json15
-rw-r--r--roles/openshift_examples/files/examples/quickstart-templates/cakephp-mysql.json9
-rw-r--r--roles/openshift_examples/files/examples/quickstart-templates/cakephp.json9
-rw-r--r--roles/openshift_examples/files/examples/quickstart-templates/dancer-mysql.json9
-rw-r--r--roles/openshift_examples/files/examples/quickstart-templates/dancer.json11
-rw-r--r--roles/openshift_examples/files/examples/quickstart-templates/nodejs-mongodb.json14
-rw-r--r--roles/openshift_examples/files/examples/quickstart-templates/nodejs.json12
-rwxr-xr-xroles/openshift_facts/library/openshift_facts.py41
-rw-r--r--roles/openshift_master/tasks/main.yml5
-rw-r--r--roles/openshift_master/templates/master.yaml.v1.j216
-rw-r--r--roles/openshift_master_ca/tasks/main.yml3
-rw-r--r--roles/openshift_master_certificates/tasks/main.yml5
-rw-r--r--roles/os_zabbix/vars/template_app_zabbix_agent.yml4
-rw-r--r--roles/os_zabbix/vars/template_app_zabbix_server.yml60
-rw-r--r--roles/os_zabbix/vars/template_docker.yml5
-rw-r--r--utils/.gitignore45
-rw-r--r--utils/README.txt24
-rw-r--r--utils/docs/config.md72
-rw-r--r--utils/etc/ansible.cfg25
-rw-r--r--utils/setup.cfg5
-rw-r--r--utils/setup.py85
-rwxr-xr-xutils/site_assets/oo-install-bootstrap.sh86
-rw-r--r--utils/site_assets/oo_install_launcher.README.txt22
-rw-r--r--utils/src/DESCRIPTION.rst13
-rw-r--r--utils/src/MANIFEST.in9
-rw-r--r--utils/src/data/data_file1
-rw-r--r--utils/src/ooinstall/__init__.py5
-rw-r--r--utils/src/ooinstall/ansible_plugins/facts_callback.py88
-rw-r--r--utils/src/ooinstall/cli_installer.py479
-rw-r--r--utils/src/ooinstall/install_transactions.py133
-rw-r--r--utils/src/ooinstall/oo_config.py195
-rw-r--r--utils/src/ooinstall/variants.py74
-rw-r--r--utils/test/__init__.py0
-rw-r--r--utils/test/cli_installer_tests.py471
-rw-r--r--utils/test/oo_config_tests.py158
-rw-r--r--utils/workflows/enterprise_deploy/openshift.sh2
52 files changed, 2353 insertions, 78 deletions
diff --git a/.tito/packages/openshift-ansible b/.tito/packages/openshift-ansible
index adbed6b1d..8f6e38491 100644
--- a/.tito/packages/openshift-ansible
+++ b/.tito/packages/openshift-ansible
@@ -1 +1 @@
-3.0.2-1 ./
+3.0.3-1 ./
diff --git a/.tito/packages/openshift-ansible-bin b/.tito/packages/openshift-ansible-bin
new file mode 100644
index 000000000..66629dd03
--- /dev/null
+++ b/.tito/packages/openshift-ansible-bin
@@ -0,0 +1 @@
+0.0.20-1 bin/
diff --git a/.tito/packages/openshift-ansible-inventory b/.tito/packages/openshift-ansible-inventory
new file mode 100644
index 000000000..46d1373e3
--- /dev/null
+++ b/.tito/packages/openshift-ansible-inventory
@@ -0,0 +1 @@
+0.0.10-1 inventory/
diff --git a/.tito/releasers.conf b/.tito/releasers.conf
new file mode 100644
index 000000000..f863ce9b1
--- /dev/null
+++ b/.tito/releasers.conf
@@ -0,0 +1,13 @@
+[brew]
+releaser = tito.release.DistGitReleaser
+branches = libra-rhel-7
+
+[ose-3.0]
+releaser = tito.release.DistGitReleaser
+branches = rhose-3.0-rhel-7
+srpm_disttag = .el7ose
+
+[aos-3.1]
+releaser = tito.release.DistGitReleaser
+branches = rhaos-3.1-rhel-7
+srpm_disttag = .el7aos
diff --git a/bin/openshift-ansible-bin.spec b/bin/openshift-ansible-bin.spec
index d90810bc3..dc206968a 100644
--- a/bin/openshift-ansible-bin.spec
+++ b/bin/openshift-ansible-bin.spec
@@ -1,6 +1,6 @@
Summary: OpenShift Ansible Scripts for working with metadata hosts
Name: openshift-ansible-bin
-Version: 0.0.19
+Version: 0.0.20
Release: 1%{?dist}
License: ASL 2.0
URL: https://github.com/openshift/openshift-ansible
@@ -42,6 +42,9 @@ cp -p openshift_ansible.conf.example %{buildroot}/etc/openshift_ansible/openshif
%config(noreplace) /etc/openshift_ansible/
%changelog
+* Wed Oct 28 2015 Kenny Woodson <kwoodson@redhat.com> 0.0.20-1
+- new package built with tito
+
* Thu Aug 20 2015 Kenny Woodson <kwoodson@redhat.com> 0.0.19-1
- Updated to show private ips when doing a list (kwoodson@redhat.com)
- Updated to read config first and default to users home dir
diff --git a/inventory/byo/hosts.example b/inventory/byo/hosts.example
index 68b2af094..914b66a93 100644
--- a/inventory/byo/hosts.example
+++ b/inventory/byo/hosts.example
@@ -41,6 +41,13 @@ openshift_master_identity_providers=[{'name': 'htpasswd_auth', 'login': 'true',
# Allow all auth
#openshift_master_identity_providers=[{'name': 'allow_all', 'login': 'true', 'challenge': 'true', 'kind': 'AllowAllPasswordIdentityProvider'}]
+# Project Configuration
+#osm_project_request_message=''
+#osm_project_request_template=''
+#osm_mcs_allocator_range='s0:/2'
+#osm_mcs_labels_per_project=5
+#osm_uid_allocator_range='1000000000-1999999999/10000'
+
# Configure Fluentd
#use_fluentd=true
diff --git a/inventory/multi_ec2.py b/inventory/multi_ec2.py
index 2cbf33473..23cf5ecf1 100755
--- a/inventory/multi_ec2.py
+++ b/inventory/multi_ec2.py
@@ -239,22 +239,33 @@ class MultiEc2(object):
def apply_account_config(self, acc_config):
''' Apply account config settings
'''
- if not acc_config.has_key('hostvars') and not acc_config.has_key('all_group'):
- return
-
results = self.all_ec2_results[acc_config['name']]
- # Update each hostvar with the newly desired key: value
- for host_property, value in acc_config['hostvars'].items():
+
+ # Update each hostvar with the newly desired key: value
+ for new_var, value in acc_config.get('extra_vars', {}).items():
# Verify the account results look sane
# by checking for these keys ('_meta' and 'hostvars' exist)
if results.has_key('_meta') and results['_meta'].has_key('hostvars'):
for data in results['_meta']['hostvars'].values():
- data[str(host_property)] = str(value)
+ data[str(new_var)] = str(value)
# Add this group
if results.has_key(acc_config['all_group']):
- results["%s_%s" % (host_property, value)] = \
- copy.copy(results[acc_config['all_group']])
+ results["%s_%s" % (new_var, value)] = \
+ copy.copy(results[acc_config['all_group']])
+
+ # Clone groups goes here
+ for name_from, name_to in acc_config.get('clone_groups', {}).items():
+ if results.has_key(name_from):
+ results[name_to] = copy.copy(results[name_from])
+
+ # Clone vars goes here
+ for to_name, from_name in acc_config.get('clone_vars', {}).items():
+ # Verify the account results look sane
+ # by checking for these keys ('_meta' and 'hostvars' exist)
+ if results.has_key('_meta') and results['_meta'].has_key('hostvars'):
+ for data in results['_meta']['hostvars'].values():
+ data[str(to_name)] = data.get(str(from_name), 'nil')
# store the results back into all_ec2_results
self.all_ec2_results[acc_config['name']] = results
diff --git a/inventory/openshift-ansible-inventory.spec b/inventory/openshift-ansible-inventory.spec
index f163f865a..725708be4 100644
--- a/inventory/openshift-ansible-inventory.spec
+++ b/inventory/openshift-ansible-inventory.spec
@@ -1,6 +1,6 @@
Summary: OpenShift Ansible Inventories
Name: openshift-ansible-inventory
-Version: 0.0.9
+Version: 0.0.10
Release: 1%{?dist}
License: ASL 2.0
URL: https://github.com/openshift/openshift-ansible
@@ -36,6 +36,9 @@ cp -p gce/hosts/gce.py %{buildroot}/usr/share/ansible/inventory/gce
/usr/share/ansible/inventory/gce/gce.py*
%changelog
+* Wed Oct 28 2015 Kenny Woodson <kwoodson@redhat.com> 0.0.10-1
+- new package built with tito
+
* Thu Aug 20 2015 Kenny Woodson <kwoodson@redhat.com> 0.0.9-1
- Merge pull request #408 from sdodson/docker-buildvm (bleanhar@redhat.com)
- Merge pull request #428 from jtslear/issue-383
diff --git a/openshift-ansible.spec b/openshift-ansible.spec
index 0c754a7b9..a7fff9dfb 100644
--- a/openshift-ansible.spec
+++ b/openshift-ansible.spec
@@ -5,7 +5,7 @@
}
Name: openshift-ansible
-Version: 3.0.2
+Version: 3.0.3
Release: 1%{?dist}
Summary: Openshift and Atomic Enterprise Ansible
License: ASL 2.0
@@ -26,6 +26,10 @@ for Openshift and Atomic Enterprise.
%build
+# atomic-openshift-utils install
+pushd utils
+%{__python} setup.py build
+popd
%install
# Base openshift-ansible install
@@ -73,6 +77,13 @@ cp -rp filter_plugins %{buildroot}%{_datadir}/ansible_plugins/
# openshift-ansible-lookup-plugins install
cp -rp lookup_plugins %{buildroot}%{_datadir}/ansible_plugins/
+# atomic-openshift-utils install
+pushd utils
+%{__python} setup.py install --skip-build --root %{buildroot}
+# Remove this line once the name change has happened
+mv -f %{buildroot}%{_bindir}/oo-install %{buildroot}%{_bindir}/atomic-openshift-installer
+popd
+
# Base openshift-ansible files
%files
%doc LICENSE.md README*
@@ -190,8 +201,51 @@ BuildArch: noarch
%files lookup-plugins
%{_datadir}/ansible_plugins/lookup_plugins
+# ----------------------------------------------------------------------------------
+# atomic-openshift-utils subpackage
+# ----------------------------------------------------------------------------------
+
+%package -n atomic-openshift-utils
+Summary: Atomic OpenShift Utilities
+BuildRequires: python-setuptools
+Requires: ansible
+Requires: python-click
+Requires: python-setuptools
+Requires: PyYAML
+BuildArch: noarch
+
+%description -n atomic-openshift-utils
+Atomic OpenShift Utilities includes
+ - atomic-openshift-installer
+ - other utilities
+
+%files -n atomic-openshift-utils
+%{python_sitelib}/ooinstall*
+%{_bindir}/atomic-openshift-installer
+
%changelog
+* Tue Oct 27 2015 Troy Dawson <tdawson@redhat.com> 3.0.3-1
+- Pylint fixes and ignores for incoming oo-install code. (dgoodwin@redhat.com)
+- Pylint fixes (abutcher@redhat.com)
+- Adding zabbix type and fixing zabbix agent vars (kwoodson@redhat.com)
+- Add atomic-openshift-utils add atomic-openshift-utils to openshift-
+ ansible.spec file (tdawson@redhat.com)
+- Fix quotes (spinolacastro@gmail.com)
+- Use standard library for version comparison. (abutcher@redhat.com)
+- added docker info to the end of docker loop to direct lvm playbook.
+ (twiest@redhat.com)
+- Add missing quotes (spinolacastro@gmail.com)
+- Adding Docker Log Options capabilities (epo@jemba.net)
+- Move version greater_than_fact into openshift_facts (abutcher@redhat.com)
+- Don't include proxy client cert when <3.1 or <1.1 (abutcher@redhat.com)
+- Add proxy client certs to master config. (abutcher@redhat.com)
+- Update imagestreams and quickstarts from origin (sdodson@redhat.com)
+- Get default values from openshift_facts (spinolacastro@gmail.com)
+- Cleanup (spinolacastro@gmail.com)
+- Add missing inventory example (spinolacastro@gmail.com)
+- Custom Project Config (spinolacastro@gmail.com)
+
* Mon Oct 19 2015 Troy Dawson <tdawson@redhat.com> 3.0.2-1
- Initial Package
diff --git a/playbooks/adhoc/docker_loopback_to_lvm/ops-docker-loopback-to-direct-lvm.yml b/playbooks/adhoc/docker_loopback_to_lvm/ops-docker-loopback-to-direct-lvm.yml
index 614b2537a..72fcd77b3 100755
--- a/playbooks/adhoc/docker_loopback_to_lvm/ops-docker-loopback-to-direct-lvm.yml
+++ b/playbooks/adhoc/docker_loopback_to_lvm/ops-docker-loopback-to-direct-lvm.yml
@@ -97,8 +97,19 @@
- debug: var=setup_output
+ - name: extend the vg
+ command: lvextend -l 90%VG /dev/docker_vg/docker-pool
+ register: extend_output
+
+ - debug: var=extend_output
+
- name: start docker
- command: systemctl start docker.service
- register: dockerstart
+ service:
+ name: docker
+ state: restarted
+
+ - name: docker info
+ command: docker info
+ register: dockerinfo
- - debug: var=dockerstart
+ - debug: var=dockerinfo
diff --git a/playbooks/adhoc/uninstall.yml b/playbooks/adhoc/uninstall.yml
index 40db668da..7d1544be8 100644
--- a/playbooks/adhoc/uninstall.yml
+++ b/playbooks/adhoc/uninstall.yml
@@ -1,6 +1,6 @@
# This deletes *ALL* Origin, Atomic Enterprise Platform and OpenShift
# Enterprise content installed by ansible. This includes:
-#
+#
# configuration
# containers
# example templates and imagestreams
@@ -13,6 +13,15 @@
sudo: yes
tasks:
+ - name: Detecting Operating System
+ shell: ls /run/ostree-booted
+ ignore_errors: yes
+ failed_when: false
+ register: ostree_output
+
+ - set_fact:
+ is_atomic: "{{ ostree_output.rc == 0 }}"
+
- service: name={{ item }} state=stopped
with_items:
- atomic-enterprise-master
@@ -33,6 +42,7 @@
- origin-node
- yum: name={{ item }} state=absent
+ when: not is_atomic | bool
with_items:
- atomic-enterprise
- atomic-enterprise-master
@@ -127,6 +137,7 @@
- /etc/sysconfig/origin-master
- /etc/sysconfig/origin-node
- /root/.kube
+ - "~{{ ansible_ssh_user }}/.kube"
- /usr/share/openshift/examples
- /var/lib/atomic-enterprise
- /var/lib/etcd
diff --git a/playbooks/adhoc/upgrades/upgrade.yml b/playbooks/adhoc/upgrades/upgrade.yml
index 56a1df860..ae1d0127c 100644
--- a/playbooks/adhoc/upgrades/upgrade.yml
+++ b/playbooks/adhoc/upgrades/upgrade.yml
@@ -1,4 +1,14 @@
---
+- name: Upgrade base package on masters
+ hosts: masters
+ roles:
+ - openshift_facts
+ vars:
+ openshift_version: "{{ openshift_pkg_version | default('') }}"
+ tasks:
+ - name: Upgrade base package
+ yum: pkg={{ openshift.common.service_type }}{{ openshift_version }} state=latest
+
- name: Re-Run cluster configuration to apply latest configuration changes
include: ../../common/openshift-cluster/config.yml
vars:
diff --git a/playbooks/common/openshift-master/config.yml b/playbooks/common/openshift-master/config.yml
index 0a3fe90e1..1dec923fc 100644
--- a/playbooks/common/openshift-master/config.yml
+++ b/playbooks/common/openshift-master/config.yml
@@ -137,6 +137,7 @@
openshift_master_certs_no_etcd:
- admin.crt
- master.kubelet-client.crt
+ - "{{ 'master.proxy-client.crt' if openshift.common.version_greater_than_3_1_or_1_1 else omit }}"
- master.server.crt
- openshift-master.crt
- openshift-registry.crt
@@ -144,6 +145,7 @@
- etcd.server.crt
openshift_master_certs_etcd:
- master.etcd-client.crt
+
- set_fact:
openshift_master_certs: "{{ (openshift_master_certs_no_etcd | union(openshift_master_certs_etcd)) if (groups.oo_etcd_to_config is defined and groups.oo_etcd_to_config) else openshift_master_certs_no_etcd }}"
@@ -153,9 +155,9 @@
with_items: openshift_master_certs
register: g_master_cert_stat_result
- set_fact:
- master_certs_missing: "{{ g_master_cert_stat_result.results
+ master_certs_missing: "{{ False in (g_master_cert_stat_result.results
| map(attribute='stat.exists')
- | list | intersect([false])}}"
+ | list ) }}"
master_cert_subdir: master-{{ openshift.common.hostname }}
master_cert_config_dir: "{{ openshift.common.config_base }}/master"
@@ -187,6 +189,7 @@
args:
creates: "{{ master_generated_certs_dir }}/{{ item.master_cert_subdir }}.tgz"
with_items: masters_needing_certs
+
- name: Retrieve the master cert tarball from the master
fetch:
src: "{{ master_generated_certs_dir }}/{{ item.master_cert_subdir }}.tgz"
diff --git a/roles/lib_zabbix/library/zbx_item.py b/roles/lib_zabbix/library/zbx_item.py
index 2cd00dd27..5dc3cff9b 100644
--- a/roles/lib_zabbix/library/zbx_item.py
+++ b/roles/lib_zabbix/library/zbx_item.py
@@ -107,6 +107,39 @@ def get_multiplier(inval):
return rval, 0
+def get_zabbix_type(ztype):
+ '''
+ Determine which type of discoverrule this is
+ '''
+ _types = {'agent': 0,
+ 'SNMPv1': 1,
+ 'trapper': 2,
+ 'simple': 3,
+ 'SNMPv2': 4,
+ 'internal': 5,
+ 'SNMPv3': 6,
+ 'active': 7,
+ 'aggregate': 8,
+ 'web': 9,
+ 'external': 10,
+ 'database monitor': 11,
+ 'ipmi': 12,
+ 'ssh': 13,
+ 'telnet': 14,
+ 'calculated': 15,
+ 'JMX': 16,
+ 'SNMP trap': 17,
+ }
+
+ for typ in _types.keys():
+ if ztype in typ or ztype == typ:
+ _vtype = _types[typ]
+ break
+ else:
+ _vtype = 2
+
+ return _vtype
+
# The branches are needed for CRUD and error handling
# pylint: disable=too-many-branches
def main():
@@ -123,7 +156,7 @@ def main():
name=dict(default=None, type='str'),
key=dict(default=None, type='str'),
template_name=dict(default=None, type='str'),
- zabbix_type=dict(default=2, type='int'),
+ zabbix_type=dict(default='trapper', type='str'),
value_type=dict(default='int', type='str'),
interval=dict(default=60, type='int'),
delta=dict(default=0, type='int'),
@@ -184,7 +217,7 @@ def main():
params = {'name': module.params.get('name', module.params['key']),
'key_': module.params['key'],
'hostid': templateid[0],
- 'type': module.params['zabbix_type'],
+ 'type': get_zabbix_type(module.params['zabbix_type']),
'value_type': get_value_type(module.params['value_type']),
'applications': get_app_ids(module.params['applications'], app_name_ids),
'formula': formula,
diff --git a/roles/lib_zabbix/tasks/create_template.yml b/roles/lib_zabbix/tasks/create_template.yml
index d5168a9f4..ac9cf756b 100644
--- a/roles/lib_zabbix/tasks/create_template.yml
+++ b/roles/lib_zabbix/tasks/create_template.yml
@@ -38,7 +38,7 @@
units: "{{ item.units | default('', True) }}"
template_name: "{{ template.name }}"
applications: "{{ item.applications }}"
- zabbix_type: "{{ item.zabbix_type | default(2, True) }}"
+ zabbix_type: "{{ item.zabbix_type | default('trapper') }}"
interval: "{{ item.interval | default(60, True) }}"
delta: "{{ item.delta | default(0, True) }}"
with_items: template.zitems
diff --git a/roles/openshift_examples/files/examples/image-streams/image-streams-centos7.json b/roles/openshift_examples/files/examples/image-streams/image-streams-centos7.json
index f213d99ca..268d680f4 100644
--- a/roles/openshift_examples/files/examples/image-streams/image-streams-centos7.json
+++ b/roles/openshift_examples/files/examples/image-streams/image-streams-centos7.json
@@ -23,7 +23,8 @@
"iconClass": "icon-ruby",
"tags": "builder,ruby",
"supports": "ruby:2.0,ruby",
- "version": "2.0"
+ "version": "2.0",
+ "sampleRepo": "https://github.com/openshift/ruby-ex.git"
},
"from": {
"Kind": "ImageStreamTag",
@@ -53,7 +54,8 @@
"iconClass": "icon-nodejs",
"tags": "builder,nodejs",
"supports":"nodejs:0.10,nodejs:0.1,nodejs",
- "version": "0.10"
+ "version": "0.10",
+ "sampleRepo": "https://github.com/openshift/nodejs-ex.git"
},
"from": {
"Kind": "ImageStreamTag",
@@ -83,7 +85,8 @@
"iconClass": "icon-perl",
"tags": "builder,perl",
"supports":"perl:5.16,perl",
- "version": "5.16"
+ "version": "5.16",
+ "sampleRepo": "https://github.com/openshift/dancer-ex.git"
},
"from": {
"Kind": "ImageStreamTag",
@@ -113,7 +116,8 @@
"iconClass": "icon-php",
"tags": "builder,php",
"supports":"php:5.5,php",
- "version": "5.5"
+ "version": "5.5",
+ "sampleRepo": "https://github.com/openshift/cakephp-ex.git"
},
"from": {
"Kind": "ImageStreamTag",
@@ -143,7 +147,8 @@
"iconClass": "icon-python",
"tags": "builder,python",
"supports":"python:3.3,python",
- "version": "3.3"
+ "version": "3.3",
+ "sampleRepo": "https://github.com/openshift/django-ex.git"
},
"from": {
"Kind": "ImageStreamTag",
@@ -173,7 +178,8 @@
"iconClass": "icon-wildfly",
"tags": "builder,wildfly,java",
"supports":"wildfly:8.1,jee,java",
- "version": "8.1"
+ "version": "8.1",
+ "sampleRepo": "https://github.com/bparees/openshift-jee-sample.git"
},
"from": {
"Kind": "ImageStreamTag",
diff --git a/roles/openshift_examples/files/examples/image-streams/image-streams-rhel7.json b/roles/openshift_examples/files/examples/image-streams/image-streams-rhel7.json
index 8c125f76a..aa62ebd53 100644
--- a/roles/openshift_examples/files/examples/image-streams/image-streams-rhel7.json
+++ b/roles/openshift_examples/files/examples/image-streams/image-streams-rhel7.json
@@ -23,7 +23,8 @@
"iconClass": "icon-ruby",
"tags": "builder,ruby",
"supports": "ruby:2.0,ruby",
- "version": "2.0"
+ "version": "2.0",
+ "sampleRepo": "https://github.com/openshift/ruby-ex.git"
},
"from": {
"Kind": "ImageStreamTag",
@@ -53,7 +54,8 @@
"iconClass": "icon-nodejs",
"tags": "builder,nodejs",
"supports":"nodejs:0.10,nodejs:0.1,nodejs",
- "version": "0.10"
+ "version": "0.10",
+ "sampleRepo": "https://github.com/openshift/nodejs-ex.git"
},
"from": {
"Kind": "ImageStreamTag",
@@ -83,7 +85,8 @@
"iconClass": "icon-perl",
"tags": "builder,perl",
"supports":"perl:5.16,perl",
- "version": "5.16"
+ "version": "5.16",
+ "sampleRepo": "https://github.com/openshift/dancer-ex.git"
},
"from": {
"Kind": "ImageStreamTag",
@@ -113,7 +116,8 @@
"iconClass": "icon-php",
"tags": "builder,php",
"supports":"php:5.5,php",
- "version": "5.5"
+ "version": "5.5",
+ "sampleRepo": "https://github.com/openshift/cakephp-ex.git"
},
"from": {
"Kind": "ImageStreamTag",
@@ -143,7 +147,8 @@
"iconClass": "icon-python",
"tags": "builder,python",
"supports":"python:3.3,python",
- "version": "3.3"
+ "version": "3.3",
+ "sampleRepo": "https://github.com/openshift/django-ex.git"
},
"from": {
"Kind": "ImageStreamTag",
diff --git a/roles/openshift_examples/files/examples/quickstart-templates/cakephp-mysql.json b/roles/openshift_examples/files/examples/quickstart-templates/cakephp-mysql.json
index deac2010f..da5679444 100644
--- a/roles/openshift_examples/files/examples/quickstart-templates/cakephp-mysql.json
+++ b/roles/openshift_examples/files/examples/quickstart-templates/cakephp-mysql.json
@@ -201,6 +201,10 @@
{
"name": "CAKEPHP_SECURITY_CIPHER_SEED",
"value": "${CAKEPHP_SECURITY_CIPHER_SEED}"
+ },
+ {
+ "name": "OPCACHE_REVALIDATE_FREQ",
+ "value": "${OPCACHE_REVALIDATE_FREQ}"
}
]
}
@@ -364,6 +368,11 @@
"description": "Security cipher seed for session hash",
"generate": "expression",
"from": "[0-9]{30}"
+ },
+ {
+ "name": "OPCACHE_REVALIDATE_FREQ",
+ "description": "The How often to check script timestamps for updates, in seconds. 0 will result in OPcache checking for updates on every request.",
+ "value": "2"
}
]
}
diff --git a/roles/openshift_examples/files/examples/quickstart-templates/cakephp.json b/roles/openshift_examples/files/examples/quickstart-templates/cakephp.json
index ec556ea13..f426e1dd6 100644
--- a/roles/openshift_examples/files/examples/quickstart-templates/cakephp.json
+++ b/roles/openshift_examples/files/examples/quickstart-templates/cakephp.json
@@ -190,6 +190,10 @@
{
"name": "CAKEPHP_SECURITY_CIPHER_SEED",
"value": "${CAKEPHP_SECURITY_CIPHER_SEED}"
+ },
+ {
+ "name": "OPCACHE_REVALIDATE_FREQ",
+ "value": "${OPCACHE_REVALIDATE_FREQ}"
}
]
}
@@ -261,6 +265,11 @@
"description": "Security cipher seed for session hash",
"generate": "expression",
"from": "[0-9]{30}"
+ },
+ {
+ "name": "OPCACHE_REVALIDATE_FREQ",
+ "description": "The How often to check script timestamps for updates, in seconds. 0 will result in OPcache checking for updates on every request.",
+ "value": "2"
}
]
}
diff --git a/roles/openshift_examples/files/examples/quickstart-templates/dancer-mysql.json b/roles/openshift_examples/files/examples/quickstart-templates/dancer-mysql.json
index 2cbcc0889..55f655102 100644
--- a/roles/openshift_examples/files/examples/quickstart-templates/dancer-mysql.json
+++ b/roles/openshift_examples/files/examples/quickstart-templates/dancer-mysql.json
@@ -175,6 +175,10 @@
{
"name": "SECRET_KEY_BASE",
"value": "${SECRET_KEY_BASE}"
+ },
+ {
+ "name": "PERL_APACHE2_RELOAD",
+ "value": "${PERL_APACHE2_RELOAD}"
}
]
}
@@ -330,6 +334,11 @@
"value": "openshift/mysql-55-centos7"
},
{
+ "name": "PERL_APACHE2_RELOAD",
+ "description": "Set this to \"true\" to enable automatic reloading of modified Perl modules",
+ "value": ""
+ },
+ {
"name": "SECRET_KEY_BASE",
"description": "Your secret key for verifying the integrity of signed cookies",
"generate": "expression",
diff --git a/roles/openshift_examples/files/examples/quickstart-templates/dancer.json b/roles/openshift_examples/files/examples/quickstart-templates/dancer.json
index 43271dfc5..3ee19be83 100644
--- a/roles/openshift_examples/files/examples/quickstart-templates/dancer.json
+++ b/roles/openshift_examples/files/examples/quickstart-templates/dancer.json
@@ -157,6 +157,12 @@
{
"containerPort": 8080
}
+ ],
+ "env": [
+ {
+ "name": "PERL_APACHE2_RELOAD",
+ "value": "${PERL_APACHE2_RELOAD}"
+ }
]
}
]
@@ -195,6 +201,11 @@
"description": "Your secret key for verifying the integrity of signed cookies",
"generate": "expression",
"from": "[a-z0-9]{127}"
+ },
+ {
+ "name": "PERL_APACHE2_RELOAD",
+ "description": "Set this to \"true\" to enable automatic reloading of modified Perl modules",
+ "value": ""
}
]
}
diff --git a/roles/openshift_examples/files/examples/quickstart-templates/nodejs-mongodb.json b/roles/openshift_examples/files/examples/quickstart-templates/nodejs-mongodb.json
index 017b5be19..8760b074c 100644
--- a/roles/openshift_examples/files/examples/quickstart-templates/nodejs-mongodb.json
+++ b/roles/openshift_examples/files/examples/quickstart-templates/nodejs-mongodb.json
@@ -102,6 +102,12 @@
"github": {
"secret": "${GITHUB_WEBHOOK_SECRET}"
}
+ },
+ {
+ "type": "Generic",
+ "generic": {
+ "secret": "${GENERIC_WEBHOOK_SECRET}"
+ }
}
]
}
@@ -298,6 +304,12 @@
"from": "[a-zA-Z0-9]{40}"
},
{
+ "name": "GENERIC_WEBHOOK_SECRET",
+ "description": "A secret string used to configure the Generic webhook",
+ "generate": "expression",
+ "from": "[a-zA-Z0-9]{40}"
+ },
+ {
"name": "DATABASE_SERVICE_NAME",
"description": "Database service name",
"value": "mongodb"
@@ -328,7 +340,7 @@
{
"name": "MONGODB_IMAGE",
"description": "Image to use for mongodb",
- "value": "openshift/mongodb-24-centos7"
+ "value": "openshift/mongodb-24-centos7"
}
]
}
diff --git a/roles/openshift_examples/files/examples/quickstart-templates/nodejs.json b/roles/openshift_examples/files/examples/quickstart-templates/nodejs.json
index 55488ab41..e047266e3 100644
--- a/roles/openshift_examples/files/examples/quickstart-templates/nodejs.json
+++ b/roles/openshift_examples/files/examples/quickstart-templates/nodejs.json
@@ -102,6 +102,12 @@
"github": {
"secret": "${GITHUB_WEBHOOK_SECRET}"
}
+ },
+ {
+ "type": "Generic",
+ "generic": {
+ "secret": "${GENERIC_WEBHOOK_SECRET}"
+ }
}
]
}
@@ -213,6 +219,12 @@
"from": "[a-zA-Z0-9]{40}"
},
{
+ "name": "GENERIC_WEBHOOK_SECRET",
+ "description": "A secret string used to configure the Generic webhook",
+ "generate": "expression",
+ "from": "[a-zA-Z0-9]{40}"
+ },
+ {
"name": "DATABASE_SERVICE_NAME",
"description": "Database service name"
},
diff --git a/roles/openshift_facts/library/openshift_facts.py b/roles/openshift_facts/library/openshift_facts.py
index 3570de693..67994d11d 100755
--- a/roles/openshift_facts/library/openshift_facts.py
+++ b/roles/openshift_facts/library/openshift_facts.py
@@ -21,6 +21,7 @@ import ConfigParser
import copy
import os
from distutils.util import strtobool
+from distutils.version import LooseVersion
def hostname_valid(hostname):
@@ -362,6 +363,33 @@ def set_metrics_facts_if_unset(facts):
facts['common']['use_cluster_metrics'] = use_cluster_metrics
return facts
+def set_project_cfg_facts_if_unset(facts):
+ """ Set Project Configuration facts if not already present in facts dict
+ dict:
+ Args:
+ facts (dict): existing facts
+ Returns:
+ dict: the facts dict updated with the generated Project Configuration
+ facts if they were not already present
+
+ """
+
+ config = {
+ 'default_node_selector': '',
+ 'project_request_message': '',
+ 'project_request_template': '',
+ 'mcs_allocator_range': 's0:/2',
+ 'mcs_labels_per_project': 5,
+ 'uid_allocator_range': '1000000000-1999999999/10000'
+ }
+
+ if 'master' in facts:
+ for key, value in config.items():
+ if key not in facts['master']:
+ facts['master'][key] = value
+
+ return facts
+
def set_identity_providers_if_unset(facts):
""" Set identity_providers fact if not already present in facts dict
@@ -501,7 +529,15 @@ def set_deployment_facts_if_unset(facts):
if deployment_type in ['enterprise', 'online']:
data_dir = '/var/lib/openshift'
facts['common']['data_dir'] = data_dir
- facts['common']['version'] = get_openshift_version()
+ facts['common']['version'] = version = get_openshift_version()
+ if version is not None:
+ if deployment_type == 'origin':
+ version_gt_3_1_or_1_1 = LooseVersion(version) > LooseVersion('1.0.6')
+ else:
+ version_gt_3_1_or_1_1 = LooseVersion(version) > LooseVersion('3.0.2')
+ else:
+ version_gt_3_1_or_1_1 = True
+ facts['common']['version_greater_than_3_1_or_1_1'] = version_gt_3_1_or_1_1
for role in ('master', 'node'):
if role in facts:
@@ -632,7 +668,7 @@ def get_openshift_version():
Returns:
version: the current openshift version
"""
- version = ''
+ version = None
if os.path.isfile('/usr/bin/openshift'):
_, output, _ = module.run_command(['/usr/bin/openshift', 'version'])
@@ -807,6 +843,7 @@ class OpenShiftFacts(object):
facts = merge_facts(facts, local_facts)
facts['current_config'] = get_current_config(facts)
facts = set_url_facts_if_unset(facts)
+ facts = set_project_cfg_facts_if_unset(facts)
facts = set_fluentd_facts_if_unset(facts)
facts = set_node_schedulability(facts)
facts = set_master_selectors(facts)
diff --git a/roles/openshift_master/tasks/main.yml b/roles/openshift_master/tasks/main.yml
index fca41307d..94eb73346 100644
--- a/roles/openshift_master/tasks/main.yml
+++ b/roles/openshift_master/tasks/main.yml
@@ -52,6 +52,11 @@
default_subdomain: "{{ osm_default_subdomain | default(None) }}"
custom_cors_origins: "{{ osm_custom_cors_origins | default(None) }}"
default_node_selector: "{{ osm_default_node_selector | default(None) }}"
+ project_request_message: "{{ osm_project_request_message | default(None) }}"
+ project_request_template: "{{ osm_project_request_template | default(None) }}"
+ mcs_allocator_range: "{{ osm_mcs_allocator_range | default(None) }}"
+ mcs_labels_per_project: "{{ osm_mcs_labels_per_project | default(None) }}"
+ uid_allocator_range: "{{ osm_uid_allocator_range | default(None) }}"
router_selector: "{{ openshift_router_selector | default(None) }}"
registry_selector: "{{ openshift_registry_selector | default(None) }}"
api_server_args: "{{ osm_api_server_args | default(None) }}"
diff --git a/roles/openshift_master/templates/master.yaml.v1.j2 b/roles/openshift_master/templates/master.yaml.v1.j2
index 6e45eaad7..3e4f78b17 100644
--- a/roles/openshift_master/templates/master.yaml.v1.j2
+++ b/roles/openshift_master/templates/master.yaml.v1.j2
@@ -74,6 +74,9 @@ kubernetesMasterConfig:
masterCount: 1
masterIP: ""
podEvictionTimeout: ""
+ proxyClientInfo:
+ certFile: master.proxy-client.crt
+ keyFile: master.proxy-client.key
schedulerConfigFile: {{ openshift_master_scheduler_conf }}
servicesNodePortRange: ""
servicesSubnet: {{ openshift.master.portal_net }}
@@ -97,15 +100,14 @@ policyConfig:
bootstrapPolicyFile: {{ openshift_master_policy }}
openshiftInfrastructureNamespace: openshift-infra
openshiftSharedResourcesNamespace: openshift
-{# TODO: Allow users to override projectConfig items #}
projectConfig:
- defaultNodeSelector: "{{ openshift.master.default_node_selector | default("") }}"
- projectRequestMessage: ""
- projectRequestTemplate: ""
+ defaultNodeSelector: "{{ openshift.master.default_node_selector }}"
+ projectRequestMessage: "{{ openshift.master.project_request_message }}"
+ projectRequestTemplate: "{{ openshift.master.project_request_template }}"
securityAllocator:
- mcsAllocatorRange: s0:/2
- mcsLabelsPerProject: 5
- uidAllocatorRange: 1000000000-1999999999/10000
+ mcsAllocatorRange: "{{ openshift.master.mcs_allocator_range }}"
+ mcsLabelsPerProject: {{ openshift.master.mcs_labels_per_project }}
+ uidAllocatorRange: "{{ openshift.master.uid_allocator_range }}"
routingConfig:
subdomain: "{{ openshift.master.default_subdomain | default("") }}"
serviceAccountConfig:
diff --git a/roles/openshift_master_ca/tasks/main.yml b/roles/openshift_master_ca/tasks/main.yml
index 5c9639ea5..cfd1ceabf 100644
--- a/roles/openshift_master_ca/tasks/main.yml
+++ b/roles/openshift_master_ca/tasks/main.yml
@@ -18,5 +18,4 @@
--master={{ openshift.master.api_url }}
--public-master={{ openshift.master.public_api_url }}
--cert-dir={{ openshift_master_config_dir }} --overwrite=false
- args:
- creates: "{{ openshift_master_config_dir }}/master.server.key"
+ when: master_certs_missing
diff --git a/roles/openshift_master_certificates/tasks/main.yml b/roles/openshift_master_certificates/tasks/main.yml
index 0d75a9eb3..e4602337e 100644
--- a/roles/openshift_master_certificates/tasks/main.yml
+++ b/roles/openshift_master_certificates/tasks/main.yml
@@ -20,6 +20,8 @@
- admin.kubeconfig
- master.kubelet-client.crt
- master.kubelet-client.key
+ - "{{ 'master.proxy-client.crt' if openshift.common.version_greater_than_3_1_or_1_1 else omit }}"
+ - "{{ 'master.proxy-client.key' if openshift.common.version_greater_than_3_1_or_1_1 else omit }}"
- openshift-master.crt
- openshift-master.key
- openshift-master.kubeconfig
@@ -41,6 +43,5 @@
--public-master={{ item.openshift.master.public_api_url }}
--cert-dir={{ openshift_generated_configs_dir }}/{{ item.master_cert_subdir }}
--overwrite=false
- args:
- creates: "{{ openshift_generated_configs_dir }}/{{ item.master_cert_subdir }}/master.server.crt"
+ when: master_certs_missing
with_items: masters_needing_certs
diff --git a/roles/os_zabbix/vars/template_app_zabbix_agent.yml b/roles/os_zabbix/vars/template_app_zabbix_agent.yml
index 6349b6384..d636d4822 100644
--- a/roles/os_zabbix/vars/template_app_zabbix_agent.yml
+++ b/roles/os_zabbix/vars/template_app_zabbix_agent.yml
@@ -6,14 +6,14 @@ g_template_app_zabbix_agent:
applications:
- Zabbix agent
value_type: character
- zabbix_type: 0
+ zabbix_type: agent
- key: agent.ping
applications:
- Zabbix agent
description: The agent always returns 1 for this item. It could be used in combination with nodata() for availability check.
value_type: int
- zabbix_type: 0
+ zabbix_type: agent
ztriggers:
- name: '[Reboot] Zabbix agent on {HOST.NAME} is unreachable for 15 minutes'
diff --git a/roles/os_zabbix/vars/template_app_zabbix_server.yml b/roles/os_zabbix/vars/template_app_zabbix_server.yml
index aeec16254..43517113b 100644
--- a/roles/os_zabbix/vars/template_app_zabbix_server.yml
+++ b/roles/os_zabbix/vars/template_app_zabbix_server.yml
@@ -8,7 +8,7 @@ g_template_app_zabbix_server:
description: A simple count of the number of partition creates output by the housekeeper script.
units: ''
value_type: int
- zabbix_type: 5
+ zabbix_type: internal
- key: housekeeper_drops
applications:
@@ -16,7 +16,7 @@ g_template_app_zabbix_server:
description: A simple count of the number of partition drops output by the housekeeper script.
units: ''
value_type: int
- zabbix_type: 5
+ zabbix_type: internal
- key: housekeeper_errors
applications:
@@ -24,7 +24,7 @@ g_template_app_zabbix_server:
description: A simple count of the number of errors output by the housekeeper script.
units: ''
value_type: int
- zabbix_type: 5
+ zabbix_type: internal
- key: housekeeper_total
applications:
@@ -33,7 +33,7 @@ g_template_app_zabbix_server:
script.
units: ''
value_type: int
- zabbix_type: 5
+ zabbix_type: internal
- key: zabbix[process,alerter,avg,busy]
applications:
@@ -41,7 +41,7 @@ g_template_app_zabbix_server:
description: ''
units: '%'
value_type: float
- zabbix_type: 5
+ zabbix_type: internal
- key: zabbix[process,configuration syncer,avg,busy]
applications:
@@ -49,7 +49,7 @@ g_template_app_zabbix_server:
description: ''
units: '%'
value_type: float
- zabbix_type: 5
+ zabbix_type: internal
- key: zabbix[process,db watchdog,avg,busy]
applications:
@@ -57,7 +57,7 @@ g_template_app_zabbix_server:
description: ''
units: '%'
value_type: float
- zabbix_type: 5
+ zabbix_type: internal
- key: zabbix[process,discoverer,avg,busy]
applications:
@@ -65,7 +65,7 @@ g_template_app_zabbix_server:
description: ''
units: '%'
value_type: float
- zabbix_type: 5
+ zabbix_type: internal
- key: zabbix[process,escalator,avg,busy]
applications:
@@ -73,7 +73,7 @@ g_template_app_zabbix_server:
description: ''
units: '%'
value_type: float
- zabbix_type: 5
+ zabbix_type: internal
- key: zabbix[process,history syncer,avg,busy]
applications:
@@ -81,7 +81,7 @@ g_template_app_zabbix_server:
description: ''
units: '%'
value_type: float
- zabbix_type: 5
+ zabbix_type: internal
- key: zabbix[process,housekeeper,avg,busy]
applications:
@@ -89,7 +89,7 @@ g_template_app_zabbix_server:
description: ''
units: '%'
value_type: float
- zabbix_type: 5
+ zabbix_type: internal
- key: zabbix[process,http poller,avg,busy]
applications:
@@ -97,7 +97,7 @@ g_template_app_zabbix_server:
description: ''
units: '%'
value_type: float
- zabbix_type: 5
+ zabbix_type: internal
- key: zabbix[process,icmp pinger,avg,busy]
applications:
@@ -105,7 +105,7 @@ g_template_app_zabbix_server:
description: ''
units: '%'
value_type: float
- zabbix_type: 5
+ zabbix_type: internal
- key: zabbix[process,ipmi poller,avg,busy]
applications:
@@ -113,7 +113,7 @@ g_template_app_zabbix_server:
description: ''
units: '%'
value_type: float
- zabbix_type: 5
+ zabbix_type: internal
- key: zabbix[process,java poller,avg,busy]
applications:
@@ -121,7 +121,7 @@ g_template_app_zabbix_server:
description: ''
units: '%'
value_type: float
- zabbix_type: 5
+ zabbix_type: internal
- key: zabbix[process,node watcher,avg,busy]
applications:
@@ -129,7 +129,7 @@ g_template_app_zabbix_server:
description: ''
units: '%'
value_type: float
- zabbix_type: 5
+ zabbix_type: internal
- key: zabbix[process,poller,avg,busy]
applications:
@@ -137,7 +137,7 @@ g_template_app_zabbix_server:
description: ''
units: '%'
value_type: float
- zabbix_type: 5
+ zabbix_type: internal
- key: zabbix[process,proxy poller,avg,busy]
applications:
@@ -145,7 +145,7 @@ g_template_app_zabbix_server:
description: ''
units: '%'
value_type: float
- zabbix_type: 5
+ zabbix_type: internal
- key: zabbix[process,self-monitoring,avg,busy]
applications:
@@ -153,7 +153,7 @@ g_template_app_zabbix_server:
description: ''
units: '%'
value_type: float
- zabbix_type: 5
+ zabbix_type: internal
- key: zabbix[process,snmp trapper,avg,busy]
applications:
@@ -161,7 +161,7 @@ g_template_app_zabbix_server:
description: ''
units: '%'
value_type: float
- zabbix_type: 5
+ zabbix_type: internal
- key: zabbix[process,timer,avg,busy]
applications:
@@ -169,7 +169,7 @@ g_template_app_zabbix_server:
description: ''
units: '%'
value_type: float
- zabbix_type: 5
+ zabbix_type: internal
- key: zabbix[process,trapper,avg,busy]
applications:
@@ -177,7 +177,7 @@ g_template_app_zabbix_server:
description: ''
units: '%'
value_type: float
- zabbix_type: 5
+ zabbix_type: internal
- key: zabbix[process,unreachable poller,avg,busy]
applications:
@@ -185,7 +185,7 @@ g_template_app_zabbix_server:
description: ''
units: '%'
value_type: float
- zabbix_type: 5
+ zabbix_type: internal
- key: zabbix[queue,10m]
applications:
@@ -193,7 +193,7 @@ g_template_app_zabbix_server:
description: ''
units: ''
value_type: int
- zabbix_type: 5
+ zabbix_type: internal
interval: 600
- key: zabbix[queue]
@@ -202,7 +202,7 @@ g_template_app_zabbix_server:
description: ''
units: ''
value_type: int
- zabbix_type: 5
+ zabbix_type: internal
interval: 600
- key: zabbix[rcache,buffer,pfree]
@@ -211,7 +211,7 @@ g_template_app_zabbix_server:
description: ''
units: ''
value_type: float
- zabbix_type: 5
+ zabbix_type: internal
- key: zabbix[wcache,history,pfree]
applications:
@@ -219,7 +219,7 @@ g_template_app_zabbix_server:
description: ''
units: ''
value_type: float
- zabbix_type: 5
+ zabbix_type: internal
- key: zabbix[wcache,text,pfree]
applications:
@@ -227,7 +227,7 @@ g_template_app_zabbix_server:
description: ''
units: ''
value_type: float
- zabbix_type: 5
+ zabbix_type: internal
- key: zabbix[wcache,trend,pfree]
applications:
@@ -235,7 +235,7 @@ g_template_app_zabbix_server:
description: ''
units: ''
value_type: float
- zabbix_type: 5
+ zabbix_type: internal
- key: zabbix[wcache,values]
applications:
@@ -243,7 +243,7 @@ g_template_app_zabbix_server:
description: ''
units: ''
value_type: float
- zabbix_type: 5
+ zabbix_type: internal
delta: 1 # speed per second
ztriggers:
diff --git a/roles/os_zabbix/vars/template_docker.yml b/roles/os_zabbix/vars/template_docker.yml
index 395e054de..bfabf50c5 100644
--- a/roles/os_zabbix/vars/template_docker.yml
+++ b/roles/os_zabbix/vars/template_docker.yml
@@ -7,6 +7,11 @@ g_template_docker:
- Docker Daemon
value_type: int
+ - key: docker.info_elapsed_ms
+ applications:
+ - Docker Daemon
+ value_type: int
+
- key: docker.storage.is_loopback
applications:
- Docker Storage
diff --git a/utils/.gitignore b/utils/.gitignore
new file mode 100644
index 000000000..68759c0ba
--- /dev/null
+++ b/utils/.gitignore
@@ -0,0 +1,45 @@
+package/
+
+# Backup files
+*.~
+
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+
+# C extensions
+*.so
+
+# Distribution / packaging
+bin/
+build/
+develop-eggs/
+dist/
+eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+.tox/
+.coverage
+.cache
+.noseids
+nosetests.xml
+coverage.xml
+
+# Translations
+*.mo
+
+# Sphinx documentation
+docs/_build/
diff --git a/utils/README.txt b/utils/README.txt
new file mode 100644
index 000000000..6a6a1d24d
--- /dev/null
+++ b/utils/README.txt
@@ -0,0 +1,24 @@
+## Running From Source
+
+You will need to setup a virtualenv to run from source and execute the unit tests.
+
+$ virtualenv oo-install
+$ source ./oo-install/bin/activate
+$ virtualenv --relocatable ./oo-install/
+$ python setup.py install
+
+The virtualenv bin directory should now be at the start of your $PATH, and oo-install is ready to use from your shell.
+
+You can exit the virtualenv with:
+
+$ deactivate
+
+## Testing
+
+Install some testing libraries: (we cannot do this via setuptools due to the version virtualenv bundles)
+
+$ pip install mock nose
+
+Then run the tests with:
+
+$ oo-install/bin/nosetests
diff --git a/utils/docs/config.md b/utils/docs/config.md
new file mode 100644
index 000000000..9399409dd
--- /dev/null
+++ b/utils/docs/config.md
@@ -0,0 +1,72 @@
+# oo-install Supported Configuration File
+
+Upon completion oo-install will write out a configuration file representing the settings that were gathered and used. This configuration file, or one crafted by hand, can be used to run or re-run the installer and add additional hosts, upgrade, or re-install.
+
+The default location this config file will be written to ~/.config/openshift/installer.cfg.yml.
+
+## Example
+
+```
+variant: openshift-enterprise
+variant_version: 3.0
+ansible_ssh_user: root
+hosts:
+- ip: 10.0.0.1
+ hostname: master-private.example.com
+ public_ip: 24.222.0.1
+ public_hostname: master.example.com
+ master: true
+ node: true
+ containerized: true
+- ip: 10.0.0.2
+ hostname: node1-private.example.com
+ public_ip: 24.222.0.2
+ public_hostname: node1.example.com
+ node: true
+- ip: 10.0.0.3
+ hostname: node2-private.example.com
+ public_ip: 24.222.0.3
+ public_hostname: node2.example.com
+ node: true
+```
+
+## Primary Settings
+
+### variant
+
+The OpenShift variant to install. Currently valid options are:
+
+ * openshift-enterprise
+ * atomic-enterprise
+
+### variant_version (optional)
+
+Default: Latest version for your chosen variant.
+
+A version which must be valid for your selected variant. If not specified the latest will be assumed.
+
+Examples: 3.0, 3.1, etc.
+
+### hosts
+
+This section defines a list of the hosts you wish to install the OpenShift master/node service on.
+
+*ip* or *hostname* must be specified so the installer can connect to the system to gather facts before proceeding with the install.
+
+If *public_ip* or *public_hostname* are not specified, this information will be gathered from the facts and the user will be asked to confirm in an editor. For an unattended install, the installer will error out. (you must provide complete host records for an unattended install)
+
+*master* and *node* determine the type of services that will be installed. One of these must be set to true for the configuration file to be considered valid.
+
+*containerized* indicates you want to run OpenShift services in a container on this host.
+
+### ansible_ssh_user
+
+Default: root
+
+Defines the user ansible will use to ssh to remote systems for gathering facts and the installation.
+
+### ansible_log_path
+
+Default: /tmp/ansible.log
+
+
diff --git a/utils/etc/ansible.cfg b/utils/etc/ansible.cfg
new file mode 100644
index 000000000..b7376ddfc
--- /dev/null
+++ b/utils/etc/ansible.cfg
@@ -0,0 +1,25 @@
+# config file for ansible -- http://ansible.com/
+# ==============================================
+
+# This config file provides examples for running
+# the OpenShift playbooks with the provided
+# inventory scripts. Only global defaults are
+# left uncommented
+
+[defaults]
+# Add the roles directory to the roles path
+roles_path = roles/
+
+# Set the log_path
+log_path = /tmp/ansible.log
+
+forks = 10
+host_key_checking = False
+nocows = 1
+# Need to handle:
+# inventory - derive from OO_ANSIBLE_DIRECTORY env var
+# callback_plugins - derive from pkg_resource.resource_filename
+# private_key_file - prompt if missing
+# remote_tmp - set if provided by user (cli)
+# ssh_args - set if provided by user (cli)
+# control_path \ No newline at end of file
diff --git a/utils/setup.cfg b/utils/setup.cfg
new file mode 100644
index 000000000..79bc67848
--- /dev/null
+++ b/utils/setup.cfg
@@ -0,0 +1,5 @@
+[bdist_wheel]
+# This flag says that the code is written to work on both Python 2 and Python
+# 3. If at all possible, it is good practice to do this. If you cannot, you
+# will need to generate wheels for each Python version that you support.
+universal=1
diff --git a/utils/setup.py b/utils/setup.py
new file mode 100644
index 000000000..6e2fdd9c0
--- /dev/null
+++ b/utils/setup.py
@@ -0,0 +1,85 @@
+"""A setuptools based setup module.
+
+"""
+
+# Always prefer setuptools over distutils
+from setuptools import setup
+
+setup(
+ name='ooinstall',
+
+ # Versions should comply with PEP440. For a discussion on single-sourcing
+ # the version across setup.py and the project code, see
+ # https://packaging.python.org/en/latest/single_source_version.html
+ version="3.0.0",
+
+ description="Ansible wrapper for OpenShift Enterprise 3 installation.",
+
+ # The project's main homepage.
+ url="http://github.com/openshift/openshift-extras/tree/enterprise-3.0/oo-install",
+
+ # Author details
+ author="openshift@redhat.com",
+ author_email="OpenShift",
+
+ # Choose your license
+ license="Apache 2.0",
+
+ # See https://pypi.python.org/pypi?%3Aaction=list_classifiers
+ classifiers=[
+ 'Development Status :: 4 - Beta',
+ 'License :: OSI Approved :: Apache Software License',
+ 'Programming Language :: Python :: 2.7',
+ 'Topic :: Utilities',
+ ],
+
+ # What does your project relate to?
+ keywords='oo-install setuptools development',
+
+ # You can just specify the packages manually here if your project is
+ # simple. Or you can use find_packages().
+ #packages=find_packages(exclude=['contrib', 'docs', 'tests*']),
+ packages=['ooinstall'],
+ package_dir={'ooinstall': 'src/ooinstall'},
+
+
+ # List run-time dependencies here. These will be installed by pip when
+ # your project is installed. For an analysis of "install_requires" vs pip's
+ # requirements files see:
+ # https://packaging.python.org/en/latest/requirements.html
+ install_requires=['click', 'PyYAML'],
+
+ # List additional groups of dependencies here (e.g. development
+ # dependencies). You can install these using the following syntax,
+ # for example:
+ # $ pip install -e .[dev,test]
+ #extras_require={
+ # 'dev': ['check-manifest'],
+ # 'test': ['coverage'],
+ #},
+
+ # If there are data files included in your packages that need to be
+ # installed, specify them here. If using Python 2.6 or less, then these
+ # have to be included in MANIFEST.in as well.
+ package_data={
+ 'ooinstall': ['ansible.cfg', 'ansible_plugins/*'],
+ },
+
+ # Although 'package_data' is the preferred approach, in some case you may
+ # need to place data files outside of your packages. See:
+ # http://docs.python.org/3.4/distutils/setupscript.html#installing-additional-files # noqa
+ # In this case, 'data_file' will be installed into '<sys.prefix>/my_data'
+ #data_files=[('my_data', ['data/data_file'])],
+ tests_require=['nose'],
+
+ test_suite='nose.collector',
+
+ # To provide executable scripts, use entry points in preference to the
+ # "scripts" keyword. Entry points provide cross-platform support and allow
+ # pip to create the appropriate form of executable for the target platform.
+ entry_points={
+ 'console_scripts': [
+ 'oo-install=ooinstall.cli_installer:main',
+ ],
+ },
+)
diff --git a/utils/site_assets/oo-install-bootstrap.sh b/utils/site_assets/oo-install-bootstrap.sh
new file mode 100755
index 000000000..e1b2cec90
--- /dev/null
+++ b/utils/site_assets/oo-install-bootstrap.sh
@@ -0,0 +1,86 @@
+#!/bin/sh
+
+# Grab command-line arguments
+cmdlnargs="$@"
+
+: ${OO_INSTALL_KEEP_ASSETS:="false"}
+: ${OO_INSTALL_CONTEXT:="INSTALLCONTEXT"}
+: ${TMPDIR:=/tmp}
+: ${OO_INSTALL_LOG:=${TMPDIR}/INSTALLPKGNAME.log}
+[[ $TMPDIR != */ ]] && TMPDIR="${TMPDIR}/"
+
+if [ $OO_INSTALL_CONTEXT != 'origin_vm' ]
+then
+ clear
+ echo "Checking for necessary tools..."
+fi
+if [ -e /etc/redhat-release ]
+then
+ for i in python python-virtualenv openssh-clients gcc
+ do
+ rpm -q $i >/dev/null 2>&1 || { echo >&2 "Missing installation dependency detected. Please run \"yum install ${i}\"."; exit 1; }
+ done
+fi
+for i in python virtualenv ssh gcc
+do
+ command -v $i >/dev/null 2>&1 || { echo >&2 "OpenShift installation requires $i on the PATH but it does not appear to be available. Correct this and rerun the installer."; exit 1; }
+done
+
+# All instances of INSTALLPKGNAME are replaced during packaging with the actual package name.
+if [[ -e ./INSTALLPKGNAME.tgz ]]
+then
+ if [ $OO_INSTALL_CONTEXT != 'origin_vm' ]
+ then
+ echo "Using bundled assets."
+ fi
+ cp INSTALLPKGNAME.tgz ${TMPDIR}/INSTALLPKGNAME.tgz
+elif [[ $OO_INSTALL_KEEP_ASSETS == 'true' && -e ${TMPDIR}/INSTALLPKGNAME.tgz ]]
+then
+ if [ $OO_INSTALL_CONTEXT != 'origin_vm' ]
+ then
+ echo "Using existing installer assets."
+ fi
+else
+ echo "Downloading oo-install package to ${TMPDIR}INSTALLPKGNAME.tgz..."
+ curl -s -o ${TMPDIR}INSTALLPKGNAME.tgz https://install.openshift.com/INSTALLVERPATHINSTALLPKGNAME.tgz
+fi
+
+if [ $OO_INSTALL_CONTEXT != 'origin_vm' ]
+then
+ echo "Extracting oo-install to ${TMPDIR}INSTALLPKGNAME..."
+fi
+tar xzf ${TMPDIR}INSTALLPKGNAME.tgz -C ${TMPDIR} 2>&1 >> $OO_INSTALL_LOG
+
+echo "Preparing to install. This can take a minute or two..."
+virtualenv ${TMPDIR}/INSTALLPKGNAME 2>&1 >> $OO_INSTALL_LOG
+cd ${TMPDIR}/INSTALLPKGNAME 2>&1 >> $OO_INSTALL_LOG
+source ./bin/activate 2>&1 >> $OO_INSTALL_LOG
+pip install --no-index -f file:///$(readlink -f deps) ansible 2>&1 >> $OO_INSTALL_LOG
+
+# TODO: these deps should technically be handled as part of installing ooinstall
+pip install --no-index -f file:///$(readlink -f deps) click 2>&1 >> $OO_INSTALL_LOG
+pip install --no-index ./src/ 2>&1 >> $OO_INSTALL_LOG
+echo "Installation preperation done!" 2>&1 >> $OO_INSTALL_LOG
+
+echo "Using `ansible --version`" 2>&1 >> $OO_INSTALL_LOG
+
+if [ $OO_INSTALL_CONTEXT != 'origin_vm' ]
+then
+ echo "Starting oo-install..." 2>&1 >> $OO_INSTALL_LOG
+else
+ clear
+fi
+oo-install $cmdlnargs --ansible-playbook-directory ${TMPDIR}/INSTALLPKGNAME/openshift-ansible-*/ --ansible-log-path $OO_INSTALL_LOG
+
+if [ $OO_INSTALL_KEEP_ASSETS == 'true' ]
+then
+ echo "Keeping temporary assets in ${TMPDIR}"
+else
+ echo "Removing temporary assets."
+ rm -rf ${TMPDIR}INSTALLPKGNAME
+ rm -rf ${TMPDIR}INSTALLPKGNAME.tgz
+fi
+
+echo "Please see $OO_INSTALL_LOG for full output."
+
+exit
diff --git a/utils/site_assets/oo_install_launcher.README.txt b/utils/site_assets/oo_install_launcher.README.txt
new file mode 100644
index 000000000..46947b481
--- /dev/null
+++ b/utils/site_assets/oo_install_launcher.README.txt
@@ -0,0 +1,22 @@
+= oo-install Portable Installer Package
+
+This package is identical to the installer package that can be downloaded
+and executed directly from https://install.openshift.com/.
+
+NOTE: It will still be necessary for this installer to download RPMs from the
+internet, unless you have already set up the necessary local repositories.
+
+To run the installer from this package, run the following command:
+
+$ ./LAUNCHERNAME
+
+That command script and the packaged zip file can be burned to a CD or
+written to a USB drive and used to run the oo-install utility in places
+where the web-based installer is not reachable.
+
+All of the command-line arguments supported by oo-install can be passed
+to this launcher application.
+
+For more information for Enterprise installs, refer to the OpenShift
+Enterprise Administrator Guide:
+https://docs.openshift.com/enterprise/latest/welcome/index.html
diff --git a/utils/src/DESCRIPTION.rst b/utils/src/DESCRIPTION.rst
new file mode 100644
index 000000000..68b3a57f2
--- /dev/null
+++ b/utils/src/DESCRIPTION.rst
@@ -0,0 +1,13 @@
+A sample Python project
+=======================
+
+This is the description file for the project.
+
+The file should use UTF-8 encoding and be written using ReStructured Text. It
+will be used to generate the project webpage on PyPI, and should be written for
+that purpose.
+
+Typical contents for this file would include an overview of the project, basic
+usage examples, etc. Generally, including the project changelog in here is not
+a good idea, although a simple "What's New" section for the most recent version
+may be appropriate.
diff --git a/utils/src/MANIFEST.in b/utils/src/MANIFEST.in
new file mode 100644
index 000000000..d4153e738
--- /dev/null
+++ b/utils/src/MANIFEST.in
@@ -0,0 +1,9 @@
+include DESCRIPTION.rst
+
+# Include the test suite (FIXME: does not work yet)
+# recursive-include tests *
+
+# If using Python 2.6 or less, then have to include package data, even though
+# it's already declared in setup.py
+include ooinstall/*
+include ansible.cfg
diff --git a/utils/src/data/data_file b/utils/src/data/data_file
new file mode 100644
index 000000000..7c0646bfd
--- /dev/null
+++ b/utils/src/data/data_file
@@ -0,0 +1 @@
+some data \ No newline at end of file
diff --git a/utils/src/ooinstall/__init__.py b/utils/src/ooinstall/__init__.py
new file mode 100644
index 000000000..944dea3b5
--- /dev/null
+++ b/utils/src/ooinstall/__init__.py
@@ -0,0 +1,5 @@
+# TODO: Temporarily disabled due to importing old code into openshift-ansible
+# repo. We will work on these over time.
+# pylint: disable=missing-docstring
+
+from .oo_config import OOConfig
diff --git a/utils/src/ooinstall/ansible_plugins/facts_callback.py b/utils/src/ooinstall/ansible_plugins/facts_callback.py
new file mode 100644
index 000000000..ea6ed6574
--- /dev/null
+++ b/utils/src/ooinstall/ansible_plugins/facts_callback.py
@@ -0,0 +1,88 @@
+# TODO: Temporarily disabled due to importing old code into openshift-ansible
+# repo. We will work on these over time.
+# pylint: disable=bad-continuation,missing-docstring,no-self-use,invalid-name,no-value-for-parameter
+
+import os
+import yaml
+
+class CallbackModule(object):
+
+ def __init__(self):
+ ######################
+ # This is ugly stoopid. This should be updated in the following ways:
+ # 1) it should probably only be used for the
+ # openshift_facts.yml playbook, so maybe there's some way to check
+ # a variable that's set when that playbook is run?
+ try:
+ self.hosts_yaml_name = os.environ['OO_INSTALL_CALLBACK_FACTS_YAML']
+ except KeyError:
+ raise ValueError('The OO_INSTALL_CALLBACK_FACTS_YAML environment '
+ 'variable must be set.')
+ self.hosts_yaml = os.open(self.hosts_yaml_name, os.O_CREAT |
+ os.O_WRONLY)
+
+ def on_any(self, *args, **kwargs):
+ pass
+
+ def runner_on_failed(self, host, res, ignore_errors=False):
+ pass
+
+ def runner_on_ok(self, host, res):
+ if res['invocation']['module_args'] == 'var=result':
+ facts = res['var']['result']['ansible_facts']['openshift']
+ hosts_yaml = {}
+ hosts_yaml[host] = facts
+ os.write(self.hosts_yaml, yaml.safe_dump(hosts_yaml))
+
+ def runner_on_skipped(self, host, item=None):
+ pass
+
+ def runner_on_unreachable(self, host, res):
+ pass
+
+ def runner_on_no_hosts(self):
+ pass
+
+ def runner_on_async_poll(self, host, res):
+ pass
+
+ def runner_on_async_ok(self, host, res):
+ pass
+
+ def runner_on_async_failed(self, host, res):
+ pass
+
+ def playbook_on_start(self):
+ pass
+
+ def playbook_on_notify(self, host, handler):
+ pass
+
+ def playbook_on_no_hosts_matched(self):
+ pass
+
+ def playbook_on_no_hosts_remaining(self):
+ pass
+
+ def playbook_on_task_start(self, name, is_conditional):
+ pass
+
+ #pylint: disable=too-many-arguments
+ def playbook_on_vars_prompt(self, varname, private=True, prompt=None,
+ encrypt=None, confirm=False, salt_size=None, salt=None, default=None):
+ pass
+
+ def playbook_on_setup(self):
+ pass
+
+ def playbook_on_import_for_host(self, host, imported_file):
+ pass
+
+ def playbook_on_not_import_for_host(self, host, missing_file):
+ pass
+
+ def playbook_on_play_start(self, name):
+ pass
+
+ def playbook_on_stats(self, stats):
+ pass
diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py
new file mode 100644
index 000000000..c2ae00bd1
--- /dev/null
+++ b/utils/src/ooinstall/cli_installer.py
@@ -0,0 +1,479 @@
+# TODO: Temporarily disabled due to importing old code into openshift-ansible
+# repo. We will work on these over time.
+# pylint: disable=bad-continuation,missing-docstring,no-self-use,invalid-name,no-value-for-parameter
+
+import click
+import os
+import re
+import sys
+from ooinstall import install_transactions
+from ooinstall import OOConfig
+from ooinstall.oo_config import Host
+from ooinstall.variants import find_variant, get_variant_version_combos
+
+DEFAULT_ANSIBLE_CONFIG = '/usr/share/atomic-openshift-util/ansible.cfg'
+
+def validate_ansible_dir(path):
+ if not path:
+ raise click.BadParameter('An ansible path must be provided')
+ return path
+ # if not os.path.exists(path)):
+ # raise click.BadParameter("Path \"{}\" doesn't exist".format(path))
+
+def is_valid_hostname(hostname):
+ if not hostname or len(hostname) > 255:
+ return False
+ if hostname[-1] == ".":
+ hostname = hostname[:-1] # strip exactly one dot from the right, if present
+ allowed = re.compile(r"(?!-)[A-Z\d-]{1,63}(?<!-)$", re.IGNORECASE)
+ return all(allowed.match(x) for x in hostname.split("."))
+
+def validate_prompt_hostname(hostname):
+ if '' == hostname or is_valid_hostname(hostname):
+ return hostname
+ raise click.BadParameter('"{}" appears to be an invalid hostname. ' \
+ 'Please double-check this value i' \
+ 'and re-enter it.'.format(hostname))
+
+def get_ansible_ssh_user():
+ click.clear()
+ message = """
+This installation process will involve connecting to remote hosts via ssh. Any
+account may be used however if a non-root account is used it must have
+passwordless sudo access.
+"""
+ click.echo(message)
+ return click.prompt('User for ssh access', default='root')
+
+def list_hosts(hosts):
+ hosts_idx = range(len(hosts))
+ for idx in hosts_idx:
+ click.echo(' {}: {}'.format(idx, hosts[idx]))
+
+def delete_hosts(hosts):
+ while True:
+ list_hosts(hosts)
+ del_idx = click.prompt('Select host to delete, y/Y to confirm, ' \
+ 'or n/N to add more hosts', default='n')
+ try:
+ del_idx = int(del_idx)
+ hosts.remove(hosts[del_idx])
+ except IndexError:
+ click.echo("\"{}\" doesn't match any hosts listed.".format(del_idx))
+ except ValueError:
+ try:
+ response = del_idx.lower()
+ if response in ['y', 'n']:
+ return hosts, response
+ click.echo("\"{}\" doesn't coorespond to any valid input.".format(del_idx))
+ except AttributeError:
+ click.echo("\"{}\" doesn't coorespond to any valid input.".format(del_idx))
+ return hosts, None
+
+def collect_hosts():
+ """
+ Collect host information from user. This will later be filled in using
+ ansible.
+
+ Returns: a list of host information collected from the user
+ """
+ click.clear()
+ click.echo('***Host Configuration***')
+ message = """
+The OpenShift Master serves the API and web console. It also coordinates the
+jobs that have to run across the environment. It can even run the datastore.
+For wizard based installations the database will be embedded. It's possible to
+change this later using etcd from Red Hat Enterprise Linux 7.
+
+Any Masters configured as part of this installation process will also be
+configured as Nodes. This is so that the Master will be able to proxy to Pods
+from the API. By default this Node will be unscheduleable but this can be changed
+after installation with 'oadm manage-node'.
+
+The OpenShift Node provides the runtime environments for containers. It will
+host the required services to be managed by the Master.
+
+http://docs.openshift.com/enterprise/latest/architecture/infrastructure_components/kubernetes_infrastructure.html#master
+http://docs.openshift.com/enterprise/3.0/architecture/infrastructure_components/kubernetes_infrastructure.html#node
+ """
+ click.echo(message)
+
+ hosts = []
+ more_hosts = True
+ ip_regex = re.compile(r'^\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}$')
+
+ while more_hosts:
+ host_props = {}
+ hostname_or_ip = click.prompt('Enter hostname or IP address:',
+ default='',
+ value_proc=validate_prompt_hostname)
+
+ if ip_regex.match(hostname_or_ip):
+ host_props['ip'] = hostname_or_ip
+ else:
+ host_props['hostname'] = hostname_or_ip
+
+ host_props['master'] = click.confirm('Will this host be an OpenShift Master?')
+ host_props['node'] = True
+
+ rpm_or_container = click.prompt('Will this host be RPM or Container based (rpm/container)?',
+ type=click.Choice(['rpm', 'container']),
+ default='rpm')
+ if rpm_or_container == 'container':
+ host_props['containerized'] = True
+ else:
+ host_props['containerized'] = False
+
+ host = Host(**host_props)
+
+ hosts.append(host)
+
+ more_hosts = click.confirm('Do you want to add additional hosts?')
+ return hosts
+
+def confirm_hosts_facts(oo_cfg, callback_facts):
+ hosts = oo_cfg.hosts
+ click.clear()
+ message = """
+A list of the facts gathered from the provided hosts follows. Because it is
+often the case that the hostname for a system inside the cluster is different
+from the hostname that is resolveable from command line or web clients
+these settings cannot be validated automatically.
+
+For some cloud providers the installer is able to gather metadata exposed in
+the instance so reasonable defaults will be provided.
+
+Plese confirm that they are correct before moving forward.
+
+"""
+ notes = """
+Format:
+
+IP,public IP,hostname,public hostname
+
+Notes:
+ * The installation host is the hostname from the installer's perspective.
+ * The IP of the host should be the internal IP of the instance.
+ * The public IP should be the externally accessible IP associated with the instance
+ * The hostname should resolve to the internal IP from the instances
+ themselves.
+ * The public hostname should resolve to the external ip from hosts outside of
+ the cloud.
+"""
+
+ # For testing purposes we need to click.echo only once, so build up
+ # the message:
+ output = message
+
+ default_facts_lines = []
+ default_facts = {}
+ validated_facts = {}
+ for h in hosts:
+ default_facts[h] = {}
+ h.ip = callback_facts[str(h)]["common"]["ip"]
+ h.public_ip = callback_facts[str(h)]["common"]["public_ip"]
+ h.hostname = callback_facts[str(h)]["common"]["hostname"]
+ h.public_hostname = callback_facts[str(h)]["common"]["public_hostname"]
+
+ validated_facts[h] = {}
+ default_facts_lines.append(",".join([h.ip,
+ h.public_ip,
+ h.hostname,
+ h.public_hostname]))
+ output = "%s\n%s" % (output, ",".join([h.ip,
+ h.public_ip,
+ h.hostname,
+ h.public_hostname]))
+
+ output = "%s\n%s" % (output, notes)
+ click.echo(output)
+ facts_confirmed = click.confirm("Do the above facts look correct?")
+ if not facts_confirmed:
+ message = """
+Edit %s with the desired values and rerun oo-install with --unattended .
+""" % oo_cfg.config_path
+ click.echo(message)
+ # Make sure we actually write out the config file.
+ oo_cfg.save_to_disk()
+ sys.exit(0)
+ return default_facts
+
+def get_variant_and_version():
+ message = "\nWhich variant would you like to install?\n\n"
+
+ i = 1
+ combos = get_variant_version_combos()
+ for (variant, version) in combos:
+ message = "%s\n(%s) %s %s" % (message, i, variant.description,
+ version.name)
+ i = i + 1
+
+ click.echo(message)
+ response = click.prompt("Choose a variant from above: ", default=1)
+ product, version = combos[response - 1]
+
+ return product, version
+
+def confirm_continue(message):
+ click.echo(message)
+ click.confirm("Are you ready to continue?", default=False, abort=True)
+ return
+
+def error_if_missing_info(oo_cfg):
+ missing_info = False
+ if not oo_cfg.hosts:
+ missing_info = True
+ click.echo('For unattended installs, hosts must be specified on the '
+ 'command line or in the config file: %s' % oo_cfg.config_path)
+ sys.exit(1)
+
+ if 'ansible_ssh_user' not in oo_cfg.settings:
+ click.echo("Must specify ansible_ssh_user in configuration file.")
+ sys.exit(1)
+
+ # Lookup a variant based on the key we were given:
+ if not oo_cfg.settings['variant']:
+ click.echo("No variant specified in configuration file.")
+ sys.exit(1)
+
+ ver = None
+ if 'variant_version' in oo_cfg.settings:
+ ver = oo_cfg.settings['variant_version']
+ variant, version = find_variant(oo_cfg.settings['variant'], version=ver)
+ if variant is None or version is None:
+ err_variant_name = oo_cfg.settings['variant']
+ if ver:
+ err_variant_name = "%s %s" % (err_variant_name, ver)
+ click.echo("%s is not an installable variant." % err_variant_name)
+ sys.exit(1)
+ oo_cfg.settings['variant_version'] = version.name
+
+ missing_facts = oo_cfg.calc_missing_facts()
+ if len(missing_facts) > 0:
+ missing_info = True
+ click.echo('For unattended installs, facts must be provided for all masters/nodes:')
+ for host in missing_facts:
+ click.echo('Host "%s" missing facts: %s' % (host, ", ".join(missing_facts[host])))
+
+ if missing_info:
+ sys.exit(1)
+
+
+def get_missing_info_from_user(oo_cfg):
+ """ Prompts the user for any information missing from the given configuration. """
+ click.clear()
+
+ message = """
+Welcome to the OpenShift Enterprise 3 installation.
+
+Please confirm that following prerequisites have been met:
+
+* All systems where OpenShift will be installed are running Red Hat Enterprise
+ Linux 7.
+* All systems are properly subscribed to the required OpenShift Enterprise 3
+ repositories.
+* All systems have run docker-storage-setup (part of the Red Hat docker RPM).
+* All systems have working DNS that resolves not only from the perspective of
+ the installer but also from within the cluster.
+
+When the process completes you will have a default configuration for Masters
+and Nodes. For ongoing environment maintenance it's recommended that the
+official Ansible playbooks be used.
+
+For more information on installation prerequisites please see:
+https://docs.openshift.com/enterprise/latest/admin_guide/install/prerequisites.html
+"""
+ confirm_continue(message)
+ click.clear()
+
+ if oo_cfg.settings.get('ansible_ssh_user', '') == '':
+ oo_cfg.settings['ansible_ssh_user'] = get_ansible_ssh_user()
+ click.clear()
+
+ if not oo_cfg.hosts:
+ oo_cfg.hosts = collect_hosts()
+ click.clear()
+
+ if oo_cfg.settings.get('variant', '') == '':
+ variant, version = get_variant_and_version()
+ oo_cfg.settings['variant'] = variant.name
+ oo_cfg.settings['variant_version'] = version.name
+ click.clear()
+
+ return oo_cfg
+
+
+def collect_new_nodes():
+ click.clear()
+ click.echo('***New Node Configuration***')
+ message = """
+Add new nodes here
+ """
+ click.echo(message)
+ return collect_hosts()
+
+def get_installed_hosts(hosts, callback_facts):
+ installed_hosts = []
+ for host in hosts:
+ if(host.name in callback_facts.keys()
+ and 'common' in callback_facts[host.name].keys()
+ and callback_facts[host.name]['common'].get('version', '')
+ and callback_facts[host.name]['common'].get('version', '') != 'None'):
+ installed_hosts.append(host)
+ return installed_hosts
+
+def get_hosts_to_run_on(oo_cfg, callback_facts, unattended, force):
+
+ # Copy the list of existing hosts so we can remove any already installed nodes.
+ hosts_to_run_on = list(oo_cfg.hosts)
+
+ # Check if master or nodes already have something installed
+ installed_hosts = get_installed_hosts(oo_cfg.hosts, callback_facts)
+ if len(installed_hosts) > 0:
+ # present a message listing already installed hosts
+ for host in installed_hosts:
+ if host.master:
+ click.echo("{} is already an OpenShift Master".format(host))
+ # Masters stay in the list, we need to run against them when adding
+ # new nodes.
+ elif host.node:
+ click.echo("{} is already an OpenShift Node".format(host))
+ hosts_to_run_on.remove(host)
+ # for unattended either continue if they force install or exit if they didn't
+ if unattended:
+ if not force:
+ click.echo('Installed environment detected and no additional nodes specified: ' \
+ 'aborting. If you want a fresh install, use --force')
+ sys.exit(1)
+ # for attended ask the user what to do
+ else:
+ click.echo('Installed environment detected and no additional nodes specified. ')
+ response = click.prompt('Do you want to (1) add more nodes or ' \
+ '(2) perform a clean install?', type=int)
+ if response == 1: # add more nodes
+ new_nodes = collect_new_nodes()
+
+ hosts_to_run_on.extend(new_nodes)
+ oo_cfg.hosts.extend(new_nodes)
+
+ install_transactions.set_config(oo_cfg)
+ callback_facts, error = install_transactions.default_facts(oo_cfg.hosts)
+ if error:
+ click.echo("There was a problem fetching the required information. " \
+ "See {} for details.".format(oo_cfg.settings['ansible_log_path']))
+ sys.exit(1)
+ else:
+ pass # proceeding as normal should do a clean install
+
+ return hosts_to_run_on, callback_facts
+
+@click.command()
+@click.option('--configuration', '-c',
+ type=click.Path(file_okay=True,
+ dir_okay=False,
+ writable=True,
+ readable=True),
+ default=None)
+@click.option('--ansible-playbook-directory',
+ '-a',
+ type=click.Path(exists=True,
+ file_okay=False,
+ dir_okay=True,
+ writable=True,
+ readable=True),
+ # callback=validate_ansible_dir,
+ envvar='OO_ANSIBLE_PLAYBOOK_DIRECTORY')
+@click.option('--ansible-config',
+ type=click.Path(file_okay=True,
+ dir_okay=False,
+ writable=True,
+ readable=True),
+ default=None)
+@click.option('--ansible-log-path',
+ type=click.Path(file_okay=True,
+ dir_okay=False,
+ writable=True,
+ readable=True),
+ default="/tmp/ansible.log")
+@click.option('--unattended', '-u', is_flag=True, default=False)
+@click.option('--force', '-f', is_flag=True, default=False)
+#pylint: disable=too-many-arguments
+# Main CLI entrypoint, not much we can do about too many arguments.
+def main(configuration, ansible_playbook_directory, ansible_config, ansible_log_path, unattended, force):
+ oo_cfg = OOConfig(configuration)
+
+ if not ansible_playbook_directory:
+ ansible_playbook_directory = oo_cfg.settings.get('ansible_playbook_directory', '')
+
+ if ansible_config:
+ oo_cfg.settings['ansible_config'] = ansible_config
+ elif os.path.exists(DEFAULT_ANSIBLE_CONFIG):
+ # If we're installed by RPM this file should exist and we can use it as our default:
+ oo_cfg.settings['ansible_config'] = DEFAULT_ANSIBLE_CONFIG
+
+ validate_ansible_dir(ansible_playbook_directory)
+ oo_cfg.settings['ansible_playbook_directory'] = ansible_playbook_directory
+ oo_cfg.ansible_playbook_directory = ansible_playbook_directory
+
+ oo_cfg.settings['ansible_log_path'] = ansible_log_path
+ install_transactions.set_config(oo_cfg)
+
+ if unattended:
+ error_if_missing_info(oo_cfg)
+ else:
+ oo_cfg = get_missing_info_from_user(oo_cfg)
+
+ click.echo('Gathering information from hosts...')
+ callback_facts, error = install_transactions.default_facts(oo_cfg.hosts)
+ if error:
+ click.echo("There was a problem fetching the required information. " \
+ "Please see {} for details.".format(oo_cfg.settings['ansible_log_path']))
+ sys.exit(1)
+
+ hosts_to_run_on, callback_facts = get_hosts_to_run_on(oo_cfg, callback_facts, unattended, force)
+
+
+ click.echo('Writing config to: %s' % oo_cfg.config_path)
+
+ # We already verified this is not the case for unattended installs, so this can
+ # only trigger for live CLI users:
+ # TODO: if there are *new* nodes and this is a live install, we may need the user
+ # to confirm the settings for new nodes. Look into this once we're distinguishing
+ # between new and pre-existing nodes.
+ if len(oo_cfg.calc_missing_facts()) > 0:
+ confirm_hosts_facts(oo_cfg, callback_facts)
+
+ oo_cfg.save_to_disk()
+
+ click.echo('Ready to run installation process.')
+ message = """
+If changes are needed to the values recorded by the installer please update {}.
+""".format(oo_cfg.config_path)
+ if not unattended:
+ confirm_continue(message)
+
+ error = install_transactions.run_main_playbook(oo_cfg.hosts,
+ hosts_to_run_on)
+ if error:
+ # The bootstrap script will print out the log location.
+ message = """
+An error was detected. After resolving the problem please relaunch the
+installation process.
+"""
+ click.echo(message)
+ sys.exit(1)
+ else:
+ message = """
+The installation was successful!
+
+If this is your first time installing please take a look at the Administrator
+Guide for advanced options related to routing, storage, authentication and much
+more:
+
+http://docs.openshift.com/enterprise/latest/admin_guide/overview.html
+"""
+ click.echo(message)
+ click.pause()
+
+if __name__ == '__main__':
+ main()
diff --git a/utils/src/ooinstall/install_transactions.py b/utils/src/ooinstall/install_transactions.py
new file mode 100644
index 000000000..cef6662d7
--- /dev/null
+++ b/utils/src/ooinstall/install_transactions.py
@@ -0,0 +1,133 @@
+# TODO: Temporarily disabled due to importing old code into openshift-ansible
+# repo. We will work on these over time.
+# pylint: disable=bad-continuation,missing-docstring,no-self-use,invalid-name,global-statement,global-variable-not-assigned
+
+import subprocess
+import os
+import yaml
+from ooinstall.variants import find_variant
+
+CFG = None
+
+def set_config(cfg):
+ global CFG
+ CFG = cfg
+
+def generate_inventory(hosts):
+ print hosts
+ global CFG
+ base_inventory_path = CFG.settings['ansible_inventory_path']
+ base_inventory = open(base_inventory_path, 'w')
+ base_inventory.write('\n[OSEv3:children]\nmasters\nnodes\n')
+ base_inventory.write('\n[OSEv3:vars]\n')
+ base_inventory.write('ansible_ssh_user={}\n'.format(CFG.settings['ansible_ssh_user']))
+ if CFG.settings['ansible_ssh_user'] != 'root':
+ base_inventory.write('ansible_sudo=true\n')
+
+ # Find the correct deployment type for ansible:
+ ver = find_variant(CFG.settings['variant'],
+ version=CFG.settings.get('variant_version', None))[1]
+ base_inventory.write('deployment_type={}\n'.format(ver.ansible_key))
+
+ if 'OO_INSTALL_DEVEL_REGISTRY' in os.environ:
+ base_inventory.write('oreg_url=rcm-img-docker01.build.eng.bos.redhat.com:'
+ '5001/openshift3/ose-${component}:${version}\n')
+ if 'OO_INSTALL_PUDDLE_REPO_ENABLE' in os.environ:
+ base_inventory.write("openshift_additional_repos=[{'id': 'ose-devel', "
+ "'name': 'ose-devel', "
+ "'baseurl': 'http://buildvm-devops.usersys.redhat.com"
+ "/puddle/build/AtomicOpenShift/3.1/latest/RH7-RHAOS-3.1/$basearch/os', "
+ "'enabled': 1, 'gpgcheck': 0}]\n")
+ if 'OO_INSTALL_STAGE_REGISTRY' in os.environ:
+ base_inventory.write('oreg_url=registry.access.stage.redhat.com/openshift3/ose-${component}:${version}\n')
+
+ base_inventory.write('\n[masters]\n')
+ masters = (host for host in hosts if host.master)
+ for master in masters:
+ write_host(master, base_inventory)
+ base_inventory.write('\n[nodes]\n')
+ nodes = (host for host in hosts if host.node)
+ for node in nodes:
+ # TODO: Until the Master can run the SDN itself we have to configure the Masters
+ # as Nodes too.
+ scheduleable = True
+ # If there's only one Node and it's also a Master we want it to be scheduleable:
+ if node in masters and len(masters) != 1:
+ scheduleable = False
+ write_host(node, base_inventory, scheduleable)
+ base_inventory.close()
+ return base_inventory_path
+
+
+def write_host(host, inventory, scheduleable=True):
+ global CFG
+ facts = ''
+ if host.ip:
+ facts += ' openshift_ip={}'.format(host.ip)
+ if host.public_ip:
+ facts += ' openshift_public_ip={}'.format(host.public_ip)
+ if host.hostname:
+ facts += ' openshift_hostname={}'.format(host.hostname)
+ if host.public_hostname:
+ facts += ' openshift_public_hostname={}'.format(host.public_hostname)
+ # TODO: For not write_host is handles both master and nodes.
+ # Technically only nodes will ever need this.
+ if not scheduleable:
+ facts += ' openshift_scheduleable=False'
+ inventory.write('{} {}\n'.format(host, facts))
+
+
+def load_system_facts(inventory_file, os_facts_path, env_vars):
+ """
+ Retrieves system facts from the remote systems.
+ """
+ FNULL = open(os.devnull, 'w')
+ status = subprocess.call(['ansible-playbook',
+ '--inventory-file={}'.format(inventory_file),
+ os_facts_path],
+ env=env_vars,
+ stdout=FNULL)
+ if not status == 0:
+ return [], 1
+ callback_facts_file = open(CFG.settings['ansible_callback_facts_yaml'], 'r')
+ callback_facts = yaml.load(callback_facts_file)
+ callback_facts_file.close()
+ return callback_facts, 0
+
+
+def default_facts(hosts):
+ global CFG
+ inventory_file = generate_inventory(hosts)
+ os_facts_path = '{}/playbooks/byo/openshift_facts.yml'.format(CFG.ansible_playbook_directory)
+
+ facts_env = os.environ.copy()
+ facts_env["OO_INSTALL_CALLBACK_FACTS_YAML"] = CFG.settings['ansible_callback_facts_yaml']
+ facts_env["ANSIBLE_CALLBACK_PLUGINS"] = CFG.settings['ansible_plugins_directory']
+ if 'ansible_log_path' in CFG.settings:
+ facts_env["ANSIBLE_LOG_PATH"] = CFG.settings['ansible_log_path']
+ if 'ansible_config' in CFG.settings:
+ facts_env['ANSIBLE_CONFIG'] = CFG.settings['ansible_config']
+ return load_system_facts(inventory_file, os_facts_path, facts_env)
+
+
+def run_main_playbook(hosts, hosts_to_run_on):
+ global CFG
+ inventory_file = generate_inventory(hosts)
+ if len(hosts_to_run_on) != len(hosts):
+ main_playbook_path = os.path.join(CFG.ansible_playbook_directory,
+ 'playbooks/common/openshift-cluster/scaleup.yml')
+ else:
+ main_playbook_path = os.path.join(CFG.ansible_playbook_directory,
+ 'playbooks/byo/config.yml')
+ facts_env = os.environ.copy()
+ if 'ansible_log_path' in CFG.settings:
+ facts_env['ANSIBLE_LOG_PATH'] = CFG.settings['ansible_log_path']
+ if 'ansible_config' in CFG.settings:
+ facts_env['ANSIBLE_CONFIG'] = CFG.settings['ansible_config']
+ return run_ansible(main_playbook_path, inventory_file, facts_env)
+
+def run_ansible(playbook, inventory, env_vars):
+ return subprocess.call(['ansible-playbook',
+ '--inventory-file={}'.format(inventory),
+ playbook],
+ env=env_vars)
diff --git a/utils/src/ooinstall/oo_config.py b/utils/src/ooinstall/oo_config.py
new file mode 100644
index 000000000..a2f53cf78
--- /dev/null
+++ b/utils/src/ooinstall/oo_config.py
@@ -0,0 +1,195 @@
+# TODO: Temporarily disabled due to importing old code into openshift-ansible
+# repo. We will work on these over time.
+# pylint: disable=bad-continuation,missing-docstring,no-self-use,invalid-name,too-many-instance-attributes,too-few-public-methods
+
+import os
+import yaml
+from pkg_resources import resource_filename
+
+PERSIST_SETTINGS = [
+ 'ansible_ssh_user',
+ 'ansible_config',
+ 'ansible_log_path',
+ 'variant',
+ 'variant_version',
+ ]
+REQUIRED_FACTS = ['ip', 'public_ip', 'hostname', 'public_hostname']
+
+
+class OOConfigFileError(Exception):
+ """The provided config file path can't be read/written
+ """
+ pass
+
+
+class OOConfigInvalidHostError(Exception):
+ """ Host in config is missing both ip and hostname. """
+ pass
+
+
+class Host(object):
+ """ A system we will or have installed OpenShift on. """
+ def __init__(self, **kwargs):
+ self.ip = kwargs.get('ip', None)
+ self.hostname = kwargs.get('hostname', None)
+ self.public_ip = kwargs.get('public_ip', None)
+ self.public_hostname = kwargs.get('public_hostname', None)
+
+ # Should this host run as an OpenShift master:
+ self.master = kwargs.get('master', False)
+
+ # Should this host run as an OpenShift node:
+ self.node = kwargs.get('node', False)
+ self.containerized = kwargs.get('containerized', False)
+
+ if self.ip is None and self.hostname is None:
+ raise OOConfigInvalidHostError("You must specify either 'ip' or 'hostname'")
+
+ if self.master is False and self.node is False:
+ raise OOConfigInvalidHostError(
+ "You must specify each host as either a master or a node.")
+
+ # Hosts can be specified with an ip, hostname, or both. However we need
+ # something authoritative we can connect to and refer to the host by.
+ # Preference given to the IP if specified as this is more specific.
+ # We know one must be set by this point.
+ self.name = self.ip if self.ip is not None else self.hostname
+
+ def __str__(self):
+ return self.name
+
+ def __repr__(self):
+ return self.name
+
+ def to_dict(self):
+ """ Used when exporting to yaml. """
+ d = {}
+ for prop in ['ip', 'hostname', 'public_ip', 'public_hostname',
+ 'master', 'node', 'containerized']:
+ # If the property is defined (not None or False), export it:
+ if getattr(self, prop):
+ d[prop] = getattr(self, prop)
+ return d
+
+
+class OOConfig(object):
+ new_config = True
+ default_dir = os.path.normpath(
+ os.environ.get('XDG_CONFIG_HOME',
+ os.environ['HOME'] + '/.config/') + '/openshift/')
+ default_file = '/installer.cfg.yml'
+
+ def __init__(self, config_path):
+ if config_path:
+ self.config_path = os.path.normpath(config_path)
+ else:
+ self.config_path = os.path.normpath(self.default_dir +
+ self.default_file)
+ self.settings = {}
+ self.read_config()
+ self.set_defaults()
+
+ def read_config(self, is_new=False):
+ self.hosts = []
+ try:
+ new_settings = None
+ if os.path.exists(self.config_path):
+ cfgfile = open(self.config_path, 'r')
+ new_settings = yaml.safe_load(cfgfile.read())
+ cfgfile.close()
+ if new_settings:
+ self.settings = new_settings
+ # Parse the hosts into DTO objects:
+ if 'hosts' in self.settings:
+ for host in self.settings['hosts']:
+ self.hosts.append(Host(**host))
+
+ # Watchout for the variant_version coming in as a float:
+ if 'variant_version' in self.settings:
+ self.settings['variant_version'] = \
+ str(self.settings['variant_version'])
+
+ except IOError, ferr:
+ raise OOConfigFileError('Cannot open config file "{}": {}'.format(ferr.filename,
+ ferr.strerror))
+ except yaml.scanner.ScannerError:
+ raise OOConfigFileError('Config file "{}" is not a valid YAML document'.format(self.config_path))
+ self.new_config = is_new
+
+ def set_defaults(self):
+
+ if 'ansible_inventory_directory' not in self.settings:
+ self.settings['ansible_inventory_directory'] = \
+ self._default_ansible_inv_dir()
+ if not os.path.exists(self.settings['ansible_inventory_directory']):
+ os.makedirs(self.settings['ansible_inventory_directory'])
+ if 'ansible_plugins_directory' not in self.settings:
+ self.settings['ansible_plugins_directory'] = resource_filename(__name__, 'ansible_plugins')
+
+ if 'ansible_callback_facts_yaml' not in self.settings:
+ self.settings['ansible_callback_facts_yaml'] = '%s/callback_facts.yaml' % \
+ self.settings['ansible_inventory_directory']
+
+ if 'ansible_ssh_user' not in self.settings:
+ self.settings['ansible_ssh_user'] = ''
+
+ self.settings['ansible_inventory_path'] = '{}/hosts'.format(self.settings['ansible_inventory_directory'])
+
+ # clean up any empty sets
+ for setting in self.settings.keys():
+ if not self.settings[setting]:
+ self.settings.pop(setting)
+
+ def _default_ansible_inv_dir(self):
+ return os.path.normpath(
+ os.path.dirname(self.config_path) + "/.ansible")
+
+ def calc_missing_facts(self):
+ """
+ Determine which host facts are not defined in the config.
+
+ Returns a hash of host to a list of the missing facts.
+ """
+ result = {}
+
+ for host in self.hosts:
+ missing_facts = []
+ for required_fact in REQUIRED_FACTS:
+ if not getattr(host, required_fact):
+ missing_facts.append(required_fact)
+ if len(missing_facts) > 0:
+ result[host.name] = missing_facts
+ return result
+
+ def save_to_disk(self):
+ out_file = open(self.config_path, 'w')
+ out_file.write(self.yaml())
+ out_file.close()
+
+ def persist_settings(self):
+ p_settings = {}
+ for setting in PERSIST_SETTINGS:
+ if setting in self.settings and self.settings[setting]:
+ p_settings[setting] = self.settings[setting]
+ p_settings['hosts'] = []
+ for host in self.hosts:
+ p_settings['hosts'].append(host.to_dict())
+
+ if self.settings['ansible_inventory_directory'] != \
+ self._default_ansible_inv_dir():
+ p_settings['ansible_inventory_directory'] = \
+ self.settings['ansible_inventory_directory']
+
+ return p_settings
+
+ def yaml(self):
+ return yaml.safe_dump(self.persist_settings(), default_flow_style=False)
+
+ def __str__(self):
+ return self.yaml()
+
+ def get_host(self, name):
+ for host in self.hosts:
+ if host.name == name:
+ return host
+ return None
diff --git a/utils/src/ooinstall/variants.py b/utils/src/ooinstall/variants.py
new file mode 100644
index 000000000..ed98429fc
--- /dev/null
+++ b/utils/src/ooinstall/variants.py
@@ -0,0 +1,74 @@
+# TODO: Temporarily disabled due to importing old code into openshift-ansible
+# repo. We will work on these over time.
+# pylint: disable=bad-continuation,missing-docstring,no-self-use,invalid-name,too-few-public-methods
+
+"""
+Defines the supported variants and versions the installer supports, and metadata
+required to run Ansible correctly.
+
+This module needs to be updated for each major release to allow the new version
+to be specified by the user, and to point the generic variants to the latest
+version.
+"""
+
+
+class Version(object):
+ def __init__(self, name, ansible_key):
+ self.name = name # i.e. 3.0, 3.1
+
+ self.ansible_key = ansible_key
+
+
+class Variant(object):
+ def __init__(self, name, description, versions):
+ # Supported variant name:
+ self.name = name
+
+ # Friendly name for the variant:
+ self.description = description
+
+ self.versions = versions
+
+
+# WARNING: Keep the versions ordered, most recent last:
+OSE = Variant('openshift-enterprise', 'OpenShift Enterprise',
+ [
+ Version('3.0', 'enterprise'),
+ Version('3.1', 'openshift-enterprise')
+ ]
+)
+
+AEP = Variant('atomic-enterprise', 'Atomic OpenShift Enterprise',
+ [
+ Version('3.1', 'atomic-enterprise')
+ ]
+)
+
+# Ordered list of variants we can install, first is the default.
+SUPPORTED_VARIANTS = (OSE, AEP)
+
+
+def find_variant(name, version=None):
+ """
+ Locate the variant object for the variant given in config file, and
+ the correct version to use for it.
+ Return (None, None) if we can't find a match.
+ """
+ prod = None
+ for prod in SUPPORTED_VARIANTS:
+ if prod.name == name:
+ if version is None:
+ return (prod, prod.versions[-1])
+ for v in prod.versions:
+ if v.name == version:
+ return (prod, v)
+
+ return (None, None)
+
+def get_variant_version_combos():
+ combos = []
+ for variant in SUPPORTED_VARIANTS:
+ for ver in variant.versions:
+ combos.append((variant, ver))
+ return combos
+
diff --git a/utils/test/__init__.py b/utils/test/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/utils/test/__init__.py
diff --git a/utils/test/cli_installer_tests.py b/utils/test/cli_installer_tests.py
new file mode 100644
index 000000000..076fe5dc9
--- /dev/null
+++ b/utils/test/cli_installer_tests.py
@@ -0,0 +1,471 @@
+# TODO: Temporarily disabled due to importing old code into openshift-ansible
+# repo. We will work on these over time.
+# pylint: disable=bad-continuation,missing-docstring,no-self-use,invalid-name
+
+import copy
+import os
+import ConfigParser
+import yaml
+
+import ooinstall.cli_installer as cli
+
+from click.testing import CliRunner
+from test.oo_config_tests import OOInstallFixture
+from mock import patch
+
+
+MOCK_FACTS = {
+ '10.0.0.1': {
+ 'common': {
+ 'ip': '10.0.0.1',
+ 'public_ip': '10.0.0.1',
+ 'hostname': 'master-private.example.com',
+ 'public_hostname': 'master.example.com'
+ }
+ },
+ '10.0.0.2': {
+ 'common': {
+ 'ip': '10.0.0.2',
+ 'public_ip': '10.0.0.2',
+ 'hostname': 'node1-private.example.com',
+ 'public_hostname': 'node1.example.com'
+ }
+ },
+ '10.0.0.3': {
+ 'common': {
+ 'ip': '10.0.0.3',
+ 'public_ip': '10.0.0.3',
+ 'hostname': 'node2-private.example.com',
+ 'public_hostname': 'node2.example.com'
+ }
+ },
+}
+
+# Substitute in a product name before use:
+SAMPLE_CONFIG = """
+variant: %s
+ansible_ssh_user: root
+hosts:
+ - ip: 10.0.0.1
+ hostname: master-private.example.com
+ public_ip: 24.222.0.1
+ public_hostname: master.example.com
+ master: true
+ node: true
+ - ip: 10.0.0.2
+ hostname: node1-private.example.com
+ public_ip: 24.222.0.2
+ public_hostname: node1.example.com
+ node: true
+ - ip: 10.0.0.3
+ hostname: node2-private.example.com
+ public_ip: 24.222.0.3
+ public_hostname: node2.example.com
+ node: true
+"""
+
+
+class OOCliFixture(OOInstallFixture):
+
+ def setUp(self):
+ OOInstallFixture.setUp(self)
+ self.runner = CliRunner()
+
+ # Add any arguments you would like to test here, the defaults ensure
+ # we only do unattended invocations here, and using temporary files/dirs.
+ self.cli_args = ["-a", self.work_dir]
+
+ def run_cli(self):
+ return self.runner.invoke(cli.main, self.cli_args)
+
+ def assert_result(self, result, exit_code):
+ if result.exception is not None or result.exit_code != exit_code:
+ print "Unexpected result from CLI execution"
+ print "Exit code: %s" % result.exit_code
+ print "Exception: %s" % result.exception
+ print result.exc_info
+ import traceback
+ traceback.print_exception(*result.exc_info)
+ print "Output:\n%s" % result.output
+ self.fail("Exception during CLI execution")
+
+ def _read_yaml(self, config_file_path):
+ f = open(config_file_path, 'r')
+ config = yaml.safe_load(f.read())
+ f.close()
+ return config
+
+
+class UnattendedCliTests(OOCliFixture):
+
+ def setUp(self):
+ OOCliFixture.setUp(self)
+ self.cli_args.append("-u")
+
+ @patch('ooinstall.install_transactions.run_main_playbook')
+ @patch('ooinstall.install_transactions.load_system_facts')
+ def test_cfg_full_run(self, load_facts_mock, run_playbook_mock):
+ load_facts_mock.return_value = (MOCK_FACTS, 0)
+ run_playbook_mock.return_value = 0
+
+ config_file = self.write_config(os.path.join(self.work_dir,
+ 'ooinstall.conf'), SAMPLE_CONFIG % 'openshift-enterprise')
+
+ self.cli_args.extend(["-c", config_file])
+ result = self.runner.invoke(cli.main, self.cli_args)
+ self.assert_result(result, 0)
+
+ load_facts_args = load_facts_mock.call_args[0]
+ self.assertEquals(os.path.join(self.work_dir, ".ansible/hosts"),
+ load_facts_args[0])
+ self.assertEquals(os.path.join(self.work_dir,
+ "playbooks/byo/openshift_facts.yml"), load_facts_args[1])
+ env_vars = load_facts_args[2]
+ self.assertEquals(os.path.join(self.work_dir,
+ '.ansible/callback_facts.yaml'),
+ env_vars['OO_INSTALL_CALLBACK_FACTS_YAML'])
+ self.assertEqual('/tmp/ansible.log', env_vars['ANSIBLE_LOG_PATH'])
+ self.assertTrue('ANSIBLE_CONFIG' not in env_vars)
+
+ # Make sure we ran on the expected masters and nodes:
+ hosts = run_playbook_mock.call_args[0][0]
+ hosts_to_run_on = run_playbook_mock.call_args[0][1]
+ self.assertEquals(3, len(hosts))
+ self.assertEquals(3, len(hosts_to_run_on))
+
+ @patch('ooinstall.install_transactions.run_main_playbook')
+ @patch('ooinstall.install_transactions.load_system_facts')
+ def test_inventory_write(self, load_facts_mock, run_playbook_mock):
+
+ # Add an ssh user so we can verify it makes it to the inventory file:
+ merged_config = "%s\n%s" % (SAMPLE_CONFIG % 'openshift-enterprise',
+ "ansible_ssh_user: bob")
+ load_facts_mock.return_value = (MOCK_FACTS, 0)
+ run_playbook_mock.return_value = 0
+
+ config_file = self.write_config(os.path.join(self.work_dir,
+ 'ooinstall.conf'), merged_config)
+
+ self.cli_args.extend(["-c", config_file])
+ result = self.runner.invoke(cli.main, self.cli_args)
+ self.assert_result(result, 0)
+
+ # Check the inventory file looks as we would expect:
+ inventory = ConfigParser.ConfigParser(allow_no_value=True)
+ inventory.read(os.path.join(self.work_dir, '.ansible/hosts'))
+ self.assertEquals('bob',
+ inventory.get('OSEv3:vars', 'ansible_ssh_user'))
+ self.assertEquals('openshift-enterprise',
+ inventory.get('OSEv3:vars', 'deployment_type'))
+
+ # Check the masters:
+ self.assertEquals(1, len(inventory.items('masters')))
+ self.assertEquals(3, len(inventory.items('nodes')))
+
+ for item in inventory.items('masters'):
+ # ansible host lines do NOT parse nicely:
+ master_line = item[0]
+ if item[1] is not None:
+ master_line = "%s=%s" % (master_line, item[1])
+ self.assertTrue('openshift_ip' in master_line)
+ self.assertTrue('openshift_public_ip' in master_line)
+ self.assertTrue('openshift_hostname' in master_line)
+ self.assertTrue('openshift_public_hostname' in master_line)
+
+ @patch('ooinstall.install_transactions.run_main_playbook')
+ @patch('ooinstall.install_transactions.load_system_facts')
+ def test_variant_version_latest_assumed(self, load_facts_mock,
+ run_playbook_mock):
+ load_facts_mock.return_value = (MOCK_FACTS, 0)
+ run_playbook_mock.return_value = 0
+
+ config_file = self.write_config(os.path.join(self.work_dir,
+ 'ooinstall.conf'), SAMPLE_CONFIG % 'openshift-enterprise')
+
+ self.cli_args.extend(["-c", config_file])
+ result = self.runner.invoke(cli.main, self.cli_args)
+ self.assert_result(result, 0)
+
+ written_config = self._read_yaml(config_file)
+
+ self.assertEquals('openshift-enterprise', written_config['variant'])
+ # We didn't specify a version so the latest should have been assumed,
+ # and written to disk:
+ self.assertEquals('3.1', written_config['variant_version'])
+
+ # Make sure the correct value was passed to ansible:
+ inventory = ConfigParser.ConfigParser(allow_no_value=True)
+ inventory.read(os.path.join(self.work_dir, '.ansible/hosts'))
+ self.assertEquals('openshift-enterprise',
+ inventory.get('OSEv3:vars', 'deployment_type'))
+
+ @patch('ooinstall.install_transactions.run_main_playbook')
+ @patch('ooinstall.install_transactions.load_system_facts')
+ def test_variant_version_preserved(self, load_facts_mock,
+ run_playbook_mock):
+ load_facts_mock.return_value = (MOCK_FACTS, 0)
+ run_playbook_mock.return_value = 0
+
+ config = SAMPLE_CONFIG % 'openshift-enterprise'
+ config = '%s\n%s' % (config, 'variant_version: 3.0')
+ config_file = self.write_config(os.path.join(self.work_dir,
+ 'ooinstall.conf'), config)
+
+ self.cli_args.extend(["-c", config_file])
+ result = self.runner.invoke(cli.main, self.cli_args)
+ self.assert_result(result, 0)
+
+ written_config = self._read_yaml(config_file)
+
+ self.assertEquals('openshift-enterprise', written_config['variant'])
+ # Make sure our older version was preserved:
+ # and written to disk:
+ self.assertEquals('3.0', written_config['variant_version'])
+
+ inventory = ConfigParser.ConfigParser(allow_no_value=True)
+ inventory.read(os.path.join(self.work_dir, '.ansible/hosts'))
+ self.assertEquals('enterprise',
+ inventory.get('OSEv3:vars', 'deployment_type'))
+
+ @patch('ooinstall.install_transactions.run_ansible')
+ @patch('ooinstall.install_transactions.load_system_facts')
+ def test_no_ansible_config_specified(self, load_facts_mock, run_ansible_mock):
+ load_facts_mock.return_value = (MOCK_FACTS, 0)
+ run_ansible_mock.return_value = 0
+
+ config = SAMPLE_CONFIG % 'openshift-enterprise'
+
+ self._ansible_config_test(load_facts_mock, run_ansible_mock,
+ config, None, None)
+
+ @patch('ooinstall.install_transactions.run_ansible')
+ @patch('ooinstall.install_transactions.load_system_facts')
+ def test_ansible_config_specified_cli(self, load_facts_mock, run_ansible_mock):
+ load_facts_mock.return_value = (MOCK_FACTS, 0)
+ run_ansible_mock.return_value = 0
+
+ config = SAMPLE_CONFIG % 'openshift-enterprise'
+ ansible_config = os.path.join(self.work_dir, 'ansible.cfg')
+
+ self._ansible_config_test(load_facts_mock, run_ansible_mock,
+ config, ansible_config, ansible_config)
+
+ @patch('ooinstall.install_transactions.run_ansible')
+ @patch('ooinstall.install_transactions.load_system_facts')
+ def test_ansible_config_specified_in_installer_config(self,
+ load_facts_mock, run_ansible_mock):
+
+ load_facts_mock.return_value = (MOCK_FACTS, 0)
+ run_ansible_mock.return_value = 0
+
+ ansible_config = os.path.join(self.work_dir, 'ansible.cfg')
+ config = SAMPLE_CONFIG % 'openshift-enterprise'
+ config = "%s\nansible_config: %s" % (config, ansible_config)
+ self._ansible_config_test(load_facts_mock, run_ansible_mock,
+ config, None, ansible_config)
+
+ #pylint: disable=too-many-arguments
+ # This method allows for drastically simpler tests to write, and the args
+ # are all useful.
+ def _ansible_config_test(self, load_facts_mock, run_ansible_mock,
+ installer_config, ansible_config_cli=None, expected_result=None):
+ """
+ Utility method for testing the ways you can specify the ansible config.
+ """
+
+ load_facts_mock.return_value = (MOCK_FACTS, 0)
+ run_ansible_mock.return_value = 0
+
+ config_file = self.write_config(os.path.join(self.work_dir,
+ 'ooinstall.conf'), installer_config)
+
+ self.cli_args.extend(["-c", config_file])
+ if ansible_config_cli:
+ self.cli_args.extend(["--ansible-config", ansible_config_cli])
+ result = self.runner.invoke(cli.main, self.cli_args)
+ self.assert_result(result, 0)
+
+ # Test the env vars for facts playbook:
+ facts_env_vars = load_facts_mock.call_args[0][2]
+ if expected_result:
+ self.assertEquals(expected_result, facts_env_vars['ANSIBLE_CONFIG'])
+ else:
+ self.assertFalse('ANSIBLE_CONFIG' in facts_env_vars)
+
+ # Test the env vars for main playbook:
+ env_vars = run_ansible_mock.call_args[0][2]
+ if expected_result:
+ self.assertEquals(expected_result, env_vars['ANSIBLE_CONFIG'])
+ else:
+ self.assertFalse('ANSIBLE_CONFIG' in env_vars)
+
+
+class AttendedCliTests(OOCliFixture):
+
+ def setUp(self):
+ OOCliFixture.setUp(self)
+ # Doesn't exist but keeps us from reading the local users config:
+ self.config_file = os.path.join(self.work_dir, 'config.yml')
+ self.cli_args.extend(["-c", self.config_file])
+
+ #pylint: disable=too-many-arguments
+ def _build_input(self, ssh_user=None, hosts=None, variant_num=None,
+ add_nodes=None, confirm_facts=None):
+ """
+ Builds a CLI input string with newline characters to simulate
+ the full run.
+ This gives us only one place to update when the input prompts change.
+ """
+
+ inputs = [
+ 'y', # let's proceed
+ ]
+ if ssh_user:
+ inputs.append(ssh_user)
+
+ if hosts:
+ i = 0
+ for (host, is_master) in hosts:
+ inputs.append(host)
+ inputs.append('y' if is_master else 'n')
+ inputs.append('rpm')
+ if i < len(hosts) - 1:
+ inputs.append('y') # Add more hosts
+ else:
+ inputs.append('n') # Done adding hosts
+ i += 1
+
+ if variant_num:
+ inputs.append(str(variant_num)) # Choose variant + version
+
+ # TODO: support option 2, fresh install
+ if add_nodes:
+ inputs.append('1') # Add more nodes
+ i = 0
+ for (host, is_master) in add_nodes:
+ inputs.append(host)
+ inputs.append('y' if is_master else 'n')
+ inputs.append('rpm')
+ if i < len(add_nodes) - 1:
+ inputs.append('y') # Add more hosts
+ else:
+ inputs.append('n') # Done adding hosts
+ i += 1
+
+ inputs.extend([
+ confirm_facts,
+ 'y', # lets do this
+ ])
+
+ return '\n'.join(inputs)
+
+ def _verify_load_facts(self, load_facts_mock):
+ """ Check that we ran load facts with expected inputs. """
+ load_facts_args = load_facts_mock.call_args[0]
+ self.assertEquals(os.path.join(self.work_dir, ".ansible/hosts"),
+ load_facts_args[0])
+ self.assertEquals(os.path.join(self.work_dir,
+ "playbooks/byo/openshift_facts.yml"), load_facts_args[1])
+ env_vars = load_facts_args[2]
+ self.assertEquals(os.path.join(self.work_dir,
+ '.ansible/callback_facts.yaml'),
+ env_vars['OO_INSTALL_CALLBACK_FACTS_YAML'])
+ self.assertEqual('/tmp/ansible.log', env_vars['ANSIBLE_LOG_PATH'])
+
+ def _verify_run_playbook(self, run_playbook_mock, exp_hosts_len, exp_hosts_to_run_on_len):
+ """ Check that we ran playbook with expected inputs. """
+ hosts = run_playbook_mock.call_args[0][0]
+ hosts_to_run_on = run_playbook_mock.call_args[0][1]
+ self.assertEquals(exp_hosts_len, len(hosts))
+ self.assertEquals(exp_hosts_to_run_on_len, len(hosts_to_run_on))
+
+ def _verify_config_hosts(self, written_config, host_count):
+ self.assertEquals(host_count, len(written_config['hosts']))
+ for h in written_config['hosts']:
+ self.assertTrue(h['node'])
+ self.assertTrue('ip' in h)
+ self.assertTrue('hostname' in h)
+ self.assertTrue('public_ip' in h)
+ self.assertTrue('public_hostname' in h)
+
+ @patch('ooinstall.install_transactions.run_main_playbook')
+ @patch('ooinstall.install_transactions.load_system_facts')
+ def test_full_run(self, load_facts_mock, run_playbook_mock):
+ load_facts_mock.return_value = (MOCK_FACTS, 0)
+ run_playbook_mock.return_value = 0
+
+ cli_input = self._build_input(hosts=[
+ ('10.0.0.1', True),
+ ('10.0.0.2', False),
+ ('10.0.0.3', False)],
+ ssh_user='root',
+ variant_num=1,
+ confirm_facts='y')
+ result = self.runner.invoke(cli.main, self.cli_args,
+ input=cli_input)
+ self.assert_result(result, 0)
+
+ self._verify_load_facts(load_facts_mock)
+ self._verify_run_playbook(run_playbook_mock, 3, 3)
+
+ written_config = self._read_yaml(self.config_file)
+ self._verify_config_hosts(written_config, 3)
+
+ @patch('ooinstall.install_transactions.run_main_playbook')
+ @patch('ooinstall.install_transactions.load_system_facts')
+ def test_add_nodes(self, load_facts_mock, run_playbook_mock):
+
+ # Modify the mock facts to return a version indicating OpenShift
+ # is already installed on our master, and the first node.
+ mock_facts = copy.deepcopy(MOCK_FACTS)
+ mock_facts['10.0.0.1']['common']['version'] = "3.0.0"
+ mock_facts['10.0.0.2']['common']['version'] = "3.0.0"
+
+ load_facts_mock.return_value = (mock_facts, 0)
+ run_playbook_mock.return_value = 0
+
+ cli_input = self._build_input(hosts=[
+ ('10.0.0.1', True),
+ ('10.0.0.2', False),
+ ],
+ add_nodes=[('10.0.0.3', False)],
+ ssh_user='root',
+ variant_num=1,
+ confirm_facts='y')
+ result = self.runner.invoke(cli.main,
+ self.cli_args,
+ input=cli_input)
+ self.assert_result(result, 0)
+
+ self._verify_load_facts(load_facts_mock)
+ self._verify_run_playbook(run_playbook_mock, 3, 2)
+
+ written_config = self._read_yaml(self.config_file)
+ self._verify_config_hosts(written_config, 3)
+
+ @patch('ooinstall.install_transactions.run_main_playbook')
+ @patch('ooinstall.install_transactions.load_system_facts')
+ def test_fresh_install_with_config(self, load_facts_mock, run_playbook_mock):
+ load_facts_mock.return_value = (MOCK_FACTS, 0)
+ run_playbook_mock.return_value = 0
+
+ config_file = self.write_config(os.path.join(self.work_dir,
+ 'ooinstall.conf'),
+ SAMPLE_CONFIG % 'openshift-enterprise')
+ cli_input = self._build_input(confirm_facts='y')
+ self.cli_args.extend(["-c", config_file])
+ result = self.runner.invoke(cli.main,
+ self.cli_args,
+ input=cli_input)
+ self.assert_result(result, 0)
+
+ self._verify_load_facts(load_facts_mock)
+ self._verify_run_playbook(run_playbook_mock, 3, 3)
+
+ written_config = self._read_yaml(config_file)
+ self._verify_config_hosts(written_config, 3)
+
+# TODO: test with config file, attended add node
+# TODO: test with config file, attended new node already in config file
+# TODO: test with config file, attended new node already in config file, plus manually added nodes
+# TODO: test with config file, attended reject facts
diff --git a/utils/test/oo_config_tests.py b/utils/test/oo_config_tests.py
new file mode 100644
index 000000000..01af33fd9
--- /dev/null
+++ b/utils/test/oo_config_tests.py
@@ -0,0 +1,158 @@
+# TODO: Temporarily disabled due to importing old code into openshift-ansible
+# repo. We will work on these over time.
+# pylint: disable=bad-continuation,missing-docstring,no-self-use,invalid-name
+
+import os
+import unittest
+import tempfile
+import shutil
+import yaml
+
+from ooinstall.oo_config import OOConfig, Host, OOConfigInvalidHostError
+
+SAMPLE_CONFIG = """
+variant: openshift-enterprise
+ansible_ssh_user: root
+hosts:
+ - ip: 10.0.0.1
+ hostname: master-private.example.com
+ public_ip: 24.222.0.1
+ public_hostname: master.example.com
+ master: true
+ node: true
+ - ip: 10.0.0.2
+ hostname: node1-private.example.com
+ public_ip: 24.222.0.2
+ public_hostname: node1.example.com
+ node: true
+ - ip: 10.0.0.3
+ hostname: node2-private.example.com
+ public_ip: 24.222.0.3
+ public_hostname: node2.example.com
+ node: true
+"""
+
+CONFIG_INCOMPLETE_FACTS = """
+hosts:
+ - ip: 10.0.0.1
+ hostname: master-private.example.com
+ public_ip: 24.222.0.1
+ public_hostname: master.example.com
+ master: true
+ - ip: 10.0.0.2
+ hostname: node1-private.example.com
+ public_ip: 24.222.0.2
+ node: true
+ - ip: 10.0.0.3
+ node: true
+"""
+
+
+class OOInstallFixture(unittest.TestCase):
+
+ def setUp(self):
+ self.tempfiles = []
+ self.work_dir = tempfile.mkdtemp(prefix='ooconfigtests')
+ self.tempfiles.append(self.work_dir)
+
+ def tearDown(self):
+ for path in self.tempfiles:
+ if os.path.isdir(path):
+ shutil.rmtree(path)
+ else:
+ os.remove(path)
+
+ def write_config(self, path, config_str):
+ """
+ Write given config to a temporary file which will be cleaned
+ up in teardown.
+ Returns full path to the file.
+ """
+ cfg_file = open(path, 'w')
+ cfg_file.write(config_str)
+ cfg_file.close()
+ return path
+
+
+class OOConfigTests(OOInstallFixture):
+
+ def test_load_config(self):
+
+ cfg_path = self.write_config(os.path.join(self.work_dir,
+ 'ooinstall.conf'), SAMPLE_CONFIG)
+ ooconfig = OOConfig(cfg_path)
+
+ self.assertEquals(3, len(ooconfig.hosts))
+ self.assertEquals("10.0.0.1", ooconfig.hosts[0].name)
+ self.assertEquals("10.0.0.1", ooconfig.hosts[0].ip)
+ self.assertEquals("master-private.example.com", ooconfig.hosts[0].hostname)
+
+ self.assertEquals(["10.0.0.1", "10.0.0.2", "10.0.0.3"],
+ [host['ip'] for host in ooconfig.settings['hosts']])
+
+ self.assertEquals('openshift-enterprise', ooconfig.settings['variant'])
+
+ def test_load_complete_facts(self):
+ cfg_path = self.write_config(os.path.join(self.work_dir,
+ 'ooinstall.conf'), SAMPLE_CONFIG)
+ ooconfig = OOConfig(cfg_path)
+ missing_host_facts = ooconfig.calc_missing_facts()
+ self.assertEquals(0, len(missing_host_facts))
+
+ # Test missing optional facts the user must confirm:
+ def test_load_host_incomplete_facts(self):
+ cfg_path = self.write_config(os.path.join(self.work_dir,
+ 'ooinstall.conf'), CONFIG_INCOMPLETE_FACTS)
+ ooconfig = OOConfig(cfg_path)
+ missing_host_facts = ooconfig.calc_missing_facts()
+ self.assertEquals(2, len(missing_host_facts))
+ self.assertEquals(1, len(missing_host_facts['10.0.0.2']))
+ self.assertEquals(3, len(missing_host_facts['10.0.0.3']))
+
+ def test_write_config(self):
+ cfg_path = self.write_config(os.path.join(self.work_dir,
+ 'ooinstall.conf'), SAMPLE_CONFIG)
+ ooconfig = OOConfig(cfg_path)
+ ooconfig.save_to_disk()
+
+ f = open(cfg_path, 'r')
+ written_config = yaml.safe_load(f.read())
+ f.close()
+
+ self.assertEquals(3, len(written_config['hosts']))
+ for h in written_config['hosts']:
+ self.assertTrue('ip' in h)
+ self.assertTrue('public_ip' in h)
+ self.assertTrue('hostname' in h)
+ self.assertTrue('public_hostname' in h)
+
+ self.assertTrue('ansible_ssh_user' in written_config)
+ self.assertTrue('variant' in written_config)
+
+ # Some advanced settings should not get written out if they
+ # were not specified by the user:
+ self.assertFalse('ansible_inventory_directory' in written_config)
+
+
+class HostTests(OOInstallFixture):
+
+ def test_load_host_no_ip_or_hostname(self):
+ yaml_props = {
+ 'public_ip': '192.168.0.1',
+ 'public_hostname': 'a.example.com',
+ 'master': True
+ }
+ self.assertRaises(OOConfigInvalidHostError, Host, **yaml_props)
+
+ def test_load_host_no_master_or_node_specified(self):
+ yaml_props = {
+ 'ip': '192.168.0.1',
+ 'hostname': 'a.example.com',
+ 'public_ip': '192.168.0.1',
+ 'public_hostname': 'a.example.com',
+ }
+ self.assertRaises(OOConfigInvalidHostError, Host, **yaml_props)
+
+
+
+
diff --git a/utils/workflows/enterprise_deploy/openshift.sh b/utils/workflows/enterprise_deploy/openshift.sh
new file mode 100644
index 000000000..040a9a84d
--- /dev/null
+++ b/utils/workflows/enterprise_deploy/openshift.sh
@@ -0,0 +1,2 @@
+# This file is not used for OpenShift 3.0. It's merely an artifact of the the
+# installation framework originally used for OpenShift 2.x.