mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-05-28 03:49:09 -07:00
Initial commit
This commit is contained in:
commit
aebc1b03fd
4861 changed files with 812621 additions and 0 deletions
627
plugins/modules/cloud/cloudstack/cs_host.py
Normal file
627
plugins/modules/cloud/cloudstack/cs_host.py
Normal file
|
@ -0,0 +1,627 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# (c) 2016, René Moser <mail@renemoser.net>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'}
|
||||
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: cs_host
|
||||
short_description: Manages hosts on Apache CloudStack based clouds.
|
||||
description:
|
||||
- Create, update and remove hosts.
|
||||
author: René Moser (@resmo)
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Name of the host.
|
||||
type: str
|
||||
required: true
|
||||
aliases: [ ip_address ]
|
||||
url:
|
||||
description:
|
||||
- Url of the host used to create a host.
|
||||
- If not provided, C(http://) and param I(name) is used as url.
|
||||
- Only considered if I(state=present) and host does not yet exist.
|
||||
type: str
|
||||
username:
|
||||
description:
|
||||
- Username for the host.
|
||||
- Required if I(state=present) and host does not yet exist.
|
||||
type: str
|
||||
password:
|
||||
description:
|
||||
- Password for the host.
|
||||
- Required if I(state=present) and host does not yet exist.
|
||||
type: str
|
||||
pod:
|
||||
description:
|
||||
- Name of the pod.
|
||||
- Required if I(state=present) and host does not yet exist.
|
||||
type: str
|
||||
cluster:
|
||||
description:
|
||||
- Name of the cluster.
|
||||
type: str
|
||||
hypervisor:
|
||||
description:
|
||||
- Name of the cluster.
|
||||
- Required if I(state=present) and host does not yet exist.
|
||||
- Possible values are C(KVM), C(VMware), C(BareMetal), C(XenServer), C(LXC), C(HyperV), C(UCS), C(OVM), C(Simulator).
|
||||
type: str
|
||||
allocation_state:
|
||||
description:
|
||||
- Allocation state of the host.
|
||||
type: str
|
||||
choices: [ enabled, disabled, maintenance ]
|
||||
host_tags:
|
||||
description:
|
||||
- Tags of the host.
|
||||
type: list
|
||||
aliases: [ host_tag ]
|
||||
state:
|
||||
description:
|
||||
- State of the host.
|
||||
type: str
|
||||
default: present
|
||||
choices: [ present, absent ]
|
||||
zone:
|
||||
description:
|
||||
- Name of the zone in which the host should be deployed.
|
||||
- If not set, default zone is used.
|
||||
type: str
|
||||
extends_documentation_fragment:
|
||||
- community.general.cloudstack
|
||||
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Ensure a host is present but disabled
|
||||
cs_host:
|
||||
name: pod01.zone01.example.com
|
||||
cluster: vcenter.example.com/zone01/cluster01
|
||||
pod: pod01
|
||||
zone: zone01
|
||||
hypervisor: VMware
|
||||
allocation_state: disabled
|
||||
host_tags:
|
||||
- perf
|
||||
- gpu
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Ensure an existing host is disabled
|
||||
cs_host:
|
||||
name: pod01.zone01.example.com
|
||||
zone: zone01
|
||||
allocation_state: disabled
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Ensure an existing host is enabled
|
||||
cs_host:
|
||||
name: pod01.zone01.example.com
|
||||
zone: zone01
|
||||
allocation_state: enabled
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Ensure a host is absent
|
||||
cs_host:
|
||||
name: pod01.zone01.example.com
|
||||
zone: zone01
|
||||
state: absent
|
||||
delegate_to: localhost
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
---
|
||||
capabilities:
|
||||
description: Capabilities of the host.
|
||||
returned: success
|
||||
type: str
|
||||
sample: hvm
|
||||
cluster:
|
||||
description: Cluster of the host.
|
||||
returned: success
|
||||
type: str
|
||||
sample: vcenter.example.com/zone/cluster01
|
||||
cluster_type:
|
||||
description: Type of the cluster of the host.
|
||||
returned: success
|
||||
type: str
|
||||
sample: ExternalManaged
|
||||
cpu_allocated:
|
||||
description: Amount in percent of the host's CPU currently allocated.
|
||||
returned: success
|
||||
type: str
|
||||
sample: 166.25%
|
||||
cpu_number:
|
||||
description: Number of CPUs of the host.
|
||||
returned: success
|
||||
type: str
|
||||
sample: 24
|
||||
cpu_sockets:
|
||||
description: Number of CPU sockets of the host.
|
||||
returned: success
|
||||
type: int
|
||||
sample: 2
|
||||
cpu_speed:
|
||||
description: CPU speed in Mhz
|
||||
returned: success
|
||||
type: int
|
||||
sample: 1999
|
||||
cpu_used:
|
||||
description: Amount of the host's CPU currently used.
|
||||
returned: success
|
||||
type: str
|
||||
sample: 33.6%
|
||||
cpu_with_overprovisioning:
|
||||
description: Amount of the host's CPU after applying the cpu.overprovisioning.factor.
|
||||
returned: success
|
||||
type: str
|
||||
sample: 959520.0
|
||||
created:
|
||||
description: Date when the host was created.
|
||||
returned: success
|
||||
type: str
|
||||
sample: 2015-05-03T15:05:51+0200
|
||||
disconnected:
|
||||
description: Date when the host was disconnected.
|
||||
returned: success
|
||||
type: str
|
||||
sample: 2015-05-03T15:05:51+0200
|
||||
disk_size_allocated:
|
||||
description: Host's currently allocated disk size.
|
||||
returned: success
|
||||
type: int
|
||||
sample: 2593
|
||||
disk_size_total:
|
||||
description: Total disk size of the host
|
||||
returned: success
|
||||
type: int
|
||||
sample: 259300
|
||||
events:
|
||||
description: Events available for the host
|
||||
returned: success
|
||||
type: str
|
||||
sample: "Ping; HostDown; AgentConnected; AgentDisconnected; PingTimeout; ShutdownRequested; Remove; StartAgentRebalance; ManagementServerDown"
|
||||
ha_host:
|
||||
description: Whether the host is a HA host.
|
||||
returned: success
|
||||
type: bool
|
||||
sample: false
|
||||
has_enough_capacity:
|
||||
description: Whether the host has enough CPU and RAM capacity to migrate a VM to it.
|
||||
returned: success
|
||||
type: bool
|
||||
sample: true
|
||||
host_tags:
|
||||
description: Comma-separated list of tags for the host.
|
||||
returned: success
|
||||
type: str
|
||||
sample: "perf"
|
||||
hypervisor:
|
||||
description: Host's hypervisor.
|
||||
returned: success
|
||||
type: str
|
||||
sample: VMware
|
||||
hypervisor_version:
|
||||
description: Hypervisor version.
|
||||
returned: success
|
||||
type: str
|
||||
sample: 5.1
|
||||
ip_address:
|
||||
description: IP address of the host
|
||||
returned: success
|
||||
type: str
|
||||
sample: 10.10.10.1
|
||||
is_local_storage_active:
|
||||
description: Whether the local storage is available or not.
|
||||
returned: success
|
||||
type: bool
|
||||
sample: false
|
||||
last_pinged:
|
||||
description: Date and time the host was last pinged.
|
||||
returned: success
|
||||
type: str
|
||||
sample: "1970-01-17T17:27:32+0100"
|
||||
management_server_id:
|
||||
description: Management server ID of the host.
|
||||
returned: success
|
||||
type: int
|
||||
sample: 345050593418
|
||||
memory_allocated:
|
||||
description: Amount of the host's memory currently allocated.
|
||||
returned: success
|
||||
type: int
|
||||
sample: 69793218560
|
||||
memory_total:
|
||||
description: Total of memory of the host.
|
||||
returned: success
|
||||
type: int
|
||||
sample: 206085263360
|
||||
memory_used:
|
||||
description: Amount of the host's memory currently used.
|
||||
returned: success
|
||||
type: int
|
||||
sample: 65504776192
|
||||
name:
|
||||
description: Name of the host.
|
||||
returned: success
|
||||
type: str
|
||||
sample: esx32.example.com
|
||||
network_kbs_read:
|
||||
description: Incoming network traffic on the host.
|
||||
returned: success
|
||||
type: int
|
||||
sample: 0
|
||||
network_kbs_write:
|
||||
description: Outgoing network traffic on the host.
|
||||
returned: success
|
||||
type: int
|
||||
sample: 0
|
||||
os_category:
|
||||
description: OS category name of the host.
|
||||
returned: success
|
||||
type: str
|
||||
sample: ...
|
||||
out_of_band_management:
|
||||
description: Host out-of-band management information.
|
||||
returned: success
|
||||
type: str
|
||||
sample: ...
|
||||
pod:
|
||||
description: Pod name of the host.
|
||||
returned: success
|
||||
type: str
|
||||
sample: Pod01
|
||||
removed:
|
||||
description: Date and time the host was removed.
|
||||
returned: success
|
||||
type: str
|
||||
sample: "1970-01-17T17:27:32+0100"
|
||||
resource_state:
|
||||
description: Resource state of the host.
|
||||
returned: success
|
||||
type: str
|
||||
sample: Enabled
|
||||
allocation_state::
|
||||
description: Allocation state of the host.
|
||||
returned: success
|
||||
type: str
|
||||
sample: enabled
|
||||
state:
|
||||
description: State of the host.
|
||||
returned: success
|
||||
type: str
|
||||
sample: Up
|
||||
suitable_for_migration:
|
||||
description: Whether this host is suitable (has enough capacity and satisfies all conditions like hosttags, max guests VM limit, etc) to migrate a VM
|
||||
to it or not.
|
||||
returned: success
|
||||
type: str
|
||||
sample: true
|
||||
host_type:
|
||||
description: Type of the host.
|
||||
returned: success
|
||||
type: str
|
||||
sample: Routing
|
||||
host_version:
|
||||
description: Version of the host.
|
||||
returned: success
|
||||
type: str
|
||||
sample: 4.5.2
|
||||
gpu_group:
|
||||
description: GPU cards present in the host.
|
||||
returned: success
|
||||
type: list
|
||||
sample: []
|
||||
zone:
|
||||
description: Zone of the host.
|
||||
returned: success
|
||||
type: str
|
||||
sample: zone01
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.cloudstack import (
|
||||
AnsibleCloudStack,
|
||||
cs_argument_spec,
|
||||
cs_required_together,
|
||||
)
|
||||
import time
|
||||
|
||||
|
||||
class AnsibleCloudStackHost(AnsibleCloudStack):
|
||||
|
||||
def __init__(self, module):
|
||||
super(AnsibleCloudStackHost, self).__init__(module)
|
||||
self.returns = {
|
||||
'averageload': 'average_load',
|
||||
'capabilities': 'capabilities',
|
||||
'clustername': 'cluster',
|
||||
'clustertype': 'cluster_type',
|
||||
'cpuallocated': 'cpu_allocated',
|
||||
'cpunumber': 'cpu_number',
|
||||
'cpusockets': 'cpu_sockets',
|
||||
'cpuspeed': 'cpu_speed',
|
||||
'cpuused': 'cpu_used',
|
||||
'cpuwithoverprovisioning': 'cpu_with_overprovisioning',
|
||||
'disconnected': 'disconnected',
|
||||
'details': 'details',
|
||||
'disksizeallocated': 'disk_size_allocated',
|
||||
'disksizetotal': 'disk_size_total',
|
||||
'events': 'events',
|
||||
'hahost': 'ha_host',
|
||||
'hasenoughcapacity': 'has_enough_capacity',
|
||||
'hypervisor': 'hypervisor',
|
||||
'hypervisorversion': 'hypervisor_version',
|
||||
'ipaddress': 'ip_address',
|
||||
'islocalstorageactive': 'is_local_storage_active',
|
||||
'lastpinged': 'last_pinged',
|
||||
'managementserverid': 'management_server_id',
|
||||
'memoryallocated': 'memory_allocated',
|
||||
'memorytotal': 'memory_total',
|
||||
'memoryused': 'memory_used',
|
||||
'networkkbsread': 'network_kbs_read',
|
||||
'networkkbswrite': 'network_kbs_write',
|
||||
'oscategoryname': 'os_category',
|
||||
'outofbandmanagement': 'out_of_band_management',
|
||||
'podname': 'pod',
|
||||
'removed': 'removed',
|
||||
'resourcestate': 'resource_state',
|
||||
'suitableformigration': 'suitable_for_migration',
|
||||
'type': 'host_type',
|
||||
'version': 'host_version',
|
||||
'gpugroup': 'gpu_group',
|
||||
}
|
||||
# States only usable by the updateHost API
|
||||
self.allocation_states_for_update = {
|
||||
'enabled': 'Enable',
|
||||
'disabled': 'Disable',
|
||||
}
|
||||
self.host = None
|
||||
|
||||
def get_pod(self, key=None):
|
||||
pod_name = self.module.params.get('pod')
|
||||
if not pod_name:
|
||||
return None
|
||||
args = {
|
||||
'name': pod_name,
|
||||
'zoneid': self.get_zone(key='id'),
|
||||
}
|
||||
pods = self.query_api('listPods', **args)
|
||||
if pods:
|
||||
return self._get_by_key(key, pods['pod'][0])
|
||||
self.module.fail_json(msg="Pod %s not found" % pod_name)
|
||||
|
||||
def get_cluster(self, key=None):
|
||||
cluster_name = self.module.params.get('cluster')
|
||||
if not cluster_name:
|
||||
return None
|
||||
args = {
|
||||
'name': cluster_name,
|
||||
'zoneid': self.get_zone(key='id'),
|
||||
}
|
||||
clusters = self.query_api('listClusters', **args)
|
||||
if clusters:
|
||||
return self._get_by_key(key, clusters['cluster'][0])
|
||||
self.module.fail_json(msg="Cluster %s not found" % cluster_name)
|
||||
|
||||
def get_host_tags(self):
|
||||
host_tags = self.module.params.get('host_tags')
|
||||
if host_tags is None:
|
||||
return None
|
||||
return ','.join(host_tags)
|
||||
|
||||
def get_host(self, refresh=False):
|
||||
if self.host is not None and not refresh:
|
||||
return self.host
|
||||
|
||||
name = self.module.params.get('name')
|
||||
args = {
|
||||
'zoneid': self.get_zone(key='id'),
|
||||
'fetch_list': True,
|
||||
}
|
||||
res = self.query_api('listHosts', **args)
|
||||
if res:
|
||||
for h in res:
|
||||
if name in [h['ipaddress'], h['name']]:
|
||||
self.host = h
|
||||
return self.host
|
||||
|
||||
def _handle_allocation_state(self, host):
|
||||
allocation_state = self.module.params.get('allocation_state')
|
||||
if not allocation_state:
|
||||
return host
|
||||
|
||||
host = self._set_host_allocation_state(host)
|
||||
|
||||
# In case host in maintenance and target is maintenance
|
||||
if host['allocationstate'].lower() == allocation_state and allocation_state == 'maintenance':
|
||||
return host
|
||||
|
||||
# Cancel maintenance if target state is enabled/disabled
|
||||
elif allocation_state in list(self.allocation_states_for_update.keys()):
|
||||
host = self.disable_maintenance(host)
|
||||
host = self._update_host(host, self.allocation_states_for_update[allocation_state])
|
||||
|
||||
# Only an enabled host can put in maintenance
|
||||
elif allocation_state == 'maintenance':
|
||||
host = self._update_host(host, 'Enable')
|
||||
host = self.enable_maintenance(host)
|
||||
|
||||
return host
|
||||
|
||||
def _set_host_allocation_state(self, host):
|
||||
if host is None:
|
||||
host['allocationstate'] = 'Enable'
|
||||
|
||||
# Set host allocationstate to be disabled/enabled
|
||||
elif host['resourcestate'].lower() in list(self.allocation_states_for_update.keys()):
|
||||
host['allocationstate'] = self.allocation_states_for_update[host['resourcestate'].lower()]
|
||||
|
||||
else:
|
||||
host['allocationstate'] = host['resourcestate']
|
||||
|
||||
return host
|
||||
|
||||
def present_host(self):
|
||||
host = self.get_host()
|
||||
|
||||
if not host:
|
||||
host = self._create_host(host)
|
||||
else:
|
||||
host = self._update_host(host)
|
||||
|
||||
if host:
|
||||
host = self._handle_allocation_state(host)
|
||||
|
||||
return host
|
||||
|
||||
def _get_url(self):
|
||||
url = self.module.params.get('url')
|
||||
if url:
|
||||
return url
|
||||
else:
|
||||
return "http://%s" % self.module.params.get('name')
|
||||
|
||||
def _create_host(self, host):
|
||||
required_params = [
|
||||
'password',
|
||||
'username',
|
||||
'hypervisor',
|
||||
'pod',
|
||||
]
|
||||
self.module.fail_on_missing_params(required_params=required_params)
|
||||
self.result['changed'] = True
|
||||
args = {
|
||||
'hypervisor': self.module.params.get('hypervisor'),
|
||||
'url': self._get_url(),
|
||||
'username': self.module.params.get('username'),
|
||||
'password': self.module.params.get('password'),
|
||||
'podid': self.get_pod(key='id'),
|
||||
'zoneid': self.get_zone(key='id'),
|
||||
'clusterid': self.get_cluster(key='id'),
|
||||
'hosttags': self.get_host_tags(),
|
||||
}
|
||||
if not self.module.check_mode:
|
||||
host = self.query_api('addHost', **args)
|
||||
host = host['host'][0]
|
||||
return host
|
||||
|
||||
def _update_host(self, host, allocation_state=None):
|
||||
args = {
|
||||
'id': host['id'],
|
||||
'hosttags': self.get_host_tags(),
|
||||
'allocationstate': allocation_state,
|
||||
}
|
||||
|
||||
if allocation_state is not None:
|
||||
host = self._set_host_allocation_state(host)
|
||||
|
||||
if self.has_changed(args, host):
|
||||
self.result['changed'] = True
|
||||
if not self.module.check_mode:
|
||||
host = self.query_api('updateHost', **args)
|
||||
host = host['host']
|
||||
|
||||
return host
|
||||
|
||||
def absent_host(self):
|
||||
host = self.get_host()
|
||||
if host:
|
||||
self.result['changed'] = True
|
||||
args = {
|
||||
'id': host['id'],
|
||||
}
|
||||
if not self.module.check_mode:
|
||||
res = self.enable_maintenance(host)
|
||||
if res:
|
||||
res = self.query_api('deleteHost', **args)
|
||||
return host
|
||||
|
||||
def enable_maintenance(self, host):
|
||||
if host['resourcestate'] not in ['PrepareForMaintenance', 'Maintenance']:
|
||||
self.result['changed'] = True
|
||||
args = {
|
||||
'id': host['id'],
|
||||
}
|
||||
if not self.module.check_mode:
|
||||
res = self.query_api('prepareHostForMaintenance', **args)
|
||||
self.poll_job(res, 'host')
|
||||
host = self._poll_for_maintenance()
|
||||
return host
|
||||
|
||||
def disable_maintenance(self, host):
|
||||
if host['resourcestate'] in ['PrepareForMaintenance', 'Maintenance']:
|
||||
self.result['changed'] = True
|
||||
args = {
|
||||
'id': host['id'],
|
||||
}
|
||||
if not self.module.check_mode:
|
||||
res = self.query_api('cancelHostMaintenance', **args)
|
||||
host = self.poll_job(res, 'host')
|
||||
return host
|
||||
|
||||
def _poll_for_maintenance(self):
|
||||
for i in range(0, 300):
|
||||
time.sleep(2)
|
||||
host = self.get_host(refresh=True)
|
||||
if not host:
|
||||
return None
|
||||
elif host['resourcestate'] != 'PrepareForMaintenance':
|
||||
return host
|
||||
self.fail_json(msg="Polling for maintenance timed out")
|
||||
|
||||
def get_result(self, host):
|
||||
super(AnsibleCloudStackHost, self).get_result(host)
|
||||
if host:
|
||||
self.result['allocation_state'] = host['resourcestate'].lower()
|
||||
self.result['host_tags'] = host['hosttags'].split(',') if host.get('hosttags') else []
|
||||
return self.result
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = cs_argument_spec()
|
||||
argument_spec.update(dict(
|
||||
name=dict(required=True, aliases=['ip_address']),
|
||||
url=dict(),
|
||||
password=dict(no_log=True),
|
||||
username=dict(),
|
||||
hypervisor=dict(),
|
||||
allocation_state=dict(choices=['enabled', 'disabled', 'maintenance']),
|
||||
pod=dict(),
|
||||
cluster=dict(),
|
||||
host_tags=dict(type='list', aliases=['host_tag']),
|
||||
zone=dict(),
|
||||
state=dict(choices=['present', 'absent'], default='present'),
|
||||
))
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
required_together=cs_required_together(),
|
||||
supports_check_mode=True
|
||||
)
|
||||
|
||||
acs_host = AnsibleCloudStackHost(module)
|
||||
|
||||
state = module.params.get('state')
|
||||
if state == 'absent':
|
||||
host = acs_host.absent_host()
|
||||
else:
|
||||
host = acs_host.present_host()
|
||||
|
||||
result = acs_host.get_result(host)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
Add table
Add a link
Reference in a new issue