Browse Source

Adding oc_obj to the lib_openshift library

Kenny Woodson 8 years ago
parent
commit
2d122d692b

+ 18 - 6
roles/lib_openshift/library/oc_edit.py

@@ -764,14 +764,14 @@ class OpenShiftCLI(object):
         return {'returncode': 0, 'updated': False}
 
     def _replace(self, fname, force=False):
-        '''return all pods '''
+        '''replace the current object with oc replace'''
         cmd = ['-n', self.namespace, 'replace', '-f', fname]
         if force:
             cmd.append('--force')
         return self.openshift_cmd(cmd)
 
     def _create_from_content(self, rname, content):
-        '''return all pods '''
+        '''create a temporary file and then call oc create on it'''
         fname = '/tmp/%s' % rname
         yed = Yedit(fname, content=content)
         yed.write()
@@ -781,11 +781,11 @@ class OpenShiftCLI(object):
         return self._create(fname)
 
     def _create(self, fname):
-        '''return all pods '''
+        '''call oc create on a filename'''
         return self.openshift_cmd(['create', '-f', fname, '-n', self.namespace])
 
     def _delete(self, resource, rname, selector=None):
-        '''return all pods '''
+        '''call oc delete on a resource'''
         cmd = ['delete', resource, rname, '-n', self.namespace]
         if selector:
             cmd.append('--selector=%s' % selector)
@@ -793,7 +793,14 @@ class OpenShiftCLI(object):
         return self.openshift_cmd(cmd)
 
     def _process(self, template_name, create=False, params=None, template_data=None):  # noqa: E501
-        '''return all pods '''
+        '''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', '-n', self.namespace]
         if template_data:
             cmd.extend(['-f', '-'])
@@ -855,7 +862,12 @@ class OpenShiftCLI(object):
         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 manage-node evacuate '''
+        ''' 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)

File diff suppressed because it is too large
+ 1390 - 0
roles/lib_openshift/library/oc_obj.py


+ 18 - 6
roles/lib_openshift/library/oc_route.py

@@ -768,14 +768,14 @@ class OpenShiftCLI(object):
         return {'returncode': 0, 'updated': False}
 
     def _replace(self, fname, force=False):
-        '''return all pods '''
+        '''replace the current object with oc replace'''
         cmd = ['-n', self.namespace, 'replace', '-f', fname]
         if force:
             cmd.append('--force')
         return self.openshift_cmd(cmd)
 
     def _create_from_content(self, rname, content):
-        '''return all pods '''
+        '''create a temporary file and then call oc create on it'''
         fname = '/tmp/%s' % rname
         yed = Yedit(fname, content=content)
         yed.write()
@@ -785,11 +785,11 @@ class OpenShiftCLI(object):
         return self._create(fname)
 
     def _create(self, fname):
-        '''return all pods '''
+        '''call oc create on a filename'''
         return self.openshift_cmd(['create', '-f', fname, '-n', self.namespace])
 
     def _delete(self, resource, rname, selector=None):
-        '''return all pods '''
+        '''call oc delete on a resource'''
         cmd = ['delete', resource, rname, '-n', self.namespace]
         if selector:
             cmd.append('--selector=%s' % selector)
@@ -797,7 +797,14 @@ class OpenShiftCLI(object):
         return self.openshift_cmd(cmd)
 
     def _process(self, template_name, create=False, params=None, template_data=None):  # noqa: E501
-        '''return all pods '''
+        '''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', '-n', self.namespace]
         if template_data:
             cmd.extend(['-f', '-'])
@@ -859,7 +866,12 @@ class OpenShiftCLI(object):
         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 manage-node evacuate '''
+        ''' 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)

+ 37 - 0
roles/lib_openshift/src/ansible/oc_obj.py

@@ -0,0 +1,37 @@
+# pylint: skip-file
+# flake8: noqa
+
+# pylint: disable=too-many-branches
+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', 'absent', 'list']),
+            debug=dict(default=False, type='bool'),
+            namespace=dict(default='default', type='str'),
+            all_namespaces=dict(defaul=False, type='bool'),
+            name=dict(default=None, type='str'),
+            files=dict(default=None, type='list'),
+            kind=dict(required=True, type='str'),
+            delete_after=dict(default=False, type='bool'),
+            content=dict(default=None, type='dict'),
+            force=dict(default=False, type='bool'),
+            selector=dict(default=None, type='str'),
+        ),
+        mutually_exclusive=[["content", "files"]],
+
+        supports_check_mode=True,
+    )
+    rval = OCObject.run_ansible(module.params, module.check_mode)
+    if 'failed' in rval:
+        module.fail_json(**rval)
+
+    module.exit_json(**rval)
+
+if __name__ == '__main__':
+    main()

+ 193 - 0
roles/lib_openshift/src/class/oc_obj.py

@@ -0,0 +1,193 @@
+# pylint: skip-file
+# flake8: noqa
+
+# pylint: disable=too-many-instance-attributes
+class OCObject(OpenShiftCLI):
+    ''' Class to wrap the oc command line tools '''
+
+    # pylint allows 5. we need 6
+    # pylint: disable=too-many-arguments
+    def __init__(self,
+                 kind,
+                 namespace,
+                 rname=None,
+                 selector=None,
+                 kubeconfig='/etc/origin/master/admin.kubeconfig',
+                 verbose=False,
+                 all_namespaces=False):
+        ''' Constructor for OpenshiftOC '''
+        super(OCObject, self).__init__(namespace, kubeconfig,
+                                       all_namespaces=all_namespaces)
+        self.kind = kind
+        self.namespace = namespace
+        self.name = rname
+        self.selector = selector
+        self.kubeconfig = kubeconfig
+        self.verbose = verbose
+
+    def get(self):
+        '''return a kind by name '''
+        results = self._get(self.kind, rname=self.name, selector=self.selector)
+        if results['returncode'] != 0 and 'stderr' in results and \
+           '\"%s\" not found' % self.name in results['stderr']:
+            results['returncode'] = 0
+
+        return results
+
+    def delete(self):
+        '''return all pods '''
+        return self._delete(self.kind, self.name)
+
+    def create(self, files=None, content=None):
+        '''
+           Create a config
+
+           NOTE: This creates the first file OR the first conent.
+           TODO: Handle all files and content passed in
+        '''
+        if files:
+            return self._create(files[0])
+
+        content['data'] = yaml.dump(content['data'])
+        content_file = Utils.create_files_from_contents(content)[0]
+
+        return self._create(content_file['path'])
+
+    # pylint: disable=too-many-function-args
+    def update(self, files=None, content=None, force=False):
+        '''update a current openshift object
+
+           This receives a list of file names or content
+           and takes the first and calls replace.
+
+           TODO: take an entire list
+        '''
+        if files:
+            return self._replace(files[0], force)
+
+        if content and 'data' in content:
+            content = content['data']
+
+        return self.update_content(content, force)
+
+    def update_content(self, content, force=False):
+        '''update an object through using the content param'''
+        return self._replace_content(self.kind, self.name, content, force=force)
+
+    def needs_update(self, files=None, content=None, content_type='yaml'):
+        ''' check to see if we need to update '''
+        objects = self.get()
+        if objects['returncode'] != 0:
+            return objects
+
+        # pylint: disable=no-member
+        data = None
+        if files:
+            data = Utils.get_resource_file(files[0], content_type)
+        elif content and 'data' in content:
+            data = content['data']
+        else:
+            data = content
+
+            # if equal then no need.  So not equal is True
+        return not Utils.check_def_equal(data, objects['results'][0], skip_keys=None, debug=False)
+
+    # pylint: disable=too-many-return-statements,too-many-branches
+    @staticmethod
+    def run_ansible(params, check_mode=False):
+        '''perform the ansible idempotent code'''
+
+        ocobj = OCObject(params['kind'],
+                         params['namespace'],
+                         params['name'],
+                         params['selector'],
+                         kubeconfig=params['kubeconfig'],
+                         verbose=params['debug'],
+                         all_namespaces=params['all_namespaces'])
+
+        state = params['state']
+
+        api_rval = ocobj.get()
+
+        #####
+        # Get
+        #####
+        if state == 'list':
+            return {'changed': False, 'results': api_rval, 'state': 'list'}
+
+        if not params['name']:
+            return {'failed': True, 'msg': 'Please specify a name when state is absent|present.'}  # noqa: E501
+
+        ########
+        # Delete
+        ########
+        if state == 'absent':
+            if not Utils.exists(api_rval['results'], params['name']):
+                return {'changed': False, 'state': 'absent'}
+
+            if check_mode:
+                return {'changed': True, 'msg': 'CHECK_MODE: Would have performed a delete'}
+
+            api_rval = ocobj.delete()
+
+            return {'changed': True, 'results': api_rval, 'state': 'absent'}
+
+        if state == 'present':
+            ########
+            # Create
+            ########
+            if not Utils.exists(api_rval['results'], params['name']):
+
+                if check_mode:
+                    return {'changed': True, 'msg': 'CHECK_MODE: Would have performed a create'}
+
+                # Create it here
+                api_rval = ocobj.create(params['files'], params['content'])
+                if api_rval['returncode'] != 0:
+                    return {'failed': True, 'msg': api_rval}
+
+                # return the created object
+                api_rval = ocobj.get()
+
+                if api_rval['returncode'] != 0:
+                    return {'failed': True, 'msg': api_rval}
+
+                # Remove files
+                if params['files'] and params['delete_after']:
+                    Utils.cleanup(params['files'])
+
+                return {'changed': True, 'results': api_rval, 'state': "present"}
+
+            ########
+            # Update
+            ########
+            # if a file path is passed, use it.
+            update = ocobj.needs_update(params['files'], params['content'])
+            if not isinstance(update, bool):
+                return {'failed': True, 'msg': update}
+
+            # No changes
+            if not update:
+                if params['files'] and params['delete_after']:
+                    Utils.cleanup(params['files'])
+
+                return {'changed': False, 'results': api_rval['results'][0], 'state': "present"}
+
+            if check_mode:
+                return {'changed': True, 'msg': 'CHECK_MODE: Would have performed an update.'}
+
+            api_rval = ocobj.update(params['files'],
+                                    params['content'],
+                                    params['force'])
+
+
+            if api_rval['returncode'] != 0:
+                return {'failed': True, 'msg': api_rval}
+
+            # return the created object
+            api_rval = ocobj.get()
+
+            if api_rval['returncode'] != 0:
+                return {'failed': True, 'msg': api_rval}
+
+            return {'changed': True, 'results': api_rval, 'state': "present"}

+ 95 - 0
roles/lib_openshift/src/doc/obj

@@ -0,0 +1,95 @@
+# flake8: noqa
+# pylint: skip-file
+
+DOCUMENTATION = '''
+---
+module: oc_obj
+short_description: Generic interface to openshift objects
+description:
+  - Manage openshift objects programmatically.
+options:
+  state:
+    description:
+    - Currently present is only supported state.
+    required: true
+    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: []
+  name:
+    description:
+    - Name of the object that is being queried.
+    required: false
+    default: None
+    aliases: []
+  namespace:
+    description:
+    - The namespace where the object lives.
+    required: false
+    default: str
+    aliases: []
+  all_namespace:
+    description:
+    - The namespace where the object lives.
+    required: false
+    default: false
+    aliases: []
+  kind:
+    description:
+    - The kind attribute of the object. e.g. dc, bc, svc, route
+    required: True
+    default: None
+    aliases: []
+  files:
+    description:
+    - A list of files provided for object
+    required: false
+    default: None
+    aliases: []
+  delete_after:
+    description:
+    - Whether or not to delete the files after processing them.
+    required: false
+    default: false
+    aliases: []
+  content:
+    description:
+    - Content of the object being managed.
+    required: false
+    default: None
+    aliases: []
+  force:
+    description:
+    - Whether or not to force the operation
+    required: false
+    default: None
+    aliases: []
+  selector:
+    description:
+    - Selector that gets added to the query.
+    required: false
+    default: None
+    aliases: []
+author:
+- "Kenny Woodson <kwoodson@redhat.com>"
+extends_documentation_fragment: []
+'''
+
+EXAMPLES = '''
+oc_obj:
+  kind: dc
+  name: router
+  namespace: default
+register: router_output
+'''

+ 18 - 6
roles/lib_openshift/src/lib/base.py

@@ -47,14 +47,14 @@ class OpenShiftCLI(object):
         return {'returncode': 0, 'updated': False}
 
     def _replace(self, fname, force=False):
-        '''return all pods '''
+        '''replace the current object with oc replace'''
         cmd = ['-n', self.namespace, 'replace', '-f', fname]
         if force:
             cmd.append('--force')
         return self.openshift_cmd(cmd)
 
     def _create_from_content(self, rname, content):
-        '''return all pods '''
+        '''create a temporary file and then call oc create on it'''
         fname = '/tmp/%s' % rname
         yed = Yedit(fname, content=content)
         yed.write()
@@ -64,11 +64,11 @@ class OpenShiftCLI(object):
         return self._create(fname)
 
     def _create(self, fname):
-        '''return all pods '''
+        '''call oc create on a filename'''
         return self.openshift_cmd(['create', '-f', fname, '-n', self.namespace])
 
     def _delete(self, resource, rname, selector=None):
-        '''return all pods '''
+        '''call oc delete on a resource'''
         cmd = ['delete', resource, rname, '-n', self.namespace]
         if selector:
             cmd.append('--selector=%s' % selector)
@@ -76,7 +76,14 @@ class OpenShiftCLI(object):
         return self.openshift_cmd(cmd)
 
     def _process(self, template_name, create=False, params=None, template_data=None):  # noqa: E501
-        '''return all pods '''
+        '''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', '-n', self.namespace]
         if template_data:
             cmd.extend(['-f', '-'])
@@ -138,7 +145,12 @@ class OpenShiftCLI(object):
         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 manage-node evacuate '''
+        ''' 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)

+ 18 - 9
roles/lib_openshift/src/sources.yml

@@ -1,20 +1,29 @@
 ---
-oc_route.py:
+oc_edit.py:
 - doc/generated
 - doc/license
 - lib/import.py
-- doc/route
+- doc/edit
 - ../../lib_utils/src/class/yedit.py
 - lib/base.py
-- lib/route.py
-- class/oc_route.py
-- ansible/oc_route.py
-oc_edit.py:
+- class/oc_edit.py
+- ansible/oc_edit.py
+oc_obj.py:
 - doc/generated
 - doc/license
 - lib/import.py
-- doc/edit
+- doc/obj
 - ../../lib_utils/src/class/yedit.py
 - lib/base.py
-- class/oc_edit.py
-- ansible/oc_edit.py
+- class/oc_obj.py
+- ansible/oc_obj.py
+oc_route.py:
+- doc/generated
+- doc/license
+- lib/import.py
+- doc/route
+- ../../lib_utils/src/class/yedit.py
+- lib/base.py
+- lib/route.py
+- class/oc_route.py
+- ansible/oc_route.py