summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKenny Woodson <kwoodson@redhat.com>2016-03-24 16:18:51 -0400
committerKenny Woodson <kwoodson@redhat.com>2016-03-24 16:18:51 -0400
commit9c895c5e0ac2b0efa6b3357234ffc0fdb9aaeeb9 (patch)
tree8a8e1653684324fc4b9502542fdba509592e8ef6
parent7b0a4588a728a5eb5cbf7f80ff48f7f1d704238e (diff)
parente25f7c86d6c31e325cb2c1790e8f6049d05332d0 (diff)
downloadopenshift-9c895c5e0ac2b0efa6b3357234ffc0fdb9aaeeb9.tar.gz
openshift-9c895c5e0ac2b0efa6b3357234ffc0fdb9aaeeb9.tar.bz2
openshift-9c895c5e0ac2b0efa6b3357234ffc0fdb9aaeeb9.tar.xz
openshift-9c895c5e0ac2b0efa6b3357234ffc0fdb9aaeeb9.zip
Merge pull request #1664 from kwoodson/api_dc
Deployment config module
-rw-r--r--roles/lib_openshift_api/library/oc_deploymentconfig.py377
-rw-r--r--roles/lib_openshift_api/library/oc_secret.py85
-rw-r--r--roles/lib_openshift_api/library/oc_service.py96
3 files changed, 490 insertions, 68 deletions
diff --git a/roles/lib_openshift_api/library/oc_deploymentconfig.py b/roles/lib_openshift_api/library/oc_deploymentconfig.py
new file mode 100644
index 000000000..fbdaa8e9c
--- /dev/null
+++ b/roles/lib_openshift_api/library/oc_deploymentconfig.py
@@ -0,0 +1,377 @@
+#!/usr/bin/env python
+'''
+ OpenShiftCLI class that wraps the oc commands in a subprocess
+'''
+import atexit
+import json
+import os
+import shutil
+import subprocess
+import yaml
+
+class OpenShiftCLI(object):
+ ''' Class to wrap the oc command line tools '''
+ def __init__(self,
+ namespace,
+ kubeconfig='/etc/origin/master/admin.kubeconfig',
+ verbose=False):
+ ''' Constructor for OpenshiftOC '''
+ self.namespace = namespace
+ self.verbose = verbose
+ self.kubeconfig = kubeconfig
+
+ def replace(self, fname, force=False):
+ '''return all pods '''
+ cmd = ['replace', '-f', fname]
+ if force:
+ cmd = ['replace', '--force', '-f', fname]
+ return self.oc_cmd(cmd)
+
+ def create(self, fname):
+ '''return all pods '''
+ return self.oc_cmd(['create', '-f', fname, '-n', self.namespace])
+
+ def delete(self, resource, rname):
+ '''return all pods '''
+ return self.oc_cmd(['delete', resource, rname, '-n', self.namespace])
+
+ def get(self, resource, rname=None):
+ '''return a secret by name '''
+ cmd = ['get', resource, '-o', 'json', '-n', self.namespace]
+ if rname:
+ cmd.append(rname)
+
+ rval = self.oc_cmd(cmd, output=True)
+
+ # Ensure results are retuned in an array
+ if rval.has_key('items'):
+ rval['results'] = rval['items']
+ elif not isinstance(rval['results'], list):
+ rval['results'] = [rval['results']]
+
+ return rval
+
+ def oc_cmd(self, cmd, output=False):
+ '''Base command for oc '''
+ #cmds = ['/usr/bin/oc', '--config', self.kubeconfig]
+ cmds = ['/usr/bin/oc']
+ cmds.extend(cmd)
+
+ results = ''
+
+ if self.verbose:
+ print ' '.join(cmds)
+
+ proc = subprocess.Popen(cmds,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ env={'KUBECONFIG': self.kubeconfig})
+ proc.wait()
+ if proc.returncode == 0:
+ if output:
+ try:
+ results = json.loads(proc.stdout.read())
+ except ValueError as err:
+ if "No JSON object could be decoded" in err.message:
+ results = err.message
+
+ if self.verbose:
+ print proc.stderr.read()
+ print results
+ print
+
+ return {"returncode": proc.returncode, "results": results}
+
+ return {"returncode": proc.returncode,
+ "stderr": proc.stderr.read(),
+ "stdout": proc.stdout.read(),
+ "results": {}
+ }
+
+class Utils(object):
+ ''' utilities for openshiftcli modules '''
+ @staticmethod
+ def create_file(rname, data, ftype=None):
+ ''' 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, default_flow_style=False))
+
+ elif ftype == 'json':
+ fds.write(json.dumps(data))
+ else:
+ fds.write(data)
+
+ # Register cleanup when module is done
+ atexit.register(Utils.cleanup, [path])
+ return path
+
+ @staticmethod
+ def create_files_from_contents(data):
+ '''Turn an array of dict: filename, content into a files array'''
+ files = []
+
+ for sfile in data:
+ path = Utils.create_file(sfile['path'], sfile['content'])
+ files.append(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 result.has_key('metadata') 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)
+ elif sfile_type == 'json':
+ contents = json.loads(contents)
+
+ return contents
+
+ # Disabling too-many-branches. This is a yaml dictionary comparison function
+ # pylint: disable=too-many-branches,too-many-return-statements
+ @staticmethod
+ def check_def_equal(user_def, result_def, 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 = ['creationTimestamp', 'selfLink', 'resourceVersion', 'uid', 'namespace']
+
+ for key, value in result_def.items():
+ if key in skip:
+ continue
+
+ # Both are lists
+ if isinstance(value, list):
+ if not isinstance(user_def[key], list):
+ return False
+
+ # lists should be identical
+ if value != user_def[key]:
+ return False
+
+ # recurse on a dictionary
+ elif isinstance(value, dict):
+ 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 api_values
+ print user_values
+ print "keys are not equal in dict"
+ return False
+
+ result = Utils.check_def_equal(user_def[key], value, debug=debug)
+ if not result:
+ if debug:
+ print "dict returned false"
+ return False
+
+ # Verify each key, value pair is the same
+ else:
+ if not user_def.has_key(key) or value != user_def[key]:
+ if debug:
+ print "value not equal; user_def does not have key"
+ print value
+ print user_def[key]
+ return False
+
+ return True
+
+class DeploymentConfig(OpenShiftCLI):
+ ''' Class to wrap the oc command line tools
+ '''
+ def __init__(self,
+ namespace,
+ dname=None,
+ kubeconfig='/etc/origin/master/admin.kubeconfig',
+ verbose=False):
+ ''' Constructor for OpenshiftOC '''
+ super(DeploymentConfig, self).__init__(namespace, kubeconfig)
+ self.namespace = namespace
+ self.name = dname
+ self.kubeconfig = kubeconfig
+ self.verbose = verbose
+
+ def get_dc(self):
+ '''return a deploymentconfig by name '''
+ return self.get('dc', self.name)
+
+ def delete_dc(self):
+ '''return all pods '''
+ return self.delete('dc', self.name)
+
+ def new_dc(self, dfile):
+ '''Create a deploymentconfig '''
+ return self.create(dfile)
+
+ def update_dc(self, dfile, force=False):
+ '''run update dc
+
+ This receives a list of file names and takes the first filename and calls replace.
+ '''
+ return self.replace(dfile, force)
+
+
+# pylint: disable=too-many-branches
+def main():
+ '''
+ ansible oc module for deploymentconfig
+ '''
+
+ module = AnsibleModule(
+ argument_spec=dict(
+ kubeconfig=dict(default='/etc/origin/master/admin.kubeconfig', type='str'),
+ state=dict(default='present', type='str',
+ choices=['present', 'absent', 'list']),
+ debug=dict(default=False, type='bool'),
+ namespace=dict(default='default', type='str'),
+ name=dict(default=None, type='str'),
+ deploymentconfig_file=dict(default=None, type='str'),
+ input_type=dict(default='yaml', choices=['yaml', 'json'], type='str'),
+ delete_after=dict(default=False, type='bool'),
+ content=dict(default=None, type='dict'),
+ force=dict(default=False, type='bool'),
+ ),
+ mutually_exclusive=[["contents", "deploymentconfig_file"]],
+
+ supports_check_mode=True,
+ )
+ occmd = DeploymentConfig(module.params['namespace'],
+ dname=module.params['name'],
+ kubeconfig=module.params['kubeconfig'],
+ verbose=module.params['debug'])
+
+ state = module.params['state']
+
+ api_rval = occmd.get_dc()
+
+ #####
+ # Get
+ #####
+ if state == 'list':
+ module.exit_json(changed=False, results=api_rval['results'], state="list")
+
+ if not module.params['name']:
+ module.fail_json(msg='Please specify a name when state is absent|present.')
+ ########
+ # Delete
+ ########
+ if state == 'absent':
+ if not Utils.exists(api_rval['results'], module.params['name']):
+ module.exit_json(changed=False, state="absent")
+
+ if module.check_mode:
+ module.exit_json(change=False, msg='Would have performed a delete.')
+
+ api_rval = occmd.delete_dc()
+ module.exit_json(changed=True, results=api_rval, state="absent")
+
+
+ if state == 'present':
+ if module.params['deploymentconfig_file']:
+ dfile = module.params['deploymentconfig_file']
+ elif module.params['content']:
+ dfile = Utils.create_file('dc', module.params['content'])
+ else:
+ module.fail_json(msg="Please specify content or deploymentconfig file.")
+
+ ########
+ # Create
+ ########
+ if not Utils.exists(api_rval['results'], module.params['name']):
+
+ if module.check_mode:
+ module.exit_json(change=False, msg='Would have performed a create.')
+
+ api_rval = occmd.new_dc(dfile)
+
+ # Remove files
+ if module.params['deploymentconfig_file'] and module.params['delete_after']:
+ Utils.cleanup([dfile])
+
+ if api_rval['returncode'] != 0:
+ module.fail_json(msg=api_rval)
+
+ module.exit_json(changed=True, results=api_rval, state="present")
+
+ ########
+ # Update
+ ########
+ if Utils.check_def_equal(Utils.get_resource_file(dfile), api_rval['results'][0]):
+
+ # Remove files
+ if module.params['deploymentconfig_file'] and module.params['delete_after']:
+ Utils.cleanup([dfile])
+
+ module.exit_json(changed=False, results=api_rval['results'], state="present")
+
+ if module.check_mode:
+ module.exit_json(change=False, msg='Would have performed an update.')
+
+ api_rval = occmd.update_dc(dfile, force=module.params['force'])
+
+ # Remove files
+ if module.params['deploymentconfig_file'] and module.params['delete_after']:
+ Utils.cleanup([dfile])
+
+ if api_rval['returncode'] != 0:
+ module.fail_json(msg=api_rval)
+
+
+ module.exit_json(changed=True, results=api_rval, state="present")
+
+ module.exit_json(failed=True,
+ changed=False,
+ results='Unknown state passed. %s' % state,
+ state="unknown")
+
+# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, locally-disabled
+# import module snippets. This are required
+from ansible.module_utils.basic import *
+
+main()
diff --git a/roles/lib_openshift_api/library/oc_secret.py b/roles/lib_openshift_api/library/oc_secret.py
index d69d490ac..96a0f1db1 100644
--- a/roles/lib_openshift_api/library/oc_secret.py
+++ b/roles/lib_openshift_api/library/oc_secret.py
@@ -9,9 +9,6 @@ import shutil
import subprocess
import yaml
-# The base class is here to share methods.
-# Currently there is only 1 but will grow in the future.
-# pylint: disable=too-few-public-methods
class OpenShiftCLI(object):
''' Class to wrap the oc command line tools '''
def __init__(self,
@@ -23,6 +20,37 @@ class OpenShiftCLI(object):
self.verbose = verbose
self.kubeconfig = kubeconfig
+ def replace(self, fname, force=False):
+ '''return all pods '''
+ cmd = ['replace', '-f', fname]
+ if force:
+ cmd = ['replace', '--force', '-f', fname]
+ return self.oc_cmd(cmd)
+
+ def create(self, fname):
+ '''return all pods '''
+ return self.oc_cmd(['create', '-f', fname, '-n', self.namespace])
+
+ def delete(self, resource, rname):
+ '''return all pods '''
+ return self.oc_cmd(['delete', resource, rname, '-n', self.namespace])
+
+ def get(self, resource, rname=None):
+ '''return a secret by name '''
+ cmd = ['get', resource, '-o', 'json', '-n', self.namespace]
+ if rname:
+ cmd.append(rname)
+
+ rval = self.oc_cmd(cmd, output=True)
+
+ # Ensure results are retuned in an array
+ if rval.has_key('items'):
+ rval['results'] = rval['items']
+ elif not isinstance(rval['results'], list):
+ rval['results'] = [rval['results']]
+
+ return rval
+
def oc_cmd(self, cmd, output=False):
'''Base command for oc '''
#cmds = ['/usr/bin/oc', '--config', self.kubeconfig]
@@ -63,21 +91,33 @@ class OpenShiftCLI(object):
class Utils(object):
''' utilities for openshiftcli modules '''
@staticmethod
+ def create_file(rname, data, ftype=None):
+ ''' 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, default_flow_style=False))
+
+ elif ftype == 'json':
+ fds.write(json.dumps(data))
+ else:
+ fds.write(data)
+
+ # Register cleanup when module is done
+ atexit.register(Utils.cleanup, [path])
+ return path
+
+ @staticmethod
def create_files_from_contents(data):
'''Turn an array of dict: filename, content into a files array'''
files = []
for sfile in data:
- path = os.path.join('/tmp', sfile['path'])
- with open(path, 'w') as fds:
- fds.write(sfile['content'])
+ path = Utils.create_file(sfile['path'], sfile['content'])
files.append(path)
- # Register cleanup when module is done
- atexit.register(Utils.cleanup, files)
return files
-
@staticmethod
def cleanup(files):
'''Clean up on exit '''
@@ -106,7 +146,6 @@ class Utils(object):
''' Find the specified result by name'''
rval = None
for result in results:
- #print "%s == %s" % (result['metadata']['name'], name)
if result.has_key('metadata') and result['metadata']['name'] == _name:
rval = result
break
@@ -166,7 +205,7 @@ class Utils(object):
print "keys are not equal in dict"
return False
- result = Utils.check_def_equal(user_def[key], value)
+ result = Utils.check_def_equal(user_def[key], value, debug=debug)
if not result:
if debug:
print "dict returned false"
@@ -192,7 +231,7 @@ class Secret(OpenShiftCLI):
kubeconfig='/etc/origin/master/admin.kubeconfig',
verbose=False):
''' Constructor for OpenshiftOC '''
- super(Secret, OpenShiftCLI).__init__(namespace, kubeconfig)
+ super(Secret, self).__init__(namespace, kubeconfig)
self.namespace = namespace
self.name = secret_name
self.kubeconfig = kubeconfig
@@ -200,23 +239,11 @@ class Secret(OpenShiftCLI):
def get_secrets(self):
'''return a secret by name '''
- cmd = ['get', 'secrets', '-o', 'json', '-n', self.namespace]
- if self.name:
- cmd.append(self.name)
-
- rval = self.oc_cmd(cmd, output=True)
-
- # Ensure results are retuned in an array
- if rval.has_key('items'):
- rval['results'] = rval['items']
- elif not isinstance(rval['results'], list):
- rval['results'] = [rval['results']]
-
- return rval
+ return self.get('secrets', self.name)
def delete_secret(self):
'''return all pods '''
- return self.oc_cmd(['delete', 'secrets', self.name, '-n', self.namespace])
+ return self.delete('secrets', self.name)
def secret_new(self, files=None, contents=None):
'''Create a secret with all pods '''
@@ -243,13 +270,9 @@ class Secret(OpenShiftCLI):
with open(sfile_path, 'w') as sfd:
sfd.write(json.dumps(secret['results']))
- cmd = ['replace', '-f', sfile_path]
- if force:
- cmd = ['replace', '--force', '-f', sfile_path]
-
atexit.register(Utils.cleanup, [sfile_path])
- return self.oc_cmd(cmd)
+ return self.replace(sfile_path, force=force)
def prep_secret(self, files=None, contents=None):
''' return what the secret would look like if created
diff --git a/roles/lib_openshift_api/library/oc_service.py b/roles/lib_openshift_api/library/oc_service.py
index 48281f254..e7bd2514e 100644
--- a/roles/lib_openshift_api/library/oc_service.py
+++ b/roles/lib_openshift_api/library/oc_service.py
@@ -9,9 +9,6 @@ import shutil
import subprocess
import yaml
-# The base class is here to share methods.
-# Currently there is only 1 but will grow in the future.
-# pylint: disable=too-few-public-methods
class OpenShiftCLI(object):
''' Class to wrap the oc command line tools '''
def __init__(self,
@@ -23,6 +20,37 @@ class OpenShiftCLI(object):
self.verbose = verbose
self.kubeconfig = kubeconfig
+ def replace(self, fname, force=False):
+ '''return all pods '''
+ cmd = ['replace', '-f', fname]
+ if force:
+ cmd = ['replace', '--force', '-f', fname]
+ return self.oc_cmd(cmd)
+
+ def create(self, fname):
+ '''return all pods '''
+ return self.oc_cmd(['create', '-f', fname, '-n', self.namespace])
+
+ def delete(self, resource, rname):
+ '''return all pods '''
+ return self.oc_cmd(['delete', resource, rname, '-n', self.namespace])
+
+ def get(self, resource, rname=None):
+ '''return a secret by name '''
+ cmd = ['get', resource, '-o', 'json', '-n', self.namespace]
+ if rname:
+ cmd.append(rname)
+
+ rval = self.oc_cmd(cmd, output=True)
+
+ # Ensure results are retuned in an array
+ if rval.has_key('items'):
+ rval['results'] = rval['items']
+ elif not isinstance(rval['results'], list):
+ rval['results'] = [rval['results']]
+
+ return rval
+
def oc_cmd(self, cmd, output=False):
'''Base command for oc '''
#cmds = ['/usr/bin/oc', '--config', self.kubeconfig]
@@ -63,21 +91,33 @@ class OpenShiftCLI(object):
class Utils(object):
''' utilities for openshiftcli modules '''
@staticmethod
+ def create_file(rname, data, ftype=None):
+ ''' 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, default_flow_style=False))
+
+ elif ftype == 'json':
+ fds.write(json.dumps(data))
+ else:
+ fds.write(data)
+
+ # Register cleanup when module is done
+ atexit.register(Utils.cleanup, [path])
+ return path
+
+ @staticmethod
def create_files_from_contents(data):
'''Turn an array of dict: filename, content into a files array'''
files = []
for sfile in data:
- path = os.path.join('/tmp', sfile['path'])
- with open(path, 'w') as fds:
- fds.write(sfile['content'])
+ path = Utils.create_file(sfile['path'], sfile['content'])
files.append(path)
- # Register cleanup when module is done
- atexit.register(Utils.cleanup, files)
return files
-
@staticmethod
def cleanup(files):
'''Clean up on exit '''
@@ -106,7 +146,6 @@ class Utils(object):
''' Find the specified result by name'''
rval = None
for result in results:
- #print "%s == %s" % (result['metadata']['name'], name)
if result.has_key('metadata') and result['metadata']['name'] == _name:
rval = result
break
@@ -166,7 +205,7 @@ class Utils(object):
print "keys are not equal in dict"
return False
- result = Utils.check_def_equal(user_def[key], value)
+ result = Utils.check_def_equal(user_def[key], value, debug=debug)
if not result:
if debug:
print "dict returned false"
@@ -192,7 +231,7 @@ class Service(OpenShiftCLI):
kubeconfig='/etc/origin/master/admin.kubeconfig',
verbose=False):
''' Constructor for OpenshiftOC '''
- super(Service, OpenShiftCLI).__init__(namespace, kubeconfig)
+ super(Service, self).__init__(namespace, kubeconfig)
self.namespace = namespace
self.name = service_name
self.verbose = verbose
@@ -200,27 +239,15 @@ class Service(OpenShiftCLI):
def create_service(self, sfile):
''' create the service '''
- return self.oc_cmd(['create', '-f', sfile])
+ return self.create(sfile)
def get_services(self):
'''return a secret by name '''
- cmd = ['get', 'services', '-o', 'json', '-n', self.namespace]
- if self.name:
- cmd.append(self.name)
-
- rval = self.oc_cmd(cmd, output=True)
-
- # Ensure results are retuned in an array
- if rval.has_key('items'):
- rval['results'] = rval['items']
- elif not isinstance(rval['results'], list):
- rval['results'] = [rval['results']]
-
- return rval
+ return self.get('services', self.name)
def delete_service(self):
'''return all pods '''
- return self.oc_cmd(['delete', 'service', self.name, '-n', self.namespace])
+ return self.delete('service', self.name)
def update_service(self, sfile, force=False):
'''run update service
@@ -228,14 +255,7 @@ class Service(OpenShiftCLI):
This receives a list of file names and converts it into a secret.
The secret is then written to disk and passed into the `oc replace` command.
'''
-
- cmd = ['replace', '-f', sfile]
- if force:
- cmd = ['replace', '--force', '-f', sfile]
-
- atexit.register(Utils.cleanup, [sfile])
-
- return self.oc_cmd(cmd)
+ return self.replace(sfile, force=force)
# pylint: disable=too-many-branches
@@ -253,7 +273,9 @@ def main():
namespace=dict(default='default', type='str'),
name=dict(default=None, type='str'),
service_file=dict(default=None, type='str'),
- service_file_type=dict(default=None, type='str'),
+ input_type=dict(default='yaml',
+ choices=['json', 'yaml'],
+ type='str'),
delete_after=dict(default=False, type='bool'),
contents=dict(default=None, type='list'),
force=dict(default=False, type='bool'),
@@ -320,7 +342,7 @@ def main():
########
# Update
########
- sfile_contents = Utils.get_resource_file(sfile, module.params['service_file_type'])
+ sfile_contents = Utils.get_resource_file(sfile, module.params['input_type'])
if Utils.check_def_equal(sfile_contents, api_rval['results'][0]):
# Remove files