(cherry picked from commit 1f5839777b28c479783c9a9316c702ee3b6f96bf)
Rene Moser authored on 2017/06/19 16:18:19... | ... |
@@ -36,7 +36,14 @@ options: |
36 | 36 |
description: |
37 | 37 |
- Name of the host. |
38 | 38 |
required: true |
39 |
- aliases: [ 'url', 'ip_address' ] |
|
39 |
+ aliases: [ 'ip_address' ] |
|
40 |
+ url: |
|
41 |
+ description: |
|
42 |
+ - Url of the host used to create a host. |
|
43 |
+ - If not provided, C(http://) and param C(name) is used as url. |
|
44 |
+ - Only considered if C(state=present) and host does not yet exist. |
|
45 |
+ required: false |
|
46 |
+ default: null |
|
40 | 47 |
username: |
41 | 48 |
description: |
42 | 49 |
- Username for the host. |
... | ... |
@@ -301,6 +308,11 @@ resource_state: |
301 | 301 |
returned: success |
302 | 302 |
type: string |
303 | 303 |
sample: Enabled |
304 |
+allocation_state:: |
|
305 |
+ description: Allocation state of the host. |
|
306 |
+ returned: success |
|
307 |
+ type: string |
|
308 |
+ sample: enabled |
|
304 | 309 |
state: |
305 | 310 |
description: State of the host. |
306 | 311 |
returned: success |
... | ... |
@@ -334,7 +346,14 @@ zone: |
334 | 334 |
''' |
335 | 335 |
|
336 | 336 |
from ansible.module_utils.basic import AnsibleModule |
337 |
-from ansible.module_utils.cloudstack import AnsibleCloudStack, CloudStackException, cs_argument_spec, cs_required_together, CS_HYPERVISORS |
|
337 |
+from ansible.module_utils.cloudstack import ( |
|
338 |
+ AnsibleCloudStack, |
|
339 |
+ CloudStackException, |
|
340 |
+ cs_argument_spec, |
|
341 |
+ cs_required_together, |
|
342 |
+ CS_HYPERVISORS |
|
343 |
+) |
|
344 |
+import time |
|
338 | 345 |
|
339 | 346 |
|
340 | 347 |
class AnsibleCloudStackHost(AnsibleCloudStack): |
... | ... |
@@ -359,7 +378,6 @@ class AnsibleCloudStackHost(AnsibleCloudStack): |
359 | 359 |
'events': 'events', |
360 | 360 |
'hahost': 'ha_host', |
361 | 361 |
'hasenoughcapacity': 'has_enough_capacity', |
362 |
- 'hosttags': 'host_tags', |
|
363 | 362 |
'hypervisor': 'hypervisor', |
364 | 363 |
'hypervisorversion': 'hypervisor_version', |
365 | 364 |
'ipaddress': 'ip_address', |
... | ... |
@@ -380,12 +398,12 @@ class AnsibleCloudStackHost(AnsibleCloudStack): |
380 | 380 |
'type': 'host_type', |
381 | 381 |
'version': 'host_version', |
382 | 382 |
'gpugroup': 'gpu_group', |
383 |
- |
|
384 | 383 |
} |
385 | 384 |
self.allocation_states = { |
386 |
- 'enabled': 'enable', |
|
387 |
- 'disabled': 'disable', |
|
385 |
+ 'enabled': 'Enable', |
|
386 |
+ 'disabled': 'Disable', |
|
388 | 387 |
} |
388 |
+ self.host = None |
|
389 | 389 |
|
390 | 390 |
def get_pod(self, key=None): |
391 | 391 |
pod_name = self.module.params.get('pod') |
... | ... |
@@ -425,8 +443,10 @@ class AnsibleCloudStackHost(AnsibleCloudStack): |
425 | 425 |
return None |
426 | 426 |
return self.allocation_states[allocation_state] |
427 | 427 |
|
428 |
- def get_host(self): |
|
429 |
- host = None |
|
428 |
+ def get_host(self, refresh=False): |
|
429 |
+ if self.host is not None and not refresh: |
|
430 |
+ return self.host |
|
431 |
+ |
|
430 | 432 |
name = self.module.params.get('name') |
431 | 433 |
args = { |
432 | 434 |
'zoneid': self.get_zone(key='id'), |
... | ... |
@@ -435,8 +455,8 @@ class AnsibleCloudStackHost(AnsibleCloudStack): |
435 | 435 |
if res: |
436 | 436 |
for h in res['host']: |
437 | 437 |
if name in [h['ipaddress'], h['name']]: |
438 |
- host = h |
|
439 |
- return host |
|
438 |
+ self.host = h |
|
439 |
+ return self.host |
|
440 | 440 |
|
441 | 441 |
def present_host(self): |
442 | 442 |
host = self.get_host() |
... | ... |
@@ -446,6 +466,13 @@ class AnsibleCloudStackHost(AnsibleCloudStack): |
446 | 446 |
host = self._update_host(host) |
447 | 447 |
return host |
448 | 448 |
|
449 |
+ def _get_url(self): |
|
450 |
+ url = self.module.params.get('url') |
|
451 |
+ if url: |
|
452 |
+ return url |
|
453 |
+ else: |
|
454 |
+ return "http://%s" % self.module.params.get('name') |
|
455 |
+ |
|
449 | 456 |
def _create_host(self, host): |
450 | 457 |
required_params = [ |
451 | 458 |
'password', |
... | ... |
@@ -457,7 +484,7 @@ class AnsibleCloudStackHost(AnsibleCloudStack): |
457 | 457 |
self.result['changed'] = True |
458 | 458 |
args = { |
459 | 459 |
'hypervisor': self.module.params.get('hypervisor'), |
460 |
- 'url': self.module.params.get('name'), |
|
460 |
+ 'url': self._get_url(), |
|
461 | 461 |
'username': self.module.params.get('username'), |
462 | 462 |
'password': self.module.params.get('password'), |
463 | 463 |
'podid': self.get_pod(key='id'), |
... | ... |
@@ -470,24 +497,24 @@ class AnsibleCloudStackHost(AnsibleCloudStack): |
470 | 470 |
host = self.cs.addHost(**args) |
471 | 471 |
if 'errortext' in host: |
472 | 472 |
self.module.fail_json(msg="Failed: '%s'" % host['errortext']) |
473 |
- host = host['host'] |
|
473 |
+ host = host['host'][0] |
|
474 | 474 |
return host |
475 | 475 |
|
476 | 476 |
def _update_host(self, host): |
477 | 477 |
args = { |
478 | 478 |
'id': host['id'], |
479 | 479 |
'hosttags': self.get_host_tags(), |
480 |
- 'allocationstate': self.module.params.get('allocation_state'), |
|
480 |
+ 'allocationstate': self.get_allocation_state() |
|
481 | 481 |
} |
482 |
- host['allocationstate'] = host['resourcestate'].lower() |
|
482 |
+ host['allocationstate'] = self.allocation_states[host['resourcestate'].lower()] |
|
483 | 483 |
if self.has_changed(args, host): |
484 |
- args['allocationstate'] = self.get_allocation_state() |
|
485 | 484 |
self.result['changed'] = True |
486 | 485 |
if not self.module.check_mode: |
487 | 486 |
host = self.cs.updateHost(**args) |
488 | 487 |
if 'errortext' in host: |
489 | 488 |
self.module.fail_json(msg="Failed: '%s'" % host['errortext']) |
490 | 489 |
host = host['host'] |
490 |
+ |
|
491 | 491 |
return host |
492 | 492 |
|
493 | 493 |
def absent_host(self): |
... | ... |
@@ -498,16 +525,51 @@ class AnsibleCloudStackHost(AnsibleCloudStack): |
498 | 498 |
'id': host['id'], |
499 | 499 |
} |
500 | 500 |
if not self.module.check_mode: |
501 |
- res = self.cs.deleteHost(**args) |
|
501 |
+ res = self.enable_maintenance() |
|
502 |
+ if res: |
|
503 |
+ res = self.cs.deleteHost(**args) |
|
504 |
+ if 'errortext' in res: |
|
505 |
+ self.module.fail_json(msg="Failed: '%s'" % res['errortext']) |
|
506 |
+ return host |
|
507 |
+ |
|
508 |
+ def enable_maintenance(self): |
|
509 |
+ host = self.get_host() |
|
510 |
+ if host['resourcestate'] not in ['PrepareForMaintenance', 'Maintenance']: |
|
511 |
+ self.result['changed'] = True |
|
512 |
+ args = { |
|
513 |
+ 'id': host['id'], |
|
514 |
+ } |
|
515 |
+ if not self.module.check_mode: |
|
516 |
+ res = self.cs.prepareHostForMaintenance(**args) |
|
502 | 517 |
if 'errortext' in res: |
503 | 518 |
self.module.fail_json(msg="Failed: '%s'" % res['errortext']) |
519 |
+ host = self.poll_job(res, 'host') |
|
520 |
+ self._poll_for_maintenance() |
|
504 | 521 |
return host |
505 | 522 |
|
523 |
+ def _poll_for_maintenance(self): |
|
524 |
+ for i in range(0, 300): |
|
525 |
+ time.sleep(2) |
|
526 |
+ host = self.get_host(refresh=True) |
|
527 |
+ if not host: |
|
528 |
+ return None |
|
529 |
+ elif host['resourcestate'] != 'PrepareForMaintenance': |
|
530 |
+ return host |
|
531 |
+ self.fail_json("Polling for maintenance timed out") |
|
532 |
+ |
|
533 |
+ def get_result(self, host): |
|
534 |
+ super(AnsibleCloudStackHost, self).get_result(host) |
|
535 |
+ if host: |
|
536 |
+ self.result['allocation_state'] = host['resourcestate'].lower() |
|
537 |
+ self.result['host_tags'] = host['hosttags'].split(',') if host.get('hosttags') else [] |
|
538 |
+ return self.result |
|
539 |
+ |
|
506 | 540 |
|
507 | 541 |
def main(): |
508 | 542 |
argument_spec = cs_argument_spec() |
509 | 543 |
argument_spec.update(dict( |
510 |
- name=dict(required=True, aliases=['url', 'ip_address']), |
|
544 |
+ name=dict(required=True, aliases=['ip_address']), |
|
545 |
+ url=dict(), |
|
511 | 546 |
password=dict(default=None, no_log=True), |
512 | 547 |
username=dict(default=None), |
513 | 548 |
hypervisor=dict(choices=CS_HYPERVISORS, default=None), |