oc_obj.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. # pylint: skip-file
  2. # flake8: noqa
  3. # pylint: disable=too-many-instance-attributes
  4. class OCObject(OpenShiftCLI):
  5. ''' Class to wrap the oc command line tools '''
  6. # pylint allows 5. we need 6
  7. # pylint: disable=too-many-arguments
  8. def __init__(self,
  9. kind,
  10. namespace,
  11. name=None,
  12. selector=None,
  13. kubeconfig='/etc/origin/master/admin.kubeconfig',
  14. verbose=False,
  15. all_namespaces=False,
  16. field_selector=None):
  17. ''' Constructor for OpenshiftOC '''
  18. super(OCObject, self).__init__(namespace, kubeconfig=kubeconfig, verbose=verbose,
  19. all_namespaces=all_namespaces)
  20. self.kind = kind
  21. self.name = name
  22. self.selector = selector
  23. self.field_selector = field_selector
  24. def get(self):
  25. '''return a kind by name '''
  26. results = self._get(self.kind, name=self.name, selector=self.selector, field_selector=self.field_selector)
  27. if (results['returncode'] != 0 and 'stderr' in results and
  28. '\"{}\" not found'.format(self.name) in results['stderr']):
  29. results['returncode'] = 0
  30. return results
  31. def delete(self):
  32. '''delete the object'''
  33. results = self._delete(self.kind, name=self.name, selector=self.selector)
  34. if (results['returncode'] != 0 and 'stderr' in results and
  35. '\"{}\" not found'.format(self.name) in results['stderr']):
  36. results['returncode'] = 0
  37. return results
  38. def create(self, files=None, content=None):
  39. '''
  40. Create a config
  41. NOTE: This creates the first file OR the first conent.
  42. TODO: Handle all files and content passed in
  43. '''
  44. if files:
  45. return self._create(files[0])
  46. # pylint: disable=no-member
  47. # The purpose of this change is twofold:
  48. # - we need a check to only use the ruamel specific dumper if ruamel is loaded
  49. # - the dumper or the flow style change is needed so openshift is able to parse
  50. # the resulting yaml, at least until gopkg.in/yaml.v2 is updated
  51. if hasattr(yaml, 'RoundTripDumper'):
  52. content['data'] = yaml.dump(content['data'], Dumper=yaml.RoundTripDumper)
  53. else:
  54. content['data'] = yaml.safe_dump(content['data'], default_flow_style=False)
  55. content_file = Utils.create_tmp_files_from_contents(content)[0]
  56. return self._create(content_file['path'])
  57. # pylint: disable=too-many-function-args
  58. def update(self, files=None, content=None, force=False):
  59. '''update a current openshift object
  60. This receives a list of file names or content
  61. and takes the first and calls replace.
  62. TODO: take an entire list
  63. '''
  64. if files:
  65. return self._replace(files[0], force)
  66. if content and 'data' in content:
  67. content = content['data']
  68. return self.update_content(content, force)
  69. def update_content(self, content, force=False):
  70. '''update an object through using the content param'''
  71. return self._replace_content(self.kind, self.name, content, force=force)
  72. def needs_update(self, files=None, content=None, content_type='yaml'):
  73. ''' check to see if we need to update '''
  74. objects = self.get()
  75. if objects['returncode'] != 0:
  76. return objects
  77. data = None
  78. if files:
  79. data = Utils.get_resource_file(files[0], content_type)
  80. elif content and 'data' in content:
  81. data = content['data']
  82. else:
  83. data = content
  84. # if equal then no need. So not equal is True
  85. return not Utils.check_def_equal(data, objects['results'][0], skip_keys=None, debug=False)
  86. # pylint: disable=too-many-return-statements,too-many-branches
  87. @staticmethod
  88. def run_ansible(params, check_mode=False):
  89. '''perform the ansible idempotent code'''
  90. ocobj = OCObject(params['kind'],
  91. params['namespace'],
  92. params['name'],
  93. params['selector'],
  94. kubeconfig=params['kubeconfig'],
  95. verbose=params['debug'],
  96. all_namespaces=params['all_namespaces'],
  97. field_selector=params['field_selector'])
  98. state = params['state']
  99. api_rval = ocobj.get()
  100. #####
  101. # Get
  102. #####
  103. if state == 'list':
  104. if api_rval['returncode'] != 0:
  105. return {'changed': False, 'failed': True, 'msg': api_rval}
  106. return {'changed': False, 'results': api_rval, 'state': state}
  107. ########
  108. # Delete
  109. ########
  110. if state == 'absent':
  111. # verify its not in our results
  112. if (params['name'] is not None or params['selector'] is not None) and \
  113. (len(api_rval['results']) == 0 or \
  114. ('items' in api_rval['results'][0] and len(api_rval['results'][0]['items']) == 0)):
  115. return {'changed': False, 'state': state}
  116. if check_mode:
  117. return {'changed': True, 'msg': 'CHECK_MODE: Would have performed a delete'}
  118. api_rval = ocobj.delete()
  119. if api_rval['returncode'] != 0:
  120. return {'failed': True, 'msg': api_rval}
  121. return {'changed': True, 'results': api_rval, 'state': state}
  122. # create/update: Must define a name beyond this point
  123. if not params['name']:
  124. return {'failed': True, 'msg': 'Please specify a name when state is present.'}
  125. if state == 'present':
  126. ########
  127. # Create
  128. ########
  129. if not Utils.exists(api_rval['results'], params['name']):
  130. if check_mode:
  131. return {'changed': True, 'msg': 'CHECK_MODE: Would have performed a create'}
  132. # Create it here
  133. api_rval = ocobj.create(params['files'], params['content'])
  134. if api_rval['returncode'] != 0:
  135. return {'failed': True, 'msg': api_rval}
  136. # return the created object
  137. api_rval = ocobj.get()
  138. if api_rval['returncode'] != 0:
  139. return {'failed': True, 'msg': api_rval}
  140. # Remove files
  141. if params['files'] and params['delete_after']:
  142. Utils.cleanup(params['files'])
  143. return {'changed': True, 'results': api_rval, 'state': state}
  144. ########
  145. # Update
  146. ########
  147. # if a file path is passed, use it.
  148. update = ocobj.needs_update(params['files'], params['content'])
  149. if not isinstance(update, bool):
  150. return {'failed': True, 'msg': update}
  151. # No changes
  152. if not update:
  153. if params['files'] and params['delete_after']:
  154. Utils.cleanup(params['files'])
  155. return {'changed': False, 'results': api_rval['results'][0], 'state': state}
  156. if check_mode:
  157. return {'changed': True, 'msg': 'CHECK_MODE: Would have performed an update.'}
  158. api_rval = ocobj.update(params['files'],
  159. params['content'],
  160. params['force'])
  161. if api_rval['returncode'] != 0:
  162. return {'failed': True, 'msg': api_rval}
  163. # return the created object
  164. api_rval = ocobj.get()
  165. if api_rval['returncode'] != 0:
  166. return {'failed': True, 'msg': api_rval}
  167. return {'changed': True, 'results': api_rval, 'state': state}