mirror of https://github.com/ansible/ansible.git
cloudstack: new module cs_host (#19331)
parent
3519f2c1c9
commit
cb8cc51fdf
@ -0,0 +1,546 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# (c) 2016, René Moser <mail@renemoser.net>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: cs_host
|
||||
short_description: Manages hosts on Apache CloudStack based clouds.
|
||||
description:
|
||||
- Create, update and remove hosts.
|
||||
version_added: "2.3"
|
||||
author: "René Moser (@resmo)"
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Name of the host.
|
||||
required: true
|
||||
aliases: [ 'url' ]
|
||||
username:
|
||||
description:
|
||||
- Username for the host.
|
||||
- Required if C(state=present) and host does not yet exist.
|
||||
required: false
|
||||
default: null
|
||||
password:
|
||||
description:
|
||||
- Password for the host.
|
||||
- Required if C(state=present) and host does not yet exist.
|
||||
required: false
|
||||
default: null
|
||||
pod:
|
||||
description:
|
||||
- Name of the pod.
|
||||
- Required if C(state=present) and host does not yet exist.
|
||||
required: false
|
||||
default: null
|
||||
cluster:
|
||||
description:
|
||||
- Name of the cluster.
|
||||
required: false
|
||||
default: null
|
||||
hypervisor:
|
||||
description:
|
||||
- Name of the cluster.
|
||||
- Required if C(state=present) and host does not yet exist.
|
||||
choices: [ 'KVM', 'VMware', 'BareMetal', 'XenServer', 'LXC', 'HyperV', 'UCS', 'OVM', 'Simulator' ]
|
||||
required: false
|
||||
default: null
|
||||
allocation_state:
|
||||
description:
|
||||
- Allocation state of the host.
|
||||
choices: [ 'enabled', 'disabled' ]
|
||||
required: false
|
||||
default: null
|
||||
host_tags:
|
||||
description:
|
||||
- Tags of the host.
|
||||
required: false
|
||||
default: null
|
||||
state:
|
||||
description:
|
||||
- State of the host.
|
||||
required: false
|
||||
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.
|
||||
required: false
|
||||
default: null
|
||||
extends_documentation_fragment: cloudstack
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# Ensure a host is present but disabled
|
||||
- local_action:
|
||||
module: cs_host
|
||||
name: ix-pod01-esx01.example.com
|
||||
cluster: vcenter.example.com/ch-zrh-ix/pod01-cluster01
|
||||
pod: pod01
|
||||
zone: ch-zrh-ix-01
|
||||
hypervisor: VMware
|
||||
allocation_state: disabled
|
||||
host_tags:
|
||||
- perf
|
||||
- gpu
|
||||
|
||||
# Ensure an existing host is disabled
|
||||
- local_action:
|
||||
module: cs_host
|
||||
name: ix-pod01-esx01.example.com
|
||||
zone: ch-zrh-ix-01
|
||||
allocation_state: disabled
|
||||
|
||||
# Ensure an existing host is disabled
|
||||
- local_action:
|
||||
module: cs_host
|
||||
name: ix-pod01-esx01.example.com
|
||||
zone: ch-zrh-ix-01
|
||||
allocation_state: enabled
|
||||
|
||||
# Ensure a host is absent
|
||||
- local_action:
|
||||
module: cs_host
|
||||
name: ix-pod01-esx01.example.com
|
||||
zone: ch-zrh-ix-01
|
||||
state: absent
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
---
|
||||
capabilities:
|
||||
description: Capabilities of the host.
|
||||
returned: success
|
||||
type: string
|
||||
sample: hvm
|
||||
cluster:
|
||||
description: Cluster of the host.
|
||||
returned: success
|
||||
type: string
|
||||
sample: vcenter.example.com/zone/cluster01
|
||||
cluster_type:
|
||||
description: Type of the cluster of the host.
|
||||
returned: success
|
||||
type: string
|
||||
sample: ExternalManaged
|
||||
cpu_allocated:
|
||||
description: Amount in percent of the host's CPU currently allocated.
|
||||
returned: success
|
||||
type: string
|
||||
sample: 166.25%
|
||||
cpu_number:
|
||||
description: Number of CPUs of the host.
|
||||
returned: success
|
||||
type: string
|
||||
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: string
|
||||
sample: 33.6%
|
||||
cpu_with_overprovisioning:
|
||||
description: Amount of the host's CPU after applying the cpu.overprovisioning.factor.
|
||||
returned: success
|
||||
type: string
|
||||
sample: 959520.0
|
||||
created:
|
||||
description: Date when the host was created.
|
||||
returned: success
|
||||
type: string
|
||||
sample: 2015-05-03T15:05:51+0200
|
||||
disconnected:
|
||||
description: Date when the host was disconnected.
|
||||
returned: success
|
||||
type: string
|
||||
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: string
|
||||
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: string
|
||||
sample: "perf"
|
||||
hypervisor:
|
||||
description: Host's hypervisor.
|
||||
returned: success
|
||||
type: string
|
||||
sample: VMware
|
||||
hypervisor_version:
|
||||
description: Hypervisor version.
|
||||
returned: success
|
||||
type: string
|
||||
sample: 5.1
|
||||
ip_address:
|
||||
description: IP address of the host
|
||||
returned: success
|
||||
type: string
|
||||
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: string
|
||||
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: string
|
||||
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: string
|
||||
sample: ...
|
||||
out_of_band_management:
|
||||
description: Host out-of-band management information.
|
||||
returned: success
|
||||
type: string
|
||||
sample: ...
|
||||
pod:
|
||||
description: Pod name of the host.
|
||||
returned: success
|
||||
type: string
|
||||
sample: Pod01
|
||||
removed:
|
||||
description: Date and time the host was removed.
|
||||
returned: success
|
||||
type: string
|
||||
sample: "1970-01-17T17:27:32+0100"
|
||||
resource_state:
|
||||
description: Resource state of the host.
|
||||
returned: success
|
||||
type: string
|
||||
sample: Enabled
|
||||
state:
|
||||
description: State of the host.
|
||||
returned: success
|
||||
type: string
|
||||
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: string
|
||||
sample: true
|
||||
host_type:
|
||||
description: Type of the host.
|
||||
returned: success
|
||||
type: string
|
||||
sample: Routing
|
||||
host_version:
|
||||
description: Version of the host.
|
||||
returned: success
|
||||
type: string
|
||||
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: string
|
||||
sample: zone01
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.cloudstack import AnsibleCloudStack, CloudStackException, cs_argument_spec, cs_required_together, CS_HYPERVISORS
|
||||
|
||||
|
||||
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',
|
||||
'hosttags': 'host_tags',
|
||||
'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',
|
||||
|
||||
}
|
||||
self.allocation_states = {
|
||||
'enabled': 'enable',
|
||||
'disabled': 'disable',
|
||||
}
|
||||
|
||||
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.cs.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.cs.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_allocation_state(self):
|
||||
allocation_state = self.module.params.get('allocation_state')
|
||||
if allocation_state is None:
|
||||
return None
|
||||
return self.allocation_states[allocation_state]
|
||||
|
||||
def get_host(self):
|
||||
host = None
|
||||
args = {
|
||||
'zoneid': self.get_zone(key='id'),
|
||||
'name': self.module.params.get('name'),
|
||||
}
|
||||
hosts = self.cs.listHosts(**args)
|
||||
if hosts:
|
||||
host = hosts['host'][0]
|
||||
return host
|
||||
|
||||
def present_host(self):
|
||||
host = self.get_host()
|
||||
if not host:
|
||||
host = self._create_host(host)
|
||||
else:
|
||||
host = self._update_host(host)
|
||||
return host
|
||||
|
||||
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.module.params.get('name'),
|
||||
'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'),
|
||||
'allocationstate': self.get_allocation_state(),
|
||||
'hosttags': self.get_host_tags(),
|
||||
}
|
||||
if not self.module.check_mode:
|
||||
host = self.cs.addHost(**args)
|
||||
if 'errortext' in host:
|
||||
self.module.fail_json(msg="Failed: '%s'" % host['errortext'])
|
||||
host = host['host']
|
||||
return host
|
||||
|
||||
def _update_host(self, host):
|
||||
args = {
|
||||
'id': host['id'],
|
||||
'hosttags': self.get_host_tags(),
|
||||
'allocationstate': self.module.params.get('allocation_state'),
|
||||
}
|
||||
host['allocationstate'] = host['resourcestate'].lower()
|
||||
if self.has_changed(args, host):
|
||||
args['allocationstate'] = self.get_allocation_state()
|
||||
self.result['changed'] = True
|
||||
if not self.module.check_mode:
|
||||
host = self.cs.updateHost(**args)
|
||||
if 'errortext' in host:
|
||||
self.module.fail_json(msg="Failed: '%s'" % host['errortext'])
|
||||
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.cs.deleteHost(**args)
|
||||
if 'errortext' in res:
|
||||
self.module.fail_json(msg="Failed: '%s'" % res['errortext'])
|
||||
return host
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = cs_argument_spec()
|
||||
argument_spec.update(dict(
|
||||
name=dict(required=True, aliases=['url']),
|
||||
password=dict(default=None, not_log=True),
|
||||
username=dict(default=None),
|
||||
hypervisor=dict(choices=CS_HYPERVISORS, default=None),
|
||||
allocation_state=dict(default=None),
|
||||
pod=dict(default=None),
|
||||
cluster=dict(default=None),
|
||||
host_tags=dict(default=None, type='list'),
|
||||
zone=dict(default=None),
|
||||
state=dict(choices=['present', 'absent'], default='present'),
|
||||
))
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
required_together=cs_required_together(),
|
||||
supports_check_mode=True
|
||||
)
|
||||
|
||||
try:
|
||||
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)
|
||||
|
||||
except CloudStackException as e:
|
||||
module.fail_json(msg='CloudStackException: %s' % str(e))
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
Reference in New Issue