summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--filter_plugins/openshift_master.py16
-rw-r--r--inventory/byo/hosts.origin.example7
-rw-r--r--inventory/byo/hosts.ose.example7
-rw-r--r--playbooks/common/openshift-cluster/redeploy-certificates/ca.yml21
-rw-r--r--playbooks/common/openshift-master/restart_hosts.yml1
-rw-r--r--roles/cockpit-ui/tasks/main.yml2
-rw-r--r--roles/lib_openshift/library/oadm_manage_node.py67
-rw-r--r--roles/lib_openshift/library/oc_edit.py67
-rw-r--r--roles/lib_openshift/library/oc_label.py69
-rw-r--r--roles/lib_openshift/library/oc_obj.py69
-rw-r--r--roles/lib_openshift/library/oc_process.py1493
-rw-r--r--roles/lib_openshift/library/oc_route.py179
-rw-r--r--roles/lib_openshift/library/oc_scale.py67
-rw-r--r--roles/lib_openshift/library/oc_secret.py75
-rw-r--r--roles/lib_openshift/library/oc_service.py67
-rw-r--r--roles/lib_openshift/library/oc_serviceaccount.py67
-rw-r--r--roles/lib_openshift/library/oc_serviceaccount_secret.py67
-rw-r--r--roles/lib_openshift/library/oc_version.py67
-rw-r--r--roles/lib_openshift/src/ansible/oc_label.py2
-rw-r--r--roles/lib_openshift/src/ansible/oc_process.py32
-rw-r--r--roles/lib_openshift/src/ansible/oc_route.py39
-rw-r--r--roles/lib_openshift/src/class/oc_obj.py2
-rw-r--r--roles/lib_openshift/src/class/oc_process.py188
-rw-r--r--roles/lib_openshift/src/class/oc_route.py43
-rw-r--r--roles/lib_openshift/src/class/oc_secret.py8
-rw-r--r--roles/lib_openshift/src/doc/process84
-rw-r--r--roles/lib_openshift/src/doc/route6
-rw-r--r--roles/lib_openshift/src/lib/base.py66
-rw-r--r--roles/lib_openshift/src/lib/import.py1
-rw-r--r--roles/lib_openshift/src/lib/route.py24
-rw-r--r--roles/lib_openshift/src/sources.yml10
-rwxr-xr-xroles/lib_openshift/src/test/generate-and-run-tests.sh54
-rwxr-xr-xroles/lib_openshift/src/test/integration/oadm_manage_node.yml27
-rwxr-xr-xroles/lib_openshift/src/test/integration/oc_label.yml59
-rwxr-xr-xroles/lib_openshift/src/test/integration/oc_process.yml83
-rwxr-xr-xroles/lib_openshift/src/test/integration/oc_route.yml40
-rwxr-xr-xroles/lib_openshift/src/test/integration/oc_service.yml2
-rwxr-xr-xroles/lib_openshift/src/test/unit/oadm_manage_node.py15
-rwxr-xr-xroles/lib_openshift/src/test/unit/oc_label.py14
-rwxr-xr-xroles/lib_openshift/src/test/unit/oc_process.py483
-rwxr-xr-xroles/lib_openshift/src/test/unit/oc_route.py258
-rwxr-xr-xroles/lib_openshift/src/test/unit/oc_scale.py21
-rwxr-xr-xroles/lib_openshift/src/test/unit/oc_secret.py38
-rwxr-xr-xroles/lib_openshift/src/test/unit/oc_service.py14
-rwxr-xr-xroles/lib_openshift/src/test/unit/oc_serviceaccount.py7
-rwxr-xr-xroles/lib_openshift/src/test/unit/oc_serviceaccount_secret.py24
-rwxr-xr-xroles/lib_openshift/src/test/unit/oc_version.py7
-rw-r--r--roles/lib_openshift/tasks/main.yml9
-rwxr-xr-xroles/lib_utils/src/test/generate-and-run-tests.sh42
-rwxr-xr-xroles/lib_utils/src/test/integration/yedit.yml (renamed from roles/lib_utils/src/test/integration/yedit_test.yml)5
-rw-r--r--roles/openshift_ca/tasks/main.yml2
-rw-r--r--roles/openshift_logging/files/fluent.conf1
-rw-r--r--roles/openshift_logging/tasks/upgrade_logging.yaml2
-rw-r--r--roles/openshift_master/templates/master.yaml.v1.j212
-rw-r--r--roles/openshift_metrics/README.md4
-rw-r--r--roles/openshift_metrics/defaults/main.yaml4
-rw-r--r--roles/openshift_metrics/tasks/generate_certificates.yaml15
-rw-r--r--roles/openshift_metrics/tasks/generate_rolebindings.yaml18
-rw-r--r--roles/openshift_metrics/tasks/generate_serviceaccounts.yaml12
-rw-r--r--roles/openshift_metrics/tasks/generate_services.yaml13
-rw-r--r--roles/openshift_metrics/tasks/install_cassandra.yaml8
-rw-r--r--roles/openshift_metrics/tasks/install_heapster.yaml52
-rw-r--r--roles/openshift_metrics/tasks/install_metrics.yaml16
-rw-r--r--roles/openshift_metrics/tasks/pre_install.yaml27
-rw-r--r--roles/openshift_metrics/tasks/start_metrics.yaml3
-rw-r--r--roles/openshift_metrics/tasks/stop_metrics.yaml2
-rw-r--r--roles/openshift_metrics/templates/hawkular_cassandra_rc.j22
67 files changed, 3833 insertions, 475 deletions
diff --git a/filter_plugins/openshift_master.py b/filter_plugins/openshift_master.py
index 4ccee91f9..6d009077a 100644
--- a/filter_plugins/openshift_master.py
+++ b/filter_plugins/openshift_master.py
@@ -162,7 +162,7 @@ class LDAPPasswordIdentityProvider(IdentityProviderBase):
AnsibleFilterError:
"""
def __init__(self, api_version, idp):
- super(self.__class__, self).__init__(api_version, idp)
+ super(LDAPPasswordIdentityProvider, self).__init__(api_version, idp)
self._allow_additional = False
self._required += [['attributes'], ['url'], ['insecure']]
self._optional += [['ca'],
@@ -206,7 +206,7 @@ class KeystonePasswordIdentityProvider(IdentityProviderBase):
AnsibleFilterError:
"""
def __init__(self, api_version, idp):
- super(self.__class__, self).__init__(api_version, idp)
+ super(KeystonePasswordIdentityProvider, self).__init__(api_version, idp)
self._allow_additional = False
self._required += [['url'], ['domainName', 'domain_name']]
self._optional += [['ca'], ['certFile', 'cert_file'], ['keyFile', 'key_file']]
@@ -225,7 +225,7 @@ class RequestHeaderIdentityProvider(IdentityProviderBase):
AnsibleFilterError:
"""
def __init__(self, api_version, idp):
- super(self.__class__, self).__init__(api_version, idp)
+ super(RequestHeaderIdentityProvider, self).__init__(api_version, idp)
self._allow_additional = False
self._required += [['headers']]
self._optional += [['challengeURL', 'challenge_url'],
@@ -256,7 +256,7 @@ class AllowAllPasswordIdentityProvider(IdentityProviderBase):
AnsibleFilterError:
"""
def __init__(self, api_version, idp):
- super(self.__class__, self).__init__(api_version, idp)
+ super(AllowAllPasswordIdentityProvider, self).__init__(api_version, idp)
self._allow_additional = False
@@ -273,7 +273,7 @@ class DenyAllPasswordIdentityProvider(IdentityProviderBase):
AnsibleFilterError:
"""
def __init__(self, api_version, idp):
- super(self.__class__, self).__init__(api_version, idp)
+ super(DenyAllPasswordIdentityProvider, self).__init__(api_version, idp)
self._allow_additional = False
@@ -290,7 +290,7 @@ class HTPasswdPasswordIdentityProvider(IdentityProviderBase):
AnsibleFilterError:
"""
def __init__(self, api_version, idp):
- super(self.__class__, self).__init__(api_version, idp)
+ super(HTPasswdPasswordIdentityProvider, self).__init__(api_version, idp)
self._allow_additional = False
self._required += [['file', 'filename', 'fileName', 'file_name']]
@@ -315,7 +315,7 @@ class BasicAuthPasswordIdentityProvider(IdentityProviderBase):
AnsibleFilterError:
"""
def __init__(self, api_version, idp):
- super(self.__class__, self).__init__(api_version, idp)
+ super(BasicAuthPasswordIdentityProvider, self).__init__(api_version, idp)
self._allow_additional = False
self._required += [['url']]
self._optional += [['ca'], ['certFile', 'cert_file'], ['keyFile', 'key_file']]
@@ -334,7 +334,7 @@ class IdentityProviderOauthBase(IdentityProviderBase):
AnsibleFilterError:
"""
def __init__(self, api_version, idp):
- super(self.__class__, self).__init__(api_version, idp)
+ super(IdentityProviderOauthBase, self).__init__(api_version, idp)
self._allow_additional = False
self._required += [['clientID', 'client_id'], ['clientSecret', 'client_secret']]
diff --git a/inventory/byo/hosts.origin.example b/inventory/byo/hosts.origin.example
index 38284e691..7741730ad 100644
--- a/inventory/byo/hosts.origin.example
+++ b/inventory/byo/hosts.origin.example
@@ -301,6 +301,13 @@ openshift_master_identity_providers=[{'name': 'htpasswd_auth', 'login': 'true',
# Disable management of the OpenShift Router
#openshift_hosted_manage_router=false
+# OpenShift Registry Console Options
+# Override the console image prefix for enterprise deployments, not used in origin
+# default is "registry.access.redhat.com/openshift3/" and the image appended is "registry-console"
+#openshift_cockpit_deployer_prefix=registry.example.com/myrepo/
+# Override image version, defaults to latest for origin, matches the product version for enterprise
+#openshift_cockpit_deployer_version=1.4.1
+
# Openshift Registry Options
#
# An OpenShift registry will be created during install if there are
diff --git a/inventory/byo/hosts.ose.example b/inventory/byo/hosts.ose.example
index 551918fe4..3da9be081 100644
--- a/inventory/byo/hosts.ose.example
+++ b/inventory/byo/hosts.ose.example
@@ -301,6 +301,13 @@ openshift_master_identity_providers=[{'name': 'htpasswd_auth', 'login': 'true',
# Disable management of the OpenShift Router
#openshift_hosted_manage_router=false
+# OpenShift Registry Console Options
+# Override the console image prefix for enterprise deployments, not used in origin
+# default is "registry.access.redhat.com/openshift3/" and the image appended is "registry-console"
+#openshift_cockpit_deployer_prefix=registry.example.com/myrepo/
+# Override image version, defaults to latest for origin, matches the product version for enterprise
+#openshift_cockpit_deployer_version=1.4.1
+
# Openshift Registry Options
#
# An OpenShift registry will be created during install if there are
diff --git a/playbooks/common/openshift-cluster/redeploy-certificates/ca.yml b/playbooks/common/openshift-cluster/redeploy-certificates/ca.yml
index 0b1c39ba4..9d4d3ea26 100644
--- a/playbooks/common/openshift-cluster/redeploy-certificates/ca.yml
+++ b/playbooks/common/openshift-cluster/redeploy-certificates/ca.yml
@@ -160,6 +160,27 @@
yaml_key: servingInfo.clientCA
yaml_value: ca-bundle.crt
when: (g_master_config_output.content|b64decode|from_yaml).servingInfo.clientCA != 'ca-bundle.crt'
+ - modify_yaml:
+ dest: "{{ openshift.common.config_base }}/master/master-config.yaml"
+ yaml_key: etcdClientInfo.ca
+ yaml_value: ca-bundle.crt
+ when:
+ - groups.oo_etcd_to_config | default([]) | length == 0
+ - (g_master_config_output.content|b64decode|from_yaml).etcdClientInfo.ca != 'ca-bundle.crt'
+ - modify_yaml:
+ dest: "{{ openshift.common.config_base }}/master/master-config.yaml"
+ yaml_key: etcdConfig.peerServingInfo.clientCA
+ yaml_value: ca-bundle.crt
+ when:
+ - groups.oo_etcd_to_config | default([]) | length == 0
+ - (g_master_config_output.content|b64decode|from_yaml).etcdConfig.peerServingInfo.clientCA != 'ca-bundle.crt'
+ - modify_yaml:
+ dest: "{{ openshift.common.config_base }}/master/master-config.yaml"
+ yaml_key: etcdConfig.servingInfo.clientCA
+ yaml_value: ca-bundle.crt
+ when:
+ - groups.oo_etcd_to_config | default([]) | length == 0
+ - (g_master_config_output.content|b64decode|from_yaml).etcdConfig.servingInfo.clientCA != 'ca-bundle.crt'
- name: Copy current OpenShift CA to legacy directory
hosts: oo_masters_to_config
diff --git a/playbooks/common/openshift-master/restart_hosts.yml b/playbooks/common/openshift-master/restart_hosts.yml
index 475144dbf..a9750e40f 100644
--- a/playbooks/common/openshift-master/restart_hosts.yml
+++ b/playbooks/common/openshift-master/restart_hosts.yml
@@ -14,6 +14,7 @@
state=started
delay=10
timeout=600
+ port="{{ ansible_ssh_port }}"
become: no
# Now that ssh is back up we can wait for API on the remote system,
diff --git a/roles/cockpit-ui/tasks/main.yml b/roles/cockpit-ui/tasks/main.yml
index 87ed7fee7..f2ef4f161 100644
--- a/roles/cockpit-ui/tasks/main.yml
+++ b/roles/cockpit-ui/tasks/main.yml
@@ -63,10 +63,12 @@
changed_when: false
when: check_docker_registry_exists.rc == 0
+# TODO: Need to fix the origin and enterprise templates so that they both respect IMAGE_PREFIX
- name: Deploy registry-console
command: >
{{ openshift.common.client_binary }} new-app --template=registry-console
{% if openshift_cockpit_deployer_prefix is defined %}-p IMAGE_PREFIX="{{ openshift_cockpit_deployer_prefix }}"{% endif %}
+ {% if openshift_cockpit_deployer_version is defined %}-p IMAGE_VERSION="{{ openshift_cockpit_deployer_version }}"{% endif %}
-p OPENSHIFT_OAUTH_PROVIDER_URL="{{ openshift.master.public_api_url }}"
-p REGISTRY_HOST="{{ docker_registry_route.stdout }}"
-p COCKPIT_KUBE_URL="{{ registry_console_cockpit_kube_url.stdout }}"
diff --git a/roles/lib_openshift/library/oadm_manage_node.py b/roles/lib_openshift/library/oadm_manage_node.py
index 93c52e0df..8e217ac28 100644
--- a/roles/lib_openshift/library/oadm_manage_node.py
+++ b/roles/lib_openshift/library/oadm_manage_node.py
@@ -38,6 +38,7 @@ import os
import re
import shutil
import subprocess
+import tempfile
# pylint: disable=import-error
import ruamel.yaml as yaml
from ansible.module_utils.basic import AnsibleModule
@@ -730,7 +731,7 @@ class OpenShiftCLI(object):
''' Constructor for OpenshiftCLI '''
self.namespace = namespace
self.verbose = verbose
- self.kubeconfig = kubeconfig
+ self.kubeconfig = Utils.create_tmpfile_copy(kubeconfig)
self.all_namespaces = all_namespaces
# Pylint allows only 5 arguments to be passed.
@@ -741,7 +742,8 @@ class OpenShiftCLI(object):
if not res['results']:
return res
- fname = '/tmp/%s' % rname
+ fname = Utils.create_tmpfile(rname + '-')
+
yed = Yedit(fname, res['results'][0], separator=sep)
changes = []
for key, value in content.items():
@@ -765,7 +767,7 @@ class OpenShiftCLI(object):
def _create_from_content(self, rname, content):
'''create a temporary file and then call oc create on it'''
- fname = '/tmp/%s' % rname
+ fname = Utils.create_tmpfile(rname + '-')
yed = Yedit(fname, content=content)
yed.write()
@@ -808,7 +810,7 @@ class OpenShiftCLI(object):
if results['returncode'] != 0 or not create:
return results
- fname = '/tmp/%s' % template_name
+ fname = Utils.create_tmpfile(template_name + '-')
yed = Yedit(fname, results['results'])
yed.write()
@@ -989,32 +991,61 @@ class OpenShiftCLI(object):
class Utils(object):
''' utilities for openshiftcli modules '''
+
@staticmethod
- def create_file(rname, data, ftype='yaml'):
+ def _write(filename, contents):
+ ''' Actually write the file contents to disk. This helps with mocking. '''
+
+ with open(filename, 'w') as sfd:
+ sfd.write(contents)
+
+ @staticmethod
+ def create_tmp_file_from_contents(rname, data, ftype='yaml'):
''' create a file in tmp with name and contents'''
- path = os.path.join('/tmp', rname)
- with open(path, 'w') as fds:
- if ftype == 'yaml':
- fds.write(yaml.dump(data, Dumper=yaml.RoundTripDumper))
- elif ftype == 'json':
- fds.write(json.dumps(data))
- else:
- fds.write(data)
+ tmp = Utils.create_tmpfile(prefix=rname)
+
+ if ftype == 'yaml':
+ Utils._write(tmp, yaml.dump(data, Dumper=yaml.RoundTripDumper))
+ elif ftype == 'json':
+ Utils._write(tmp, json.dumps(data))
+ else:
+ Utils._write(tmp, data)
# Register cleanup when module is done
- atexit.register(Utils.cleanup, [path])
- return path
+ atexit.register(Utils.cleanup, [tmp])
+ return tmp
+
+ @staticmethod
+ def create_tmpfile_copy(inc_file):
+ '''create a temporary copy of a file'''
+ tmpfile = Utils.create_tmpfile('lib_openshift-')
+ Utils._write(tmpfile, open(inc_file).read())
+
+ # Cleanup the tmpfile
+ atexit.register(Utils.cleanup, [tmpfile])
+
+ return tmpfile
+
+ @staticmethod
+ def create_tmpfile(prefix='tmp'):
+ ''' Generates and returns a temporary file name '''
+
+ with tempfile.NamedTemporaryFile(prefix=prefix, delete=False) as tmp:
+ return tmp.name
@staticmethod
- def create_files_from_contents(content, content_type=None):
+ def create_tmp_files_from_contents(content, content_type=None):
'''Turn an array of dict: filename, content into a files array'''
if not isinstance(content, list):
content = [content]
files = []
for item in content:
- path = Utils.create_file(item['path'], item['data'], ftype=content_type)
- files.append({'name': os.path.basename(path), 'path': path})
+ path = Utils.create_tmp_file_from_contents(item['path'] + '-',
+ item['data'],
+ ftype=content_type)
+ files.append({'name': os.path.basename(item['path']),
+ 'path': path})
return files
@staticmethod
diff --git a/roles/lib_openshift/library/oc_edit.py b/roles/lib_openshift/library/oc_edit.py
index e9011da42..11b87a015 100644
--- a/roles/lib_openshift/library/oc_edit.py
+++ b/roles/lib_openshift/library/oc_edit.py
@@ -38,6 +38,7 @@ import os
import re
import shutil
import subprocess
+import tempfile
# pylint: disable=import-error
import ruamel.yaml as yaml
from ansible.module_utils.basic import AnsibleModule
@@ -758,7 +759,7 @@ class OpenShiftCLI(object):
''' Constructor for OpenshiftCLI '''
self.namespace = namespace
self.verbose = verbose
- self.kubeconfig = kubeconfig
+ self.kubeconfig = Utils.create_tmpfile_copy(kubeconfig)
self.all_namespaces = all_namespaces
# Pylint allows only 5 arguments to be passed.
@@ -769,7 +770,8 @@ class OpenShiftCLI(object):
if not res['results']:
return res
- fname = '/tmp/%s' % rname
+ fname = Utils.create_tmpfile(rname + '-')
+
yed = Yedit(fname, res['results'][0], separator=sep)
changes = []
for key, value in content.items():
@@ -793,7 +795,7 @@ class OpenShiftCLI(object):
def _create_from_content(self, rname, content):
'''create a temporary file and then call oc create on it'''
- fname = '/tmp/%s' % rname
+ fname = Utils.create_tmpfile(rname + '-')
yed = Yedit(fname, content=content)
yed.write()
@@ -836,7 +838,7 @@ class OpenShiftCLI(object):
if results['returncode'] != 0 or not create:
return results
- fname = '/tmp/%s' % template_name
+ fname = Utils.create_tmpfile(template_name + '-')
yed = Yedit(fname, results['results'])
yed.write()
@@ -1017,32 +1019,61 @@ class OpenShiftCLI(object):
class Utils(object):
''' utilities for openshiftcli modules '''
+
@staticmethod
- def create_file(rname, data, ftype='yaml'):
+ def _write(filename, contents):
+ ''' Actually write the file contents to disk. This helps with mocking. '''
+
+ with open(filename, 'w') as sfd:
+ sfd.write(contents)
+
+ @staticmethod
+ def create_tmp_file_from_contents(rname, data, ftype='yaml'):
''' create a file in tmp with name and contents'''
- path = os.path.join('/tmp', rname)
- with open(path, 'w') as fds:
- if ftype == 'yaml':
- fds.write(yaml.dump(data, Dumper=yaml.RoundTripDumper))
- elif ftype == 'json':
- fds.write(json.dumps(data))
- else:
- fds.write(data)
+ tmp = Utils.create_tmpfile(prefix=rname)
+
+ if ftype == 'yaml':
+ Utils._write(tmp, yaml.dump(data, Dumper=yaml.RoundTripDumper))
+ elif ftype == 'json':
+ Utils._write(tmp, json.dumps(data))
+ else:
+ Utils._write(tmp, data)
# Register cleanup when module is done
- atexit.register(Utils.cleanup, [path])
- return path
+ atexit.register(Utils.cleanup, [tmp])
+ return tmp
+
+ @staticmethod
+ def create_tmpfile_copy(inc_file):
+ '''create a temporary copy of a file'''
+ tmpfile = Utils.create_tmpfile('lib_openshift-')
+ Utils._write(tmpfile, open(inc_file).read())
+
+ # Cleanup the tmpfile
+ atexit.register(Utils.cleanup, [tmpfile])
+
+ return tmpfile
+
+ @staticmethod
+ def create_tmpfile(prefix='tmp'):
+ ''' Generates and returns a temporary file name '''
+
+ with tempfile.NamedTemporaryFile(prefix=prefix, delete=False) as tmp:
+ return tmp.name
@staticmethod
- def create_files_from_contents(content, content_type=None):
+ def create_tmp_files_from_contents(content, content_type=None):
'''Turn an array of dict: filename, content into a files array'''
if not isinstance(content, list):
content = [content]
files = []
for item in content:
- path = Utils.create_file(item['path'], item['data'], ftype=content_type)
- files.append({'name': os.path.basename(path), 'path': path})
+ path = Utils.create_tmp_file_from_contents(item['path'] + '-',
+ item['data'],
+ ftype=content_type)
+ files.append({'name': os.path.basename(item['path']),
+ 'path': path})
return files
@staticmethod
diff --git a/roles/lib_openshift/library/oc_label.py b/roles/lib_openshift/library/oc_label.py
index f2f5787f5..f67eb2552 100644
--- a/roles/lib_openshift/library/oc_label.py
+++ b/roles/lib_openshift/library/oc_label.py
@@ -38,6 +38,7 @@ import os
import re
import shutil
import subprocess
+import tempfile
# pylint: disable=import-error
import ruamel.yaml as yaml
from ansible.module_utils.basic import AnsibleModule
@@ -734,7 +735,7 @@ class OpenShiftCLI(object):
''' Constructor for OpenshiftCLI '''
self.namespace = namespace
self.verbose = verbose
- self.kubeconfig = kubeconfig
+ self.kubeconfig = Utils.create_tmpfile_copy(kubeconfig)
self.all_namespaces = all_namespaces
# Pylint allows only 5 arguments to be passed.
@@ -745,7 +746,8 @@ class OpenShiftCLI(object):
if not res['results']:
return res
- fname = '/tmp/%s' % rname
+ fname = Utils.create_tmpfile(rname + '-')
+
yed = Yedit(fname, res['results'][0], separator=sep)
changes = []
for key, value in content.items():
@@ -769,7 +771,7 @@ class OpenShiftCLI(object):
def _create_from_content(self, rname, content):
'''create a temporary file and then call oc create on it'''
- fname = '/tmp/%s' % rname
+ fname = Utils.create_tmpfile(rname + '-')
yed = Yedit(fname, content=content)
yed.write()
@@ -812,7 +814,7 @@ class OpenShiftCLI(object):
if results['returncode'] != 0 or not create:
return results
- fname = '/tmp/%s' % template_name
+ fname = Utils.create_tmpfile(template_name + '-')
yed = Yedit(fname, results['results'])
yed.write()
@@ -993,32 +995,61 @@ class OpenShiftCLI(object):
class Utils(object):
''' utilities for openshiftcli modules '''
+
@staticmethod
- def create_file(rname, data, ftype='yaml'):
+ def _write(filename, contents):
+ ''' Actually write the file contents to disk. This helps with mocking. '''
+
+ with open(filename, 'w') as sfd:
+ sfd.write(contents)
+
+ @staticmethod
+ def create_tmp_file_from_contents(rname, data, ftype='yaml'):
''' create a file in tmp with name and contents'''
- path = os.path.join('/tmp', rname)
- with open(path, 'w') as fds:
- if ftype == 'yaml':
- fds.write(yaml.dump(data, Dumper=yaml.RoundTripDumper))
- elif ftype == 'json':
- fds.write(json.dumps(data))
- else:
- fds.write(data)
+ tmp = Utils.create_tmpfile(prefix=rname)
+
+ if ftype == 'yaml':
+ Utils._write(tmp, yaml.dump(data, Dumper=yaml.RoundTripDumper))
+ elif ftype == 'json':
+ Utils._write(tmp, json.dumps(data))
+ else:
+ Utils._write(tmp, data)
# Register cleanup when module is done
- atexit.register(Utils.cleanup, [path])
- return path
+ atexit.register(Utils.cleanup, [tmp])
+ return tmp
+
+ @staticmethod
+ def create_tmpfile_copy(inc_file):
+ '''create a temporary copy of a file'''
+ tmpfile = Utils.create_tmpfile('lib_openshift-')
+ Utils._write(tmpfile, open(inc_file).read())
+
+ # Cleanup the tmpfile
+ atexit.register(Utils.cleanup, [tmpfile])
+
+ return tmpfile
+
+ @staticmethod
+ def create_tmpfile(prefix='tmp'):
+ ''' Generates and returns a temporary file name '''
+
+ with tempfile.NamedTemporaryFile(prefix=prefix, delete=False) as tmp:
+ return tmp.name
@staticmethod
- def create_files_from_contents(content, content_type=None):
+ def create_tmp_files_from_contents(content, content_type=None):
'''Turn an array of dict: filename, content into a files array'''
if not isinstance(content, list):
content = [content]
files = []
for item in content:
- path = Utils.create_file(item['path'], item['data'], ftype=content_type)
- files.append({'name': os.path.basename(path), 'path': path})
+ path = Utils.create_tmp_file_from_contents(item['path'] + '-',
+ item['data'],
+ ftype=content_type)
+ files.append({'name': os.path.basename(item['path']),
+ 'path': path})
return files
@staticmethod
@@ -1552,7 +1583,7 @@ def main():
state=dict(default='present', type='str',
choices=['present', 'absent', 'list', 'add']),
debug=dict(default=False, type='bool'),
- kind=dict(default='node', type='str', required=True,
+ kind=dict(default='node', type='str',
choices=['node', 'pod', 'namespace']),
name=dict(default=None, type='str'),
namespace=dict(default=None, type='str'),
diff --git a/roles/lib_openshift/library/oc_obj.py b/roles/lib_openshift/library/oc_obj.py
index c55827c47..e4b8ac26c 100644
--- a/roles/lib_openshift/library/oc_obj.py
+++ b/roles/lib_openshift/library/oc_obj.py
@@ -38,6 +38,7 @@ import os
import re
import shutil
import subprocess
+import tempfile
# pylint: disable=import-error
import ruamel.yaml as yaml
from ansible.module_utils.basic import AnsibleModule
@@ -737,7 +738,7 @@ class OpenShiftCLI(object):
''' Constructor for OpenshiftCLI '''
self.namespace = namespace
self.verbose = verbose
- self.kubeconfig = kubeconfig
+ self.kubeconfig = Utils.create_tmpfile_copy(kubeconfig)
self.all_namespaces = all_namespaces
# Pylint allows only 5 arguments to be passed.
@@ -748,7 +749,8 @@ class OpenShiftCLI(object):
if not res['results']:
return res
- fname = '/tmp/%s' % rname
+ fname = Utils.create_tmpfile(rname + '-')
+
yed = Yedit(fname, res['results'][0], separator=sep)
changes = []
for key, value in content.items():
@@ -772,7 +774,7 @@ class OpenShiftCLI(object):
def _create_from_content(self, rname, content):
'''create a temporary file and then call oc create on it'''
- fname = '/tmp/%s' % rname
+ fname = Utils.create_tmpfile(rname + '-')
yed = Yedit(fname, content=content)
yed.write()
@@ -815,7 +817,7 @@ class OpenShiftCLI(object):
if results['returncode'] != 0 or not create:
return results
- fname = '/tmp/%s' % template_name
+ fname = Utils.create_tmpfile(template_name + '-')
yed = Yedit(fname, results['results'])
yed.write()
@@ -996,32 +998,61 @@ class OpenShiftCLI(object):
class Utils(object):
''' utilities for openshiftcli modules '''
+
@staticmethod
- def create_file(rname, data, ftype='yaml'):
+ def _write(filename, contents):
+ ''' Actually write the file contents to disk. This helps with mocking. '''
+
+ with open(filename, 'w') as sfd:
+ sfd.write(contents)
+
+ @staticmethod
+ def create_tmp_file_from_contents(rname, data, ftype='yaml'):
''' create a file in tmp with name and contents'''
- path = os.path.join('/tmp', rname)
- with open(path, 'w') as fds:
- if ftype == 'yaml':
- fds.write(yaml.dump(data, Dumper=yaml.RoundTripDumper))
- elif ftype == 'json':
- fds.write(json.dumps(data))
- else:
- fds.write(data)
+ tmp = Utils.create_tmpfile(prefix=rname)
+
+ if ftype == 'yaml':
+ Utils._write(tmp, yaml.dump(data, Dumper=yaml.RoundTripDumper))
+ elif ftype == 'json':
+ Utils._write(tmp, json.dumps(data))
+ else:
+ Utils._write(tmp, data)
# Register cleanup when module is done
- atexit.register(Utils.cleanup, [path])
- return path
+ atexit.register(Utils.cleanup, [tmp])
+ return tmp
+
+ @staticmethod
+ def create_tmpfile_copy(inc_file):
+ '''create a temporary copy of a file'''
+ tmpfile = Utils.create_tmpfile('lib_openshift-')
+ Utils._write(tmpfile, open(inc_file).read())
+
+ # Cleanup the tmpfile
+ atexit.register(Utils.cleanup, [tmpfile])
+
+ return tmpfile
+
+ @staticmethod
+ def create_tmpfile(prefix='tmp'):
+ ''' Generates and returns a temporary file name '''
+
+ with tempfile.NamedTemporaryFile(prefix=prefix, delete=False) as tmp:
+ return tmp.name
@staticmethod
- def create_files_from_contents(content, content_type=None):
+ def create_tmp_files_from_contents(content, content_type=None):
'''Turn an array of dict: filename, content into a files array'''
if not isinstance(content, list):
content = [content]
files = []
for item in content:
- path = Utils.create_file(item['path'], item['data'], ftype=content_type)
- files.append({'name': os.path.basename(path), 'path': path})
+ path = Utils.create_tmp_file_from_contents(item['path'] + '-',
+ item['data'],
+ ftype=content_type)
+ files.append({'name': os.path.basename(item['path']),
+ 'path': path})
return files
@staticmethod
@@ -1298,7 +1329,7 @@ class OCObject(OpenShiftCLI):
return self._create(files[0])
content['data'] = yaml.dump(content['data'])
- content_file = Utils.create_files_from_contents(content)[0]
+ content_file = Utils.create_tmp_files_from_contents(content)[0]
return self._create(content_file['path'])
diff --git a/roles/lib_openshift/library/oc_process.py b/roles/lib_openshift/library/oc_process.py
new file mode 100644
index 000000000..702cb02d4
--- /dev/null
+++ b/roles/lib_openshift/library/oc_process.py
@@ -0,0 +1,1493 @@
+#!/usr/bin/env python
+# pylint: disable=missing-docstring
+# flake8: noqa: T001
+# ___ ___ _ _ ___ ___ _ _____ ___ ___
+# / __| __| \| | __| _ \ /_\_ _| __| \
+# | (_ | _|| .` | _|| / / _ \| | | _|| |) |
+# \___|___|_|\_|___|_|_\/_/_\_\_|_|___|___/_ _____
+# | \ / _ \ | \| |/ _ \_ _| | __| \_ _|_ _|
+# | |) | (_) | | .` | (_) || | | _|| |) | | | |
+# |___/ \___/ |_|\_|\___/ |_| |___|___/___| |_|
+#
+# Copyright 2016 Red Hat, Inc. and/or its affiliates
+# and other contributors as indicated by the @author tags.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# -*- -*- -*- Begin included fragment: lib/import.py -*- -*- -*-
+'''
+ OpenShiftCLI class that wraps the oc commands in a subprocess
+'''
+# pylint: disable=too-many-lines
+
+from __future__ import print_function
+import atexit
+import json
+import os
+import re
+import shutil
+import subprocess
+import tempfile
+# pylint: disable=import-error
+import ruamel.yaml as yaml
+from ansible.module_utils.basic import AnsibleModule
+
+# -*- -*- -*- End included fragment: lib/import.py -*- -*- -*-
+
+# -*- -*- -*- Begin included fragment: doc/process -*- -*- -*-
+
+DOCUMENTATION = '''
+---
+module: oc_process
+short_description: Module to process openshift templates
+description:
+ - Process openshift templates programmatically.
+options:
+ state:
+ description:
+ - State has a few different meanings when it comes to process.
+ - state: present - This state runs an `oc process <template>`. When used in
+ - conjunction with 'create: True' the process will be piped to | oc create -f
+ - state: absent - will remove a template
+ - state: list - will perform an `oc get template <template_name>`
+ default: present
+ choices: ["present", "absent", "list"]
+ aliases: []
+ kubeconfig:
+ description:
+ - The path for the kubeconfig file to use for authentication
+ required: false
+ default: /etc/origin/master/admin.kubeconfig
+ aliases: []
+ debug:
+ description:
+ - Turn on debug output.
+ required: false
+ default: False
+ aliases: []
+ template_name:
+ description:
+ - Name of the openshift template that is being processed.
+ required: false
+ default: None
+ aliases: []
+ namespace:
+ description:
+ - The namespace where the template lives.
+ required: false
+ default: default
+ aliases: []
+ content:
+ description:
+ - Template content that will be processed.
+ required: false
+ default: None
+ aliases: []
+ params:
+ description:
+ - A list of parameters that will be inserted into the template.
+ required: false
+ default: None
+ aliases: []
+ create:
+ description:
+ - Whether or not to create the template after being processed. e.g. oc process | oc create -f -
+ required: False
+ default: False
+ aliases: []
+ reconcile:
+ description:
+ - Whether or not to attempt to determine if there are updates or changes in the incoming template.
+ default: true
+ aliases: []
+author:
+- "Kenny Woodson <kwoodson@redhat.com>"
+extends_documentation_fragment: []
+'''
+
+EXAMPLES = '''
+- name: process the cloud volume provisioner template with variables
+ oc_process:
+ namespace: openshift-infra
+ template_name: online-volume-provisioner
+ create: True
+ params:
+ PLAT: rhel7
+ register: processout
+ run_once: true
+- debug: var=processout
+'''
+
+# -*- -*- -*- End included fragment: doc/process -*- -*- -*-
+
+# -*- -*- -*- Begin included fragment: ../../lib_utils/src/class/yedit.py -*- -*- -*-
+# noqa: E301,E302
+
+
+class YeditException(Exception):
+ ''' Exception class for Yedit '''
+ pass
+
+
+# pylint: disable=too-many-public-methods
+class Yedit(object):
+ ''' Class to modify yaml files '''
+ re_valid_key = r"(((\[-?\d+\])|([0-9a-zA-Z%s/_-]+)).?)+$"
+ re_key = r"(?:\[(-?\d+)\])|([0-9a-zA-Z%s/_-]+)"
+ com_sep = set(['.', '#', '|', ':'])
+
+ # pylint: disable=too-many-arguments
+ def __init__(self,
+ filename=None,
+ content=None,
+ content_type='yaml',
+ separator='.',
+ backup=False):
+ self.content = content
+ self._separator = separator
+ self.filename = filename
+ self.__yaml_dict = content
+ self.content_type = content_type
+ self.backup = backup
+ self.load(content_type=self.content_type)
+ if self.__yaml_dict is None:
+ self.__yaml_dict = {}
+
+ @property
+ def separator(self):
+ ''' getter method for yaml_dict '''
+ return self._separator
+
+ @separator.setter
+ def separator(self):
+ ''' getter method for yaml_dict '''
+ return self._separator
+
+ @property
+ def yaml_dict(self):
+ ''' getter method for yaml_dict '''
+ return self.__yaml_dict
+
+ @yaml_dict.setter
+ def yaml_dict(self, value):
+ ''' setter method for yaml_dict '''
+ self.__yaml_dict = value
+
+ @staticmethod
+ def parse_key(key, sep='.'):
+ '''parse the key allowing the appropriate separator'''
+ common_separators = list(Yedit.com_sep - set([sep]))
+ return re.findall(Yedit.re_key % ''.join(common_separators), key)
+
+ @staticmethod
+ def valid_key(key, sep='.'):
+ '''validate the incoming key'''
+ common_separators = list(Yedit.com_sep - set([sep]))
+ if not re.match(Yedit.re_valid_key % ''.join(common_separators), key):
+ return False
+
+ return True
+
+ @staticmethod
+ def remove_entry(data, key, sep='.'):
+ ''' remove data at location key '''
+ if key == '' and isinstance(data, dict):
+ data.clear()
+ return True
+ elif key == '' and isinstance(data, list):
+ del data[:]
+ return True
+
+ if not (key and Yedit.valid_key(key, sep)) and \
+ isinstance(data, (list, dict)):
+ return None
+
+ key_indexes = Yedit.parse_key(key, sep)
+ for arr_ind, dict_key in key_indexes[:-1]:
+ if dict_key and isinstance(data, dict):
+ data = data.get(dict_key, None)
+ elif (arr_ind and isinstance(data, list) and
+ int(arr_ind) <= len(data) - 1):
+ data = data[int(arr_ind)]
+ else:
+ return None
+
+ # process last index for remove
+ # expected list entry
+ if key_indexes[-1][0]:
+ if isinstance(data, list) and int(key_indexes[-1][0]) <= len(data) - 1: # noqa: E501
+ del data[int(key_indexes[-1][0])]
+ return True
+
+ # expected dict entry
+ elif key_indexes[-1][1]:
+ if isinstance(data, dict):
+ del data[key_indexes[-1][1]]
+ return True
+
+ @staticmethod
+ def add_entry(data, key, item=None, sep='.'):
+ ''' Get an item from a dictionary with key notation a.b.c
+ d = {'a': {'b': 'c'}}}
+ key = a#b
+ return c
+ '''
+ if key == '':
+ pass
+ elif (not (key and Yedit.valid_key(key, sep)) and
+ isinstance(data, (list, dict))):
+ return None
+
+ key_indexes = Yedit.parse_key(key, sep)
+ for arr_ind, dict_key in key_indexes[:-1]:
+ if dict_key:
+ if isinstance(data, dict) and dict_key in data and data[dict_key]: # noqa: E501
+ data = data[dict_key]
+ continue
+
+ elif data and not isinstance(data, dict):
+ return None
+
+ data[dict_key] = {}
+ data = data[dict_key]
+
+ elif (arr_ind and isinstance(data, list) and
+ int(arr_ind) <= len(data) - 1):
+ data = data[int(arr_ind)]
+ else:
+ return None
+
+ if key == '':
+ data = item
+
+ # process last index for add
+ # expected list entry
+ elif key_indexes[-1][0] and isinstance(data, list) and int(key_indexes[-1][0]) <= len(data) - 1: # noqa: E501
+ data[int(key_indexes[-1][0])] = item
+
+ # expected dict entry
+ elif key_indexes[-1][1] and isinstance(data, dict):
+ data[key_indexes[-1][1]] = item
+
+ return data
+
+ @staticmethod
+ def get_entry(data, key, sep='.'):
+ ''' Get an item from a dictionary with key notation a.b.c
+ d = {'a': {'b': 'c'}}}
+ key = a.b
+ return c
+ '''
+ if key == '':
+ pass
+ elif (not (key and Yedit.valid_key(key, sep)) and
+ isinstance(data, (list, dict))):
+ return None
+
+ key_indexes = Yedit.parse_key(key, sep)
+ for arr_ind, dict_key in key_indexes:
+ if dict_key and isinstance(data, dict):
+ data = data.get(dict_key, None)
+ elif (arr_ind and isinstance(data, list) and
+ int(arr_ind) <= len(data) - 1):
+ data = data[int(arr_ind)]
+ else:
+ return None
+
+ return data
+
+ @staticmethod
+ def _write(filename, contents):
+ ''' Actually write the file contents to disk. This helps with mocking. '''
+
+ tmp_filename = filename + '.yedit'
+
+ with open(tmp_filename, 'w') as yfd:
+ yfd.write(contents)
+
+ os.rename(tmp_filename, filename)
+
+ def write(self):
+ ''' write to file '''
+ if not self.filename:
+ raise YeditException('Please specify a filename.')
+
+ if self.backup and self.file_exists():
+ shutil.copy(self.filename, self.filename + '.orig')
+
+ # pylint: disable=no-member
+ if hasattr(self.yaml_dict, 'fa'):
+ self.yaml_dict.fa.set_block_style()
+
+ Yedit._write(self.filename, yaml.dump(self.yaml_dict, Dumper=yaml.RoundTripDumper))
+
+ return (True, self.yaml_dict)
+
+ def read(self):
+ ''' read from file '''
+ # check if it exists
+ if self.filename is None or not self.file_exists():
+ return None
+
+ contents = None
+ with open(self.filename) as yfd:
+ contents = yfd.read()
+
+ return contents
+
+ def file_exists(self):
+ ''' return whether file exists '''
+ if os.path.exists(self.filename):
+ return True
+
+ return False
+
+ def load(self, content_type='yaml'):
+ ''' return yaml file '''
+ contents = self.read()
+
+ if not contents and not self.content:
+ return None
+
+ if self.content:
+ if isinstance(self.content, dict):
+ self.yaml_dict = self.content
+ return self.yaml_dict
+ elif isinstance(self.content, str):
+ contents = self.content
+
+ # check if it is yaml
+ try:
+ if content_type == 'yaml' and contents:
+ self.yaml_dict = yaml.load(contents, yaml.RoundTripLoader)
+ # pylint: disable=no-member
+ if hasattr(self.yaml_dict, 'fa'):
+ self.yaml_dict.fa.set_block_style()
+ elif content_type == 'json' and contents:
+ self.yaml_dict = json.loads(contents)
+ except yaml.YAMLError as err:
+ # Error loading yaml or json
+ raise YeditException('Problem with loading yaml file. %s' % err)
+
+ return self.yaml_dict
+
+ def get(self, key):
+ ''' get a specified key'''
+ try:
+ entry = Yedit.get_entry(self.yaml_dict, key, self.separator)
+ except KeyError:
+ entry = None
+
+ return entry
+
+ def pop(self, path, key_or_item):
+ ''' remove a key, value pair from a dict or an item for a list'''
+ try:
+ entry = Yedit.get_entry(self.yaml_dict, path, self.separator)
+ except KeyError:
+ entry = None
+
+ if entry is None:
+ return (False, self.yaml_dict)
+
+ if isinstance(entry, dict):
+ # pylint: disable=no-member,maybe-no-member
+ if key_or_item in entry:
+ entry.pop(key_or_item)
+ return (True, self.yaml_dict)
+ return (False, self.yaml_dict)
+
+ elif isinstance(entry, list):
+ # pylint: disable=no-member,maybe-no-member
+ ind = None
+ try:
+ ind = entry.index(key_or_item)
+ except ValueError:
+ return (False, self.yaml_dict)
+
+ entry.pop(ind)
+ return (True, self.yaml_dict)
+
+ return (False, self.yaml_dict)
+
+ def delete(self, path):
+ ''' remove path from a dict'''
+ try:
+ entry = Yedit.get_entry(self.yaml_dict, path, self.separator)
+ except KeyError:
+ entry = None
+
+ if entry is None:
+ return (False, self.yaml_dict)
+
+ result = Yedit.remove_entry(self.yaml_dict, path, self.separator)
+ if not result:
+ return (False, self.yaml_dict)
+
+ return (True, self.yaml_dict)
+
+ def exists(self, path, value):
+ ''' check if value exists at path'''
+ try:
+ entry = Yedit.get_entry(self.yaml_dict, path, self.separator)
+ except KeyError:
+ entry = None
+
+ if isinstance(entry, list):
+ if value in entry:
+ return True
+ return False
+
+ elif isinstance(entry, dict):
+ if isinstance(value, dict):
+ rval = False
+ for key, val in value.items():
+ if entry[key] != val:
+ rval = False
+ break
+ else:
+ rval = True
+ return rval
+
+ return value in entry
+
+ return entry == value
+
+ def append(self, path, value):
+ '''append value to a list'''
+ try:
+ entry = Yedit.get_entry(self.yaml_dict, path, self.separator)
+ except KeyError:
+ entry = None
+
+ if entry is None:
+ self.put(path, [])
+ entry = Yedit.get_entry(self.yaml_dict, path, self.separator)
+ if not isinstance(entry, list):
+ return (False, self.yaml_dict)
+
+ # pylint: disable=no-member,maybe-no-member
+ entry.append(value)
+ return (True, self.yaml_dict)
+
+ # pylint: disable=too-many-arguments
+ def update(self, path, value, index=None, curr_value=None):
+ ''' put path, value into a dict '''
+ try:
+ entry = Yedit.get_entry(self.yaml_dict, path, self.separator)
+ except KeyError:
+ entry = None
+
+ if isinstance(entry, dict):
+ # pylint: disable=no-member,maybe-no-member
+ if not isinstance(value, dict):
+ raise YeditException('Cannot replace key, value entry in ' +
+ 'dict with non-dict type. value=[%s] [%s]' % (value, type(value))) # noqa: E501
+
+ entry.update(value)
+ return (True, self.yaml_dict)
+
+ elif isinstance(entry, list):
+ # pylint: disable=no-member,maybe-no-member
+ ind = None
+ if curr_value:
+ try:
+ ind = entry.index(curr_value)
+ except ValueError:
+ return (False, self.yaml_dict)
+
+ elif index is not None:
+ ind = index
+
+ if ind is not None and entry[ind] != value:
+ entry[ind] = value
+ return (True, self.yaml_dict)
+
+ # see if it exists in the list
+ try:
+ ind = entry.index(value)
+ except ValueError:
+ # doesn't exist, append it
+ entry.append(value)
+ return (True, self.yaml_dict)
+
+ # already exists, return
+ if ind is not None:
+ return (False, self.yaml_dict)
+ return (False, self.yaml_dict)
+
+ def put(self, path, value):
+ ''' put path, value into a dict '''
+ try:
+ entry = Yedit.get_entry(self.yaml_dict, path, self.separator)
+ except KeyError:
+ entry = None
+
+ if entry == value:
+ return (False, self.yaml_dict)
+
+ # deepcopy didn't work
+ tmp_copy = yaml.load(yaml.round_trip_dump(self.yaml_dict,
+ default_flow_style=False),
+ yaml.RoundTripLoader)
+ # pylint: disable=no-member
+ if hasattr(self.yaml_dict, 'fa'):
+ tmp_copy.fa.set_block_style()
+ result = Yedit.add_entry(tmp_copy, path, value, self.separator)
+ if not result:
+ return (False, self.yaml_dict)
+
+ self.yaml_dict = tmp_copy
+
+ return (True, self.yaml_dict)
+
+ def create(self, path, value):
+ ''' create a yaml file '''
+ if not self.file_exists():
+ # deepcopy didn't work
+ tmp_copy = yaml.load(yaml.round_trip_dump(self.yaml_dict, default_flow_style=False), # noqa: E501
+ yaml.RoundTripLoader)
+ # pylint: disable=no-member
+ if hasattr(self.yaml_dict, 'fa'):
+ tmp_copy.fa.set_block_style()
+ result = Yedit.add_entry(tmp_copy, path, value, self.separator)
+ if result:
+ self.yaml_dict = tmp_copy
+ return (True, self.yaml_dict)
+
+ return (False, self.yaml_dict)
+
+ @staticmethod
+ def get_curr_value(invalue, val_type):
+ '''return the current value'''
+ if invalue is None:
+ return None
+
+ curr_value = invalue
+ if val_type == 'yaml':
+ curr_value = yaml.load(invalue)
+ elif val_type == 'json':
+ curr_value = json.loads(invalue)
+
+ return curr_value
+
+ @staticmethod
+ def parse_value(inc_value, vtype=''):
+ '''determine value type passed'''
+ true_bools = ['y', 'Y', 'yes', 'Yes', 'YES', 'true', 'True', 'TRUE',
+ 'on', 'On', 'ON', ]
+ false_bools = ['n', 'N', 'no', 'No', 'NO', 'false', 'False', 'FALSE',
+ 'off', 'Off', 'OFF']
+
+ # It came in as a string but you didn't specify value_type as string
+ # we will convert to bool if it matches any of the above cases
+ if isinstance(inc_value, str) and 'bool' in vtype:
+ if inc_value not in true_bools and inc_value not in false_bools:
+ raise YeditException('Not a boolean type. str=[%s] vtype=[%s]'
+ % (inc_value, vtype))
+ elif isinstance(inc_value, bool) and 'str' in vtype:
+ inc_value = str(inc_value)
+
+ # If vtype is not str then go ahead and attempt to yaml load it.
+ if isinstance(inc_value, str) and 'str' not in vtype:
+ try:
+ inc_value = yaml.load(inc_value)
+ except Exception:
+ raise YeditException('Could not determine type of incoming ' +
+ 'value. value=[%s] vtype=[%s]'
+ % (type(inc_value), vtype))
+
+ return inc_value
+
+ # pylint: disable=too-many-return-statements,too-many-branches
+ @staticmethod
+ def run_ansible(module):
+ '''perform the idempotent crud operations'''
+ yamlfile = Yedit(filename=module.params['src'],
+ backup=module.params['backup'],
+ separator=module.params['separator'])
+
+ if module.params['src']:
+ rval = yamlfile.load()
+
+ if yamlfile.yaml_dict is None and \
+ module.params['state'] != 'present':
+ return {'failed': True,
+ 'msg': 'Error opening file [%s]. Verify that the ' +
+ 'file exists, that it is has correct' +
+ ' permissions, and is valid yaml.'}
+
+ if module.params['state'] == 'list':
+ if module.params['content']:
+ content = Yedit.parse_value(module.params['content'],
+ module.params['content_type'])
+ yamlfile.yaml_dict = content
+
+ if module.params['key']:
+ rval = yamlfile.get(module.params['key']) or {}
+
+ return {'changed': False, 'result': rval, 'state': "list"}
+
+ elif module.params['state'] == 'absent':
+ if module.params['content']:
+ content = Yedit.parse_value(module.params['content'],
+ module.params['content_type'])
+ yamlfile.yaml_dict = content
+
+ if module.params['update']:
+ rval = yamlfile.pop(module.params['key'],
+ module.params['value'])
+ else:
+ rval = yamlfile.delete(module.params['key'])
+
+ if rval[0] and module.params['src']:
+ yamlfile.write()
+
+ return {'changed': rval[0], 'result': rval[1], 'state': "absent"}
+
+ elif module.params['state'] == 'present':
+ # check if content is different than what is in the file
+ if module.params['content']:
+ content = Yedit.parse_value(module.params['content'],
+ module.params['content_type'])
+
+ # We had no edits to make and the contents are the same
+ if yamlfile.yaml_dict == content and \
+ module.params['value'] is None:
+ return {'changed': False,
+ 'result': yamlfile.yaml_dict,
+ 'state': "present"}
+
+ yamlfile.yaml_dict = content
+
+ # we were passed a value; parse it
+ if module.params['value']:
+ value = Yedit.parse_value(module.params['value'],
+ module.params['value_type'])
+ key = module.params['key']
+ if module.params['update']:
+ # pylint: disable=line-too-long
+ curr_value = Yedit.get_curr_value(Yedit.parse_value(module.params['curr_value']), # noqa: E501
+ module.params['curr_value_format']) # noqa: E501
+
+ rval = yamlfile.update(key, value, module.params['index'], curr_value) # noqa: E501
+
+ elif module.params['append']:
+ rval = yamlfile.append(key, value)
+ else:
+ rval = yamlfile.put(key, value)
+
+ if rval[0] and module.params['src']:
+ yamlfile.write()
+
+ return {'changed': rval[0],
+ 'result': rval[1], 'state': "present"}
+
+ # no edits to make
+ if module.params['src']:
+ # pylint: disable=redefined-variable-type
+ rval = yamlfile.write()
+ return {'changed': rval[0],
+ 'result': rval[1],
+ 'state': "present"}
+
+ return {'failed': True, 'msg': 'Unkown state passed'}
+
+# -*- -*- -*- End included fragment: ../../lib_utils/src/class/yedit.py -*- -*- -*-
+
+# -*- -*- -*- Begin included fragment: lib/base.py -*- -*- -*-
+# pylint: disable=too-many-lines
+# noqa: E301,E302,E303,T001
+
+
+class OpenShiftCLIError(Exception):
+ '''Exception class for openshiftcli'''
+ pass
+
+
+# pylint: disable=too-few-public-methods
+class OpenShiftCLI(object):
+ ''' Class to wrap the command line tools '''
+ def __init__(self,
+ namespace,
+ kubeconfig='/etc/origin/master/admin.kubeconfig',
+ verbose=False,
+ all_namespaces=False):
+ ''' Constructor for OpenshiftCLI '''
+ self.namespace = namespace
+ self.verbose = verbose
+ self.kubeconfig = Utils.create_tmpfile_copy(kubeconfig)
+ self.all_namespaces = all_namespaces
+
+ # Pylint allows only 5 arguments to be passed.
+ # pylint: disable=too-many-arguments
+ def _replace_content(self, resource, rname, content, force=False, sep='.'):
+ ''' replace the current object with the content '''
+ res = self._get(resource, rname)
+ if not res['results']:
+ return res
+
+ fname = Utils.create_tmpfile(rname + '-')
+
+ yed = Yedit(fname, res['results'][0], separator=sep)
+ changes = []
+ for key, value in content.items():
+ changes.append(yed.put(key, value))
+
+ if any([change[0] for change in changes]):
+ yed.write()
+
+ atexit.register(Utils.cleanup, [fname])
+
+ return self._replace(fname, force)
+
+ return {'returncode': 0, 'updated': False}
+
+ def _replace(self, fname, force=False):
+ '''replace the current object with oc replace'''
+ cmd = ['replace', '-f', fname]
+ if force:
+ cmd.append('--force')
+ return self.openshift_cmd(cmd)
+
+ def _create_from_content(self, rname, content):
+ '''create a temporary file and then call oc create on it'''
+ fname = Utils.create_tmpfile(rname + '-')
+ yed = Yedit(fname, content=content)
+ yed.write()
+
+ atexit.register(Utils.cleanup, [fname])
+
+ return self._create(fname)
+
+ def _create(self, fname):
+ '''call oc create on a filename'''
+ return self.openshift_cmd(['create', '-f', fname])
+
+ def _delete(self, resource, rname, selector=None):
+ '''call oc delete on a resource'''
+ cmd = ['delete', resource, rname]
+ if selector:
+ cmd.append('--selector=%s' % selector)
+
+ return self.openshift_cmd(cmd)
+
+ def _process(self, template_name, create=False, params=None, template_data=None): # noqa: E501
+ '''process a template
+
+ template_name: the name of the template to process
+ create: whether to send to oc create after processing
+ params: the parameters for the template
+ template_data: the incoming template's data; instead of a file
+ '''
+ cmd = ['process']
+ if template_data:
+ cmd.extend(['-f', '-'])
+ else:
+ cmd.append(template_name)
+ if params:
+ param_str = ["%s=%s" % (key, value) for key, value in params.items()]
+ cmd.append('-v')
+ cmd.extend(param_str)
+
+ results = self.openshift_cmd(cmd, output=True, input_data=template_data)
+
+ if results['returncode'] != 0 or not create:
+ return results
+
+ fname = Utils.create_tmpfile(template_name + '-')
+ yed = Yedit(fname, results['results'])
+ yed.write()
+
+ atexit.register(Utils.cleanup, [fname])
+
+ return self.openshift_cmd(['create', '-f', fname])
+
+ def _get(self, resource, rname=None, selector=None):
+ '''return a resource by name '''
+ cmd = ['get', resource]
+ if selector:
+ cmd.append('--selector=%s' % selector)
+ elif rname:
+ cmd.append(rname)
+
+ cmd.extend(['-o', 'json'])
+
+ rval = self.openshift_cmd(cmd, output=True)
+
+ # Ensure results are retuned in an array
+ if 'items' in rval:
+ rval['results'] = rval['items']
+ elif not isinstance(rval['results'], list):
+ rval['results'] = [rval['results']]
+
+ return rval
+
+ def _schedulable(self, node=None, selector=None, schedulable=True):
+ ''' perform oadm manage-node scheduable '''
+ cmd = ['manage-node']
+ if node:
+ cmd.extend(node)
+ else:
+ cmd.append('--selector=%s' % selector)
+
+ cmd.append('--schedulable=%s' % schedulable)
+
+ return self.openshift_cmd(cmd, oadm=True, output=True, output_type='raw') # noqa: E501
+
+ def _list_pods(self, node=None, selector=None, pod_selector=None):
+ ''' perform oadm list pods
+
+ node: the node in which to list pods
+ selector: the label selector filter if provided
+ pod_selector: the pod selector filter if provided
+ '''
+ cmd = ['manage-node']
+ if node:
+ cmd.extend(node)
+ else:
+ cmd.append('--selector=%s' % selector)
+
+ if pod_selector:
+ cmd.append('--pod-selector=%s' % pod_selector)
+
+ cmd.extend(['--list-pods', '-o', 'json'])
+
+ return self.openshift_cmd(cmd, oadm=True, output=True, output_type='raw')
+
+ # pylint: disable=too-many-arguments
+ def _evacuate(self, node=None, selector=None, pod_selector=None, dry_run=False, grace_period=None, force=False):
+ ''' perform oadm manage-node evacuate '''
+ cmd = ['manage-node']
+ if node:
+ cmd.extend(node)
+ else:
+ cmd.append('--selector=%s' % selector)
+
+ if dry_run:
+ cmd.append('--dry-run')
+
+ if pod_selector:
+ cmd.append('--pod-selector=%s' % pod_selector)
+
+ if grace_period:
+ cmd.append('--grace-period=%s' % int(grace_period))
+
+ if force:
+ cmd.append('--force')
+
+ cmd.append('--evacuate')
+
+ return self.openshift_cmd(cmd, oadm=True, output=True, output_type='raw')
+
+ def _version(self):
+ ''' return the openshift version'''
+ return self.openshift_cmd(['version'], output=True, output_type='raw')
+
+ def _import_image(self, url=None, name=None, tag=None):
+ ''' perform image import '''
+ cmd = ['import-image']
+
+ image = '{0}'.format(name)
+ if tag:
+ image += ':{0}'.format(tag)
+
+ cmd.append(image)
+
+ if url:
+ cmd.append('--from={0}/{1}'.format(url, image))
+
+ cmd.append('-n{0}'.format(self.namespace))
+
+ cmd.append('--confirm')
+ return self.openshift_cmd(cmd)
+
+ def _run(self, cmds, input_data):
+ ''' Actually executes the command. This makes mocking easier. '''
+ curr_env = os.environ.copy()
+ curr_env.update({'KUBECONFIG': self.kubeconfig})
+ proc = subprocess.Popen(cmds,
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ env=curr_env)
+
+ stdout, stderr = proc.communicate(input_data)
+
+ return proc.returncode, stdout, stderr
+
+ # pylint: disable=too-many-arguments,too-many-branches
+ def openshift_cmd(self, cmd, oadm=False, output=False, output_type='json', input_data=None):
+ '''Base command for oc '''
+ cmds = []
+ if oadm:
+ cmds = ['oadm']
+ else:
+ cmds = ['oc']
+
+ if self.all_namespaces:
+ cmds.extend(['--all-namespaces'])
+ elif self.namespace is not None and self.namespace.lower() not in ['none', 'emtpy']: # E501
+ cmds.extend(['-n', self.namespace])
+
+ cmds.extend(cmd)
+
+ rval = {}
+ results = ''
+ err = None
+
+ if self.verbose:
+ print(' '.join(cmds))
+
+ returncode, stdout, stderr = self._run(cmds, input_data)
+
+ rval = {"returncode": returncode,
+ "results": results,
+ "cmd": ' '.join(cmds)}
+
+ if returncode == 0:
+ if output:
+ if output_type == 'json':
+ try:
+ rval['results'] = json.loads(stdout)
+ except ValueError as err:
+ if "No JSON object could be decoded" in err.args:
+ err = err.args
+ elif output_type == 'raw':
+ rval['results'] = stdout
+
+ if self.verbose:
+ print("STDOUT: {0}".format(stdout))
+ print("STDERR: {0}".format(stderr))
+
+ if err:
+ rval.update({"err": err,
+ "stderr": stderr,
+ "stdout": stdout,
+ "cmd": cmds})
+
+ else:
+ rval.update({"stderr": stderr,
+ "stdout": stdout,
+ "results": {}})
+
+ return rval
+
+
+class Utils(object):
+ ''' utilities for openshiftcli modules '''
+
+ @staticmethod
+ def _write(filename, contents):
+ ''' Actually write the file contents to disk. This helps with mocking. '''
+
+ with open(filename, 'w') as sfd:
+ sfd.write(contents)
+
+ @staticmethod
+ def create_tmp_file_from_contents(rname, data, ftype='yaml'):
+ ''' create a file in tmp with name and contents'''
+
+ tmp = Utils.create_tmpfile(prefix=rname)
+
+ if ftype == 'yaml':
+ Utils._write(tmp, yaml.dump(data, Dumper=yaml.RoundTripDumper))
+ elif ftype == 'json':
+ Utils._write(tmp, json.dumps(data))
+ else:
+ Utils._write(tmp, data)
+
+ # Register cleanup when module is done
+ atexit.register(Utils.cleanup, [tmp])
+ return tmp
+
+ @staticmethod
+ def create_tmpfile_copy(inc_file):
+ '''create a temporary copy of a file'''
+ tmpfile = Utils.create_tmpfile('lib_openshift-')
+ Utils._write(tmpfile, open(inc_file).read())
+
+ # Cleanup the tmpfile
+ atexit.register(Utils.cleanup, [tmpfile])
+
+ return tmpfile
+
+ @staticmethod
+ def create_tmpfile(prefix='tmp'):
+ ''' Generates and returns a temporary file name '''
+
+ with tempfile.NamedTemporaryFile(prefix=prefix, delete=False) as tmp:
+ return tmp.name
+
+ @staticmethod
+ def create_tmp_files_from_contents(content, content_type=None):
+ '''Turn an array of dict: filename, content into a files array'''
+ if not isinstance(content, list):
+ content = [content]
+ files = []
+ for item in content:
+ path = Utils.create_tmp_file_from_contents(item['path'] + '-',
+ item['data'],
+ ftype=content_type)
+ files.append({'name': os.path.basename(item['path']),
+ 'path': path})
+ return files
+
+ @staticmethod
+ def cleanup(files):
+ '''Clean up on exit '''
+ for sfile in files:
+ if os.path.exists(sfile):
+ if os.path.isdir(sfile):
+ shutil.rmtree(sfile)
+ elif os.path.isfile(sfile):
+ os.remove(sfile)
+
+ @staticmethod
+ def exists(results, _name):
+ ''' Check to see if the results include the name '''
+ if not results:
+ return False
+
+ if Utils.find_result(results, _name):
+ return True
+
+ return False
+
+ @staticmethod
+ def find_result(results, _name):
+ ''' Find the specified result by name'''
+ rval = None
+ for result in results:
+ if 'metadata' in result and result['metadata']['name'] == _name:
+ rval = result
+ break
+
+ return rval
+
+ @staticmethod
+ def get_resource_file(sfile, sfile_type='yaml'):
+ ''' return the service file '''
+ contents = None
+ with open(sfile) as sfd:
+ contents = sfd.read()
+
+ if sfile_type == 'yaml':
+ contents = yaml.load(contents, yaml.RoundTripLoader)
+ elif sfile_type == 'json':
+ contents = json.loads(contents)
+
+ return contents
+
+ @staticmethod
+ def filter_versions(stdout):
+ ''' filter the oc version output '''
+
+ version_dict = {}
+ version_search = ['oc', 'openshift', 'kubernetes']
+
+ for line in stdout.strip().split('\n'):
+ for term in version_search:
+ if not line:
+ continue
+ if line.startswith(term):
+ version_dict[term] = line.split()[-1]
+
+ # horrible hack to get openshift version in Openshift 3.2
+ # By default "oc version in 3.2 does not return an "openshift" version
+ if "openshift" not in version_dict:
+ version_dict["openshift"] = version_dict["oc"]
+
+ return version_dict
+
+ @staticmethod
+ def add_custom_versions(versions):
+ ''' create custom versions strings '''
+
+ versions_dict = {}
+
+ for tech, version in versions.items():
+ # clean up "-" from version
+ if "-" in version:
+ version = version.split("-")[0]
+
+ if version.startswith('v'):
+ versions_dict[tech + '_numeric'] = version[1:].split('+')[0]
+ # "v3.3.0.33" is what we have, we want "3.3"
+ versions_dict[tech + '_short'] = version[1:4]
+
+ return versions_dict
+
+ @staticmethod
+ def openshift_installed():
+ ''' check if openshift is installed '''
+ import yum
+
+ yum_base = yum.YumBase()
+ if yum_base.rpmdb.searchNevra(name='atomic-openshift'):
+ return True
+
+ return False
+
+ # Disabling too-many-branches. This is a yaml dictionary comparison function
+ # pylint: disable=too-many-branches,too-many-return-statements,too-many-statements
+ @staticmethod
+ def check_def_equal(user_def, result_def, skip_keys=None, debug=False):
+ ''' Given a user defined definition, compare it with the results given back by our query. '''
+
+ # Currently these values are autogenerated and we do not need to check them
+ skip = ['metadata', 'status']
+ if skip_keys:
+ skip.extend(skip_keys)
+
+ for key, value in result_def.items():
+ if key in skip:
+ continue
+
+ # Both are lists
+ if isinstance(value, list):
+ if key not in user_def:
+ if debug:
+ print('User data does not have key [%s]' % key)
+ print('User data: %s' % user_def)
+ return False
+
+ if not isinstance(user_def[key], list):
+ if debug:
+ print('user_def[key] is not a list key=[%s] user_def[key]=%s' % (key, user_def[key]))
+ return False
+
+ if len(user_def[key]) != len(value):
+ if debug:
+ print("List lengths are not equal.")
+ print("key=[%s]: user_def[%s] != value[%s]" % (key, len(user_def[key]), len(value)))
+ print("user_def: %s" % user_def[key])
+ print("value: %s" % value)
+ return False
+
+ for values in zip(user_def[key], value):
+ if isinstance(values[0], dict) and isinstance(values[1], dict):
+ if debug:
+ print('sending list - list')
+ print(type(values[0]))
+ print(type(values[1]))
+ result = Utils.check_def_equal(values[0], values[1], skip_keys=skip_keys, debug=debug)
+ if not result:
+ print('list compare returned false')
+ return False
+
+ elif value != user_def[key]:
+ if debug:
+ print('value should be identical')
+ print(value)
+ print(user_def[key])
+ return False
+
+ # recurse on a dictionary
+ elif isinstance(value, dict):
+ if key not in user_def:
+ if debug:
+ print("user_def does not have key [%s]" % key)
+ return False
+ if not isinstance(user_def[key], dict):
+ if debug:
+ print("dict returned false: not instance of dict")
+ return False
+
+ # before passing ensure keys match
+ api_values = set(value.keys()) - set(skip)
+ user_values = set(user_def[key].keys()) - set(skip)
+ if api_values != user_values:
+ if debug:
+ print("keys are not equal in dict")
+ print(api_values)
+ print(user_values)
+ return False
+
+ result = Utils.check_def_equal(user_def[key], value, skip_keys=skip_keys, debug=debug)
+ if not result:
+ if debug:
+ print("dict returned false")
+ print(result)
+ return False
+
+ # Verify each key, value pair is the same
+ else:
+ if key not in user_def or value != user_def[key]:
+ if debug:
+ print("value not equal; user_def does not have key")
+ print(key)
+ print(value)
+ if key in user_def:
+ print(user_def[key])
+ return False
+
+ if debug:
+ print('returning true')
+ return True
+
+
+class OpenShiftCLIConfig(object):
+ '''Generic Config'''
+ def __init__(self, rname, namespace, kubeconfig, options):
+ self.kubeconfig = kubeconfig
+ self.name = rname
+ self.namespace = namespace
+ self._options = options
+
+ @property
+ def config_options(self):
+ ''' return config options '''
+ return self._options
+
+ def to_option_list(self):
+ '''return all options as a string'''
+ return self.stringify()
+
+ def stringify(self):
+ ''' return the options hash as cli params in a string '''
+ rval = []
+ for key, data in self.config_options.items():
+ if data['include'] \
+ and (data['value'] or isinstance(data['value'], int)):
+ rval.append('--%s=%s' % (key.replace('_', '-'), data['value']))
+
+ return rval
+
+
+# -*- -*- -*- End included fragment: lib/base.py -*- -*- -*-
+
+# -*- -*- -*- Begin included fragment: class/oc_process.py -*- -*- -*-
+
+
+# pylint: disable=too-many-instance-attributes
+class OCProcess(OpenShiftCLI):
+ ''' Class to wrap the oc command line tools '''
+
+ # pylint allows 5. we need 6
+ # pylint: disable=too-many-arguments
+ def __init__(self,
+ namespace,
+ tname=None,
+ params=None,
+ create=False,
+ kubeconfig='/etc/origin/master/admin.kubeconfig',
+ tdata=None,
+ verbose=False):
+ ''' Constructor for OpenshiftOC '''
+ super(OCProcess, self).__init__(namespace, kubeconfig)
+ self.namespace = namespace
+ self.name = tname
+ self.data = tdata
+ self.params = params
+ self.create = create
+ self.kubeconfig = kubeconfig
+ self.verbose = verbose
+ self._template = None
+
+ @property
+ def template(self):
+ '''template property'''
+ if self._template is None:
+ results = self._process(self.name, False, self.params, self.data)
+ if results['returncode'] != 0:
+ raise OpenShiftCLIError('Error processing template [%s].' % self.name)
+ self._template = results['results']['items']
+
+ return self._template
+
+ def get(self):
+ '''get the template'''
+ results = self._get('template', self.name)
+ if results['returncode'] != 0:
+ # Does the template exist??
+ if 'not found' in results['stderr']:
+ results['returncode'] = 0
+ results['exists'] = False
+ results['results'] = []
+
+ return results
+
+ def delete(self, obj):
+ '''delete a resource'''
+ return self._delete(obj['kind'], obj['metadata']['name'])
+
+ def create_obj(self, obj):
+ '''create a resource'''
+ return self._create_from_content(obj['metadata']['name'], obj)
+
+ def process(self, create=None):
+ '''process a template'''
+ do_create = False
+ if create != None:
+ do_create = create
+ else:
+ do_create = self.create
+
+ return self._process(self.name, do_create, self.params, self.data)
+
+ def exists(self):
+ '''return whether the template exists'''
+ # Always return true if we're being passed template data
+ if self.data:
+ return True
+ t_results = self._get('template', self.name)
+
+ if t_results['returncode'] != 0:
+ # Does the template exist??
+ if 'not found' in t_results['stderr']:
+ return False
+ else:
+ raise OpenShiftCLIError('Something went wrong. %s' % t_results)
+
+ return True
+
+ def needs_update(self):
+ '''attempt to process the template and return it for comparison with oc objects'''
+ obj_results = []
+ for obj in self.template:
+
+ # build a list of types to skip
+ skip = []
+
+ if obj['kind'] == 'ServiceAccount':
+ skip.extend(['secrets', 'imagePullSecrets'])
+ if obj['kind'] == 'BuildConfig':
+ skip.extend(['lastTriggeredImageID'])
+ if obj['kind'] == 'ImageStream':
+ skip.extend(['generation'])
+ if obj['kind'] == 'DeploymentConfig':
+ skip.extend(['lastTriggeredImage'])
+
+ # fetch the current object
+ curr_obj_results = self._get(obj['kind'], obj['metadata']['name'])
+ if curr_obj_results['returncode'] != 0:
+ # Does the template exist??
+ if 'not found' in curr_obj_results['stderr']:
+ obj_results.append((obj, True))
+ continue
+
+ # check the generated object against the existing object
+ if not Utils.check_def_equal(obj, curr_obj_results['results'][0], skip_keys=skip):
+ obj_results.append((obj, True))
+ continue
+
+ obj_results.append((obj, False))
+
+ return obj_results
+
+ # pylint: disable=too-many-return-statements
+ @staticmethod
+ def run_ansible(params, check_mode):
+ '''run the ansible idempotent code'''
+
+ ocprocess = OCProcess(params['namespace'],
+ params['template_name'],
+ params['params'],
+ params['create'],
+ kubeconfig=params['kubeconfig'],
+ tdata=params['content'],
+ verbose=params['debug'])
+
+ state = params['state']
+
+ api_rval = ocprocess.get()
+
+ if state == 'list':
+ if api_rval['returncode'] != 0:
+ return {"failed": True, "msg" : api_rval}
+
+ return {"changed" : False, "results": api_rval, "state": "list"}
+
+ elif state == 'present':
+ if check_mode and params['create']:
+ return {"changed": True, 'msg': "CHECK_MODE: Would have processed template."}
+
+ if not ocprocess.exists() or not params['reconcile']:
+ #FIXME: this code will never get run in a way that succeeds when
+ # module.params['reconcile'] is true. Because oc_process doesn't
+ # create the actual template, the check of ocprocess.exists()
+ # is meaningless. Either it's already here and this code
+ # won't be run, or this code will fail because there is no
+ # template available for oc process to use. Have we conflated
+ # the template's existence with the existence of the objects
+ # it describes?
+
+ # Create it here
+ api_rval = ocprocess.process()
+ if api_rval['returncode'] != 0:
+ return {"failed": True, "msg": api_rval}
+
+ if params['create']:
+ return {"changed": True, "results": api_rval, "state": "present"}
+
+ return {"changed": False, "results": api_rval, "state": "present"}
+
+ # verify results
+ update = False
+ rval = []
+ all_results = ocprocess.needs_update()
+ for obj, status in all_results:
+ if status:
+ ocprocess.delete(obj)
+ results = ocprocess.create_obj(obj)
+ results['kind'] = obj['kind']
+ rval.append(results)
+ update = True
+
+ if not update:
+ return {"changed": update, "results": api_rval, "state": "present"}
+
+ for cmd in rval:
+ if cmd['returncode'] != 0:
+ return {"failed": True, "changed": update, "results": rval, "state": "present"}
+
+ return {"changed": update, "results": rval, "state": "present"}
+
+
+# -*- -*- -*- End included fragment: class/oc_process.py -*- -*- -*-
+
+# -*- -*- -*- Begin included fragment: ansible/oc_process.py -*- -*- -*-
+
+
+def main():
+ '''
+ ansible oc module for processing templates
+ '''
+
+ module = AnsibleModule(
+ argument_spec=dict(
+ kubeconfig=dict(default='/etc/origin/master/admin.kubeconfig', type='str'),
+ state=dict(default='present', type='str', choices=['present', 'list']),
+ debug=dict(default=False, type='bool'),
+ namespace=dict(default='default', type='str'),
+ template_name=dict(default=None, type='str'),
+ content=dict(default=None, type='str'),
+ params=dict(default=None, type='dict'),
+ create=dict(default=False, type='bool'),
+ reconcile=dict(default=True, type='bool'),
+ ),
+ supports_check_mode=True,
+ )
+
+ rval = OCProcess.run_ansible(module.params, module.check_mode)
+ if 'failed' in rval:
+ module.fail_json(**rval)
+
+ module.exit_json(**rval)
+
+if __name__ == '__main__':
+ main()
+
+# -*- -*- -*- End included fragment: ansible/oc_process.py -*- -*- -*-
diff --git a/roles/lib_openshift/library/oc_route.py b/roles/lib_openshift/library/oc_route.py
index d1b2ccb14..982a43ba3 100644
--- a/roles/lib_openshift/library/oc_route.py
+++ b/roles/lib_openshift/library/oc_route.py
@@ -38,6 +38,7 @@ import os
import re
import shutil
import subprocess
+import tempfile
# pylint: disable=import-error
import ruamel.yaml as yaml
from ansible.module_utils.basic import AnsibleModule
@@ -144,6 +145,12 @@ options:
required: false
default: None
aliases: []
+ port:
+ description:
+ - The Name of the service port or number of the container port the route will route traffic to
+ required: false
+ default: None
+ aliases: []
author:
- "Kenny Woodson <kwoodson@redhat.com>"
extends_documentation_fragment: []
@@ -762,7 +769,7 @@ class OpenShiftCLI(object):
''' Constructor for OpenshiftCLI '''
self.namespace = namespace
self.verbose = verbose
- self.kubeconfig = kubeconfig
+ self.kubeconfig = Utils.create_tmpfile_copy(kubeconfig)
self.all_namespaces = all_namespaces
# Pylint allows only 5 arguments to be passed.
@@ -773,7 +780,8 @@ class OpenShiftCLI(object):
if not res['results']:
return res
- fname = '/tmp/%s' % rname
+ fname = Utils.create_tmpfile(rname + '-')
+
yed = Yedit(fname, res['results'][0], separator=sep)
changes = []
for key, value in content.items():
@@ -797,7 +805,7 @@ class OpenShiftCLI(object):
def _create_from_content(self, rname, content):
'''create a temporary file and then call oc create on it'''
- fname = '/tmp/%s' % rname
+ fname = Utils.create_tmpfile(rname + '-')
yed = Yedit(fname, content=content)
yed.write()
@@ -840,7 +848,7 @@ class OpenShiftCLI(object):
if results['returncode'] != 0 or not create:
return results
- fname = '/tmp/%s' % template_name
+ fname = Utils.create_tmpfile(template_name + '-')
yed = Yedit(fname, results['results'])
yed.write()
@@ -1021,32 +1029,61 @@ class OpenShiftCLI(object):
class Utils(object):
''' utilities for openshiftcli modules '''
+
@staticmethod
- def create_file(rname, data, ftype='yaml'):
+ def _write(filename, contents):
+ ''' Actually write the file contents to disk. This helps with mocking. '''
+
+ with open(filename, 'w') as sfd:
+ sfd.write(contents)
+
+ @staticmethod
+ def create_tmp_file_from_contents(rname, data, ftype='yaml'):
''' create a file in tmp with name and contents'''
- path = os.path.join('/tmp', rname)
- with open(path, 'w') as fds:
- if ftype == 'yaml':
- fds.write(yaml.dump(data, Dumper=yaml.RoundTripDumper))
- elif ftype == 'json':
- fds.write(json.dumps(data))
- else:
- fds.write(data)
+ tmp = Utils.create_tmpfile(prefix=rname)
+
+ if ftype == 'yaml':
+ Utils._write(tmp, yaml.dump(data, Dumper=yaml.RoundTripDumper))
+ elif ftype == 'json':
+ Utils._write(tmp, json.dumps(data))
+ else:
+ Utils._write(tmp, data)
# Register cleanup when module is done
- atexit.register(Utils.cleanup, [path])
- return path
+ atexit.register(Utils.cleanup, [tmp])
+ return tmp
+
+ @staticmethod
+ def create_tmpfile_copy(inc_file):
+ '''create a temporary copy of a file'''
+ tmpfile = Utils.create_tmpfile('lib_openshift-')
+ Utils._write(tmpfile, open(inc_file).read())
+
+ # Cleanup the tmpfile
+ atexit.register(Utils.cleanup, [tmpfile])
+
+ return tmpfile
@staticmethod
- def create_files_from_contents(content, content_type=None):
+ def create_tmpfile(prefix='tmp'):
+ ''' Generates and returns a temporary file name '''
+
+ with tempfile.NamedTemporaryFile(prefix=prefix, delete=False) as tmp:
+ return tmp.name
+
+ @staticmethod
+ def create_tmp_files_from_contents(content, content_type=None):
'''Turn an array of dict: filename, content into a files array'''
if not isinstance(content, list):
content = [content]
files = []
for item in content:
- path = Utils.create_file(item['path'], item['data'], ftype=content_type)
- files.append({'name': os.path.basename(path), 'path': path})
+ path = Utils.create_tmp_file_from_contents(item['path'] + '-',
+ item['data'],
+ ftype=content_type)
+ files.append({'name': os.path.basename(item['path']),
+ 'path': path})
return files
@staticmethod
@@ -1293,7 +1330,8 @@ class RouteConfig(object):
tls_termination=None,
service_name=None,
wildcard_policy=None,
- weight=None):
+ weight=None,
+ port=None):
''' constructor for handling route options '''
self.kubeconfig = kubeconfig
self.name = sname
@@ -1305,6 +1343,7 @@ class RouteConfig(object):
self.cert = cert
self.key = key
self.service_name = service_name
+ self.port = port
self.data = {}
self.wildcard_policy = wildcard_policy
if wildcard_policy is None:
@@ -1329,12 +1368,15 @@ class RouteConfig(object):
if self.tls_termination:
self.data['spec']['tls'] = {}
+ self.data['spec']['tls']['termination'] = self.tls_termination
+
+ if self.tls_termination != 'passthrough':
+ self.data['spec']['tls']['key'] = self.key
+ self.data['spec']['tls']['caCertificate'] = self.cacert
+ self.data['spec']['tls']['certificate'] = self.cert
+
if self.tls_termination == 'reencrypt':
self.data['spec']['tls']['destinationCACertificate'] = self.destcacert
- self.data['spec']['tls']['key'] = self.key
- self.data['spec']['tls']['caCertificate'] = self.cacert
- self.data['spec']['tls']['certificate'] = self.cert
- self.data['spec']['tls']['termination'] = self.tls_termination
self.data['spec']['to'] = {'kind': 'Service',
'name': self.service_name,
@@ -1342,11 +1384,16 @@ class RouteConfig(object):
self.data['spec']['wildcardPolicy'] = self.wildcard_policy
+ if self.port:
+ self.data['spec']['port'] = {}
+ self.data['spec']['port']['targetPort'] = self.port
+
# pylint: disable=too-many-instance-attributes,too-many-public-methods
class Route(Yedit):
''' Class to wrap the oc command line tools '''
wildcard_policy = "spec.wildcardPolicy"
host_path = "spec.host"
+ port_path = "spec.port.targetPort"
service_path = "spec.to.name"
weight_path = "spec.to.weight"
cert_path = "spec.tls.certificate"
@@ -1392,6 +1439,10 @@ class Route(Yedit):
''' return host '''
return self.get(Route.host_path)
+ def get_port(self):
+ ''' return port '''
+ return self.get(Route.port_path)
+
def get_wildcard_policy(self):
''' return wildcardPolicy '''
return self.get(Route.wildcard_policy)
@@ -1463,9 +1514,23 @@ class OCRoute(OpenShiftCLI):
skip = []
return not Utils.check_def_equal(self.config.data, self.route.yaml_dict, skip_keys=skip, debug=True)
+ @staticmethod
+ def get_cert_data(path, content):
+ '''get the data for a particular value'''
+ if not path and not content:
+ return None
+
+ rval = None
+ if path and os.path.exists(path) and os.access(path, os.R_OK):
+ rval = open(path).read()
+ elif content:
+ rval = content
+
+ return rval
+
# pylint: disable=too-many-return-statements,too-many-branches
@staticmethod
- def run_ansible(params, files, check_mode=False):
+ def run_ansible(params, check_mode=False):
''' run the idempotent asnible code
params comes from the ansible portion for this module
@@ -1477,6 +1542,30 @@ class OCRoute(OpenShiftCLI):
}
check_mode: does the module support check mode. (module.check_mode)
'''
+ files = {'destcacert': {'path': params['dest_cacert_path'],
+ 'content': params['dest_cacert_content'],
+ 'value': None, },
+ 'cacert': {'path': params['cacert_path'],
+ 'content': params['cacert_content'],
+ 'value': None, },
+ 'cert': {'path': params['cert_path'],
+ 'content': params['cert_content'],
+ 'value': None, },
+ 'key': {'path': params['key_path'],
+ 'content': params['key_content'],
+ 'value': None, }, }
+
+ if params['tls_termination'] and params['tls_termination'].lower() != 'passthrough': # E501
+
+ for key, option in files.items():
+ if key == 'destcacert' and params['tls_termination'] != 'reencrypt':
+ continue
+
+ option['value'] = OCRoute.get_cert_data(option['path'], option['content']) # E501
+
+ if not option['value']:
+ return {'failed': True,
+ 'msg': 'Verify that you pass a value for %s' % key}
rconfig = RouteConfig(params['name'],
params['namespace'],
@@ -1489,7 +1578,8 @@ class OCRoute(OpenShiftCLI):
params['tls_termination'],
params['service_name'],
params['wildcard_policy'],
- params['weight'])
+ params['weight'],
+ params['port'])
oc_route = OCRoute(rconfig, verbose=params['debug'])
@@ -1573,20 +1663,6 @@ class OCRoute(OpenShiftCLI):
# -*- -*- -*- Begin included fragment: ansible/oc_route.py -*- -*- -*-
-def get_cert_data(path, content):
- '''get the data for a particular value'''
- if not path and not content:
- return None
-
- rval = None
- if path and os.path.exists(path) and os.access(path, os.R_OK):
- rval = open(path).read()
- elif content:
- rval = content
-
- return rval
-
-
# pylint: disable=too-many-branches
def main():
'''
@@ -1613,6 +1689,7 @@ def main():
host=dict(default=None, type='str'),
wildcard_policy=dict(default=None, type='str'),
weight=dict(default=None, type='int'),
+ port=dict(default=None, type='int'),
),
mutually_exclusive=[('dest_cacert_path', 'dest_cacert_content'),
('cacert_path', 'cacert_content'),
@@ -1620,30 +1697,8 @@ def main():
('key_path', 'key_content'), ],
supports_check_mode=True,
)
- files = {'destcacert': {'path': module.params['dest_cacert_path'],
- 'content': module.params['dest_cacert_content'],
- 'value': None, },
- 'cacert': {'path': module.params['cacert_path'],
- 'content': module.params['cacert_content'],
- 'value': None, },
- 'cert': {'path': module.params['cert_path'],
- 'content': module.params['cert_content'],
- 'value': None, },
- 'key': {'path': module.params['key_path'],
- 'content': module.params['key_content'],
- 'value': None, }, }
-
- if module.params['tls_termination']:
- for key, option in files.items():
- if key == 'destcacert' and module.params['tls_termination'] != 'reencrypt':
- continue
-
- option['value'] = get_cert_data(option['path'], option['content'])
-
- if not option['value']:
- module.fail_json(msg='Verify that you pass a value for %s' % key)
- results = OCRoute.run_ansible(module.params, files, module.check_mode)
+ results = OCRoute.run_ansible(module.params, module.check_mode)
if 'failed' in results:
module.fail_json(**results)
diff --git a/roles/lib_openshift/library/oc_scale.py b/roles/lib_openshift/library/oc_scale.py
index f2b96b6ad..48a629b5e 100644
--- a/roles/lib_openshift/library/oc_scale.py
+++ b/roles/lib_openshift/library/oc_scale.py
@@ -38,6 +38,7 @@ import os
import re
import shutil
import subprocess
+import tempfile
# pylint: disable=import-error
import ruamel.yaml as yaml
from ansible.module_utils.basic import AnsibleModule
@@ -712,7 +713,7 @@ class OpenShiftCLI(object):
''' Constructor for OpenshiftCLI '''
self.namespace = namespace
self.verbose = verbose
- self.kubeconfig = kubeconfig
+ self.kubeconfig = Utils.create_tmpfile_copy(kubeconfig)
self.all_namespaces = all_namespaces
# Pylint allows only 5 arguments to be passed.
@@ -723,7 +724,8 @@ class OpenShiftCLI(object):
if not res['results']:
return res
- fname = '/tmp/%s' % rname
+ fname = Utils.create_tmpfile(rname + '-')
+
yed = Yedit(fname, res['results'][0], separator=sep)
changes = []
for key, value in content.items():
@@ -747,7 +749,7 @@ class OpenShiftCLI(object):
def _create_from_content(self, rname, content):
'''create a temporary file and then call oc create on it'''
- fname = '/tmp/%s' % rname
+ fname = Utils.create_tmpfile(rname + '-')
yed = Yedit(fname, content=content)
yed.write()
@@ -790,7 +792,7 @@ class OpenShiftCLI(object):
if results['returncode'] != 0 or not create:
return results
- fname = '/tmp/%s' % template_name
+ fname = Utils.create_tmpfile(template_name + '-')
yed = Yedit(fname, results['results'])
yed.write()
@@ -971,32 +973,61 @@ class OpenShiftCLI(object):
class Utils(object):
''' utilities for openshiftcli modules '''
+
@staticmethod
- def create_file(rname, data, ftype='yaml'):
+ def _write(filename, contents):
+ ''' Actually write the file contents to disk. This helps with mocking. '''
+
+ with open(filename, 'w') as sfd:
+ sfd.write(contents)
+
+ @staticmethod
+ def create_tmp_file_from_contents(rname, data, ftype='yaml'):
''' create a file in tmp with name and contents'''
- path = os.path.join('/tmp', rname)
- with open(path, 'w') as fds:
- if ftype == 'yaml':
- fds.write(yaml.dump(data, Dumper=yaml.RoundTripDumper))
- elif ftype == 'json':
- fds.write(json.dumps(data))
- else:
- fds.write(data)
+ tmp = Utils.create_tmpfile(prefix=rname)
+
+ if ftype == 'yaml':
+ Utils._write(tmp, yaml.dump(data, Dumper=yaml.RoundTripDumper))
+ elif ftype == 'json':
+ Utils._write(tmp, json.dumps(data))
+ else:
+ Utils._write(tmp, data)
# Register cleanup when module is done
- atexit.register(Utils.cleanup, [path])
- return path
+ atexit.register(Utils.cleanup, [tmp])
+ return tmp
+
+ @staticmethod
+ def create_tmpfile_copy(inc_file):
+ '''create a temporary copy of a file'''
+ tmpfile = Utils.create_tmpfile('lib_openshift-')
+ Utils._write(tmpfile, open(inc_file).read())
+
+ # Cleanup the tmpfile
+ atexit.register(Utils.cleanup, [tmpfile])
+
+ return tmpfile
+
+ @staticmethod
+ def create_tmpfile(prefix='tmp'):
+ ''' Generates and returns a temporary file name '''
+
+ with tempfile.NamedTemporaryFile(prefix=prefix, delete=False) as tmp:
+ return tmp.name
@staticmethod
- def create_files_from_contents(content, content_type=None):
+ def create_tmp_files_from_contents(content, content_type=None):
'''Turn an array of dict: filename, content into a files array'''
if not isinstance(content, list):
content = [content]
files = []
for item in content:
- path = Utils.create_file(item['path'], item['data'], ftype=content_type)
- files.append({'name': os.path.basename(path), 'path': path})
+ path = Utils.create_tmp_file_from_contents(item['path'] + '-',
+ item['data'],
+ ftype=content_type)
+ files.append({'name': os.path.basename(item['path']),
+ 'path': path})
return files
@staticmethod
diff --git a/roles/lib_openshift/library/oc_secret.py b/roles/lib_openshift/library/oc_secret.py
index d2ba1af51..526474f17 100644
--- a/roles/lib_openshift/library/oc_secret.py
+++ b/roles/lib_openshift/library/oc_secret.py
@@ -38,6 +38,7 @@ import os
import re
import shutil
import subprocess
+import tempfile
# pylint: disable=import-error
import ruamel.yaml as yaml
from ansible.module_utils.basic import AnsibleModule
@@ -758,7 +759,7 @@ class OpenShiftCLI(object):
''' Constructor for OpenshiftCLI '''
self.namespace = namespace
self.verbose = verbose
- self.kubeconfig = kubeconfig
+ self.kubeconfig = Utils.create_tmpfile_copy(kubeconfig)
self.all_namespaces = all_namespaces
# Pylint allows only 5 arguments to be passed.
@@ -769,7 +770,8 @@ class OpenShiftCLI(object):
if not res['results']:
return res
- fname = '/tmp/%s' % rname
+ fname = Utils.create_tmpfile(rname + '-')
+
yed = Yedit(fname, res['results'][0], separator=sep)
changes = []
for key, value in content.items():
@@ -793,7 +795,7 @@ class OpenShiftCLI(object):
def _create_from_content(self, rname, content):
'''create a temporary file and then call oc create on it'''
- fname = '/tmp/%s' % rname
+ fname = Utils.create_tmpfile(rname + '-')
yed = Yedit(fname, content=content)
yed.write()
@@ -836,7 +838,7 @@ class OpenShiftCLI(object):
if results['returncode'] != 0 or not create:
return results
- fname = '/tmp/%s' % template_name
+ fname = Utils.create_tmpfile(template_name + '-')
yed = Yedit(fname, results['results'])
yed.write()
@@ -1017,32 +1019,61 @@ class OpenShiftCLI(object):
class Utils(object):
''' utilities for openshiftcli modules '''
+
@staticmethod
- def create_file(rname, data, ftype='yaml'):
+ def _write(filename, contents):
+ ''' Actually write the file contents to disk. This helps with mocking. '''
+
+ with open(filename, 'w') as sfd:
+ sfd.write(contents)
+
+ @staticmethod
+ def create_tmp_file_from_contents(rname, data, ftype='yaml'):
''' create a file in tmp with name and contents'''
- path = os.path.join('/tmp', rname)
- with open(path, 'w') as fds:
- if ftype == 'yaml':
- fds.write(yaml.dump(data, Dumper=yaml.RoundTripDumper))
- elif ftype == 'json':
- fds.write(json.dumps(data))
- else:
- fds.write(data)
+ tmp = Utils.create_tmpfile(prefix=rname)
+
+ if ftype == 'yaml':
+ Utils._write(tmp, yaml.dump(data, Dumper=yaml.RoundTripDumper))
+ elif ftype == 'json':
+ Utils._write(tmp, json.dumps(data))
+ else:
+ Utils._write(tmp, data)
# Register cleanup when module is done
- atexit.register(Utils.cleanup, [path])
- return path
+ atexit.register(Utils.cleanup, [tmp])
+ return tmp
+
+ @staticmethod
+ def create_tmpfile_copy(inc_file):
+ '''create a temporary copy of a file'''
+ tmpfile = Utils.create_tmpfile('lib_openshift-')
+ Utils._write(tmpfile, open(inc_file).read())
+
+ # Cleanup the tmpfile
+ atexit.register(Utils.cleanup, [tmpfile])
+
+ return tmpfile
+
+ @staticmethod
+ def create_tmpfile(prefix='tmp'):
+ ''' Generates and returns a temporary file name '''
+
+ with tempfile.NamedTemporaryFile(prefix=prefix, delete=False) as tmp:
+ return tmp.name
@staticmethod
- def create_files_from_contents(content, content_type=None):
+ def create_tmp_files_from_contents(content, content_type=None):
'''Turn an array of dict: filename, content into a files array'''
if not isinstance(content, list):
content = [content]
files = []
for item in content:
- path = Utils.create_file(item['path'], item['data'], ftype=content_type)
- files.append({'name': os.path.basename(path), 'path': path})
+ path = Utils.create_tmp_file_from_contents(item['path'] + '-',
+ item['data'],
+ ftype=content_type)
+ files.append({'name': os.path.basename(item['path']),
+ 'path': path})
return files
@staticmethod
@@ -1418,7 +1449,7 @@ class OCSecret(OpenShiftCLI):
def create(self, files=None, contents=None):
'''Create a secret '''
if not files:
- files = Utils.create_files_from_contents(contents)
+ files = Utils.create_tmp_files_from_contents(contents)
secrets = ["%s=%s" % (sfile['name'], sfile['path']) for sfile in files]
cmd = ['secrets', 'new', self.name]
@@ -1451,7 +1482,7 @@ class OCSecret(OpenShiftCLI):
This is accomplished by passing -ojson. This will most likely change in the future
'''
if not files:
- files = Utils.create_files_from_contents(contents)
+ files = Utils.create_tmp_files_from_contents(contents)
secrets = ["%s=%s" % (sfile['name'], sfile['path']) for sfile in files]
cmd = ['-ojson', 'secrets', 'new', self.name]
@@ -1502,7 +1533,7 @@ class OCSecret(OpenShiftCLI):
if params['files']:
files = params['files']
elif params['contents']:
- files = Utils.create_files_from_contents(params['contents'])
+ files = Utils.create_tmp_files_from_contents(params['contents'])
else:
return {'failed': True,
'msg': 'Either specify files or contents.'}
@@ -1516,7 +1547,7 @@ class OCSecret(OpenShiftCLI):
return {'changed': True,
'msg': 'Would have performed a create.'}
- api_rval = ocsecret.create(params['files'], params['contents'])
+ api_rval = ocsecret.create(files, params['contents'])
# Remove files
if files and params['delete_after']:
diff --git a/roles/lib_openshift/library/oc_service.py b/roles/lib_openshift/library/oc_service.py
index 0979f83c6..a9baef765 100644
--- a/roles/lib_openshift/library/oc_service.py
+++ b/roles/lib_openshift/library/oc_service.py
@@ -38,6 +38,7 @@ import os
import re
import shutil
import subprocess
+import tempfile
# pylint: disable=import-error
import ruamel.yaml as yaml
from ansible.module_utils.basic import AnsibleModule
@@ -764,7 +765,7 @@ class OpenShiftCLI(object):
''' Constructor for OpenshiftCLI '''
self.namespace = namespace
self.verbose = verbose
- self.kubeconfig = kubeconfig
+ self.kubeconfig = Utils.create_tmpfile_copy(kubeconfig)
self.all_namespaces = all_namespaces
# Pylint allows only 5 arguments to be passed.
@@ -775,7 +776,8 @@ class OpenShiftCLI(object):
if not res['results']:
return res
- fname = '/tmp/%s' % rname
+ fname = Utils.create_tmpfile(rname + '-')
+
yed = Yedit(fname, res['results'][0], separator=sep)
changes = []
for key, value in content.items():
@@ -799,7 +801,7 @@ class OpenShiftCLI(object):
def _create_from_content(self, rname, content):
'''create a temporary file and then call oc create on it'''
- fname = '/tmp/%s' % rname
+ fname = Utils.create_tmpfile(rname + '-')
yed = Yedit(fname, content=content)
yed.write()
@@ -842,7 +844,7 @@ class OpenShiftCLI(object):
if results['returncode'] != 0 or not create:
return results
- fname = '/tmp/%s' % template_name
+ fname = Utils.create_tmpfile(template_name + '-')
yed = Yedit(fname, results['results'])
yed.write()
@@ -1023,32 +1025,61 @@ class OpenShiftCLI(object):
class Utils(object):
''' utilities for openshiftcli modules '''
+
@staticmethod
- def create_file(rname, data, ftype='yaml'):
+ def _write(filename, contents):
+ ''' Actually write the file contents to disk. This helps with mocking. '''
+
+ with open(filename, 'w') as sfd:
+ sfd.write(contents)
+
+ @staticmethod
+ def create_tmp_file_from_contents(rname, data, ftype='yaml'):
''' create a file in tmp with name and contents'''
- path = os.path.join('/tmp', rname)
- with open(path, 'w') as fds:
- if ftype == 'yaml':
- fds.write(yaml.dump(data, Dumper=yaml.RoundTripDumper))
- elif ftype == 'json':
- fds.write(json.dumps(data))
- else:
- fds.write(data)
+ tmp = Utils.create_tmpfile(prefix=rname)
+
+ if ftype == 'yaml':
+ Utils._write(tmp, yaml.dump(data, Dumper=yaml.RoundTripDumper))
+ elif ftype == 'json':
+ Utils._write(tmp, json.dumps(data))
+ else:
+ Utils._write(tmp, data)
# Register cleanup when module is done
- atexit.register(Utils.cleanup, [path])
- return path
+ atexit.register(Utils.cleanup, [tmp])
+ return tmp
+
+ @staticmethod
+ def create_tmpfile_copy(inc_file):
+ '''create a temporary copy of a file'''
+ tmpfile = Utils.create_tmpfile('lib_openshift-')
+ Utils._write(tmpfile, open(inc_file).read())
+
+ # Cleanup the tmpfile
+ atexit.register(Utils.cleanup, [tmpfile])
+
+ return tmpfile
+
+ @staticmethod
+ def create_tmpfile(prefix='tmp'):
+ ''' Generates and returns a temporary file name '''
+
+ with tempfile.NamedTemporaryFile(prefix=prefix, delete=False) as tmp:
+ return tmp.name
@staticmethod
- def create_files_from_contents(content, content_type=None):
+ def create_tmp_files_from_contents(content, content_type=None):
'''Turn an array of dict: filename, content into a files array'''
if not isinstance(content, list):
content = [content]
files = []
for item in content:
- path = Utils.create_file(item['path'], item['data'], ftype=content_type)
- files.append({'name': os.path.basename(path), 'path': path})
+ path = Utils.create_tmp_file_from_contents(item['path'] + '-',
+ item['data'],
+ ftype=content_type)
+ files.append({'name': os.path.basename(item['path']),
+ 'path': path})
return files
@staticmethod
diff --git a/roles/lib_openshift/library/oc_serviceaccount.py b/roles/lib_openshift/library/oc_serviceaccount.py
index 0db0d1219..cd0847963 100644
--- a/roles/lib_openshift/library/oc_serviceaccount.py
+++ b/roles/lib_openshift/library/oc_serviceaccount.py
@@ -38,6 +38,7 @@ import os
import re
import shutil
import subprocess
+import tempfile
# pylint: disable=import-error
import ruamel.yaml as yaml
from ansible.module_utils.basic import AnsibleModule
@@ -710,7 +711,7 @@ class OpenShiftCLI(object):
''' Constructor for OpenshiftCLI '''
self.namespace = namespace
self.verbose = verbose
- self.kubeconfig = kubeconfig
+ self.kubeconfig = Utils.create_tmpfile_copy(kubeconfig)
self.all_namespaces = all_namespaces
# Pylint allows only 5 arguments to be passed.
@@ -721,7 +722,8 @@ class OpenShiftCLI(object):
if not res['results']:
return res
- fname = '/tmp/%s' % rname
+ fname = Utils.create_tmpfile(rname + '-')
+
yed = Yedit(fname, res['results'][0], separator=sep)
changes = []
for key, value in content.items():
@@ -745,7 +747,7 @@ class OpenShiftCLI(object):
def _create_from_content(self, rname, content):
'''create a temporary file and then call oc create on it'''
- fname = '/tmp/%s' % rname
+ fname = Utils.create_tmpfile(rname + '-')
yed = Yedit(fname, content=content)
yed.write()
@@ -788,7 +790,7 @@ class OpenShiftCLI(object):
if results['returncode'] != 0 or not create:
return results
- fname = '/tmp/%s' % template_name
+ fname = Utils.create_tmpfile(template_name + '-')
yed = Yedit(fname, results['results'])
yed.write()
@@ -969,32 +971,61 @@ class OpenShiftCLI(object):
class Utils(object):
''' utilities for openshiftcli modules '''
+
@staticmethod
- def create_file(rname, data, ftype='yaml'):
+ def _write(filename, contents):
+ ''' Actually write the file contents to disk. This helps with mocking. '''
+
+ with open(filename, 'w') as sfd:
+ sfd.write(contents)
+
+ @staticmethod
+ def create_tmp_file_from_contents(rname, data, ftype='yaml'):
''' create a file in tmp with name and contents'''
- path = os.path.join('/tmp', rname)
- with open(path, 'w') as fds:
- if ftype == 'yaml':
- fds.write(yaml.dump(data, Dumper=yaml.RoundTripDumper))
- elif ftype == 'json':
- fds.write(json.dumps(data))
- else:
- fds.write(data)
+ tmp = Utils.create_tmpfile(prefix=rname)
+
+ if ftype == 'yaml':
+ Utils._write(tmp, yaml.dump(data, Dumper=yaml.RoundTripDumper))
+ elif ftype == 'json':
+ Utils._write(tmp, json.dumps(data))
+ else:
+ Utils._write(tmp, data)
# Register cleanup when module is done
- atexit.register(Utils.cleanup, [path])
- return path
+ atexit.register(Utils.cleanup, [tmp])
+ return tmp
+
+ @staticmethod
+ def create_tmpfile_copy(inc_file):
+ '''create a temporary copy of a file'''
+ tmpfile = Utils.create_tmpfile('lib_openshift-')
+ Utils._write(tmpfile, open(inc_file).read())
+
+ # Cleanup the tmpfile
+ atexit.register(Utils.cleanup, [tmpfile])
+
+ return tmpfile
+
+ @staticmethod
+ def create_tmpfile(prefix='tmp'):
+ ''' Generates and returns a temporary file name '''
+
+ with tempfile.NamedTemporaryFile(prefix=prefix, delete=False) as tmp:
+ return tmp.name
@staticmethod
- def create_files_from_contents(content, content_type=None):
+ def create_tmp_files_from_contents(content, content_type=None):
'''Turn an array of dict: filename, content into a files array'''
if not isinstance(content, list):
content = [content]
files = []
for item in content:
- path = Utils.create_file(item['path'], item['data'], ftype=content_type)
- files.append({'name': os.path.basename(path), 'path': path})
+ path = Utils.create_tmp_file_from_contents(item['path'] + '-',
+ item['data'],
+ ftype=content_type)
+ files.append({'name': os.path.basename(item['path']),
+ 'path': path})
return files
@staticmethod
diff --git a/roles/lib_openshift/library/oc_serviceaccount_secret.py b/roles/lib_openshift/library/oc_serviceaccount_secret.py
index 29985d62f..e22ccbfc2 100644
--- a/roles/lib_openshift/library/oc_serviceaccount_secret.py
+++ b/roles/lib_openshift/library/oc_serviceaccount_secret.py
@@ -38,6 +38,7 @@ import os
import re
import shutil
import subprocess
+import tempfile
# pylint: disable=import-error
import ruamel.yaml as yaml
from ansible.module_utils.basic import AnsibleModule
@@ -710,7 +711,7 @@ class OpenShiftCLI(object):
''' Constructor for OpenshiftCLI '''
self.namespace = namespace
self.verbose = verbose
- self.kubeconfig = kubeconfig
+ self.kubeconfig = Utils.create_tmpfile_copy(kubeconfig)
self.all_namespaces = all_namespaces
# Pylint allows only 5 arguments to be passed.
@@ -721,7 +722,8 @@ class OpenShiftCLI(object):
if not res['results']:
return res
- fname = '/tmp/%s' % rname
+ fname = Utils.create_tmpfile(rname + '-')
+
yed = Yedit(fname, res['results'][0], separator=sep)
changes = []
for key, value in content.items():
@@ -745,7 +747,7 @@ class OpenShiftCLI(object):
def _create_from_content(self, rname, content):
'''create a temporary file and then call oc create on it'''
- fname = '/tmp/%s' % rname
+ fname = Utils.create_tmpfile(rname + '-')
yed = Yedit(fname, content=content)
yed.write()
@@ -788,7 +790,7 @@ class OpenShiftCLI(object):
if results['returncode'] != 0 or not create:
return results
- fname = '/tmp/%s' % template_name
+ fname = Utils.create_tmpfile(template_name + '-')
yed = Yedit(fname, results['results'])
yed.write()
@@ -969,32 +971,61 @@ class OpenShiftCLI(object):
class Utils(object):
''' utilities for openshiftcli modules '''
+
@staticmethod
- def create_file(rname, data, ftype='yaml'):
+ def _write(filename, contents):
+ ''' Actually write the file contents to disk. This helps with mocking. '''
+
+ with open(filename, 'w') as sfd:
+ sfd.write(contents)
+
+ @staticmethod
+ def create_tmp_file_from_contents(rname, data, ftype='yaml'):
''' create a file in tmp with name and contents'''
- path = os.path.join('/tmp', rname)
- with open(path, 'w') as fds:
- if ftype == 'yaml':
- fds.write(yaml.dump(data, Dumper=yaml.RoundTripDumper))
- elif ftype == 'json':
- fds.write(json.dumps(data))
- else:
- fds.write(data)
+ tmp = Utils.create_tmpfile(prefix=rname)
+
+ if ftype == 'yaml':
+ Utils._write(tmp, yaml.dump(data, Dumper=yaml.RoundTripDumper))
+ elif ftype == 'json':
+ Utils._write(tmp, json.dumps(data))
+ else:
+ Utils._write(tmp, data)
# Register cleanup when module is done
- atexit.register(Utils.cleanup, [path])
- return path
+ atexit.register(Utils.cleanup, [tmp])
+ return tmp
+
+ @staticmethod
+ def create_tmpfile_copy(inc_file):
+ '''create a temporary copy of a file'''
+ tmpfile = Utils.create_tmpfile('lib_openshift-')
+ Utils._write(tmpfile, open(inc_file).read())
+
+ # Cleanup the tmpfile
+ atexit.register(Utils.cleanup, [tmpfile])
+
+ return tmpfile
+
+ @staticmethod
+ def create_tmpfile(prefix='tmp'):
+ ''' Generates and returns a temporary file name '''
+
+ with tempfile.NamedTemporaryFile(prefix=prefix, delete=False) as tmp:
+ return tmp.name
@staticmethod
- def create_files_from_contents(content, content_type=None):
+ def create_tmp_files_from_contents(content, content_type=None):
'''Turn an array of dict: filename, content into a files array'''
if not isinstance(content, list):
content = [content]
files = []
for item in content:
- path = Utils.create_file(item['path'], item['data'], ftype=content_type)
- files.append({'name': os.path.basename(path), 'path': path})
+ path = Utils.create_tmp_file_from_contents(item['path'] + '-',
+ item['data'],
+ ftype=content_type)
+ files.append({'name': os.path.basename(item['path']),
+ 'path': path})
return files
@staticmethod
diff --git a/roles/lib_openshift/library/oc_version.py b/roles/lib_openshift/library/oc_version.py
index 5c528b399..e44375ffa 100644
--- a/roles/lib_openshift/library/oc_version.py
+++ b/roles/lib_openshift/library/oc_version.py
@@ -38,6 +38,7 @@ import os
import re
import shutil
import subprocess
+import tempfile
# pylint: disable=import-error
import ruamel.yaml as yaml
from ansible.module_utils.basic import AnsibleModule
@@ -682,7 +683,7 @@ class OpenShiftCLI(object):
''' Constructor for OpenshiftCLI '''
self.namespace = namespace
self.verbose = verbose
- self.kubeconfig = kubeconfig
+ self.kubeconfig = Utils.create_tmpfile_copy(kubeconfig)
self.all_namespaces = all_namespaces
# Pylint allows only 5 arguments to be passed.
@@ -693,7 +694,8 @@ class OpenShiftCLI(object):
if not res['results']:
return res
- fname = '/tmp/%s' % rname
+ fname = Utils.create_tmpfile(rname + '-')
+
yed = Yedit(fname, res['results'][0], separator=sep)
changes = []
for key, value in content.items():
@@ -717,7 +719,7 @@ class OpenShiftCLI(object):
def _create_from_content(self, rname, content):
'''create a temporary file and then call oc create on it'''
- fname = '/tmp/%s' % rname
+ fname = Utils.create_tmpfile(rname + '-')
yed = Yedit(fname, content=content)
yed.write()
@@ -760,7 +762,7 @@ class OpenShiftCLI(object):
if results['returncode'] != 0 or not create:
return results
- fname = '/tmp/%s' % template_name
+ fname = Utils.create_tmpfile(template_name + '-')
yed = Yedit(fname, results['results'])
yed.write()
@@ -941,32 +943,61 @@ class OpenShiftCLI(object):
class Utils(object):
''' utilities for openshiftcli modules '''
+
@staticmethod
- def create_file(rname, data, ftype='yaml'):
+ def _write(filename, contents):
+ ''' Actually write the file contents to disk. This helps with mocking. '''
+
+ with open(filename, 'w') as sfd:
+ sfd.write(contents)
+
+ @staticmethod
+ def create_tmp_file_from_contents(rname, data, ftype='yaml'):
''' create a file in tmp with name and contents'''
- path = os.path.join('/tmp', rname)
- with open(path, 'w') as fds:
- if ftype == 'yaml':
- fds.write(yaml.dump(data, Dumper=yaml.RoundTripDumper))
- elif ftype == 'json':
- fds.write(json.dumps(data))
- else:
- fds.write(data)
+ tmp = Utils.create_tmpfile(prefix=rname)
+
+ if ftype == 'yaml':
+ Utils._write(tmp, yaml.dump(data, Dumper=yaml.RoundTripDumper))
+ elif ftype == 'json':
+ Utils._write(tmp, json.dumps(data))
+ else:
+ Utils._write(tmp, data)
# Register cleanup when module is done
- atexit.register(Utils.cleanup, [path])
- return path
+ atexit.register(Utils.cleanup, [tmp])
+ return tmp
+
+ @staticmethod
+ def create_tmpfile_copy(inc_file):
+ '''create a temporary copy of a file'''
+ tmpfile = Utils.create_tmpfile('lib_openshift-')
+ Utils._write(tmpfile, open(inc_file).read())
+
+ # Cleanup the tmpfile
+ atexit.register(Utils.cleanup, [tmpfile])
+
+ return tmpfile
+
+ @staticmethod
+ def create_tmpfile(prefix='tmp'):
+ ''' Generates and returns a temporary file name '''
+
+ with tempfile.NamedTemporaryFile(prefix=prefix, delete=False) as tmp:
+ return tmp.name
@staticmethod
- def create_files_from_contents(content, content_type=None):
+ def create_tmp_files_from_contents(content, content_type=None):
'''Turn an array of dict: filename, content into a files array'''
if not isinstance(content, list):
content = [content]
files = []
for item in content:
- path = Utils.create_file(item['path'], item['data'], ftype=content_type)
- files.append({'name': os.path.basename(path), 'path': path})
+ path = Utils.create_tmp_file_from_contents(item['path'] + '-',
+ item['data'],
+ ftype=content_type)
+ files.append({'name': os.path.basename(item['path']),
+ 'path': path})
return files
@staticmethod
diff --git a/roles/lib_openshift/src/ansible/oc_label.py b/roles/lib_openshift/src/ansible/oc_label.py
index 28f004621..84c5e336a 100644
--- a/roles/lib_openshift/src/ansible/oc_label.py
+++ b/roles/lib_openshift/src/ansible/oc_label.py
@@ -10,7 +10,7 @@ def main():
state=dict(default='present', type='str',
choices=['present', 'absent', 'list', 'add']),
debug=dict(default=False, type='bool'),
- kind=dict(default='node', type='str', required=True,
+ kind=dict(default='node', type='str',
choices=['node', 'pod', 'namespace']),
name=dict(default=None, type='str'),
namespace=dict(default=None, type='str'),
diff --git a/roles/lib_openshift/src/ansible/oc_process.py b/roles/lib_openshift/src/ansible/oc_process.py
new file mode 100644
index 000000000..17cf865b7
--- /dev/null
+++ b/roles/lib_openshift/src/ansible/oc_process.py
@@ -0,0 +1,32 @@
+# pylint: skip-file
+# flake8: noqa
+
+
+def main():
+ '''
+ ansible oc module for processing templates
+ '''
+
+ module = AnsibleModule(
+ argument_spec=dict(
+ kubeconfig=dict(default='/etc/origin/master/admin.kubeconfig', type='str'),
+ state=dict(default='present', type='str', choices=['present', 'list']),
+ debug=dict(default=False, type='bool'),
+ namespace=dict(default='default', type='str'),
+ template_name=dict(default=None, type='str'),
+ content=dict(default=None, type='str'),
+ params=dict(default=None, type='dict'),
+ create=dict(default=False, type='bool'),
+ reconcile=dict(default=True, type='bool'),
+ ),
+ supports_check_mode=True,
+ )
+
+ rval = OCProcess.run_ansible(module.params, module.check_mode)
+ if 'failed' in rval:
+ module.fail_json(**rval)
+
+ module.exit_json(**rval)
+
+if __name__ == '__main__':
+ main()
diff --git a/roles/lib_openshift/src/ansible/oc_route.py b/roles/lib_openshift/src/ansible/oc_route.py
index c87e6738f..f2f5c5095 100644
--- a/roles/lib_openshift/src/ansible/oc_route.py
+++ b/roles/lib_openshift/src/ansible/oc_route.py
@@ -2,20 +2,6 @@
# flake8: noqa
-def get_cert_data(path, content):
- '''get the data for a particular value'''
- if not path and not content:
- return None
-
- rval = None
- if path and os.path.exists(path) and os.access(path, os.R_OK):
- rval = open(path).read()
- elif content:
- rval = content
-
- return rval
-
-
# pylint: disable=too-many-branches
def main():
'''
@@ -42,6 +28,7 @@ def main():
host=dict(default=None, type='str'),
wildcard_policy=dict(default=None, type='str'),
weight=dict(default=None, type='int'),
+ port=dict(default=None, type='int'),
),
mutually_exclusive=[('dest_cacert_path', 'dest_cacert_content'),
('cacert_path', 'cacert_content'),
@@ -49,30 +36,8 @@ def main():
('key_path', 'key_content'), ],
supports_check_mode=True,
)
- files = {'destcacert': {'path': module.params['dest_cacert_path'],
- 'content': module.params['dest_cacert_content'],
- 'value': None, },
- 'cacert': {'path': module.params['cacert_path'],
- 'content': module.params['cacert_content'],
- 'value': None, },
- 'cert': {'path': module.params['cert_path'],
- 'content': module.params['cert_content'],
- 'value': None, },
- 'key': {'path': module.params['key_path'],
- 'content': module.params['key_content'],
- 'value': None, }, }
-
- if module.params['tls_termination']:
- for key, option in files.items():
- if key == 'destcacert' and module.params['tls_termination'] != 'reencrypt':
- continue
-
- option['value'] = get_cert_data(option['path'], option['content'])
-
- if not option['value']:
- module.fail_json(msg='Verify that you pass a value for %s' % key)
- results = OCRoute.run_ansible(module.params, files, module.check_mode)
+ results = OCRoute.run_ansible(module.params, module.check_mode)
if 'failed' in results:
module.fail_json(**results)
diff --git a/roles/lib_openshift/src/class/oc_obj.py b/roles/lib_openshift/src/class/oc_obj.py
index 9d0b8e45b..2ec20e72c 100644
--- a/roles/lib_openshift/src/class/oc_obj.py
+++ b/roles/lib_openshift/src/class/oc_obj.py
@@ -49,7 +49,7 @@ class OCObject(OpenShiftCLI):
return self._create(files[0])
content['data'] = yaml.dump(content['data'])
- content_file = Utils.create_files_from_contents(content)[0]
+ content_file = Utils.create_tmp_files_from_contents(content)[0]
return self._create(content_file['path'])
diff --git a/roles/lib_openshift/src/class/oc_process.py b/roles/lib_openshift/src/class/oc_process.py
new file mode 100644
index 000000000..80d81448d
--- /dev/null
+++ b/roles/lib_openshift/src/class/oc_process.py
@@ -0,0 +1,188 @@
+# pylint: skip-file
+# flake8: noqa
+
+
+# pylint: disable=too-many-instance-attributes
+class OCProcess(OpenShiftCLI):
+ ''' Class to wrap the oc command line tools '''
+
+ # pylint allows 5. we need 6
+ # pylint: disable=too-many-arguments
+ def __init__(self,
+ namespace,
+ tname=None,
+ params=None,
+ create=False,
+ kubeconfig='/etc/origin/master/admin.kubeconfig',
+ tdata=None,
+ verbose=False):
+ ''' Constructor for OpenshiftOC '''
+ super(OCProcess, self).__init__(namespace, kubeconfig)
+ self.namespace = namespace
+ self.name = tname
+ self.data = tdata
+ self.params = params
+ self.create = create
+ self.kubeconfig = kubeconfig
+ self.verbose = verbose
+ self._template = None
+
+ @property
+ def template(self):
+ '''template property'''
+ if self._template is None:
+ results = self._process(self.name, False, self.params, self.data)
+ if results['returncode'] != 0:
+ raise OpenShiftCLIError('Error processing template [%s].' % self.name)
+ self._template = results['results']['items']
+
+ return self._template
+
+ def get(self):
+ '''get the template'''
+ results = self._get('template', self.name)
+ if results['returncode'] != 0:
+ # Does the template exist??
+ if 'not found' in results['stderr']:
+ results['returncode'] = 0
+ results['exists'] = False
+ results['results'] = []
+
+ return results
+
+ def delete(self, obj):
+ '''delete a resource'''
+ return self._delete(obj['kind'], obj['metadata']['name'])
+
+ def create_obj(self, obj):
+ '''create a resource'''
+ return self._create_from_content(obj['metadata']['name'], obj)
+
+ def process(self, create=None):
+ '''process a template'''
+ do_create = False
+ if create != None:
+ do_create = create
+ else:
+ do_create = self.create
+
+ return self._process(self.name, do_create, self.params, self.data)
+
+ def exists(self):
+ '''return whether the template exists'''
+ # Always return true if we're being passed template data
+ if self.data:
+ return True
+ t_results = self._get('template', self.name)
+
+ if t_results['returncode'] != 0:
+ # Does the template exist??
+ if 'not found' in t_results['stderr']:
+ return False
+ else:
+ raise OpenShiftCLIError('Something went wrong. %s' % t_results)
+
+ return True
+
+ def needs_update(self):
+ '''attempt to process the template and return it for comparison with oc objects'''
+ obj_results = []
+ for obj in self.template:
+
+ # build a list of types to skip
+ skip = []
+
+ if obj['kind'] == 'ServiceAccount':
+ skip.extend(['secrets', 'imagePullSecrets'])
+ if obj['kind'] == 'BuildConfig':
+ skip.extend(['lastTriggeredImageID'])
+ if obj['kind'] == 'ImageStream':
+ skip.extend(['generation'])
+ if obj['kind'] == 'DeploymentConfig':
+ skip.extend(['lastTriggeredImage'])
+
+ # fetch the current object
+ curr_obj_results = self._get(obj['kind'], obj['metadata']['name'])
+ if curr_obj_results['returncode'] != 0:
+ # Does the template exist??
+ if 'not found' in curr_obj_results['stderr']:
+ obj_results.append((obj, True))
+ continue
+
+ # check the generated object against the existing object
+ if not Utils.check_def_equal(obj, curr_obj_results['results'][0], skip_keys=skip):
+ obj_results.append((obj, True))
+ continue
+
+ obj_results.append((obj, False))
+
+ return obj_results
+
+ # pylint: disable=too-many-return-statements
+ @staticmethod
+ def run_ansible(params, check_mode):
+ '''run the ansible idempotent code'''
+
+ ocprocess = OCProcess(params['namespace'],
+ params['template_name'],
+ params['params'],
+ params['create'],
+ kubeconfig=params['kubeconfig'],
+ tdata=params['content'],
+ verbose=params['debug'])
+
+ state = params['state']
+
+ api_rval = ocprocess.get()
+
+ if state == 'list':
+ if api_rval['returncode'] != 0:
+ return {"failed": True, "msg" : api_rval}
+
+ return {"changed" : False, "results": api_rval, "state": "list"}
+
+ elif state == 'present':
+ if check_mode and params['create']:
+ return {"changed": True, 'msg': "CHECK_MODE: Would have processed template."}
+
+ if not ocprocess.exists() or not params['reconcile']:
+ #FIXME: this code will never get run in a way that succeeds when
+ # module.params['reconcile'] is true. Because oc_process doesn't
+ # create the actual template, the check of ocprocess.exists()
+ # is meaningless. Either it's already here and this code
+ # won't be run, or this code will fail because there is no
+ # template available for oc process to use. Have we conflated
+ # the template's existence with the existence of the objects
+ # it describes?
+
+ # Create it here
+ api_rval = ocprocess.process()
+ if api_rval['returncode'] != 0:
+ return {"failed": True, "msg": api_rval}
+
+ if params['create']:
+ return {"changed": True, "results": api_rval, "state": "present"}
+
+ return {"changed": False, "results": api_rval, "state": "present"}
+
+ # verify results
+ update = False
+ rval = []
+ all_results = ocprocess.needs_update()
+ for obj, status in all_results:
+ if status:
+ ocprocess.delete(obj)
+ results = ocprocess.create_obj(obj)
+ results['kind'] = obj['kind']
+ rval.append(results)
+ update = True
+
+ if not update:
+ return {"changed": update, "results": api_rval, "state": "present"}
+
+ for cmd in rval:
+ if cmd['returncode'] != 0:
+ return {"failed": True, "changed": update, "results": rval, "state": "present"}
+
+ return {"changed": update, "results": rval, "state": "present"}
+
diff --git a/roles/lib_openshift/src/class/oc_route.py b/roles/lib_openshift/src/class/oc_route.py
index 42af2c01c..42388ad0b 100644
--- a/roles/lib_openshift/src/class/oc_route.py
+++ b/roles/lib_openshift/src/class/oc_route.py
@@ -64,9 +64,23 @@ class OCRoute(OpenShiftCLI):
skip = []
return not Utils.check_def_equal(self.config.data, self.route.yaml_dict, skip_keys=skip, debug=True)
+ @staticmethod
+ def get_cert_data(path, content):
+ '''get the data for a particular value'''
+ if not path and not content:
+ return None
+
+ rval = None
+ if path and os.path.exists(path) and os.access(path, os.R_OK):
+ rval = open(path).read()
+ elif content:
+ rval = content
+
+ return rval
+
# pylint: disable=too-many-return-statements,too-many-branches
@staticmethod
- def run_ansible(params, files, check_mode=False):
+ def run_ansible(params, check_mode=False):
''' run the idempotent asnible code
params comes from the ansible portion for this module
@@ -78,6 +92,30 @@ class OCRoute(OpenShiftCLI):
}
check_mode: does the module support check mode. (module.check_mode)
'''
+ files = {'destcacert': {'path': params['dest_cacert_path'],
+ 'content': params['dest_cacert_content'],
+ 'value': None, },
+ 'cacert': {'path': params['cacert_path'],
+ 'content': params['cacert_content'],
+ 'value': None, },
+ 'cert': {'path': params['cert_path'],
+ 'content': params['cert_content'],
+ 'value': None, },
+ 'key': {'path': params['key_path'],
+ 'content': params['key_content'],
+ 'value': None, }, }
+
+ if params['tls_termination'] and params['tls_termination'].lower() != 'passthrough': # E501
+
+ for key, option in files.items():
+ if key == 'destcacert' and params['tls_termination'] != 'reencrypt':
+ continue
+
+ option['value'] = OCRoute.get_cert_data(option['path'], option['content']) # E501
+
+ if not option['value']:
+ return {'failed': True,
+ 'msg': 'Verify that you pass a value for %s' % key}
rconfig = RouteConfig(params['name'],
params['namespace'],
@@ -90,7 +128,8 @@ class OCRoute(OpenShiftCLI):
params['tls_termination'],
params['service_name'],
params['wildcard_policy'],
- params['weight'])
+ params['weight'],
+ params['port'])
oc_route = OCRoute(rconfig, verbose=params['debug'])
diff --git a/roles/lib_openshift/src/class/oc_secret.py b/roles/lib_openshift/src/class/oc_secret.py
index 40b2aa4d1..e99999c37 100644
--- a/roles/lib_openshift/src/class/oc_secret.py
+++ b/roles/lib_openshift/src/class/oc_secret.py
@@ -48,7 +48,7 @@ class OCSecret(OpenShiftCLI):
def create(self, files=None, contents=None):
'''Create a secret '''
if not files:
- files = Utils.create_files_from_contents(contents)
+ files = Utils.create_tmp_files_from_contents(contents)
secrets = ["%s=%s" % (sfile['name'], sfile['path']) for sfile in files]
cmd = ['secrets', 'new', self.name]
@@ -81,7 +81,7 @@ class OCSecret(OpenShiftCLI):
This is accomplished by passing -ojson. This will most likely change in the future
'''
if not files:
- files = Utils.create_files_from_contents(contents)
+ files = Utils.create_tmp_files_from_contents(contents)
secrets = ["%s=%s" % (sfile['name'], sfile['path']) for sfile in files]
cmd = ['-ojson', 'secrets', 'new', self.name]
@@ -132,7 +132,7 @@ class OCSecret(OpenShiftCLI):
if params['files']:
files = params['files']
elif params['contents']:
- files = Utils.create_files_from_contents(params['contents'])
+ files = Utils.create_tmp_files_from_contents(params['contents'])
else:
return {'failed': True,
'msg': 'Either specify files or contents.'}
@@ -146,7 +146,7 @@ class OCSecret(OpenShiftCLI):
return {'changed': True,
'msg': 'Would have performed a create.'}
- api_rval = ocsecret.create(params['files'], params['contents'])
+ api_rval = ocsecret.create(files, params['contents'])
# Remove files
if files and params['delete_after']:
diff --git a/roles/lib_openshift/src/doc/process b/roles/lib_openshift/src/doc/process
new file mode 100644
index 000000000..86a854c07
--- /dev/null
+++ b/roles/lib_openshift/src/doc/process
@@ -0,0 +1,84 @@
+# flake8: noqa
+# pylint: skip-file
+
+DOCUMENTATION = '''
+---
+module: oc_process
+short_description: Module to process openshift templates
+description:
+ - Process openshift templates programmatically.
+options:
+ state:
+ description:
+ - State has a few different meanings when it comes to process.
+ - state: present - This state runs an `oc process <template>`. When used in
+ - conjunction with 'create: True' the process will be piped to | oc create -f
+ - state: absent - will remove a template
+ - state: list - will perform an `oc get template <template_name>`
+ default: present
+ choices: ["present", "absent", "list"]
+ aliases: []
+ kubeconfig:
+ description:
+ - The path for the kubeconfig file to use for authentication
+ required: false
+ default: /etc/origin/master/admin.kubeconfig
+ aliases: []
+ debug:
+ description:
+ - Turn on debug output.
+ required: false
+ default: False
+ aliases: []
+ template_name:
+ description:
+ - Name of the openshift template that is being processed.
+ required: false
+ default: None
+ aliases: []
+ namespace:
+ description:
+ - The namespace where the template lives.
+ required: false
+ default: default
+ aliases: []
+ content:
+ description:
+ - Template content that will be processed.
+ required: false
+ default: None
+ aliases: []
+ params:
+ description:
+ - A list of parameters that will be inserted into the template.
+ required: false
+ default: None
+ aliases: []
+ create:
+ description:
+ - Whether or not to create the template after being processed. e.g. oc process | oc create -f -
+ required: False
+ default: False
+ aliases: []
+ reconcile:
+ description:
+ - Whether or not to attempt to determine if there are updates or changes in the incoming template.
+ default: true
+ aliases: []
+author:
+- "Kenny Woodson <kwoodson@redhat.com>"
+extends_documentation_fragment: []
+'''
+
+EXAMPLES = '''
+- name: process the cloud volume provisioner template with variables
+ oc_process:
+ namespace: openshift-infra
+ template_name: online-volume-provisioner
+ create: True
+ params:
+ PLAT: rhel7
+ register: processout
+ run_once: true
+- debug: var=processout
+'''
diff --git a/roles/lib_openshift/src/doc/route b/roles/lib_openshift/src/doc/route
index 1797d4d33..a12999c9e 100644
--- a/roles/lib_openshift/src/doc/route
+++ b/roles/lib_openshift/src/doc/route
@@ -99,6 +99,12 @@ options:
required: false
default: None
aliases: []
+ port:
+ description:
+ - The Name of the service port or number of the container port the route will route traffic to
+ required: false
+ default: None
+ aliases: []
author:
- "Kenny Woodson <kwoodson@redhat.com>"
extends_documentation_fragment: []
diff --git a/roles/lib_openshift/src/lib/base.py b/roles/lib_openshift/src/lib/base.py
index 55f7d3146..a895b40b3 100644
--- a/roles/lib_openshift/src/lib/base.py
+++ b/roles/lib_openshift/src/lib/base.py
@@ -20,7 +20,7 @@ class OpenShiftCLI(object):
''' Constructor for OpenshiftCLI '''
self.namespace = namespace
self.verbose = verbose
- self.kubeconfig = kubeconfig
+ self.kubeconfig = Utils.create_tmpfile_copy(kubeconfig)
self.all_namespaces = all_namespaces
# Pylint allows only 5 arguments to be passed.
@@ -31,7 +31,8 @@ class OpenShiftCLI(object):
if not res['results']:
return res
- fname = '/tmp/%s' % rname
+ fname = Utils.create_tmpfile(rname + '-')
+
yed = Yedit(fname, res['results'][0], separator=sep)
changes = []
for key, value in content.items():
@@ -55,7 +56,7 @@ class OpenShiftCLI(object):
def _create_from_content(self, rname, content):
'''create a temporary file and then call oc create on it'''
- fname = '/tmp/%s' % rname
+ fname = Utils.create_tmpfile(rname + '-')
yed = Yedit(fname, content=content)
yed.write()
@@ -98,7 +99,7 @@ class OpenShiftCLI(object):
if results['returncode'] != 0 or not create:
return results
- fname = '/tmp/%s' % template_name
+ fname = Utils.create_tmpfile(template_name + '-')
yed = Yedit(fname, results['results'])
yed.write()
@@ -279,32 +280,61 @@ class OpenShiftCLI(object):
class Utils(object):
''' utilities for openshiftcli modules '''
+
+ @staticmethod
+ def _write(filename, contents):
+ ''' Actually write the file contents to disk. This helps with mocking. '''
+
+ with open(filename, 'w') as sfd:
+ sfd.write(contents)
+
@staticmethod
- def create_file(rname, data, ftype='yaml'):
+ def create_tmp_file_from_contents(rname, data, ftype='yaml'):
''' create a file in tmp with name and contents'''
- path = os.path.join('/tmp', rname)
- with open(path, 'w') as fds:
- if ftype == 'yaml':
- fds.write(yaml.dump(data, Dumper=yaml.RoundTripDumper))
- elif ftype == 'json':
- fds.write(json.dumps(data))
- else:
- fds.write(data)
+ tmp = Utils.create_tmpfile(prefix=rname)
+
+ if ftype == 'yaml':
+ Utils._write(tmp, yaml.dump(data, Dumper=yaml.RoundTripDumper))
+ elif ftype == 'json':
+ Utils._write(tmp, json.dumps(data))
+ else:
+ Utils._write(tmp, data)
# Register cleanup when module is done
- atexit.register(Utils.cleanup, [path])
- return path
+ atexit.register(Utils.cleanup, [tmp])
+ return tmp
+
+ @staticmethod
+ def create_tmpfile_copy(inc_file):
+ '''create a temporary copy of a file'''
+ tmpfile = Utils.create_tmpfile('lib_openshift-')
+ Utils._write(tmpfile, open(inc_file).read())
+
+ # Cleanup the tmpfile
+ atexit.register(Utils.cleanup, [tmpfile])
+
+ return tmpfile
+
+ @staticmethod
+ def create_tmpfile(prefix='tmp'):
+ ''' Generates and returns a temporary file name '''
+
+ with tempfile.NamedTemporaryFile(prefix=prefix, delete=False) as tmp:
+ return tmp.name
@staticmethod
- def create_files_from_contents(content, content_type=None):
+ def create_tmp_files_from_contents(content, content_type=None):
'''Turn an array of dict: filename, content into a files array'''
if not isinstance(content, list):
content = [content]
files = []
for item in content:
- path = Utils.create_file(item['path'], item['data'], ftype=content_type)
- files.append({'name': os.path.basename(path), 'path': path})
+ path = Utils.create_tmp_file_from_contents(item['path'] + '-',
+ item['data'],
+ ftype=content_type)
+ files.append({'name': os.path.basename(item['path']),
+ 'path': path})
return files
@staticmethod
diff --git a/roles/lib_openshift/src/lib/import.py b/roles/lib_openshift/src/lib/import.py
index c2b30e019..6344c1a54 100644
--- a/roles/lib_openshift/src/lib/import.py
+++ b/roles/lib_openshift/src/lib/import.py
@@ -12,6 +12,7 @@ import os
import re
import shutil
import subprocess
+import tempfile
# pylint: disable=import-error
import ruamel.yaml as yaml
from ansible.module_utils.basic import AnsibleModule
diff --git a/roles/lib_openshift/src/lib/route.py b/roles/lib_openshift/src/lib/route.py
index 3130e7358..3b54a24fb 100644
--- a/roles/lib_openshift/src/lib/route.py
+++ b/roles/lib_openshift/src/lib/route.py
@@ -19,7 +19,8 @@ class RouteConfig(object):
tls_termination=None,
service_name=None,
wildcard_policy=None,
- weight=None):
+ weight=None,
+ port=None):
''' constructor for handling route options '''
self.kubeconfig = kubeconfig
self.name = sname
@@ -31,6 +32,7 @@ class RouteConfig(object):
self.cert = cert
self.key = key
self.service_name = service_name
+ self.port = port
self.data = {}
self.wildcard_policy = wildcard_policy
if wildcard_policy is None:
@@ -55,12 +57,15 @@ class RouteConfig(object):
if self.tls_termination:
self.data['spec']['tls'] = {}
+ self.data['spec']['tls']['termination'] = self.tls_termination
+
+ if self.tls_termination != 'passthrough':
+ self.data['spec']['tls']['key'] = self.key
+ self.data['spec']['tls']['caCertificate'] = self.cacert
+ self.data['spec']['tls']['certificate'] = self.cert
+
if self.tls_termination == 'reencrypt':
self.data['spec']['tls']['destinationCACertificate'] = self.destcacert
- self.data['spec']['tls']['key'] = self.key
- self.data['spec']['tls']['caCertificate'] = self.cacert
- self.data['spec']['tls']['certificate'] = self.cert
- self.data['spec']['tls']['termination'] = self.tls_termination
self.data['spec']['to'] = {'kind': 'Service',
'name': self.service_name,
@@ -68,11 +73,16 @@ class RouteConfig(object):
self.data['spec']['wildcardPolicy'] = self.wildcard_policy
+ if self.port:
+ self.data['spec']['port'] = {}
+ self.data['spec']['port']['targetPort'] = self.port
+
# pylint: disable=too-many-instance-attributes,too-many-public-methods
class Route(Yedit):
''' Class to wrap the oc command line tools '''
wildcard_policy = "spec.wildcardPolicy"
host_path = "spec.host"
+ port_path = "spec.port.targetPort"
service_path = "spec.to.name"
weight_path = "spec.to.weight"
cert_path = "spec.tls.certificate"
@@ -118,6 +128,10 @@ class Route(Yedit):
''' return host '''
return self.get(Route.host_path)
+ def get_port(self):
+ ''' return port '''
+ return self.get(Route.port_path)
+
def get_wildcard_policy(self):
''' return wildcardPolicy '''
return self.get(Route.wildcard_policy)
diff --git a/roles/lib_openshift/src/sources.yml b/roles/lib_openshift/src/sources.yml
index aa02ce120..e9056655d 100644
--- a/roles/lib_openshift/src/sources.yml
+++ b/roles/lib_openshift/src/sources.yml
@@ -39,6 +39,16 @@ oc_obj.py:
- class/oc_obj.py
- ansible/oc_obj.py
+oc_process.py:
+- doc/generated
+- doc/license
+- lib/import.py
+- doc/process
+- ../../lib_utils/src/class/yedit.py
+- lib/base.py
+- class/oc_process.py
+- ansible/oc_process.py
+
oc_route.py:
- doc/generated
- doc/license
diff --git a/roles/lib_openshift/src/test/generate-and-run-tests.sh b/roles/lib_openshift/src/test/generate-and-run-tests.sh
new file mode 100755
index 000000000..cd7571372
--- /dev/null
+++ b/roles/lib_openshift/src/test/generate-and-run-tests.sh
@@ -0,0 +1,54 @@
+#!/bin/bash -e
+
+
+if [ $# -ne 1 ] ; then
+ echo "Usage: $(basename $0) <master name>"
+ exit 1
+fi
+
+MASTER=$1
+
+
+
+# Put us in the same dir as the script.
+cd $(dirname $0)
+
+
+echo
+echo "Running lib_utils generate-and-run-tests.sh"
+echo "-------------------------------------------"
+../../../lib_utils/src/test/generate-and-run-tests.sh
+
+
+echo
+echo "Running lib_openshift generate"
+echo "------------------------------"
+../generate.py
+
+
+echo
+echo "Running lib_openshift Unit Tests"
+echo "----------------------------"
+cd unit
+
+for test in *.py; do
+ echo
+ echo "--------------------------------------------------------------------------------"
+ echo
+ echo "Running $test..."
+ ./$test
+done
+
+
+echo
+echo "Running lib_openshift Integration Tests"
+echo "-----------------------------------"
+cd ../integration
+
+for test in *.yml; do
+ echo
+ echo "--------------------------------------------------------------------------------"
+ echo
+ echo "Running $test..."
+ ./$test -vvv -e cli_master_test="$MASTER"
+done
diff --git a/roles/lib_openshift/src/test/integration/oadm_manage_node.yml b/roles/lib_openshift/src/test/integration/oadm_manage_node.yml
index 69a701b17..3ee13a409 100755
--- a/roles/lib_openshift/src/test/integration/oadm_manage_node.yml
+++ b/roles/lib_openshift/src/test/integration/oadm_manage_node.yml
@@ -1,40 +1,51 @@
#!/usr/bin/ansible-playbook --module-path=../../../library/
-# ./oadm_manage_node.yml -M ../../../library -e "cli_master_test=$OPENSHIFT_MASTER cli_node_test=$OPENSHIFT_NODE
+#
+# ./oadm_manage_node.yml -e "cli_master_test=$OPENSHIFT_MASTER
---
- hosts: "{{ cli_master_test }}"
gather_facts: no
user: root
tasks:
+ - name: get list of nodes
+ oc_obj:
+ state: list
+ kind: node
+ register: obj_out
+
+ - name: Set the node to work with
+ set_fact:
+ node_to_test: "{{ obj_out['results']['results'][0]['items'][0]['metadata']['name'] }}"
+
- name: list pods from a node
oadm_manage_node:
list_pods: True
node:
- - "{{ cli_node_test }}"
+ - "{{ node_to_test }}"
register: podout
- debug: var=podout
- assert:
- that: "'{{ cli_node_test }}' in podout.results.nodes"
+ that: "'{{ node_to_test }}' in podout.results.nodes"
msg: Pod data was not returned
- name: set node to unschedulable
oadm_manage_node:
schedulable: False
node:
- - "{{ cli_node_test }}"
+ - "{{ node_to_test }}"
register: nodeout
- debug: var=nodeout
- name: assert that schedulable=False
assert:
that: nodeout.results.nodes[0]['schedulable'] == False
- msg: "{{ cli_node_test }} schedulable set to True"
+ msg: "{{ node_to_test }} schedulable set to True"
- name: get node scheduable
oc_obj:
kind: node
state: list
- name: "{{ cli_node_test }}"
+ name: "{{ node_to_test }}"
namespace: None
register: nodeout
@@ -48,11 +59,11 @@
oadm_manage_node:
schedulable: True
node:
- - "{{ cli_node_test }}"
+ - "{{ node_to_test }}"
register: nodeout
- debug: var=nodeout
- name: assert that schedulable=False
assert:
that: nodeout.results.nodes[0]['schedulable']
- msg: "{{ cli_node_test }} schedulable set to False"
+ msg: "{{ node_to_test }} schedulable set to False"
diff --git a/roles/lib_openshift/src/test/integration/oc_label.yml b/roles/lib_openshift/src/test/integration/oc_label.yml
index ce9bc25bb..b4e721407 100755
--- a/roles/lib_openshift/src/test/integration/oc_label.yml
+++ b/roles/lib_openshift/src/test/integration/oc_label.yml
@@ -1,5 +1,7 @@
#!/usr/bin/ansible-playbook --module-path=../../../library/
-# ./oc_label.yml -e "cli_master_test=$OPENSHIFT_MASTER -e "cli_node_test=ip-172-0-31-1.ec2"
+#
+# ./oc_label.yml -e "cli_master_test=$OPENSHIFT_MASTER
+#
---
- hosts: "{{ cli_master_test }}"
gather_facts: no
@@ -15,16 +17,25 @@
msg: "{{ item }} not defined"
when: "{{ item }} is not defined"
with_items:
- - cli_node_test # openshift node to be used to add/remove labels to
- cli_master_test # ansible inventory instance to run playbook against
tasks:
+ - name: get list of nodes
+ oc_obj:
+ state: list
+ kind: node
+ register: obj_out
+
+ - name: Set the node to work with
+ set_fact:
+ node_to_test: "{{ obj_out['results']['results'][0]['items'][0]['metadata']['name'] }}"
+
- name: delete test labels (start from known starting position)
oc_label:
state: absent
namespace: "{{ def_namespace }}"
kind: "{{ def_kind }}"
- name: "{{ cli_node_test }}"
+ name: "{{ node_to_test }}"
labels:
- key: testlabel2
- key: testlabel3
@@ -34,7 +45,7 @@
state: list
namespace: "{{ def_namespace }}"
kind: "{{ def_kind }}"
- name: "{{ cli_node_test }}"
+ name: "{{ node_to_test }}"
register: original_labels
- name: assert that testlabel2 and testlabel3 test labels don't exist
assert:
@@ -47,7 +58,7 @@
state: add
namespace: "{{ def_namespace }}"
kind: "{{ def_kind }}"
- name: "{{ cli_node_test }}"
+ name: "{{ node_to_test }}"
labels:
- key: testlabel2
value: "yes"
@@ -62,7 +73,7 @@
state: list
namespace: "{{ def_namespace }}"
kind: "{{ def_kind }}"
- name: "{{ cli_node_test }}"
+ name: "{{ node_to_test }}"
register: label_out
- name: assert that testlabel2 label actually added
assert:
@@ -75,7 +86,7 @@
state: add
namespace: "{{ def_namespace }}"
kind: "{{ def_kind }}"
- name: "{{ cli_node_test }}"
+ name: "{{ node_to_test }}"
labels:
- key: testlabel2
value: "yes"
@@ -90,7 +101,7 @@
state: add
namespace: "{{ def_namespace }}"
kind: "{{ def_kind }}"
- name: "{{ cli_node_test }}"
+ name: "{{ node_to_test }}"
labels:
- key: testlabel2
value: "different"
@@ -105,7 +116,7 @@
state: list
namespace: "{{ def_namespace }}"
kind: "{{ def_kind }}"
- name: "{{ cli_node_test }}"
+ name: "{{ node_to_test }}"
register: label_out
- name: assert that testlabel2 label actually modified
assert:
@@ -118,7 +129,7 @@
state: absent
namespace: "{{ def_namespace }}"
kind: "{{ def_kind }}"
- name: "{{ cli_node_test }}"
+ name: "{{ node_to_test }}"
labels:
- key: testlabelnone
register: label_out
@@ -132,7 +143,7 @@
state: absent
namespace: "{{ def_namespace }}"
kind: "{{ def_kind }}"
- name: "{{ cli_node_test }}"
+ name: "{{ node_to_test }}"
labels:
- key: testlabel2
register: label_out
@@ -146,7 +157,7 @@
state: absent
namespace: "{{ def_namespace }}"
kind: "{{ def_kind }}"
- name: "{{ cli_node_test }}"
+ name: "{{ node_to_test }}"
labels:
- key: testlabel2
register: label_out
@@ -160,7 +171,7 @@
state: list
namespace: "{{ def_namespace }}"
kind: "{{ def_kind }}"
- name: "{{ cli_node_test }}"
+ name: "{{ node_to_test }}"
register: label_out
- name: assert label actually deleted
assert:
@@ -172,7 +183,7 @@
state: add
namespace: "{{ def_namespace }}"
kind: "{{ def_kind }}"
- name: "{{ cli_node_test }}"
+ name: "{{ node_to_test }}"
labels:
- key: testlabel2
value: "yes"
@@ -189,7 +200,7 @@
state: list
namespace: "{{ def_namespace }}"
kind: "{{ def_kind }}"
- name: "{{ cli_node_test }}"
+ name: "{{ node_to_test }}"
register: label_out
- name: assert that both labels actually exist
assert:
@@ -204,7 +215,7 @@
state: absent
namespace: "{{ def_namespace }}"
kind: "{{ def_kind }}"
- name: "{{ cli_node_test }}"
+ name: "{{ node_to_test }}"
labels:
- key: testlabel2
- key: testlabel3
@@ -219,7 +230,7 @@
state: absent
namespace: "{{ def_namespace }}"
kind: "{{ def_kind }}"
- name: "{{ cli_node_test }}"
+ name: "{{ node_to_test }}"
labels:
- key: testlabel2
- key: testlabel3
@@ -237,7 +248,7 @@
state: present
namespace: "{{ def_namespace }}"
kind: "{{ def_kind }}"
- name: "{{ cli_node_test }}"
+ name: "{{ node_to_test }}"
labels: "{{ original_labels_as_key_value_list }}"
register: label_out
- name: assert that no changes are made when current list matches existing list
@@ -250,7 +261,7 @@
state: present
namespace: "{{ def_namespace }}"
kind: "{{ def_kind }}"
- name: "{{ cli_node_test }}"
+ name: "{{ node_to_test }}"
labels: "{{ original_labels_as_key_value_list + [{'key': 'testlabel2', 'value': 'yes'}] }}"
register: label_out
- name: assert that changes were made
@@ -263,7 +274,7 @@
state: list
namespace: "{{ def_namespace }}"
kind: "{{ def_kind }}"
- name: "{{ cli_node_test }}"
+ name: "{{ node_to_test }}"
register: label_out
- name: asssert that new label was actually added
assert:
@@ -276,7 +287,7 @@
state: present
namespace: "{{ def_namespace }}"
kind: "{{ def_kind }}"
- name: "{{ cli_node_test }}"
+ name: "{{ node_to_test }}"
labels: "{{ original_labels_as_key_value_list + [{'key': 'testlabel2', 'value': 'different'}]}}"
register: label_out
- name: assert that changes were made when existing key's value is changed
@@ -289,7 +300,7 @@
state: list
namespace: "{{ def_namespace }}"
kind: "{{ def_kind }}"
- name: "{{ cli_node_test }}"
+ name: "{{ node_to_test }}"
register: label_out
- name: asssert that changed label was actually changed
assert:
@@ -302,7 +313,7 @@
state: present
namespace: "{{ def_namespace }}"
kind: "{{ def_kind }}"
- name: "{{ cli_node_test }}"
+ name: "{{ node_to_test }}"
labels: "{{ original_labels_as_key_value_list }}"
register: label_out
- name: assert that changes were made
@@ -315,7 +326,7 @@
state: list
namespace: "{{ def_namespace }}"
kind: "{{ def_kind }}"
- name: "{{ cli_node_test }}"
+ name: "{{ node_to_test }}"
register: label_out
- name: asssert that present-removed actually removed
assert:
diff --git a/roles/lib_openshift/src/test/integration/oc_process.yml b/roles/lib_openshift/src/test/integration/oc_process.yml
new file mode 100755
index 000000000..7ea4c6b99
--- /dev/null
+++ b/roles/lib_openshift/src/test/integration/oc_process.yml
@@ -0,0 +1,83 @@
+#!/usr/bin/ansible-playbook --module-path=../../../library/:../../../../lib_utils/library
+
+---
+- hosts: "{{ cli_master_test }}"
+ gather_facts: no
+ user: root
+ vars:
+ template_name: mysql-ephemeral
+ ns_name: test
+
+ post_tasks:
+ - name: get the mysql-ephemeral template
+ oc_obj:
+ name: mysql-ephemeral
+ state: list
+ namespace: openshift
+ kind: template
+ register: mysqltempl
+
+ - name: fix namespace
+ yedit:
+ src: /tmp/mysql-template
+ key: metadata.namespace
+ value: test
+ backup: false
+ content: "{{ mysqltempl.results.results[0] | to_yaml }}"
+
+ - name: create the test namespace
+ oc_obj:
+ name: test
+ state: present
+ namespace: test
+ kind: namespace
+ content:
+ path: /tmp/ns_test
+ data:
+ apiVersion: v1
+ kind: Namespace
+ metadata:
+ name: test
+ spec:
+ finalizers:
+ - openshift.io/origin
+ - kubernetes
+ register: mysqltempl
+
+ - name: create the mysql-ephemeral template
+ oc_obj:
+ name: mysql-ephemeral
+ state: present
+ namespace: test
+ kind: template
+ files:
+ - /tmp/mysql-template
+ delete_after: True
+ register: mysqltempl
+
+ - name: process mysql-ephemeral
+ oc_process:
+ template_name: mysql-ephemeral
+ namespace: test
+ params:
+ NAMESPACE: test
+ DATABASE_SERVICE_NAME: testdb
+ create: False
+ reconcile: false
+ register: procout
+
+ - assert:
+ that:
+ - not procout.changed
+ - procout.results.results['items'][0]['metadata']['name'] == 'testdb'
+ - procout.results.results['items'][0]['kind'] == 'Service'
+ - procout.results.results['items'][1]['metadata']['name'] == 'testdb'
+ - procout.results.results['items'][1]['kind'] == 'DeploymentConfig'
+ msg: process failed on template
+
+ - name: remove namespace test
+ oc_obj:
+ kind: namespace
+ name: test
+ namespace: test
+ state: absent
diff --git a/roles/lib_openshift/src/test/integration/oc_route.yml b/roles/lib_openshift/src/test/integration/oc_route.yml
index 620d5d5e7..b9d635eaa 100755
--- a/roles/lib_openshift/src/test/integration/oc_route.yml
+++ b/roles/lib_openshift/src/test/integration/oc_route.yml
@@ -75,3 +75,43 @@
- assert:
that: "routeout.changed == False"
msg: Route create not idempotent
+
+ - name: delete route
+ oc_route:
+ name: test
+ namespace: default
+ state: absent
+ register: routeout
+
+ - name: create route
+ oc_route:
+ name: test
+ namespace: default
+ tls_termination: passthrough
+ service_name: test
+ host: test.example
+ port: 8443
+ register: routeout
+
+ - assert:
+ that:
+ - "routeout.changed == True"
+ - "routeout.results['results'][0]['spec']['port']['targetPort'] == 8443"
+ msg: Route create not idempotent
+
+ - name: create route
+ oc_route:
+ name: test
+ namespace: default
+ tls_termination: passthrough
+ service_name: test
+ host: test.example
+ port: 8444
+ register: routeout
+ - debug: var=routeout
+
+ - assert:
+ that:
+ - "routeout.changed == True"
+ - "routeout.results.results[0]['spec']['port']['targetPort'] == 8444"
+ msg: Route update not idempotent
diff --git a/roles/lib_openshift/src/test/integration/oc_service.yml b/roles/lib_openshift/src/test/integration/oc_service.yml
index 616694382..3eb6facef 100755
--- a/roles/lib_openshift/src/test/integration/oc_service.yml
+++ b/roles/lib_openshift/src/test/integration/oc_service.yml
@@ -123,6 +123,6 @@
- assert:
that:
- svc_out.changed == False
- - svc_out.results.returncode == 1
+ - svc_out.results.returncode == 0
- "'not found' in svc_out.results.stderr"
msg: service get failed
diff --git a/roles/lib_openshift/src/test/unit/oadm_manage_node.py b/roles/lib_openshift/src/test/unit/oadm_manage_node.py
index 8fd6f9c55..b0786dfac 100755
--- a/roles/lib_openshift/src/test/unit/oadm_manage_node.py
+++ b/roles/lib_openshift/src/test/unit/oadm_manage_node.py
@@ -35,8 +35,9 @@ class ManageNodeTest(unittest.TestCase):
''' setup method will create a file and set to known configuration '''
pass
+ @mock.patch('oadm_manage_node.Utils.create_tmpfile_copy')
@mock.patch('oadm_manage_node.ManageNode.openshift_cmd')
- def test_list_pods(self, mock_openshift_cmd):
+ def test_list_pods(self, mock_openshift_cmd, mock_tmpfile_copy):
''' Testing a get '''
params = {'node': ['ip-172-31-49-140.ec2.internal'],
'schedulable': None,
@@ -106,6 +107,10 @@ class ManageNodeTest(unittest.TestCase):
"returncode": 0}
]
+ mock_tmpfile_copy.side_effect = [
+ '/tmp/mocked_kubeconfig',
+ ]
+
results = ManageNode.run_ansible(params, False)
# returned a single node
@@ -113,8 +118,9 @@ class ManageNodeTest(unittest.TestCase):
# returned 2 pods
self.assertTrue(len(results['results']['nodes']['ip-172-31-49-140.ec2.internal']) == 2)
+ @mock.patch('oadm_manage_node.Utils.create_tmpfile_copy')
@mock.patch('oadm_manage_node.ManageNode.openshift_cmd')
- def test_schedulable_false(self, mock_openshift_cmd):
+ def test_schedulable_false(self, mock_openshift_cmd, mock_tmpfile_copy):
''' Testing a get '''
params = {'node': ['ip-172-31-49-140.ec2.internal'],
'schedulable': False,
@@ -162,6 +168,11 @@ class ManageNodeTest(unittest.TestCase):
"results": "NAME STATUS AGE\n" +
"ip-172-31-49-140.ec2.internal Ready,SchedulingDisabled 5h\n",
"returncode": 0}]
+
+ mock_tmpfile_copy.side_effect = [
+ '/tmp/mocked_kubeconfig',
+ ]
+
results = ManageNode.run_ansible(params, False)
self.assertTrue(results['changed'])
diff --git a/roles/lib_openshift/src/test/unit/oc_label.py b/roles/lib_openshift/src/test/unit/oc_label.py
index 3f7162070..3176987b0 100755
--- a/roles/lib_openshift/src/test/unit/oc_label.py
+++ b/roles/lib_openshift/src/test/unit/oc_label.py
@@ -35,8 +35,9 @@ class OCLabelTest(unittest.TestCase):
''' setup method will create a file and set to known configuration '''
pass
+ @mock.patch('oc_label.Utils.create_tmpfile_copy')
@mock.patch('oc_label.OCLabel._run')
- def test_state_list(self, mock_cmd):
+ def test_state_list(self, mock_cmd, mock_tmpfile_copy):
''' Testing a label list '''
params = {'name': 'default',
'namespace': 'default',
@@ -82,13 +83,18 @@ class OCLabelTest(unittest.TestCase):
(0, ns, ''),
]
+ mock_tmpfile_copy.side_effect = [
+ '/tmp/mocked_kubeconfig',
+ ]
+
results = OCLabel.run_ansible(params, False)
self.assertFalse(results['changed'])
self.assertTrue(results['results']['labels'] == [{'storage_pv_quota': 'False'}])
+ @mock.patch('oc_label.Utils.create_tmpfile_copy')
@mock.patch('oc_label.OCLabel._run')
- def test_state_present(self, mock_cmd):
+ def test_state_present(self, mock_cmd, mock_tmpfile_copy):
''' Testing a label list '''
params = {'name': 'default',
'namespace': 'default',
@@ -171,6 +177,10 @@ class OCLabelTest(unittest.TestCase):
(0, ns1, ''),
]
+ mock_tmpfile_copy.side_effect = [
+ '/tmp/mocked_kubeconfig',
+ ]
+
results = OCLabel.run_ansible(params, False)
self.assertTrue(results['changed'])
diff --git a/roles/lib_openshift/src/test/unit/oc_process.py b/roles/lib_openshift/src/test/unit/oc_process.py
new file mode 100755
index 000000000..450ff7071
--- /dev/null
+++ b/roles/lib_openshift/src/test/unit/oc_process.py
@@ -0,0 +1,483 @@
+#!/usr/bin/env python2
+'''
+ Unit tests for oc process
+'''
+# To run
+# python -m unittest version
+#
+# .
+# Ran 1 test in 0.597s
+#
+# OK
+
+import os
+import sys
+import unittest
+import mock
+
+# Removing invalid variable names for tests so that I can
+# keep them brief
+# pylint: disable=invalid-name,no-name-in-module
+# Disable import-error b/c our libraries aren't loaded in jenkins
+# pylint: disable=import-error
+# place class in our python path
+module_path = os.path.join('/'.join(os.path.realpath(__file__).split('/')[:-4]), 'library') # noqa: E501
+sys.path.insert(0, module_path)
+from oc_process import OCProcess # noqa: E402
+
+
+# pylint: disable=too-many-public-methods
+class OCProcessTest(unittest.TestCase):
+ '''
+ Test class for OCProcess
+ '''
+ mysql = '''{
+ "kind": "Template",
+ "apiVersion": "v1",
+ "metadata": {
+ "name": "mysql-ephemeral",
+ "namespace": "openshift",
+ "selfLink": "/oapi/v1/namespaces/openshift/templates/mysql-ephemeral",
+ "uid": "fb8b5f04-e3d3-11e6-a982-0e84250fc302",
+ "resourceVersion": "480",
+ "creationTimestamp": "2017-01-26T14:30:27Z",
+ "annotations": {
+ "iconClass": "icon-mysql-database",
+ "openshift.io/display-name": "MySQL (Ephemeral)",
+ "tags": "database,mysql"
+ }
+ },
+ "objects": [
+ {
+ "apiVersion": "v1",
+ "kind": "Service",
+ "metadata": {
+ "creationTimestamp": null,
+ "name": "${DATABASE_SERVICE_NAME}"
+ },
+ "spec": {
+ "ports": [
+ {
+ "name": "mysql",
+ "nodePort": 0,
+ "port": 3306,
+ "protocol": "TCP",
+ "targetPort": 3306
+ }
+ ],
+ "selector": {
+ "name": "${DATABASE_SERVICE_NAME}"
+ },
+ "sessionAffinity": "None",
+ "type": "ClusterIP"
+ },
+ "status": {
+ "loadBalancer": {}
+ }
+ },
+ {
+ "apiVersion": "v1",
+ "kind": "DeploymentConfig",
+ "metadata": {
+ "creationTimestamp": null,
+ "name": "${DATABASE_SERVICE_NAME}"
+ },
+ "spec": {
+ "replicas": 1,
+ "selector": {
+ "name": "${DATABASE_SERVICE_NAME}"
+ },
+ "strategy": {
+ "type": "Recreate"
+ },
+ "template": {
+ "metadata": {
+ "creationTimestamp": null,
+ "labels": {
+ "name": "${DATABASE_SERVICE_NAME}"
+ }
+ },
+ "spec": {
+ "containers": [
+ {
+ "capabilities": {},
+ "env": [
+ {
+ "name": "MYSQL_USER",
+ "value": "${MYSQL_USER}"
+ },
+ {
+ "name": "MYSQL_PASSWORD",
+ "value": "${MYSQL_PASSWORD}"
+ },
+ {
+ "name": "MYSQL_DATABASE",
+ "value": "${MYSQL_DATABASE}"
+ }
+ ],
+ "image": " ",
+ "imagePullPolicy": "IfNotPresent",
+ "livenessProbe": {
+ "initialDelaySeconds": 30,
+ "tcpSocket": {
+ "port": 3306
+ },
+ "timeoutSeconds": 1
+ },
+ "name": "mysql",
+ "ports": [
+ {
+ "containerPort": 3306,
+ "protocol": "TCP"
+ }
+ ],
+ "readinessProbe": {
+ "exec": {
+ "command": [
+ "/bin/sh",
+ "-i",
+ "-c",
+ "MYSQL_PWD=$MYSQL_PASSWORD mysql -h 127.0.0.1 -u $MYSQL_USER -D $MYSQL_DATABASE -e 'SELECT 1'"
+ ]
+ },
+ "initialDelaySeconds": 5,
+ "timeoutSeconds": 1
+ },
+ "resources": {
+ "limits": {
+ "memory": "${MEMORY_LIMIT}"
+ }
+ },
+ "securityContext": {
+ "capabilities": {},
+ "privileged": false
+ },
+ "terminationMessagePath": "/dev/termination-log",
+ "volumeMounts": [
+ {
+ "mountPath": "/var/lib/mysql/data",
+ "name": "${DATABASE_SERVICE_NAME}-data"
+ }
+ ]
+ }
+ ],
+ "dnsPolicy": "ClusterFirst",
+ "restartPolicy": "Always",
+ "volumes": [
+ {
+ "emptyDir": {
+ "medium": ""
+ },
+ "name": "${DATABASE_SERVICE_NAME}-data"
+ }
+ ]
+ }
+ },
+ "triggers": [
+ {
+ "imageChangeParams": {
+ "automatic": true,
+ "containerNames": [
+ "mysql"
+ ],
+ "from": {
+ "kind": "ImageStreamTag",
+ "name": "mysql:${MYSQL_VERSION}",
+ "namespace": "${NAMESPACE}"
+ },
+ "lastTriggeredImage": ""
+ },
+ "type": "ImageChange"
+ },
+ {
+ "type": "ConfigChange"
+ }
+ ]
+ },
+ "status": {}
+ }
+ ],
+ "parameters": [
+ {
+ "name": "MEMORY_LIMIT",
+ "displayName": "Memory Limit",
+ "description": "Maximum amount of memory the container can use.",
+ "value": "512Mi"
+ },
+ {
+ "name": "NAMESPACE",
+ "displayName": "Namespace",
+ "description": "The OpenShift Namespace where the ImageStream resides.",
+ "value": "openshift"
+ },
+ {
+ "name": "DATABASE_SERVICE_NAME",
+ "displayName": "Database Service Name",
+ "description": "The name of the OpenShift Service exposed for the database.",
+ "value": "mysql",
+ "required": true
+ },
+ {
+ "name": "MYSQL_USER",
+ "displayName": "MySQL Connection Username",
+ "description": "Username for MySQL user that will be used for accessing the database.",
+ "generate": "expression",
+ "from": "user[A-Z0-9]{3}",
+ "required": true
+ },
+ {
+ "name": "MYSQL_PASSWORD",
+ "displayName": "MySQL Connection Password",
+ "description": "Password for the MySQL connection user.",
+ "generate": "expression",
+ "from": "[a-zA-Z0-9]{16}",
+ "required": true
+ },
+ {
+ "name": "MYSQL_DATABASE",
+ "displayName": "MySQL Database Name",
+ "description": "Name of the MySQL database accessed.",
+ "value": "sampledb",
+ "required": true
+ },
+ {
+ "name": "MYSQL_VERSION",
+ "displayName": "Version of MySQL Image",
+ "description": "Version of MySQL image to be used (5.5, 5.6 or latest).",
+ "value": "5.6",
+ "required": true
+ }
+ ],
+ "labels": {
+ "template": "mysql-ephemeral-template"
+ }
+}'''
+
+ def setUp(self):
+ ''' setup method will set to known configuration '''
+ pass
+
+ @mock.patch('oc_process.Utils.create_tmpfile_copy')
+ @mock.patch('oc_process.OCProcess._run')
+ def test_state_list(self, mock_cmd, mock_tmpfile_copy):
+ ''' Testing a get '''
+ params = {'template_name': 'mysql-ephermeral',
+ 'namespace': 'test',
+ 'content': None,
+ 'state': 'list',
+ 'reconcile': False,
+ 'create': False,
+ 'params': {'NAMESPACE': 'test', 'DATABASE_SERVICE_NAME': 'testdb'},
+ 'kubeconfig': '/etc/origin/master/admin.kubeconfig',
+ 'debug': False}
+
+ mock_cmd.side_effect = [
+ (0, OCProcessTest.mysql, '')
+ ]
+
+ mock_tmpfile_copy.side_effect = [
+ '/tmp/mock_kubeconfig',
+ ]
+
+ results = OCProcess.run_ansible(params, False)
+
+ self.assertFalse(results['changed'])
+ self.assertEqual(results['results']['results'][0]['metadata']['name'], 'mysql-ephemeral')
+
+ @mock.patch('oc_process.Utils.create_tmpfile_copy')
+ @mock.patch('oc_process.OCProcess._run')
+ def test_process_no_create(self, mock_cmd, mock_tmpfile_copy):
+ ''' Testing a process with no create '''
+ params = {'template_name': 'mysql-ephermeral',
+ 'namespace': 'test',
+ 'content': None,
+ 'state': 'present',
+ 'reconcile': False,
+ 'create': False,
+ 'params': {'NAMESPACE': 'test', 'DATABASE_SERVICE_NAME': 'testdb'},
+ 'kubeconfig': '/etc/origin/master/admin.kubeconfig',
+ 'debug': False}
+
+ mysqlproc = '''{
+ "kind": "List",
+ "apiVersion": "v1",
+ "metadata": {},
+ "items": [
+ {
+ "apiVersion": "v1",
+ "kind": "Service",
+ "metadata": {
+ "creationTimestamp": null,
+ "labels": {
+ "template": "mysql-ephemeral-template"
+ },
+ "name": "testdb"
+ },
+ "spec": {
+ "ports": [
+ {
+ "name": "mysql",
+ "nodePort": 0,
+ "port": 3306,
+ "protocol": "TCP",
+ "targetPort": 3306
+ }
+ ],
+ "selector": {
+ "name": "testdb"
+ },
+ "sessionAffinity": "None",
+ "type": "ClusterIP"
+ },
+ "status": {
+ "loadBalancer": {}
+ }
+ },
+ {
+ "apiVersion": "v1",
+ "kind": "DeploymentConfig",
+ "metadata": {
+ "creationTimestamp": null,
+ "labels": {
+ "template": "mysql-ephemeral-template"
+ },
+ "name": "testdb"
+ },
+ "spec": {
+ "replicas": 1,
+ "selector": {
+ "name": "testdb"
+ },
+ "strategy": {
+ "type": "Recreate"
+ },
+ "template": {
+ "metadata": {
+ "creationTimestamp": null,
+ "labels": {
+ "name": "testdb"
+ }
+ },
+ "spec": {
+ "containers": [
+ {
+ "capabilities": {},
+ "env": [
+ {
+ "name": "MYSQL_USER",
+ "value": "userHJJ"
+ },
+ {
+ "name": "MYSQL_PASSWORD",
+ "value": "GITOAduAMaV6k688"
+ },
+ {
+ "name": "MYSQL_DATABASE",
+ "value": "sampledb"
+ }
+ ],
+ "image": " ",
+ "imagePullPolicy": "IfNotPresent",
+ "livenessProbe": {
+ "initialDelaySeconds": 30,
+ "tcpSocket": {
+ "port": 3306
+ },
+ "timeoutSeconds": 1
+ },
+ "name": "mysql",
+ "ports": [
+ {
+ "containerPort": 3306,
+ "protocol": "TCP"
+ }
+ ],
+ "readinessProbe": {
+ "exec": {
+ "command": [
+ "/bin/sh",
+ "-i",
+ "-c",
+ "MYSQL_PWD=$MYSQL_PASSWORD mysql -h 127.0.0.1 -u $MYSQL_USER -D $MYSQL_DATABASE -e 'SELECT 1'"
+ ]
+ },
+ "initialDelaySeconds": 5,
+ "timeoutSeconds": 1
+ },
+ "resources": {
+ "limits": {
+ "memory": "512Mi"
+ }
+ },
+ "securityContext": {
+ "capabilities": {},
+ "privileged": false
+ },
+ "terminationMessagePath": "/dev/termination-log",
+ "volumeMounts": [
+ {
+ "mountPath": "/var/lib/mysql/data",
+ "name": "testdb-data"
+ }
+ ]
+ }
+ ],
+ "dnsPolicy": "ClusterFirst",
+ "restartPolicy": "Always",
+ "volumes": [
+ {
+ "emptyDir": {
+ "medium": ""
+ },
+ "name": "testdb-data"
+ }
+ ]
+ }
+ },
+ "triggers": [
+ {
+ "imageChangeParams": {
+ "automatic": true,
+ "containerNames": [
+ "mysql"
+ ],
+ "from": {
+ "kind": "ImageStreamTag",
+ "name": "mysql:5.6",
+ "namespace": "test"
+ },
+ "lastTriggeredImage": ""
+ },
+ "type": "ImageChange"
+ },
+ {
+ "type": "ConfigChange"
+ }
+ ]
+ }
+ }
+ ]
+}'''
+
+ mock_cmd.side_effect = [
+ (0, OCProcessTest.mysql, ''),
+ (0, OCProcessTest.mysql, ''),
+ (0, mysqlproc, ''),
+ ]
+
+ mock_tmpfile_copy.side_effect = [
+ '/tmp/mock_kubeconfig',
+ ]
+
+ results = OCProcess.run_ansible(params, False)
+
+ self.assertFalse(results['changed'])
+ self.assertEqual(results['results']['results']['items'][0]['metadata']['name'], 'testdb')
+
+ def tearDown(self):
+ '''TearDown method'''
+ pass
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/roles/lib_openshift/src/test/unit/oc_route.py b/roles/lib_openshift/src/test/unit/oc_route.py
new file mode 100755
index 000000000..fcfa88cbf
--- /dev/null
+++ b/roles/lib_openshift/src/test/unit/oc_route.py
@@ -0,0 +1,258 @@
+#!/usr/bin/env python2
+'''
+ Unit tests for oc route
+'''
+# To run:
+# ./oc_serviceaccount.py
+#
+# .
+# Ran 1 test in 0.002s
+#
+# OK
+
+import os
+import sys
+import unittest
+import mock
+
+# Removing invalid variable names for tests so that I can
+# keep them brief
+# pylint: disable=invalid-name,no-name-in-module
+# Disable import-error b/c our libraries aren't loaded in jenkins
+# pylint: disable=import-error,wrong-import-position
+# place class in our python path
+module_path = os.path.join('/'.join(os.path.realpath(__file__).split('/')[:-4]), 'library') # noqa: E501
+sys.path.insert(0, module_path)
+from oc_route import OCRoute # noqa: E402
+
+
+class OCRouteTest(unittest.TestCase):
+ '''
+ Test class for OCServiceAccount
+ '''
+
+ def setUp(self):
+ ''' setup method will create a file and set to known configuration '''
+ pass
+
+ @mock.patch('oc_route.OCRoute._run')
+ def test_list_route(self, mock_cmd):
+ ''' Testing getting a route '''
+
+ # Arrange
+
+ # run_ansible input parameters
+ params = {
+ 'kubeconfig': '/etc/origin/master/admin.kubeconfig',
+ 'state': 'list',
+ 'debug': False,
+ 'name': 'test',
+ 'namespace': 'default',
+ 'tls_termination': 'passthrough',
+ 'dest_cacert_path': None,
+ 'cacert_path': None,
+ 'cert_path': None,
+ 'key_path': None,
+ 'dest_cacert_content': None,
+ 'cacert_content': None,
+ 'cert_content': None,
+ 'key_content': None,
+ 'service_name': 'testservice',
+ 'host': 'test.openshift.com',
+ 'wildcard_policy': None,
+ 'weight': None,
+ 'port': None
+ }
+
+ route_result = '''{
+ "kind": "Route",
+ "apiVersion": "v1",
+ "metadata": {
+ "name": "test",
+ "namespace": "default",
+ "selfLink": "/oapi/v1/namespaces/default/routes/test",
+ "uid": "1b127c67-ecd9-11e6-96eb-0e0d9bdacd26",
+ "resourceVersion": "439182",
+ "creationTimestamp": "2017-02-07T01:59:48Z"
+ },
+ "spec": {
+ "host": "test.example",
+ "to": {
+ "kind": "Service",
+ "name": "test",
+ "weight": 100
+ },
+ "port": {
+ "targetPort": 8443
+ },
+ "tls": {
+ "termination": "passthrough"
+ },
+ "wildcardPolicy": "None"
+ },
+ "status": {
+ "ingress": [
+ {
+ "host": "test.example",
+ "routerName": "router",
+ "conditions": [
+ {
+ "type": "Admitted",
+ "status": "True",
+ "lastTransitionTime": "2017-02-07T01:59:48Z"
+ }
+ ],
+ "wildcardPolicy": "None"
+ }
+ ]
+ }
+ }'''
+
+ # Return values of our mocked function call. These get returned once per call.
+ mock_cmd.side_effect = [
+ # First call to mock
+ (0, route_result, ''),
+ ]
+
+ # Act
+ results = OCRoute.run_ansible(params, False)
+
+ # Assert
+ self.assertFalse(results['changed'])
+ self.assertEqual(results['state'], 'list')
+ self.assertEqual(results['results'][0]['metadata']['name'], 'test')
+
+ # Making sure our mock was called as we expected
+ mock_cmd.assert_has_calls([
+ mock.call(['oc', '-n', 'default', 'get', 'route', 'test', '-o', 'json'], None),
+ ])
+
+ @mock.patch('oc_route.Yedit._write')
+ @mock.patch('oc_route.OCRoute._run')
+ def test_create_route(self, mock_cmd, mock_write):
+ ''' Testing getting a route '''
+
+ # Arrange
+
+ # run_ansible input parameters
+ params = {
+ 'kubeconfig': '/etc/origin/master/admin.kubeconfig',
+ 'state': 'present',
+ 'debug': False,
+ 'name': 'test',
+ 'namespace': 'default',
+ 'tls_termination': 'edge',
+ 'dest_cacert_path': None,
+ 'cacert_path': None,
+ 'cert_path': None,
+ 'key_path': None,
+ 'dest_cacert_content': None,
+ 'cacert_content': 'testing',
+ 'cert_content': 'testing',
+ 'key_content': 'testing',
+ 'service_name': 'testservice',
+ 'host': 'test.openshift.com',
+ 'wildcard_policy': None,
+ 'weight': None,
+ 'port': None
+ }
+
+ route_result = '''{
+ "apiVersion": "v1",
+ "kind": "Route",
+ "metadata": {
+ "creationTimestamp": "2017-02-07T20:55:10Z",
+ "name": "test",
+ "namespace": "default",
+ "resourceVersion": "517745",
+ "selfLink": "/oapi/v1/namespaces/default/routes/test",
+ "uid": "b6f25898-ed77-11e6-9755-0e737db1e63a"
+ },
+ "spec": {
+ "host": "test.openshift.com",
+ "tls": {
+ "caCertificate": "testing",
+ "certificate": "testing",
+ "key": "testing",
+ "termination": "edge"
+ },
+ "to": {
+ "kind": "Service",
+ "name": "testservice",
+ "weight": 100
+ },
+ "wildcardPolicy": "None"
+ },
+ "status": {
+ "ingress": [
+ {
+ "conditions": [
+ {
+ "lastTransitionTime": "2017-02-07T20:55:10Z",
+ "status": "True",
+ "type": "Admitted"
+ }
+ ],
+ "host": "test.openshift.com",
+ "routerName": "router",
+ "wildcardPolicy": "None"
+ }
+ ]
+ }
+ }'''
+
+ test_route = '''\
+kind: Route
+spec:
+ tls:
+ caCertificate: testing
+ termination: edge
+ certificate: testing
+ key: testing
+ to:
+ kind: Service
+ name: testservice
+ weight: 100
+ host: test.openshift.com
+ wildcardPolicy: None
+apiVersion: v1
+metadata:
+ namespace: default
+ name: test
+'''
+
+ # Return values of our mocked function call. These get returned once per call.
+ mock_cmd.side_effect = [
+ # First call to mock
+ (1, '', 'Error from server: routes "test" not found'),
+ (1, '', 'Error from server: routes "test" not found'),
+ (0, 'route "test" created', ''),
+ (0, route_result, ''),
+ ]
+
+ mock_write.assert_has_calls = [
+ # First call to mock
+ mock.call('/tmp/test', test_route)
+ ]
+
+ # Act
+ results = OCRoute.run_ansible(params, False)
+
+ # Assert
+ self.assertTrue(results['changed'])
+ self.assertEqual(results['state'], 'present')
+ self.assertEqual(results['results']['results'][0]['metadata']['name'], 'test')
+
+ # Making sure our mock was called as we expected
+ mock_cmd.assert_has_calls([
+ mock.call(['oc', '-n', 'default', 'get', 'route', 'test', '-o', 'json'], None),
+ mock.call(['oc', '-n', 'default', 'create', '-f', '/tmp/test'], None),
+ ])
+
+ def tearDown(self):
+ '''TearDown method'''
+ pass
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/roles/lib_openshift/src/test/unit/oc_scale.py b/roles/lib_openshift/src/test/unit/oc_scale.py
index d8d5a231f..f15eb164d 100755
--- a/roles/lib_openshift/src/test/unit/oc_scale.py
+++ b/roles/lib_openshift/src/test/unit/oc_scale.py
@@ -35,8 +35,9 @@ class OCScaleTest(unittest.TestCase):
''' setup method will create a file and set to known configuration '''
pass
+ @mock.patch('oc_scale.Utils.create_tmpfile_copy')
@mock.patch('oc_scale.OCScale.openshift_cmd')
- def test_state_list(self, mock_openshift_cmd):
+ def test_state_list(self, mock_openshift_cmd, mock_tmpfile_copy):
''' Testing a get '''
params = {'name': 'router',
'namespace': 'default',
@@ -70,13 +71,18 @@ class OCScaleTest(unittest.TestCase):
'results': dc,
'returncode': 0}]
+ mock_tmpfile_copy.side_effect = [
+ '/tmp/mocked_kubeconfig',
+ ]
+
results = OCScale.run_ansible(params, False)
self.assertFalse(results['changed'])
self.assertEqual(results['result'][0], 2)
+ @mock.patch('oc_scale.Utils.create_tmpfile_copy')
@mock.patch('oc_scale.OCScale.openshift_cmd')
- def test_scale(self, mock_openshift_cmd):
+ def test_scale(self, mock_openshift_cmd, mock_tmpfile_copy):
''' Testing a get '''
params = {'name': 'router',
'namespace': 'default',
@@ -114,13 +120,18 @@ class OCScaleTest(unittest.TestCase):
'returncode': 0}
]
+ mock_tmpfile_copy.side_effect = [
+ '/tmp/mocked_kubeconfig',
+ ]
+
results = OCScale.run_ansible(params, False)
self.assertFalse(results['changed'])
self.assertEqual(results['result'][0], 3)
+ @mock.patch('oc_scale.Utils.create_tmpfile_copy')
@mock.patch('oc_scale.OCScale.openshift_cmd')
- def test_no_dc_scale(self, mock_openshift_cmd):
+ def test_no_dc_scale(self, mock_openshift_cmd, mock_tmpfile_copy):
''' Testing a get '''
params = {'name': 'not_there',
'namespace': 'default',
@@ -138,6 +149,10 @@ class OCScaleTest(unittest.TestCase):
'stdout': ""},
]
+ mock_tmpfile_copy.side_effect = [
+ '/tmp/mocked_kubeconfig',
+ ]
+
results = OCScale.run_ansible(params, False)
self.assertTrue(results['failed'])
diff --git a/roles/lib_openshift/src/test/unit/oc_secret.py b/roles/lib_openshift/src/test/unit/oc_secret.py
index 835918b95..645aac82b 100755
--- a/roles/lib_openshift/src/test/unit/oc_secret.py
+++ b/roles/lib_openshift/src/test/unit/oc_secret.py
@@ -35,8 +35,10 @@ class OCSecretTest(unittest.TestCase):
''' setup method will create a file and set to known configuration '''
pass
- @mock.patch('oc_secret.OCSecret.openshift_cmd')
- def test_adding_a_secret(self, mock_openshift_cmd):
+ @mock.patch('oc_secret.Utils.create_tmpfile_copy')
+ @mock.patch('oc_secret.Utils._write')
+ @mock.patch('oc_secret.OCSecret._run')
+ def test_adding_a_secret(self, mock_cmd, mock_write, mock_tmpfile_copy):
''' Testing adding a secret '''
# Arrange
@@ -45,10 +47,10 @@ class OCSecretTest(unittest.TestCase):
params = {
'state': 'present',
'namespace': 'default',
- 'name': 'secretname',
+ 'name': 'testsecretname',
'contents': [{
'path': "/tmp/somesecret.json",
- 'data': "{'one': 1, 'two': 2, 'three', 3}",
+ 'data': "{'one': 1, 'two': 2, 'three': 3}",
}],
'decode': False,
'kubeconfig': '/etc/origin/master/admin.kubeconfig',
@@ -58,17 +60,13 @@ class OCSecretTest(unittest.TestCase):
}
# Return values of our mocked function call. These get returned once per call.
- mock_openshift_cmd.side_effect = [
- {
- "cmd": "/usr/bin/oc get secrets -o json secretname",
- "results": "",
- "returncode": 0,
- }, # oc output for first call to openshift_cmd (oc secrets get)
- {
- "cmd": "/usr/bin/oc secrets new secretname somesecret.json=/tmp/somesecret.json",
- "results": "",
- "returncode": 0,
- }, # oc output for second call to openshift_cmd (oc secrets new)
+ mock_cmd.side_effect = [
+ (1, '', 'Error from server: secrets "testsecretname" not found'),
+ (0, 'secret/testsecretname', ''),
+ ]
+
+ mock_tmpfile_copy.side_effect = [
+ '/tmp/mocked_kubeconfig',
]
# Act
@@ -80,9 +78,13 @@ class OCSecretTest(unittest.TestCase):
self.assertEqual(results['state'], 'present')
# Making sure our mock was called as we expected
- mock_openshift_cmd.assert_has_calls([
- mock.call(['get', 'secrets', 'secretname', '-o', 'json'], output=True),
- mock.call(['secrets', 'new', 'secretname', 'somesecret.json=/tmp/somesecret.json']),
+ mock_cmd.assert_has_calls([
+ mock.call(['oc', '-n', 'default', 'get', 'secrets', 'testsecretname', '-o', 'json'], None),
+ mock.call(['oc', '-n', 'default', 'secrets', 'new', 'testsecretname', mock.ANY], None),
+ ])
+
+ mock_write.assert_has_calls([
+ mock.call(mock.ANY, "{'one': 1, 'two': 2, 'three': 3}"),
])
def tearDown(self):
diff --git a/roles/lib_openshift/src/test/unit/oc_service.py b/roles/lib_openshift/src/test/unit/oc_service.py
index 69f7dd49c..4a845e9f3 100755
--- a/roles/lib_openshift/src/test/unit/oc_service.py
+++ b/roles/lib_openshift/src/test/unit/oc_service.py
@@ -36,8 +36,9 @@ class OCServiceTest(unittest.TestCase):
''' setup method will create a file and set to known configuration '''
pass
+ @mock.patch('oc_service.Utils.create_tmpfile_copy')
@mock.patch('oc_service.OCService._run')
- def test_state_list(self, mock_cmd):
+ def test_state_list(self, mock_cmd, mock_tmpfile_copy):
''' Testing a get '''
params = {'name': 'router',
'namespace': 'default',
@@ -108,13 +109,18 @@ class OCServiceTest(unittest.TestCase):
(0, service, '')
]
+ mock_tmpfile_copy.side_effect = [
+ '/tmp/mocked_kubeconfig',
+ ]
+
results = OCService.run_ansible(params, False)
self.assertFalse(results['changed'])
self.assertEqual(results['results']['results'][0]['metadata']['name'], 'router')
+ @mock.patch('oc_service.Utils.create_tmpfile_copy')
@mock.patch('oc_service.OCService._run')
- def test_create(self, mock_cmd):
+ def test_create(self, mock_cmd, mock_tmpfile_copy):
''' Testing a create service '''
params = {'name': 'router',
'namespace': 'default',
@@ -191,6 +197,10 @@ class OCServiceTest(unittest.TestCase):
(0, service, '')
]
+ mock_tmpfile_copy.side_effect = [
+ '/tmp/mocked_kubeconfig',
+ ]
+
results = OCService.run_ansible(params, False)
self.assertTrue(results['changed'])
diff --git a/roles/lib_openshift/src/test/unit/oc_serviceaccount.py b/roles/lib_openshift/src/test/unit/oc_serviceaccount.py
index dab751bb9..256b569eb 100755
--- a/roles/lib_openshift/src/test/unit/oc_serviceaccount.py
+++ b/roles/lib_openshift/src/test/unit/oc_serviceaccount.py
@@ -35,8 +35,9 @@ class OCServiceAccountTest(unittest.TestCase):
''' setup method will create a file and set to known configuration '''
pass
+ @mock.patch('oc_serviceaccount.Utils.create_tmpfile_copy')
@mock.patch('oc_serviceaccount.OCServiceAccount._run')
- def test_adding_a_serviceaccount(self, mock_cmd):
+ def test_adding_a_serviceaccount(self, mock_cmd, mock_tmpfile_copy):
''' Testing adding a serviceaccount '''
# Arrange
@@ -90,6 +91,10 @@ class OCServiceAccountTest(unittest.TestCase):
(0, valid_result_json, ''),
]
+ mock_tmpfile_copy.side_effect = [
+ '/tmp/mocked_kubeconfig',
+ ]
+
# Act
results = OCServiceAccount.run_ansible(params, False)
diff --git a/roles/lib_openshift/src/test/unit/oc_serviceaccount_secret.py b/roles/lib_openshift/src/test/unit/oc_serviceaccount_secret.py
index 342da961b..4d555d412 100755
--- a/roles/lib_openshift/src/test/unit/oc_serviceaccount_secret.py
+++ b/roles/lib_openshift/src/test/unit/oc_serviceaccount_secret.py
@@ -35,9 +35,10 @@ class OCServiceAccountSecretTest(unittest.TestCase):
''' setup method will create a file and set to known configuration '''
pass
+ @mock.patch('oc_serviceaccount_secret.Utils.create_tmpfile_copy')
@mock.patch('oc_serviceaccount_secret.Yedit._write')
@mock.patch('oc_serviceaccount_secret.OCServiceAccountSecret._run')
- def test_adding_a_secret_to_a_serviceaccount(self, mock_cmd, mock_write):
+ def test_adding_a_secret_to_a_serviceaccount(self, mock_cmd, mock_write, mock_tmpfile_copy):
''' Testing adding a secret to a service account '''
# Arrange
@@ -137,6 +138,10 @@ metadata:
(0, oc_get_sa_after, ''), # Fourth call to the mock
]
+ mock_tmpfile_copy.side_effect = [
+ '/tmp/mocked_kubeconfig',
+ ]
+
# Act
results = OCServiceAccountSecret.run_ansible(params, False)
@@ -149,18 +154,19 @@ metadata:
mock_cmd.assert_has_calls([
mock.call(['oc', '-n', 'default', 'get', 'sa', 'builder', '-o', 'json'], None),
mock.call(['oc', '-n', 'default', 'get', 'sa', 'builder', '-o', 'json'], None),
- mock.call(['oc', '-n', 'default', 'replace', '-f', '/tmp/builder'], None),
+ mock.call(['oc', '-n', 'default', 'replace', '-f', mock.ANY], None),
mock.call(['oc', '-n', 'default', 'get', 'sa', 'builder', '-o', 'json'], None)
])
mock_write.assert_has_calls([
- mock.call('/tmp/builder', builder_yaml_file)
+ mock.call(mock.ANY, builder_yaml_file)
])
+ @mock.patch('oc_serviceaccount_secret.Utils.create_tmpfile_copy')
@mock.patch('oc_serviceaccount_secret.Yedit._write')
@mock.patch('oc_serviceaccount_secret.OCServiceAccountSecret._run')
- def test_removing_a_secret_to_a_serviceaccount(self, mock_cmd, mock_write):
- ''' Testing adding a secret to a service account '''
+ def test_removing_a_secret_to_a_serviceaccount(self, mock_cmd, mock_write, mock_tmpfile_copy):
+ ''' Testing removing a secret to a service account '''
# Arrange
@@ -229,6 +235,10 @@ metadata:
(0, 'serviceaccount "builder" replaced', ''), # Third call to the mock
]
+ mock_tmpfile_copy.side_effect = [
+ '/tmp/mocked_kubeconfig',
+ ]
+
# Act
results = OCServiceAccountSecret.run_ansible(params, False)
@@ -241,11 +251,11 @@ metadata:
mock_cmd.assert_has_calls([
mock.call(['oc', '-n', 'default', 'get', 'sa', 'builder', '-o', 'json'], None),
mock.call(['oc', '-n', 'default', 'get', 'sa', 'builder', '-o', 'json'], None),
- mock.call(['oc', '-n', 'default', 'replace', '-f', '/tmp/builder'], None),
+ mock.call(['oc', '-n', 'default', 'replace', '-f', mock.ANY], None),
])
mock_write.assert_has_calls([
- mock.call('/tmp/builder', builder_yaml_file)
+ mock.call(mock.ANY, builder_yaml_file)
])
def tearDown(self):
diff --git a/roles/lib_openshift/src/test/unit/oc_version.py b/roles/lib_openshift/src/test/unit/oc_version.py
index f927948be..67dea415b 100755
--- a/roles/lib_openshift/src/test/unit/oc_version.py
+++ b/roles/lib_openshift/src/test/unit/oc_version.py
@@ -35,8 +35,9 @@ class OCVersionTest(unittest.TestCase):
''' setup method will create a file and set to known configuration '''
pass
+ @mock.patch('oc_version.Utils.create_tmpfile_copy')
@mock.patch('oc_version.OCVersion.openshift_cmd')
- def test_get(self, mock_openshift_cmd):
+ def test_get(self, mock_openshift_cmd, mock_tmpfile_copy):
''' Testing a get '''
params = {'kubeconfig': '/etc/origin/master/admin.kubeconfig',
'state': 'list',
@@ -52,6 +53,10 @@ class OCVersionTest(unittest.TestCase):
"returncode": 0}
]
+ mock_tmpfile_copy.side_effect = [
+ '/tmp/mocked_kubeconfig',
+ ]
+
results = OCVersion.run_ansible(params)
self.assertFalse(results['changed'])
diff --git a/roles/lib_openshift/tasks/main.yml b/roles/lib_openshift/tasks/main.yml
index 2980c8a8d..157cf8f7f 100644
--- a/roles/lib_openshift/tasks/main.yml
+++ b/roles/lib_openshift/tasks/main.yml
@@ -1,5 +1,12 @@
---
- name: lib_openshift ensure python-ruamel-yaml package is on target
package:
- name: python-ruamel-yaml
+ name: "{{ item }}"
state: present
+ with_items:
+ - ruamel.yaml
+ - ruamel.yaml
+ - ruamel.yaml
+ - ruamel.yaml
+ - ruamel.yaml
+ - ruamel.yaml
diff --git a/roles/lib_utils/src/test/generate-and-run-tests.sh b/roles/lib_utils/src/test/generate-and-run-tests.sh
new file mode 100755
index 000000000..4b534c8f2
--- /dev/null
+++ b/roles/lib_utils/src/test/generate-and-run-tests.sh
@@ -0,0 +1,42 @@
+#!/bin/bash -e
+
+
+# Put us in the same dir as the script.
+cd $(dirname $0)
+
+echo
+echo "Running lib_openshift generate"
+echo "------------------------------"
+../generate.py
+
+
+echo
+echo "Running lib_utils Unit Tests"
+echo "----------------------------"
+cd unit
+
+for test in *.py; do
+ echo
+ echo "--------------------------------------------------------------------------------"
+ echo
+ echo "Running $test..."
+ ./$test
+done
+
+
+echo
+echo "Running lib_utils Integration Tests"
+echo "-----------------------------------"
+cd ../integration
+
+for test in *.yml; do
+ echo
+ echo "--------------------------------------------------------------------------------"
+ echo
+ echo "Running $test..."
+ ./$test -vvv
+done
+
+# Clean up this damn file
+# TODO: figure out why this is being written and clean it up.
+rm kube-manager-test.yaml
diff --git a/roles/lib_utils/src/test/integration/yedit_test.yml b/roles/lib_utils/src/test/integration/yedit.yml
index 1760a7466..e3dfd490b 100755
--- a/roles/lib_utils/src/test/integration/yedit_test.yml
+++ b/roles/lib_utils/src/test/integration/yedit.yml
@@ -1,8 +1,9 @@
-#!/usr/bin/ansible-playbook
+#!/usr/bin/ansible-playbook --module-path=../../../library/
+#
# Yedit test so that we can quickly determine if features are working
# Ensure that the kube-manager.yaml file exists
#
-# ./yedit_test.yml -M ../../library
+# ./yedit_test.yml
#
---
- hosts: localhost
diff --git a/roles/openshift_ca/tasks/main.yml b/roles/openshift_ca/tasks/main.yml
index 4efc77f11..ae3ad31c3 100644
--- a/roles/openshift_ca/tasks/main.yml
+++ b/roles/openshift_ca/tasks/main.yml
@@ -87,7 +87,7 @@
# This should NOT replace the CA due to --overwrite=false when a CA already exists.
- name: Create the master certificates if they do not already exist
command: >
- {{ openshift.common.client_binary }} adm create-master-certs
+ {{ hostvars[openshift_ca_host].openshift.common.client_binary }} adm create-master-certs
{% for named_ca_certificate in openshift.master.named_certificates | default([]) | oo_collect('cafile') %}
--certificate-authority {{ named_ca_certificate }}
{% endfor %}
diff --git a/roles/openshift_logging/files/fluent.conf b/roles/openshift_logging/files/fluent.conf
index aa843e983..c0c1c8a44 100644
--- a/roles/openshift_logging/files/fluent.conf
+++ b/roles/openshift_logging/files/fluent.conf
@@ -22,6 +22,7 @@
@include configs.d/openshift/filter-k8s-flatten-hash.conf
@include configs.d/openshift/filter-k8s-record-transform.conf
@include configs.d/openshift/filter-syslog-record-transform.conf
+ @include configs.d/openshift/filter-common-data-model.conf
@include configs.d/openshift/filter-post-*.conf
##
diff --git a/roles/openshift_logging/tasks/upgrade_logging.yaml b/roles/openshift_logging/tasks/upgrade_logging.yaml
index cceacd538..0dc31932c 100644
--- a/roles/openshift_logging/tasks/upgrade_logging.yaml
+++ b/roles/openshift_logging/tasks/upgrade_logging.yaml
@@ -17,7 +17,7 @@
oc_scale:
kind: dc
name: "{{object.split('/')[1]}}"
- namespace: "{{mktemp.stdout}}/admin.kubeconfig"
+ namespace: "{{openshift_logging_namespace}}"
replicas: 1
with_items: "{{es_dc.stdout_lines}}"
loop_control:
diff --git a/roles/openshift_master/templates/master.yaml.v1.j2 b/roles/openshift_master/templates/master.yaml.v1.j2
index 9ae54dac1..cf2d2e103 100644
--- a/roles/openshift_master/templates/master.yaml.v1.j2
+++ b/roles/openshift_master/templates/master.yaml.v1.j2
@@ -65,7 +65,11 @@ dnsConfig:
bindNetwork: tcp4
{% endif %}
etcdClientInfo:
+{% if openshift.common.version_gte_3_2_or_1_2 | bool %}
+ ca: {{ "ca-bundle.crt" if (openshift.master.embedded_etcd | bool) else "master.etcd-ca.crt" }}
+{% else %}
ca: {{ "ca.crt" if (openshift.master.embedded_etcd | bool) else "master.etcd-ca.crt" }}
+{% endif %}
certFile: master.etcd-client.crt
keyFile: master.etcd-client.key
urls:
@@ -79,12 +83,20 @@ etcdConfig:
peerServingInfo:
bindAddress: {{ openshift.master.bind_addr }}:7001
certFile: etcd.server.crt
+{% if openshift.common.version_gte_3_2_or_1_2 | bool %}
+ clientCA: ca-bundle.crt
+{% else %}
clientCA: ca.crt
+{% endif %}
keyFile: etcd.server.key
servingInfo:
bindAddress: {{ openshift.master.bind_addr }}:{{ openshift.master.etcd_port }}
certFile: etcd.server.crt
+{% if openshift.common.version_gte_3_2_or_1_2 | bool %}
+ clientCA: ca-bundle.crt
+{% else %}
clientCA: ca.crt
+{% endif %}
keyFile: etcd.server.key
storageDirectory: {{ openshift.common.data_dir }}/openshift.local.etcd
{% endif %}
diff --git a/roles/openshift_metrics/README.md b/roles/openshift_metrics/README.md
index a61b0db5e..f4c61a75e 100644
--- a/roles/openshift_metrics/README.md
+++ b/roles/openshift_metrics/README.md
@@ -46,11 +46,11 @@ For default values, see [`defaults/main.yaml`](defaults/main.yaml).
testing), `pv` to use persistent volumes (which need to be created before the
installation) or `dynamic` for dynamic persistent volumes.
-- `openshift_metrics_cassandra_pv_prefix`: The name of persistent volume claims created
+- `openshift_metrics_cassandra_pvc_prefix`: The name of persistent volume claims created
for cassandra will be this with a serial number appended to the end, starting
from 1.
-- `openshift_metrics_cassandra_pv_size`: The persistent volume size for each of the
+- `openshift_metrics_cassandra_pvc_size`: The persistent volume claim size for each of the
Cassandra nodes.
- `openshift_metrics_heapster_standalone`: Deploy only heapster, without the Hawkular Metrics and
diff --git a/roles/openshift_metrics/defaults/main.yaml b/roles/openshift_metrics/defaults/main.yaml
index c5ba9aad0..45c4bf69a 100644
--- a/roles/openshift_metrics/defaults/main.yaml
+++ b/roles/openshift_metrics/defaults/main.yaml
@@ -17,7 +17,7 @@ openshift_metrics_hawkular_nodeselector: ""
openshift_metrics_cassandra_replicas: 1
openshift_metrics_cassandra_storage_type: emptydir
-openshift_metrics_cassandra_pv_size: 10Gi
+openshift_metrics_cassandra_pvc_size: 10Gi
openshift_metrics_cassandra_limits_memory: 2G
openshift_metrics_cassandra_limits_cpu: null
openshift_metrics_cassandra_requests_memory: 1G
@@ -46,7 +46,7 @@ openshift_metrics_master_url: https://kubernetes.default.svc.cluster.local
openshift_metrics_node_id: nodename
openshift_metrics_project: openshift-infra
-openshift_metrics_cassandra_pv_prefix: metrics-cassandra
+openshift_metrics_cassandra_pvc_prefix: metrics-cassandra
openshift_metrics_hawkular_user_write_access: False
diff --git a/roles/openshift_metrics/tasks/generate_certificates.yaml b/roles/openshift_metrics/tasks/generate_certificates.yaml
index 16a967aa7..4925275e8 100644
--- a/roles/openshift_metrics/tasks/generate_certificates.yaml
+++ b/roles/openshift_metrics/tasks/generate_certificates.yaml
@@ -1,18 +1,4 @@
---
-- name: create certificate output directory
- file:
- path: "{{ openshift_metrics_certs_dir }}"
- state: directory
- mode: 0700
-
-- name: list existing secrets
- command: >
- {{ openshift.common.client_binary }} -n {{ openshift_metrics_project }}
- --config={{ mktemp.stdout }}/admin.kubeconfig
- get secrets -o name
- register: metrics_secrets
- changed_when: false
-
- name: generate ca certificate chain
shell: >
{{ openshift.common.admin_binary }} ca create-signer-cert
@@ -22,5 +8,4 @@
--serial='{{ openshift_metrics_certs_dir }}/ca.serial.txt'
--name="metrics-signer@$(date +%s)"
when: not '{{ openshift_metrics_certs_dir }}/ca.key' | exists
-- include: generate_heapster_certificates.yaml
- include: generate_hawkular_certificates.yaml
diff --git a/roles/openshift_metrics/tasks/generate_rolebindings.yaml b/roles/openshift_metrics/tasks/generate_rolebindings.yaml
index 6524c3f32..e050c8eb2 100644
--- a/roles/openshift_metrics/tasks/generate_rolebindings.yaml
+++ b/roles/openshift_metrics/tasks/generate_rolebindings.yaml
@@ -13,21 +13,3 @@
- kind: ServiceAccount
name: hawkular
changed_when: no
-
-- name: generate cluster-reader role binding for the heapster service account
- template:
- src: rolebinding.j2
- dest: "{{ mktemp.stdout }}/templates/heapster-rolebinding.yaml"
- vars:
- cluster: True
- obj_name: heapster-cluster-reader
- labels:
- metrics-infra: heapster
- roleRef:
- kind: ClusterRole
- name: cluster-reader
- subjects:
- - kind: ServiceAccount
- name: heapster
- namespace: "{{ openshift_metrics_project }}"
- changed_when: no
diff --git a/roles/openshift_metrics/tasks/generate_serviceaccounts.yaml b/roles/openshift_metrics/tasks/generate_serviceaccounts.yaml
index 94f34d860..e9d70f74f 100644
--- a/roles/openshift_metrics/tasks/generate_serviceaccounts.yaml
+++ b/roles/openshift_metrics/tasks/generate_serviceaccounts.yaml
@@ -13,15 +13,3 @@
- name: cassandra
secret: hawkular-cassandra-secrets
changed_when: no
-
-- name: Generating serviceaccount for heapster
- template: src=serviceaccount.j2 dest={{mktemp.stdout}}/templates/metrics-{{obj_name}}-sa.yaml
- vars:
- obj_name: heapster
- labels:
- metrics-infra: support
- secrets:
- - heapster-secrets
- - hawkular-metrics-certificate
- - hawkular-metrics-account
- changed_when: no
diff --git a/roles/openshift_metrics/tasks/generate_services.yaml b/roles/openshift_metrics/tasks/generate_services.yaml
index 903d52bff..47d3c5c2e 100644
--- a/roles/openshift_metrics/tasks/generate_services.yaml
+++ b/roles/openshift_metrics/tasks/generate_services.yaml
@@ -1,17 +1,4 @@
---
-- name: Generate service for heapster
- template: src=service.j2 dest={{mktemp.stdout}}/templates/metrics-{{obj_name}}-svc.yaml
- vars:
- obj_name: heapster
- ports:
- - {port: 80, targetPort: http-endpoint}
- selector:
- name: "{{obj_name}}"
- labels:
- metrics-infra: "{{obj_name}}"
- name: "{{obj_name}}"
- changed_when: no
-
- name: Generate service for hawkular-metrics
template: src=service.j2 dest={{mktemp.stdout}}/templates/metrics-{{obj_name}}-svc.yaml
vars:
diff --git a/roles/openshift_metrics/tasks/install_cassandra.yaml b/roles/openshift_metrics/tasks/install_cassandra.yaml
index 9e25071af..df39c1e1f 100644
--- a/roles/openshift_metrics/tasks/install_cassandra.yaml
+++ b/roles/openshift_metrics/tasks/install_cassandra.yaml
@@ -27,12 +27,12 @@
src: pvc.j2
dest: "{{ mktemp.stdout }}/templates/hawkular-cassandra-pvc{{ item }}.yaml"
vars:
- obj_name: "{{ openshift_metrics_cassandra_pv_prefix }}-{{ item }}"
+ obj_name: "{{ openshift_metrics_cassandra_pvc_prefix }}-{{ item }}"
labels:
metrics-infra: hawkular-cassandra
access_modes:
- ReadWriteOnce
- size: "{{ openshift_metrics_cassandra_pv_size }}"
+ size: "{{ openshift_metrics_cassandra_pvc_size }}"
with_sequence: count={{ openshift_metrics_cassandra_replicas }}
when: openshift_metrics_cassandra_storage_type == 'pv'
changed_when: false
@@ -42,14 +42,14 @@
src: pvc.j2
dest: "{{ mktemp.stdout }}/templates/hawkular-cassandra-pvc{{ item }}.yaml"
vars:
- obj_name: "{{ openshift_metrics_cassandra_pv_prefix }}-{{ item }}"
+ obj_name: "{{ openshift_metrics_cassandra_pvc_prefix }}-{{ item }}"
labels:
metrics-infra: hawkular-cassandra
annotations:
volume.alpha.kubernetes.io/storage-class: dynamic
access_modes:
- ReadWriteOnce
- size: "{{ openshift_metrics_cassandra_pv_size }}"
+ size: "{{ openshift_metrics_cassandra_pvc_size }}"
with_sequence: count={{ openshift_metrics_cassandra_replicas }}
when: openshift_metrics_cassandra_storage_type == 'dynamic'
changed_when: false
diff --git a/roles/openshift_metrics/tasks/install_heapster.yaml b/roles/openshift_metrics/tasks/install_heapster.yaml
index 44bab8ace..c490bcdd3 100644
--- a/roles/openshift_metrics/tasks/install_heapster.yaml
+++ b/roles/openshift_metrics/tasks/install_heapster.yaml
@@ -13,3 +13,55 @@
replica_count: "{{heapster_replica_count.stdout | default(0)}}"
node_selector: "{{openshift_metrics_heapster_nodeselector | default('') }}"
changed_when: no
+
+- set_fact:
+ heapster_sa_secrets: ["heapster-secrets"]
+
+- set_fact:
+ heapster_sa_secrets: "{{ heapster_sa_secrets + [item] }}"
+ with_items:
+ - hawkular-metrics-certificate
+ - hawkular-metrics-account
+ when: "not {{ openshift_metrics_heapster_standalone | bool }}"
+
+- name: Generating serviceaccount for heapster
+ template: src=serviceaccount.j2 dest={{mktemp.stdout}}/templates/metrics-{{obj_name}}-sa.yaml
+ vars:
+ obj_name: heapster
+ labels:
+ metrics-infra: support
+ secrets: "{{ heapster_sa_secrets }}"
+ changed_when: no
+
+- name: Generate service for heapster
+ template: src=service.j2 dest={{mktemp.stdout}}/templates/metrics-{{obj_name}}-svc.yaml
+ vars:
+ obj_name: heapster
+ ports:
+ - {port: 80, targetPort: http-endpoint}
+ selector:
+ name: "{{obj_name}}"
+ labels:
+ metrics-infra: "{{obj_name}}"
+ name: "{{obj_name}}"
+ changed_when: no
+
+- name: generate cluster-reader role binding for the heapster service account
+ template:
+ src: rolebinding.j2
+ dest: "{{ mktemp.stdout }}/templates/heapster-rolebinding.yaml"
+ vars:
+ cluster: True
+ obj_name: heapster-cluster-reader
+ labels:
+ metrics-infra: heapster
+ roleRef:
+ kind: ClusterRole
+ name: cluster-reader
+ subjects:
+ - kind: ServiceAccount
+ name: heapster
+ namespace: "{{ openshift_metrics_project }}"
+ changed_when: no
+
+- include: generate_heapster_certificates.yaml
diff --git a/roles/openshift_metrics/tasks/install_metrics.yaml b/roles/openshift_metrics/tasks/install_metrics.yaml
index ddaa54438..66925c113 100644
--- a/roles/openshift_metrics/tasks/install_metrics.yaml
+++ b/roles/openshift_metrics/tasks/install_metrics.yaml
@@ -1,14 +1,5 @@
---
-- name: Check that hawkular_metrics_hostname is set
- fail: msg='the openshift_metrics_hawkular_hostname variable is required'
- when: openshift_metrics_hawkular_hostname is not defined
-
-- name: Check the value of openshift_metrics_cassandra_storage_type
- fail:
- msg: >
- openshift_metrics_cassandra_storage_type ({{ openshift_metrics_cassandra_storage_type }})
- is invalid, must be one of: emptydir, pv, dynamic
- when: openshift_metrics_cassandra_storage_type not in openshift_metrics_cassandra_storage_types
+- include: pre_install.yaml
- name: Install Metrics
include: "{{ role_path }}/tasks/install_{{ include_file }}.yaml"
@@ -19,6 +10,11 @@
- cassandra
loop_control:
loop_var: include_file
+ when: "not {{ openshift_metrics_heapster_standalone | bool }}"
+
+- name: Install Heapster Standalone
+ include: install_heapster.yaml
+ when: "{{ openshift_metrics_heapster_standalone | bool }}"
- find: paths={{ mktemp.stdout }}/templates patterns=*.yaml
register: object_def_files
diff --git a/roles/openshift_metrics/tasks/pre_install.yaml b/roles/openshift_metrics/tasks/pre_install.yaml
new file mode 100644
index 000000000..262acd546
--- /dev/null
+++ b/roles/openshift_metrics/tasks/pre_install.yaml
@@ -0,0 +1,27 @@
+---
+- name: Check that hawkular_metrics_hostname is set
+ fail: msg='the openshift_metrics_hawkular_hostname variable is required'
+ when: openshift_metrics_hawkular_hostname is not defined
+
+- name: Check the value of openshift_metrics_cassandra_storage_type
+ fail:
+ msg: >
+ openshift_metrics_cassandra_storage_type ({{ openshift_metrics_cassandra_storage_type }})
+ is invalid, must be one of: emptydir, pv, dynamic
+ when:
+ - openshift_metrics_cassandra_storage_type not in openshift_metrics_cassandra_storage_types
+ - "not {{ openshift_metrics_heapster_standalone | bool }}"
+
+- name: create certificate output directory
+ file:
+ path: "{{ openshift_metrics_certs_dir }}"
+ state: directory
+ mode: 0700
+
+- name: list existing secrets
+ command: >
+ {{ openshift.common.client_binary }} -n {{ openshift_metrics_project }}
+ --config={{ mktemp.stdout }}/admin.kubeconfig
+ get secrets -o name
+ register: metrics_secrets
+ changed_when: false
diff --git a/roles/openshift_metrics/tasks/start_metrics.yaml b/roles/openshift_metrics/tasks/start_metrics.yaml
index f02774e47..b5a1c8f06 100644
--- a/roles/openshift_metrics/tasks/start_metrics.yaml
+++ b/roles/openshift_metrics/tasks/start_metrics.yaml
@@ -19,6 +19,8 @@
with_items: "{{metrics_cassandra_rc.stdout_lines}}"
loop_control:
loop_var: object
+ when: metrics_cassandra_rc is defined
+ changed_when: "{{metrics_cassandra_rc | length > 0 }}"
- command: >
{{openshift.common.client_binary}}
@@ -40,6 +42,7 @@
with_items: "{{metrics_metrics_rc.stdout_lines}}"
loop_control:
loop_var: object
+ changed_when: "{{metrics_metrics_rc | length > 0 }}"
- command: >
{{openshift.common.client_binary}}
diff --git a/roles/openshift_metrics/tasks/stop_metrics.yaml b/roles/openshift_metrics/tasks/stop_metrics.yaml
index 5a73443a8..f69bb0f11 100644
--- a/roles/openshift_metrics/tasks/stop_metrics.yaml
+++ b/roles/openshift_metrics/tasks/stop_metrics.yaml
@@ -41,6 +41,7 @@
with_items: "{{metrics_hawkular_rc.stdout_lines}}"
loop_control:
loop_var: object
+ changed_when: "{{metrics_hawkular_rc | length > 0 }}"
- command: >
{{openshift.common.client_binary}} --config={{mktemp.stdout}}/admin.kubeconfig
@@ -62,3 +63,4 @@
loop_control:
loop_var: object
when: metrics_cassandra_rc is defined
+ changed_when: "{{metrics_cassandra_rc | length > 0 }}"
diff --git a/roles/openshift_metrics/templates/hawkular_cassandra_rc.j2 b/roles/openshift_metrics/templates/hawkular_cassandra_rc.j2
index 876cb1915..6f6efc469 100644
--- a/roles/openshift_metrics/templates/hawkular_cassandra_rc.j2
+++ b/roles/openshift_metrics/templates/hawkular_cassandra_rc.j2
@@ -124,7 +124,7 @@ spec:
emptyDir: {}
{% else %}
persistentVolumeClaim:
- claimName: "{{ openshift_metrics_cassandra_pv_prefix }}-{{ node }}"
+ claimName: "{{ openshift_metrics_cassandra_pvc_prefix }}-{{ node }}"
{% endif %}
- name: hawkular-cassandra-secrets
secret: