From fcf8e6f1af68797e4a54efb22a47095fc4e3bedf Mon Sep 17 00:00:00 2001 From: Kenny Woodson Date: Thu, 31 Mar 2016 16:29:20 -0400 Subject: Yedit enhancements --- roles/lib_openshift_api/build/ansible/edit.py | 77 +++++++++++++++++++++++++ roles/lib_openshift_api/build/generate.py | 12 +++- roles/lib_openshift_api/build/src/base.py | 55 ++++++++++++++---- roles/lib_openshift_api/build/src/edit.py | 49 ++++++++++++++++ roles/lib_openshift_api/build/test/edit.yml | 53 +++++++++++++++++ roles/lib_openshift_api/build/test/files/dc.yml | 9 ++- 6 files changed, 235 insertions(+), 20 deletions(-) create mode 100644 roles/lib_openshift_api/build/ansible/edit.py create mode 100644 roles/lib_openshift_api/build/src/edit.py create mode 100755 roles/lib_openshift_api/build/test/edit.yml (limited to 'roles/lib_openshift_api/build') diff --git a/roles/lib_openshift_api/build/ansible/edit.py b/roles/lib_openshift_api/build/ansible/edit.py new file mode 100644 index 000000000..d48bc7a01 --- /dev/null +++ b/roles/lib_openshift_api/build/ansible/edit.py @@ -0,0 +1,77 @@ +# pylint: skip-file + +def main(): + ''' + ansible oc module for services + ''' + + module = AnsibleModule( + argument_spec=dict( + kubeconfig=dict(default='/etc/origin/master/admin.kubeconfig', type='str'), + state=dict(default='present', type='str', + choices=['present']), + debug=dict(default=False, type='bool'), + namespace=dict(default='default', type='str'), + name=dict(default=None, type='str'), + kind=dict(required=True, + type='str', + choices=['dc', 'deploymentconfig', + 'svc', 'service', + 'secret', + ]), + file_name=dict(default=None, type='str'), + file_format=dict(default='yaml', type='str'), + content=dict(default=None, type='dict'), + force=dict(default=False, type='bool'), + ), + supports_check_mode=True, + ) + ocedit = Edit(module.params['kind'], + module.params['namespace'], + module.params['name'], + kubeconfig=module.params['kubeconfig'], + verbose=module.params['debug']) + + state = module.params['state'] + + api_rval = ocedit.get() + + ######## + # Create + ######## + if not Utils.exists(api_rval['results'], module.params['name']): + module.fail_json(msg=api_rval) + + ######## + # Update + ######## + api_rval = ocedit.update(module.params['file_name'], + module.params['content'], + module.params['force'], + module.params['file_format']) + + + if api_rval['returncode'] != 0: + module.fail_json(msg=api_rval) + + if api_rval.has_key('updated') and not api_rval['updated']: + module.exit_json(changed=False, results=api_rval, state="present") + + # return the created object + api_rval = ocedit.get() + + 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/build/generate.py b/roles/lib_openshift_api/build/generate.py index 877ca1766..cf3f61d2c 100755 --- a/roles/lib_openshift_api/build/generate.py +++ b/roles/lib_openshift_api/build/generate.py @@ -15,6 +15,7 @@ GEN_STR = "#!/usr/bin/env python\n" + \ "# | |) | (_) | | .` | (_) || | | _|| |) | | | |\n" + \ "# |___/ \___/ |_|\_|\___/ |_| |___|___/___| |_|\n" +OPENSHIFT_ANSIBLE_PATH = os.path.dirname(os.path.realpath(__file__)) FILES = {'oc_obj.py': ['src/base.py', @@ -27,18 +28,23 @@ FILES = {'oc_obj.py': ['src/base.py', 'src/secret.py', 'ansible/secret.py', ], + 'oc_edit.py': ['src/base.py', + '../../lib_yaml_editor/build/src/yedit.py', + 'src/edit.py', + 'ansible/edit.py', + ], } def main(): ''' combine the necessary files to create the ansible module ''' - openshift_ansible = ('../library/') + library = os.path.join(OPENSHIFT_ANSIBLE_PATH, '..', 'library/') for fname, parts in FILES.items(): - with open(os.path.join(openshift_ansible, fname), 'w') as afd: + with open(os.path.join(library, fname), 'w') as afd: afd.seek(0) afd.write(GEN_STR) for fpart in parts: - with open(fpart) as pfd: + with open(os.path.join(OPENSHIFT_ANSIBLE_PATH, fpart)) as pfd: # first line is pylint disable so skip it for idx, line in enumerate(pfd): if idx == 0 and 'skip-file' in line: diff --git a/roles/lib_openshift_api/build/src/base.py b/roles/lib_openshift_api/build/src/base.py index 31c102e5d..66831c4e2 100644 --- a/roles/lib_openshift_api/build/src/base.py +++ b/roles/lib_openshift_api/build/src/base.py @@ -8,7 +8,15 @@ import json import os import shutil import subprocess +import re + import yaml +# This is here because of a bug that causes yaml +# to incorrectly handle timezone info on timestamps +def timestamp_constructor(_, node): + '''return timestamps as strings''' + return str(node.value) +yaml.add_constructor(u'tag:yaml.org,2002:timestamp', timestamp_constructor) # pylint: disable=too-few-public-methods class OpenShiftCLI(object): @@ -32,8 +40,14 @@ class OpenShiftCLI(object): fname = '/tmp/%s' % rname yed = Yedit(fname, res['results'][0]) + changes = [] for key, value in content.items(): - yed.put(key, value) + changes.append(yed.put(key, value)) + + if any([not change[0] for change in changes]): + return {'returncode': 0, 'updated': False} + + yed.write() atexit.register(Utils.cleanup, [fname]) @@ -76,7 +90,9 @@ class OpenShiftCLI(object): cmds = ['/usr/bin/oc'] cmds.extend(cmd) + rval = {} results = '' + err = None if self.verbose: print ' '.join(cmds) @@ -85,27 +101,42 @@ class OpenShiftCLI(object): stdout=subprocess.PIPE, stderr=subprocess.PIPE, env={'KUBECONFIG': self.kubeconfig}) + proc.wait() + stdout = proc.stdout.read() + stderr = proc.stderr.read() + + rval = {"returncode": proc.returncode, + "results": results, + } + if proc.returncode == 0: if output: try: - results = json.loads(proc.stdout.read()) + rval['results'] = json.loads(stdout) except ValueError as err: if "No JSON object could be decoded" in err.message: - results = err.message + err = err.message if self.verbose: - print proc.stderr.read() - print results + print stdout + print stderr print - return {"returncode": proc.returncode, "results": results} + if err: + rval.update({"err": err, + "stderr": stderr, + "stdout": stdout, + "cmd": cmds + }) - return {"returncode": proc.returncode, - "stderr": proc.stderr.read(), - "stdout": proc.stdout.read(), - "results": {} - } + else: + rval.update({"stderr": stderr, + "stdout": stdout, + "results": {}, + }) + + return rval class Utils(object): ''' utilities for openshiftcli modules ''' @@ -179,7 +210,7 @@ class Utils(object): contents = sfd.read() if sfile_type == 'yaml': - contents = yaml.load(contents) + contents = yaml.safe_load(contents) elif sfile_type == 'json': contents = json.loads(contents) diff --git a/roles/lib_openshift_api/build/src/edit.py b/roles/lib_openshift_api/build/src/edit.py new file mode 100644 index 000000000..7020ace47 --- /dev/null +++ b/roles/lib_openshift_api/build/src/edit.py @@ -0,0 +1,49 @@ +# pylint: skip-file + +class Edit(OpenShiftCLI): + ''' Class to wrap the oc command line tools + ''' + # pylint: disable=too-many-arguments + def __init__(self, + kind, + namespace, + resource_name=None, + kubeconfig='/etc/origin/master/admin.kubeconfig', + verbose=False): + ''' Constructor for OpenshiftOC ''' + super(Edit, self).__init__(namespace, kubeconfig) + self.namespace = namespace + self.kind = kind + self.name = resource_name + self.kubeconfig = kubeconfig + self.verbose = verbose + + def get(self): + '''return a secret by name ''' + return self._get(self.kind, self.name) + + def update(self, file_name, content, force=False, content_type='yaml'): + '''run update ''' + if file_name: + if content_type == 'yaml': + data = yaml.load(open(file_name)) + elif content_type == 'json': + data = json.loads(open(file_name).read()) + + changes = [] + yed = Yedit(file_name, data) + for key, value in content.items(): + changes.append(yed.put(key, value)) + + if any([not change[0] for change in changes]): + return {'returncode': 0, 'updated': False} + + yed.write() + + atexit.register(Utils.cleanup, [file_name]) + + return self._replace(file_name, force=force) + + return self._replace_content(self.kind, self.name, content, force=force) + + diff --git a/roles/lib_openshift_api/build/test/edit.yml b/roles/lib_openshift_api/build/test/edit.yml new file mode 100755 index 000000000..9aa01303a --- /dev/null +++ b/roles/lib_openshift_api/build/test/edit.yml @@ -0,0 +1,53 @@ +#!/usr/bin/ansible-playbook +--- +- hosts: "oo_clusterid_mwoodson:&oo_version_3:&oo_master_primary" + gather_facts: no + user: root + + post_tasks: + - copy: + dest: "/tmp/{{ item }}" + src: "files/{{ item }}" + with_items: + - dc.yml + + - name: present dc + oc_edit: + kind: dc + namespace: default + name: router + content: + spec.template.spec.containers[0].ports[0].containerPort: 80 + spec.template.spec.containers[0].ports[0].hostPort: 80 + register: dcout + + - debug: + var: dcout + + - name: present dc + oc_edit: + kind: dc + namespace: default + name: router + content: + spec.template.spec.containers[0].ports[0].containerPort: 81 + spec.template.spec.containers[0].ports[0].hostPort: 81 + file_format: yaml + register: dcout + + - debug: + var: dcout + + - name: present dc + oc_edit: + kind: dc + namespace: default + name: router + content: + spec.template.spec.containers[0].ports[0].containerPort: 80 + spec.template.spec.containers[0].ports[0].hostPort: 80 + file_format: yaml + register: dcout + + - debug: + var: dcout diff --git a/roles/lib_openshift_api/build/test/files/dc.yml b/roles/lib_openshift_api/build/test/files/dc.yml index 7992c90dd..24f690ef4 100644 --- a/roles/lib_openshift_api/build/test/files/dc.yml +++ b/roles/lib_openshift_api/build/test/files/dc.yml @@ -1,14 +1,14 @@ apiVersion: v1 kind: DeploymentConfig metadata: - creationTimestamp: 2016-03-18T19:47:45Z + creationTimestamp: 2016-04-01T15:23:29Z labels: router: router name: router namespace: default - resourceVersion: "84016" + resourceVersion: "1338477" selfLink: /oapi/v1/namespaces/default/deploymentconfigs/router - uid: 48f8b9d9-ed42-11e5-9903-0a9a9d4e7f2b + uid: b00c7eba-f81d-11e5-809b-0a581f893e3f spec: replicas: 2 selector: @@ -117,5 +117,4 @@ status: details: causes: - type: ConfigChange - latestVersion: 1 - + latestVersion: 12 -- cgit v1.2.3