You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

309 lines
8.0 KiB

9 years ago
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. DOCUMENTATION = """
  4. ---
  5. module: kube
  6. short_description: Manage Kubernetes Cluster
  7. description:
  8. - Create, replace, remove, and stop resources within a Kubernetes Cluster
  9. version_added: "2.0"
  10. options:
  11. name:
  12. required: false
  13. default: null
  14. description:
  15. - The name associated with resource
  16. filename:
  17. required: false
  18. default: null
  19. description:
  20. - The path and filename of the resource(s) definition file.
  21. namespace:
  22. required: false
  23. default: null
  24. description:
  25. - The namespace associated with the resource(s)
  26. resource:
  27. required: false
  28. default: null
  29. description:
  30. - The resource to perform an action on. pods (po), replicationControllers (rc), services (svc)
  31. label:
  32. required: false
  33. default: null
  34. description:
  35. - The labels used to filter specific resources.
  36. server:
  37. required: false
  38. default: null
  39. description:
  40. - The url for the API server that commands are executed against.
  41. api_version:
  42. required: false
  43. choices: ['v1', 'v1beta3']
  44. default: v1
  45. description:
  46. - The API version associated with cluster.
  47. force:
  48. required: false
  49. default: false
  50. description:
  51. - A flag to indicate to force delete, replace, or stop.
  52. all:
  53. required: false
  54. default: false
  55. description:
  56. - A flag to indicate delete all, stop all, or all namespaces when checking exists.
  57. log_level:
  58. required: false
  59. default: 0
  60. description:
  61. - Indicates the level of verbosity of logging by kubectl.
  62. state:
  63. required: false
  64. choices: ['present', 'absent', 'latest', 'reloaded', 'stopped']
  65. default: present
  66. description:
  67. - present handles checking existence or creating if definition file provided,
  68. absent handles deleting resource(s) based on other options,
  69. latest handles creating ore updating based on existence,
  70. reloaded handles updating resource(s) definition using definition file,
  71. stopped handles stopping resource(s) based on other options.
  72. requirements:
  73. - kubectl
  74. author: "Kenny Jones (@kenjones-cisco)"
  75. """
  76. EXAMPLES = """
  77. - name: test nginx is present
  78. kube: name=nginx resource=rc state=present
  79. - name: test nginx is stopped
  80. kube: name=nginx resource=rc state=stopped
  81. - name: test nginx is absent
  82. kube: name=nginx resource=rc state=absent
  83. - name: test nginx is present
  84. kube: filename=/tmp/nginx.yml
  85. """
  86. class KubeManager(object):
  87. def __init__(self, module):
  88. self.module = module
  89. self.base_cmd = [module.get_bin_path('kubectl', True)]
  90. self.api_version = module.params.get('api_version')
  91. if self.api_version:
  92. self.base_cmd.append('--api-version=' + self.api_version)
  93. if module.params.get('server'):
  94. self.base_cmd.append('--server=' + module.params.get('server'))
  95. if module.params.get('log_level'):
  96. self.base_cmd.append('--v=' + str(module.params.get('log_level')))
  97. if module.params.get('namespace'):
  98. self.base_cmd.append('--namespace=' + module.params.get('namespace'))
  99. self.all = module.params.get('all')
  100. self.force = module.params.get('force')
  101. self.name = module.params.get('name')
  102. self.filename = module.params.get('filename')
  103. self.resource = module.params.get('resource')
  104. self.label = module.params.get('label')
  105. def _execute(self, cmd):
  106. args = self.base_cmd + cmd
  107. try:
  108. rc, out, err = self.module.run_command(args)
  109. if rc != 0:
  110. self.module.fail_json(
  111. msg='error running kubectl (%s) command (rc=%d): %s' % (' '.join(args), rc, out or err))
  112. except Exception as exc:
  113. self.module.fail_json(
  114. msg='error running kubectl (%s) command: %s' % (' '.join(args), str(exc)))
  115. return out.splitlines()
  116. def _execute_nofail(self, cmd):
  117. args = self.base_cmd + cmd
  118. rc, out, err = self.module.run_command(args)
  119. if rc != 0:
  120. return None
  121. return out.splitlines()
  122. def create(self, check=True):
  123. if check and self.exists():
  124. return []
  125. cmd = ['create']
  126. if not self.filename:
  127. self.module.fail_json(msg='filename required to create')
  128. cmd.append('--filename=' + self.filename)
  129. return self._execute(cmd)
  130. def replace(self):
  131. if not self.force and not self.exists():
  132. return []
  133. cmd = ['replace']
  134. if self.api_version != 'v1':
  135. cmd = ['update']
  136. if self.force:
  137. cmd.append('--force')
  138. if not self.filename:
  139. self.module.fail_json(msg='filename required to reload')
  140. cmd.append('--filename=' + self.filename)
  141. return self._execute(cmd)
  142. def delete(self):
  143. if not self.force and not self.exists():
  144. return []
  145. cmd = ['delete']
  146. if self.filename:
  147. cmd.append('--filename=' + self.filename)
  148. else:
  149. if not self.resource:
  150. self.module.fail_json(msg='resource required to delete without filename')
  151. cmd.append(self.resource)
  152. if self.name:
  153. cmd.append(self.name)
  154. if self.label:
  155. cmd.append('--selector=' + self.label)
  156. if self.all:
  157. cmd.append('--all')
  158. if self.force:
  159. cmd.append('--ignore-not-found')
  160. return self._execute(cmd)
  161. def exists(self):
  162. cmd = ['get']
  163. if not self.resource:
  164. return False
  165. cmd.append(self.resource)
  166. if self.name:
  167. cmd.append(self.name)
  168. cmd.append('--no-headers')
  169. if self.label:
  170. cmd.append('--selector=' + self.label)
  171. if self.all:
  172. cmd.append('--all-namespaces')
  173. result = self._execute_nofail(cmd)
  174. if not result:
  175. return False
  176. return True
  177. def stop(self):
  178. if not self.force and not self.exists():
  179. return []
  180. cmd = ['stop']
  181. if self.filename:
  182. cmd.append('--filename=' + self.filename)
  183. else:
  184. if not self.resource:
  185. self.module.fail_json(msg='resource required to stop without filename')
  186. cmd.append(self.resource)
  187. if self.name:
  188. cmd.append(self.name)
  189. if self.label:
  190. cmd.append('--selector=' + self.label)
  191. if self.all:
  192. cmd.append('--all')
  193. if self.force:
  194. cmd.append('--ignore-not-found')
  195. return self._execute(cmd)
  196. def main():
  197. module = AnsibleModule(
  198. argument_spec=dict(
  199. name=dict(),
  200. filename=dict(),
  201. namespace=dict(),
  202. resource=dict(),
  203. label=dict(),
  204. server=dict(),
  205. api_version=dict(default='v1', choices=['v1', 'v1beta3']),
  206. force=dict(default=False, type='bool'),
  207. all=dict(default=False, type='bool'),
  208. log_level=dict(default=0, type='int'),
  209. state=dict(default='present', choices=['present', 'absent', 'latest', 'reloaded', 'stopped']),
  210. )
  211. )
  212. changed = False
  213. manager = KubeManager(module)
  214. state = module.params.get('state')
  215. if state == 'present':
  216. result = manager.create()
  217. elif state == 'absent':
  218. result = manager.delete()
  219. elif state == 'reloaded':
  220. result = manager.replace()
  221. elif state == 'stopped':
  222. result = manager.stop()
  223. elif state == 'latest':
  224. if manager.exists():
  225. manager.force = True
  226. result = manager.replace()
  227. else:
  228. result = manager.create(check=False)
  229. else:
  230. module.fail_json(msg='Unrecognized state %s.' % state)
  231. if result:
  232. changed = True
  233. module.exit_json(changed=changed,
  234. msg='success: %s' % (' '.join(result))
  235. )
  236. from ansible.module_utils.basic import * # noqa
  237. if __name__ == '__main__':
  238. main()