2 # -*- coding: utf-8 -*-
7 short_description: Manage Kubernetes Cluster
9 - Create, replace, remove, and stop resources within a Kubernetes Cluster
16 - The name associated with resource
21 - The path and filename of the resource(s) definition file(s).
22 - To operate on several files this can accept a comma separated list of files or a list of files.
23 aliases: [ 'files', 'file', 'filenames' ]
28 - The path to the kubectl bin
33 - The namespace associated with the resource(s)
38 - The resource to perform an action on. pods (po), replicationControllers (rc), services (svc)
43 - The labels used to filter specific resources.
48 - The url for the API server that commands are executed against.
53 - A flag to indicate to force delete, replace, or stop.
58 - A flag to indicate to wait for resources to be created before continuing to the next step
63 - A flag to indicate delete all, stop all, or all namespaces when checking exists.
68 - Indicates the level of verbosity of logging by kubectl.
71 choices: ['present', 'absent', 'latest', 'reloaded', 'stopped']
74 - present handles checking existence or creating if definition file provided,
75 absent handles deleting resource(s) based on other options,
76 latest handles creating or updating based on existence,
77 reloaded handles updating resource(s) definition using definition file,
78 stopped handles stopping resource(s) based on other options.
83 - Process the directory used in -f, --filename recursively.
84 Useful when you want to manage related manifests organized
85 within the same directory.
88 author: "Kenny Jones (@kenjones-cisco)"
92 - name: test nginx is present
93 kube: name=nginx resource=rc state=present
95 - name: test nginx is stopped
96 kube: name=nginx resource=rc state=stopped
98 - name: test nginx is absent
99 kube: name=nginx resource=rc state=absent
101 - name: test nginx is present
102 kube: filename=/tmp/nginx.yml
104 - name: test nginx and postgresql are present
105 kube: files=/tmp/nginx.yml,/tmp/postgresql.yml
107 - name: test nginx and postgresql are present
111 - /tmp/postgresql.yml
115 class KubeManager(object):
117 def __init__(self, module):
121 self.kubectl = module.params.get('kubectl')
122 if self.kubectl is None:
123 self.kubectl = module.get_bin_path('kubectl', True)
124 self.base_cmd = [self.kubectl]
126 if module.params.get('server'):
127 self.base_cmd.append('--server=' + module.params.get('server'))
129 if module.params.get('log_level'):
130 self.base_cmd.append('--v=' + str(module.params.get('log_level')))
132 if module.params.get('namespace'):
133 self.base_cmd.append('--namespace=' + module.params.get('namespace'))
136 self.all = module.params.get('all')
137 self.force = module.params.get('force')
138 self.wait = module.params.get('wait')
139 self.name = module.params.get('name')
140 self.filename = [f.strip() for f in module.params.get('filename') or []]
141 self.resource = module.params.get('resource')
142 self.label = module.params.get('label')
143 self.recursive = module.params.get('recursive')
145 def _execute(self, cmd):
146 args = self.base_cmd + cmd
148 rc, out, err = self.module.run_command(args)
150 self.module.fail_json(
151 msg='error running kubectl (%s) command (rc=%d), out=\'%s\', err=\'%s\'' % (' '.join(args), rc, out, err))
152 except Exception as exc:
153 self.module.fail_json(
154 msg='error running kubectl (%s) command: %s' % (' '.join(args), str(exc)))
155 return out.splitlines()
157 def _execute_nofail(self, cmd):
158 args = self.base_cmd + cmd
159 rc, out, err = self.module.run_command(args)
162 return out.splitlines()
164 def create(self, check=True, force=True):
165 if check and self.exists():
171 cmd.append('--force')
177 cmd.append('--recursive={}'.format(self.recursive))
179 if not self.filename:
180 self.module.fail_json(msg='filename required to create')
182 cmd.append('--filename=' + ','.join(self.filename))
184 return self._execute(cmd)
186 def replace(self, force=True):
191 cmd.append('--force')
197 cmd.append('--recursive={}'.format(self.recursive))
199 if not self.filename:
200 self.module.fail_json(msg='filename required to reload')
202 cmd.append('--filename=' + ','.join(self.filename))
204 return self._execute(cmd)
208 if not self.force and not self.exists():
214 cmd.append('--filename=' + ','.join(self.filename))
216 cmd.append('--recursive={}'.format(self.recursive))
218 if not self.resource:
219 self.module.fail_json(msg='resource required to delete without filename')
221 cmd.append(self.resource)
224 cmd.append(self.name)
227 cmd.append('--selector=' + self.label)
233 cmd.append('--ignore-not-found')
236 cmd.append('--recursive={}'.format(self.recursive))
238 return self._execute(cmd)
244 cmd.append('--filename=' + ','.join(self.filename))
246 cmd.append('--recursive={}'.format(self.recursive))
248 if not self.resource:
249 self.module.fail_json(msg='resource required without filename')
251 cmd.append(self.resource)
254 cmd.append(self.name)
257 cmd.append('--selector=' + self.label)
260 cmd.append('--all-namespaces')
262 cmd.append('--no-headers')
264 result = self._execute_nofail(cmd)
269 # TODO: This is currently unused, perhaps convert to 'scale' with a replicas param?
272 if not self.force and not self.exists():
278 cmd.append('--filename=' + ','.join(self.filename))
280 cmd.append('--recursive={}'.format(self.recursive))
282 if not self.resource:
283 self.module.fail_json(msg='resource required to stop without filename')
285 cmd.append(self.resource)
288 cmd.append(self.name)
291 cmd.append('--selector=' + self.label)
297 cmd.append('--ignore-not-found')
299 return self._execute(cmd)
304 module = AnsibleModule(
307 filename=dict(type='list', aliases=['files', 'file', 'filenames']),
313 force=dict(default=False, type='bool'),
314 wait=dict(default=False, type='bool'),
315 all=dict(default=False, type='bool'),
316 log_level=dict(default=0, type='int'),
317 state=dict(default='present', choices=['present', 'absent', 'latest', 'reloaded', 'stopped', 'exists']),
318 recursive=dict(default=False, type='bool'),
320 mutually_exclusive=[['filename', 'list']]
325 manager = KubeManager(module)
326 state = module.params.get('state')
327 if state == 'present':
328 result = manager.create(check=False)
330 elif state == 'absent':
331 result = manager.delete()
333 elif state == 'reloaded':
334 result = manager.replace()
336 elif state == 'stopped':
337 result = manager.stop()
339 elif state == 'latest':
340 result = manager.replace()
342 elif state == 'exists':
343 result = manager.exists()
344 module.exit_json(changed=changed,
348 module.fail_json(msg='Unrecognized state %s.' % state)
350 module.exit_json(changed=changed,
351 msg='success: %s' % (' '.join(result))
355 from ansible.module_utils.basic import * # noqa
356 if __name__ == '__main__':