Relocating extras into lib/ansible/modules/ after merge

This commit is contained in:
James Cammarata 2016-12-08 00:36:57 -05:00 committed by Matt Clay
commit 011ea55a8f
596 changed files with 0 additions and 266 deletions

View file

@ -0,0 +1,207 @@
#!/usr/bin/pythonapi/
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
import traceback
try:
import ovirtsdk4.types as otypes
except ImportError:
pass
from collections import defaultdict
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
BaseModule,
check_sdk,
create_connection,
ovirt_full_argument_spec,
)
ANSIBLE_METADATA = {'status': 'preview',
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_affinity_labels
short_description: Module to affinity labels in oVirt
version_added: "2.3"
author: "Ondra Machacek (@machacekondra)"
description:
- "This module manage affinity labels in oVirt. It can also manage assignments
of those labels to hosts and VMs."
options:
name:
description:
- "Name of the the affinity label to manage."
required: true
state:
description:
- "Should the affinity label be present or absent."
choices: ['present', 'absent']
default: present
cluster:
description:
- "Name of the cluster where vms and hosts resides."
vms:
description:
- "List of the VMs names, which should have assigned this affinity label."
hosts:
description:
- "List of the hosts names, which should have assigned this affinity label."
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Create(if not exists) and assign affinity label to vms vm1 and vm2 and host host1
- ovirt_affinity_labels:
name: mylabel
cluster: mycluster
vms:
- vm1
- vm2
hosts:
- host1
# To detach all VMs from label
- ovirt_affinity_labels:
name: mylabel
cluster: mycluster
vms: []
# Remove affinity label
- ovirt_affinity_labels:
state: absent
name: mylabel
'''
RETURN = '''
id:
description: ID of the affinity label which is managed
returned: On success if affinity label is found.
type: str
sample: 7de90f31-222c-436c-a1ca-7e655bd5b60c
template:
description: "Dictionary of all the affinity label attributes. Affinity label attributes can be found on your oVirt instance
at following url: https://ovirt.example.com/ovirt-engine/api/model#types/affinity_label."
returned: On success if affinity label is found.
'''
class AffinityLabelsModule(BaseModule):
def build_entity(self):
return otypes.AffinityLabel(name=self._module.params['name'])
def post_create(self, entity):
self.update_check(entity)
def pre_remove(self, entity):
self._module.params['vms'] = []
self._module.params['hosts'] = []
self.update_check(entity)
def _update_label_assignments(self, entity, name, label_obj_type):
objs_service = getattr(self._connection.system_service(), '%s_service' % name)()
if self._module.params[name] is not None:
objs = self._connection.follow_link(getattr(entity, name))
objs_names = defaultdict(list)
for obj in objs:
labeled_entity = objs_service.service(obj.id).get()
if self._module.params['cluster'] is None:
objs_names[labeled_entity.name].append(obj.id)
elif self._connection.follow_link(labeled_entity.cluster).name == self._module.params['cluster']:
objs_names[labeled_entity.name].append(obj.id)
for obj in self._module.params[name]:
if obj not in objs_names:
for obj_id in objs_service.list(
search='name=%s and cluster=%s' % (obj, self._module.params['cluster'])
):
label_service = getattr(self._service.service(entity.id), '%s_service' % name)()
if not self._module.check_mode:
label_service.add(**{
name[:-1]: label_obj_type(id=obj_id.id)
})
self.changed = True
for obj in objs_names:
if obj not in self._module.params[name]:
label_service = getattr(self._service.service(entity.id), '%s_service' % name)()
if not self._module.check_mode:
for obj_id in objs_names[obj]:
label_service.service(obj_id).remove()
self.changed = True
def update_check(self, entity):
self._update_label_assignments(entity, 'vms', otypes.Vm)
self._update_label_assignments(entity, 'hosts', otypes.Host)
return True
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(
choices=['present', 'absent'],
default='present',
),
cluster=dict(default=None),
name=dict(default=None, required=True),
vms=dict(default=None, type='list'),
hosts=dict(default=None, type='list'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
('state', 'present', ['cluster']),
],
)
check_sdk(module)
try:
connection = create_connection(module.params.pop('auth'))
affinity_labels_service = connection.system_service().affinity_labels_service()
affinity_labels_module = AffinityLabelsModule(
connection=connection,
module=module,
service=affinity_labels_service,
)
state = module.params['state']
if state == 'present':
ret = affinity_labels_module.create()
elif state == 'absent':
ret = affinity_labels_module.remove()
module.exit_json(**ret)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=False)
if __name__ == "__main__":
main()

View file

@ -0,0 +1,158 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
import fnmatch
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_full_argument_spec,
)
ANSIBLE_METADATA = {'status': 'preview',
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_affinity_labels_facts
short_description: Retrieve facts about one or more oVirt affinity labels
author: "Ondra Machacek (@machacekondra)"
version_added: "2.3"
description:
- "Retrieve facts about one or more oVirt affinity labels."
notes:
- "This module creates a new top-level C(affinity_labels) fact, which
contains a list of affinity labels."
options:
name:
description:
- "Name of the affinity labels which should be listed."
vm:
description:
- "Name of the VM, which affinity labels should be listed."
host:
description:
- "Name of the host, which affinity labels should be listed."
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather facts about all affinity labels, which names start with C(label):
- ovirt_affinity_labels_facts:
name: label*
- debug:
var: affinity_labels
# Gather facts about all affinity labels, which are assigned to VMs
# which names start with C(postgres):
- ovirt_affinity_labels_facts:
vm: postgres*
- debug:
var: affinity_labels
# Gather facts about all affinity labels, which are assigned to hosts
# which names start with C(west):
- ovirt_affinity_labels_facts:
host: west*
- debug:
var: affinity_labels
# Gather facts about all affinity labels, which are assigned to hosts
# which names start with C(west) or VMs which names start with C(postgres):
- ovirt_affinity_labels_facts:
host: west*
vm: postgres*
- debug:
var: affinity_labels
'''
RETURN = '''
ovirt_vms:
description: "List of dictionaries describing the affinity labels. Affinity labels attribues are mapped to dictionary keys,
all affinity labels attributes can be found at following url: https://ovirt.example.com/ovirt-engine/api/model#types/affinity_label."
returned: On success.
type: list
'''
def main():
argument_spec = ovirt_full_argument_spec(
name=dict(default=None),
host=dict(default=None),
vm=dict(default=None),
)
module = AnsibleModule(argument_spec)
check_sdk(module)
try:
connection = create_connection(module.params.pop('auth'))
affinity_labels_service = connection.system_service().affinity_labels_service()
labels = []
all_labels = affinity_labels_service.list()
if module.params['name']:
labels.extend([
l for l in all_labels
if fnmatch.fnmatch(l.name, module.params['name'])
])
if module.params['host']:
hosts_service = connection.system_service().hosts_service()
labels.extend([
label
for label in all_labels
for host in connection.follow_link(label.hosts)
if fnmatch.fnmatch(hosts_service.service(host.id).get().name, module.params['host'])
])
if module.params['vm']:
vms_service = connection.system_service().vms_service()
labels.extend([
label
for label in all_labels
for vm in connection.follow_link(label.vms)
if fnmatch.fnmatch(vms_service.service(vm.id).get().name, module.params['vm'])
])
if not (module.params['vm'] or module.params['host'] or module.params['name']):
labels = all_labels
module.exit_json(
changed=False,
ansible_facts=dict(
affinity_labels=[
get_dict_of_struct(l) for l in labels
],
),
)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=False)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,234 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
try:
import ovirtsdk4 as sdk
except ImportError:
pass
ANSIBLE_METADATA = {'status': ['preview'],
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_auth
short_description: "Module to manage authentication to oVirt."
author: "Ondra Machacek (@machacekondra)"
version_added: "2.2"
description:
- "This module authenticates to oVirt engine and creates SSO token, which should be later used in
all other oVirt modules, so all modules don't need to perform login and logout.
This module returns an Ansible fact called I(ovirt_auth). Every module can use this
fact as C(auth) parameter, to perform authentication."
options:
state:
default: present
choices: ['present', 'absent']
description:
- "Specifies if a token should be created or revoked."
username:
required: True
description:
- "The name of the user. For example: I(admin@internal)."
password:
required: True
description:
- "The password of the user."
url:
required: True
description:
- "A string containing the base URL of the server.
For example: I(https://server.example.com/ovirt-engine/api)."
insecure:
required: False
description:
- "A boolean flag that indicates if the server TLS certificate and host name should be checked."
ca_file:
required: False
description:
- "A PEM file containing the trusted CA certificates. The
certificate presented by the server will be verified using these CA
certificates. If C(ca_file) parameter is not set, system wide
CA certificate store is used."
timeout:
required: False
description:
- "The maximum total time to wait for the response, in
seconds. A value of zero (the default) means wait forever. If
the timeout expires before the response is received an exception
will be raised."
compress:
required: False
description:
- "A boolean flag indicating if the SDK should ask
the server to send compressed responses. The default is I(True).
Note that this is a hint for the server, and that it may return
uncompressed data even when this parameter is set to I(True)."
kerberos:
required: False
description:
- "A boolean flag indicating if Kerberos authentication
should be used instead of the default basic authentication."
notes:
- "Everytime you use ovirt_auth module to obtain ticket, you need to also revoke the ticket,
when you no longer need it, otherwise the ticket would be revoked by engine when it expires.
For an example of how to achieve that, please take a look at I(examples) section."
'''
EXAMPLES = '''
tasks:
- block:
# Create a vault with `ovirt_password` variable which store your
# oVirt user's password, and include that yaml file with variable:
- include_vars: ovirt_password.yml
- name: Obtain SSO token with using username/password credentials:
ovirt_auth:
url: https://ovirt.example.com/ovirt-engine/api
username: admin@internal
ca_file: ca.pem
password: "{{ ovirt_password }}"
# Previous task generated I(ovirt_auth) fact, which you can later use
# in different modules as follows:
- ovirt_vms:
auth: "{{ ovirt_auth }}"
state: absent
name: myvm
always:
- name: Always revoke the SSO token
ovirt_auth:
state: absent
ovirt_auth: "{{ ovirt_auth }}"
'''
RETURN = '''
ovirt_auth:
description: Authentication facts, needed to perform authentication to oVirt.
returned: success
type: dictionary
contains:
token:
description: SSO token which is used for connection to oVirt engine.
returned: success
type: string
sample: "kdfVWp9ZgeewBXV-iq3Js1-xQJZPSEQ334FLb3eksoEPRaab07DhZ8ED8ghz9lJd-MQ2GqtRIeqhvhCkrUWQPw"
url:
description: URL of the oVirt engine API endpoint.
returned: success
type: string
sample: "https://ovirt.example.com/ovirt-engine/api"
ca_file:
description: CA file, which is used to verify SSL/TLS connection.
returned: success
type: string
sample: "ca.pem"
insecure:
description: Flag indicating if insecure connection is used.
returned: success
type: bool
sample: False
timeout:
description: Number of seconds to wait for response.
returned: success
type: int
sample: 0
compress:
description: Flag indicating if compression is used for connection.
returned: success
type: bool
sample: True
kerberos:
description: Flag indicating if kerberos is used for authentication.
returned: success
type: bool
sample: False
'''
def main():
module = AnsibleModule(
argument_spec=dict(
url=dict(default=None),
username=dict(default=None),
password=dict(default=None, no_log=True),
ca_file=dict(default=None, type='path'),
insecure=dict(required=False, type='bool', default=False),
timeout=dict(required=False, type='int', default=0),
compress=dict(required=False, type='bool', default=True),
kerberos=dict(required=False, type='bool', default=False),
state=dict(default='present', choices=['present', 'absent']),
ovirt_auth=dict(required=None, type='dict'),
),
required_if=[
('state', 'absent', ['ovirt_auth']),
('state', 'present', ['username', 'password', 'url']),
],
)
check_sdk(module)
state = module.params.get('state')
if state == 'present':
params = module.params
elif state == 'absent':
params = module.params['ovirt_auth']
connection = sdk.Connection(
url=params.get('url'),
username=params.get('username'),
password=params.get('password'),
ca_file=params.get('ca_file'),
insecure=params.get('insecure'),
timeout=params.get('timeout'),
compress=params.get('compress'),
kerberos=params.get('kerberos'),
token=params.get('token'),
)
try:
token = connection.authenticate()
module.exit_json(
changed=False,
ansible_facts=dict(
ovirt_auth=dict(
token=token,
url=params.get('url'),
ca_file=params.get('ca_file'),
insecure=params.get('insecure'),
timeout=params.get('timeout'),
compress=params.get('compress'),
kerberos=params.get('kerberos'),
) if state == 'present' else dict()
)
)
except Exception as e:
module.fail_json(msg="Error: %s" % e)
finally:
# Close the connection, but don't revoke token
connection.close(logout=state == 'absent')
from ansible.module_utils.basic import *
from ansible.module_utils.ovirt import *
if __name__ == "__main__":
main()

View file

@ -0,0 +1,564 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
import traceback
try:
import ovirtsdk4.types as otypes
except ImportError:
pass
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
BaseModule,
check_sdk,
create_connection,
equal,
ovirt_full_argument_spec,
search_by_name,
)
ANSIBLE_METADATA = {'status': 'preview',
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_clusters
short_description: Module to manage clusters in oVirt
version_added: "2.3"
author: "Ondra Machacek (@machacekondra)"
description:
- "Module to manage clusters in oVirt"
options:
name:
description:
- "Name of the the cluster to manage."
required: true
state:
description:
- "Should the cluster be present or absent"
choices: ['present', 'absent']
default: present
datacenter:
description:
- "Datacenter name where cluster reside."
description:
description:
- "Description of the cluster."
comment:
description:
- "Comment of the cluster."
network:
description:
- "Management network of cluster to access cluster hosts."
ballooning:
description:
- "If (True) enable memory balloon optimization. Memory balloon is used to
re-distribute / reclaim the host memory based on VM needs
in a dynamic way."
virt:
description:
- "If (True), hosts in this cluster will be used to run virtual machines."
gluster:
description:
- "If (True), hosts in this cluster will be used as Gluster Storage
server nodes, and not for running virtual machines."
- "By default the cluster is created for virtual machine hosts."
threads_as_cores:
description:
- "If (True) the exposed host threads would be treated as cores
which can be utilized by virtual machines."
ksm:
description:
- "I (True) MoM enables to run Kernel Same-page Merging (KSM) when
necessary and when it can yield a memory saving benefit that
outweighs its CPU cost."
ksm_numa:
description:
- "If (True) enables KSM C(ksm) for best berformance inside NUMA nodes."
ha_reservation:
description:
- "If (True) enable the oVirt to monitor cluster capacity for highly
available virtual machines."
trusted_service:
description:
- "If (True) enable integration with an OpenAttestation server."
vm_reason:
description:
- "If (True) enable an optional reason field when a virtual machine
is shut down from the Manager, allowing the administrator to
provide an explanation for the maintenance."
host_reason:
description:
- "If (True) enable an optional reason field when a host is placed
into maintenance mode from the Manager, allowing the administrator
to provide an explanation for the maintenance."
memory_policy:
description:
- "I(disabled) - Disables memory page sharing."
- "I(server) - Sets the memory page sharing threshold to 150% of the system memory on each host."
- "I(desktop) - Sets the memory page sharing threshold to 200% of the system memory on each host."
choices: ['disabled', 'server', 'desktop']
rng_sources:
description:
- "List that specify the random number generator devices that all hosts in the cluster will use."
- "Supported generators are: I(hwrng) and I(random)."
spice_proxy:
description:
- "The proxy by which the SPICE client will connect to virtual machines."
- "The address must be in the following format: I(protocol://[host]:[port])"
fence_enabled:
description:
- "If (True) enables fencing on the cluster."
- "Fencing is enabled by default."
fence_skip_if_sd_active:
description:
- "If (True) any hosts in the cluster that are Non Responsive
and still connected to storage will not be fenced."
fence_skip_if_connectivity_broken:
description:
- "If (True) fencing will be temporarily disabled if the percentage
of hosts in the cluster that are experiencing connectivity issues
is greater than or equal to the defined threshold."
- "The threshold can be specified by C(fence_connectivity_threshold)."
fence_connectivity_threshold:
description:
- "The threshold used by C(fence_skip_if_connectivity_broken)."
resilience_policy:
description:
- "The resilience policy defines how the virtual machines are prioritized in the migration."
- "Following values are supported:"
- "C(do_not_migrate) - Prevents virtual machines from being migrated. "
- "C(migrate) - Migrates all virtual machines in order of their defined priority."
- "C(migrate_highly_available) - Migrates only highly available virtual machines to prevent overloading other hosts."
choices: ['do_not_migrate', 'migrate', 'migrate_highly_available']
migration_bandwidth:
description:
- "The bandwidth settings define the maximum bandwidth of both outgoing and incoming migrations per host."
- "Following bandwith options are supported:"
- "C(auto) - Bandwidth is copied from the I(rate limit) [Mbps] setting in the data center host network QoS."
- "C(hypervisor_default) - Bandwidth is controlled by local VDSM setting on sending host."
- "C(custom) - Defined by user (in Mbps)."
choices: ['auto', 'hypervisor_default', 'custom']
migration_bandwidth_limit:
description:
- "Set the I(custom) migration bandwidth limit."
- "This parameter is used only when C(migration_bandwidth) is I(custom)."
migration_auto_converge:
description:
- "If (True) auto-convergence is used during live migration of virtual machines."
- "Used only when C(migration_policy) is set to I(legacy)."
- "Following options are supported:"
- "C(true) - Override the global setting to I(true)."
- "C(false) - Override the global setting to I(false)."
- "C(inherit) - Use value which is set globally."
choices: ['true', 'false', 'inherit']
migration_compressed:
description:
- "If (True) compression is used during live migration of the virtual machine."
- "Used only when C(migration_policy) is set to I(legacy)."
- "Following options are supported:"
- "C(true) - Override the global setting to I(true)."
- "C(false) - Override the global setting to I(false)."
- "C(inherit) - Use value which is set globally."
choices: ['true', 'false', 'inherit']
migration_policy:
description:
- "A migration policy defines the conditions for live migrating
virtual machines in the event of host failure."
- "Following policies are supported:"
- "C(legacy) - Legacy behavior of 3.6 version."
- "C(minimal_downtime) - Virtual machines should not experience any significant downtime."
- "C(suspend_workload) - Virtual machines may experience a more significant downtime."
choices: ['legacy', 'minimal_downtime', 'suspend_workload']
serial_policy:
description:
- "Specify a serial number policy for the virtual machines in the cluster."
- "Following options are supported:"
- "C(vm) - Sets the virtual machine's UUID as its serial number."
- "C(host) - Sets the host's UUID as the virtual machine's serial number."
- "C(custom) - Allows you to specify a custom serial number in C(serial_policy_value)."
serial_policy_value:
description:
- "Allows you to specify a custom serial number."
- "This parameter is used only when C(serial_policy) is I(custom)."
scheduling_policy:
description:
- "Name of the scheduling policy to be used for cluster."
cpu_arch:
description:
- "CPU architecture of cluster."
choices: ['x86_64', 'ppc64', 'undefined']
cpu_type:
description:
- "CPU codename. For example I(Intel SandyBridge Family)."
switch_type:
description:
- "Type of switch to be used by all networks in given cluster.
Either I(legacy) which is using linux brigde or I(ovs) using
Open vSwitch."
choices: ['legacy', 'ovs']
compatibility_version:
description:
- "The compatibility version of the cluster. All hosts in this
cluster must support at least this compatibility version."
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Create cluster
- ovirt_clusters:
datacenter: mydatacenter
name: mycluster
cpu_type: Intel SandyBridge Family
description: mycluster
compatibility_version: 4.0
# Create virt service cluster:
- ovirt_clusters:
datacenter: mydatacenter
name: mycluster
cpu_type: Intel Nehalem Family
description: mycluster
switch_type: legacy
compatibility_version: 4.0
ballooning: true
gluster: false
threads_as_cores: true
ha_reservation: true
trusted_service: false
host_reason: false
vm_reason: true
ksm_numa: true
memory_policy: server
rng_sources:
- hwrng
- random
# Remove cluster
- ovirt_clusters:
state: absent
name: mycluster
'''
RETURN = '''
id:
description: ID of the cluster which is managed
returned: On success if cluster is found.
type: str
sample: 7de90f31-222c-436c-a1ca-7e655bd5b60c
cluster:
description: "Dictionary of all the cluster attributes. Cluster attributes can be found on your oVirt instance
at following url: https://ovirt.example.com/ovirt-engine/api/model#types/cluster."
returned: On success if cluster is found.
'''
class ClustersModule(BaseModule):
def __get_major(self, full_version):
if full_version is None:
return None
if isinstance(full_version, otypes.Version):
return full_version.major
return int(full_version.split('.')[0])
def __get_minor(self, full_version):
if full_version is None:
return None
if isinstance(full_version, otypes.Version):
return full_version.minor
return int(full_version.split('.')[1])
def param(self, name, default=None):
return self._module.params.get(name, default)
def _get_memory_policy(self):
memory_policy = self.param('memory_policy')
if memory_policy == 'desktop':
return 200
elif memory_policy == 'server':
return 150
elif memory_policy == 'disabled':
return 100
def _get_policy_id(self):
# These are hardcoded IDs, once there is API, please fix this.
# legacy - 00000000-0000-0000-0000-000000000000
# minimal downtime - 80554327-0569-496b-bdeb-fcbbf52b827b
# suspend workload if needed - 80554327-0569-496b-bdeb-fcbbf52b827c
migration_policy = self.param('migration_policy')
if migration_policy == 'legacy':
return '00000000-0000-0000-0000-000000000000'
elif migration_policy == 'minimal_downtime':
return '80554327-0569-496b-bdeb-fcbbf52b827b'
elif migration_policy == 'suspend_workload':
return '80554327-0569-496b-bdeb-fcbbf52b827c'
def _get_sched_policy(self):
sched_policy = None
if self.param('serial_policy'):
sched_policies_service = self._connection.system_service().scheduling_policies_service()
sched_policy = search_by_name(sched_policies_service, self.param('scheduling_policy'))
if not sched_policy:
raise Exception("Scheduling policy '%s' was not found" % self.param('scheduling_policy'))
return sched_policy
def build_entity(self):
sched_policy = self._get_sched_policy()
return otypes.Cluster(
name=self.param('name'),
comment=self.param('comment'),
description=self.param('description'),
ballooning_enabled=self.param('ballooning'),
gluster_service=self.param('gluster'),
virt_service=self.param('virt'),
threads_as_cores=self.param('threads_as_cores'),
ha_reservation=self.param('ha_reservation'),
trusted_service=self.param('trusted_service'),
optional_reason=self.param('vm_reason'),
maintenance_reason_required=self.param('host_reason'),
scheduling_policy=otypes.SchedulingPolicy(
id=sched_policy.id,
) if sched_policy else None,
serial_number=otypes.SerialNumber(
policy=otypes.SerialNumberPolicy(self.param('serial_policy')),
value=self.param('serial_policy_value'),
) if (
self.param('serial_policy') is not None or
self.param('serial_policy_value') is not None
) else None,
migration=otypes.MigrationOptions(
auto_converge=otypes.InheritableBoolean(
self.param('migration_auto_converge'),
) if self.param('migration_auto_converge') else None,
bandwidth=otypes.MigrationBandwidth(
assignment_method=otypes.MigrationBandwidthAssignmentMethod(
self.param('migration_bandwidth'),
) if self.param('migration_bandwidth') else None,
custom_value=self.param('migration_bandwidth_limit'),
) if (
self.param('migration_bandwidth') or
self.param('migration_bandwidth_limit')
) else None,
compressed=otypes.InheritableBoolean(
self.param('migration_compressed'),
) if self.param('migration_compressed') else None,
policy=otypes.MigrationPolicy(
id=self._get_policy_id()
) if self.param('migration_policy') else None,
) if (
self.param('migration_bandwidth') is not None or
self.param('migration_bandwidth_limit') is not None or
self.param('migration_auto_converge') is not None or
self.param('migration_compressed') is not None or
self.param('migration_policy') is not None
) else None,
error_handling=otypes.ErrorHandling(
on_error=otypes.MigrateOnError(
self.param('resilience_policy')
),
) if self.param('resilience_policy') else None,
fencing_policy=otypes.FencingPolicy(
enabled=(
self.param('fence_enabled') or
self.param('fence_skip_if_connectivity_broken') or
self.param('fence_skip_if_sd_active')
),
skip_if_connectivity_broken=otypes.SkipIfConnectivityBroken(
enabled=self.param('fence_skip_if_connectivity_broken'),
threshold=self.param('fence_connectivity_threshold'),
) if (
self.param('fence_skip_if_connectivity_broken') is not None or
self.param('fence_connectivity_threshold') is not None
) else None,
skip_if_sd_active=otypes.SkipIfSdActive(
enabled=self.param('fence_skip_if_sd_active'),
) if self.param('fence_skip_if_sd_active') else None,
) if (
self.param('fence_enabled') is not None or
self.param('fence_skip_if_sd_active') is not None or
self.param('fence_skip_if_connectivity_broken') is not None or
self.param('fence_connectivity_threshold') is not None
) else None,
display=otypes.Display(
proxy=self.param('spice_proxy'),
) if self.param('spice_proxy') else None,
required_rng_sources=[
otypes.RngSource(rng) for rng in self.param('rng_sources')
] if self.param('rng_sources') else None,
memory_policy=otypes.MemoryPolicy(
over_commit=otypes.MemoryOverCommit(
percent=self._get_memory_policy(),
),
) if self.param('memory_policy') else None,
ksm=otypes.Ksm(
enabled=self.param('ksm') or self.param('ksm_numa'),
merge_across_nodes=not self.param('ksm_numa'),
) if (
self.param('ksm_numa') is not None or
self.param('ksm') is not None
) else None,
data_center=otypes.DataCenter(
name=self.param('datacenter'),
) if self.param('datacenter') else None,
management_network=otypes.Network(
name=self.param('network'),
) if self.param('network') else None,
cpu=otypes.Cpu(
architecture=self.param('cpu_arch'),
type=self.param('cpu_type'),
) if (
self.param('cpu_arch') or self.param('cpu_type')
) else None,
version=otypes.Version(
major=self.__get_major(self.param('compatibility_version')),
minor=self.__get_minor(self.param('compatibility_version')),
) if self.param('compatibility_version') else None,
switch_type=otypes.SwitchType(
self.param('switch_type')
) if self.param('switch_type') else None,
)
def update_check(self, entity):
return (
equal(self.param('comment'), entity.comment) and
equal(self.param('description'), entity.description) and
equal(self.param('switch_type'), str(entity.switch_type)) and
equal(self.param('cpu_arch'), str(entity.cpu.architecture)) and
equal(self.param('cpu_type'), entity.cpu.type) and
equal(self.param('ballooning'), entity.ballooning_enabled) and
equal(self.param('gluster'), entity.gluster_service) and
equal(self.param('virt'), entity.virt_service) and
equal(self.param('threads_as_cores'), entity.threads_as_cores) and
equal(self.param('ksm_numa'), not entity.ksm.merge_across_nodes and entity.ksm.enabled) and
equal(self.param('ksm'), entity.ksm.merge_across_nodes and entity.ksm.enabled) and
equal(self.param('ha_reservation'), entity.ha_reservation) and
equal(self.param('trusted_service'), entity.trusted_service) and
equal(self.param('host_reason'), entity.maintenance_reason_required) and
equal(self.param('vm_reason'), entity.optional_reason) and
equal(self.param('spice_proxy'), getattr(entity.display, 'proxy', None)) and
equal(self.param('fence_enabled'), entity.fencing_policy.enabled) and
equal(self.param('fence_skip_if_sd_active'), entity.fencing_policy.skip_if_sd_active.enabled) and
equal(self.param('fence_skip_if_connectivity_broken'), entity.fencing_policy.skip_if_connectivity_broken.enabled) and
equal(self.param('fence_connectivity_threshold'), entity.fencing_policy.skip_if_connectivity_broken.threshold) and
equal(self.param('resilience_policy'), str(entity.error_handling.on_error)) and
equal(self.param('migration_bandwidth'), str(entity.migration.bandwidth.assignment_method)) and
equal(self.param('migration_auto_converge'), str(entity.migration.auto_converge)) and
equal(self.param('migration_compressed'), str(entity.migration.compressed)) and
equal(self.param('serial_policy'), str(entity.serial_number.policy)) and
equal(self.param('serial_policy_value'), entity.serial_number.value) and
equal(self.param('scheduling_policy'), self._get_sched_policy().name) and
equal(self._get_policy_id(), entity.migration.policy.id) and
equal(self._get_memory_policy(), entity.memory_policy.over_commit.percent) and
equal(self.__get_minor(self.param('compatibility_version')), self.__get_minor(entity.version)) and
equal(self.__get_major(self.param('compatibility_version')), self.__get_major(entity.version)) and
equal(
self.param('migration_bandwidth_limit') if self.param('migration_bandwidth') == 'custom' else None,
entity.migration.bandwidth.custom_value
) and
equal(
sorted(self.param('rng_sources')) if self.param('rng_sources') else None,
sorted([
str(source) for source in entity.required_rng_sources
])
)
)
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(
choices=['present', 'absent'],
default='present',
),
name=dict(default=None, required=True),
ballooning=dict(default=None, type='bool', aliases=['balloon']),
gluster=dict(default=None, type='bool'),
virt=dict(default=None, type='bool'),
threads_as_cores=dict(default=None, type='bool'),
ksm_numa=dict(default=None, type='bool'),
ksm=dict(default=None, type='bool'),
ha_reservation=dict(default=None, type='bool'),
trusted_service=dict(default=None, type='bool'),
vm_reason=dict(default=None, type='bool'),
host_reason=dict(default=None, type='bool'),
memory_policy=dict(default=None, choices=['disabled', 'server', 'desktop']),
rng_sources=dict(default=None, type='list'),
spice_proxy=dict(default=None),
fence_enabled=dict(default=None, type='bool'),
fence_skip_if_sd_active=dict(default=None, type='bool'),
fence_skip_if_connectivity_broken=dict(default=None, type='bool'),
fence_connectivity_threshold=dict(default=None, type='int'),
resilience_policy=dict(default=None, choices=['migrate_highly_available', 'migrate', 'do_not_migrate']),
migration_bandwidth=dict(default=None, choices=['auto', 'hypervisor_default', 'custom']),
migration_bandwidth_limit=dict(default=None, type='int'),
migration_auto_converge=dict(default=None, choices=['true', 'false', 'inherit']),
migration_compressed=dict(default=None, choices=['true', 'false', 'inherit']),
migration_policy=dict(default=None, choices=['legacy', 'minimal_downtime', 'suspend_workload']),
serial_policy=dict(default=None, choices=['vm', 'host', 'custom']),
serial_policy_value=dict(default=None),
scheduling_policy=dict(default=None),
datacenter=dict(default=None),
description=dict(default=None),
comment=dict(default=None),
network=dict(default=None),
cpu_arch=dict(default=None, choices=['ppc64', 'undefined', 'x86_64']),
cpu_type=dict(default=None),
switch_type=dict(default=None, choices=['legacy', 'ovs']),
compatibility_version=dict(default=None),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
)
check_sdk(module)
try:
connection = create_connection(module.params.pop('auth'))
clusters_service = connection.system_service().clusters_service()
clusters_module = ClustersModule(
connection=connection,
module=module,
service=clusters_service,
)
state = module.params['state']
if state == 'present':
ret = clusters_module.create()
elif state == 'absent':
ret = clusters_module.remove()
module.exit_json(**ret)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=False)
if __name__ == "__main__":
main()

View file

@ -0,0 +1,103 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_full_argument_spec,
)
ANSIBLE_METADATA = {'status': 'preview',
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_clusters_facts
short_description: Retrieve facts about one or more oVirt clusters
author: "Ondra Machacek (@machacekondra)"
version_added: "2.3"
description:
- "Retrieve facts about one or more oVirt clusters."
notes:
- "This module creates a new top-level C(ovirt_clusters) fact, which
contains a list of clusters."
options:
pattern:
description:
- "Search term which is accepted by oVirt search backend."
- "For example to search cluster X from datacenter Y use following pattern:
name=X and datacenter=Y"
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather facts about all clusters which names start with C<production>:
- ovirt_clusters_facts:
pattern: name=production*
- debug:
var: ovirt_clusters
'''
RETURN = '''
ovirt_clusters:
description: "List of dictionaries describing the clusters. Cluster attribues are mapped to dictionary keys,
all clusters attributes can be found at following url: https://ovirt.example.com/ovirt-engine/api/model#types/cluster."
returned: On success.
type: list
'''
def main():
argument_spec = ovirt_full_argument_spec(
pattern=dict(default='', required=False),
)
module = AnsibleModule(argument_spec)
check_sdk(module)
try:
connection = create_connection(module.params.pop('auth'))
clusters_service = connection.system_service().clusters_service()
clusters = clusters_service.list(search=module.params['pattern'])
module.exit_json(
changed=False,
ansible_facts=dict(
ovirt_clusters=[
get_dict_of_struct(c) for c in clusters
],
),
)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=False)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,221 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
import traceback
try:
import ovirtsdk4.types as otypes
except ImportError:
pass
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
BaseModule,
check_sdk,
check_params,
create_connection,
equal,
ovirt_full_argument_spec,
search_by_name,
)
ANSIBLE_METADATA = {'status': 'preview',
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_datacenters
short_description: Module to manage data centers in oVirt
version_added: "2.3"
author: "Ondra Machacek (@machacekondra)"
description:
- "Module to manage data centers in oVirt"
options:
name:
description:
- "Name of the the data center to manage."
required: true
state:
description:
- "Should the data center be present or absent"
choices: ['present', 'absent']
default: present
description:
description:
- "Description of the data center."
comment:
description:
- "Comment of the data center."
local:
description:
- "I(True) if the data center should be local, I(False) if should be shared."
- "Default value is set by engine."
compatibility_version:
description:
- "Compatibility version of the data center."
quota_mode:
description:
- "Quota mode of the data center. One of I(disabled), I(audit) or I(enabled)"
choices: ['disabled', 'audit', 'enabled']
mac_pool:
description:
- "MAC pool to be used by this datacenter."
- "IMPORTANT: This option is deprecated in oVirt 4.1. You should
use C(mac_pool) in C(ovirt_clusters) module, as MAC pools are
set per cluster since 4.1."
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Create datacenter
- ovirt_datacenters:
name: mydatacenter
local: True
compatibility_version: 4.0
quota_mode: enabled
# Remove datacenter
- ovirt_datacenters:
state: absent
name: mydatacenter
'''
RETURN = '''
id:
description: "ID of the managed datacenter"
returned: "On success if datacenter is found."
type: str
sample: 7de90f31-222c-436c-a1ca-7e655bd5b60c
data_center:
description: "Dictionary of all the datacenter attributes. Datacenter attributes can be found on your oVirt instance
at following url: https://ovirt.example.com/ovirt-engine/api/model#types/datacenter."
returned: "On success if datacenter is found."
'''
class DatacentersModule(BaseModule):
def __get_major(self, full_version):
if full_version is None:
return None
if isinstance(full_version, otypes.Version):
return full_version.major
return int(full_version.split('.')[0])
def __get_minor(self, full_version):
if full_version is None:
return None
if isinstance(full_version, otypes.Version):
return full_version.minor
return int(full_version.split('.')[1])
def _get_mac_pool(self):
mac_pool = None
if self._module.params.get('mac_pool'):
mac_pool = search_by_name(
self._connection.system_service().mac_pools_service(),
self._module.params.get('mac_pool'),
)
return mac_pool
def build_entity(self):
return otypes.DataCenter(
name=self._module.params['name'],
comment=self._module.params['comment'],
description=self._module.params['description'],
mac_pool=otypes.MacPool(
id=getattr(self._get_mac_pool(), 'id', None),
) if self._module.params.get('mac_pool') else None,
quota_mode=otypes.QuotaModeType(
self._module.params['quota_mode']
) if self._module.params['quota_mode'] else None,
local=self._module.params['local'],
version=otypes.Version(
major=self.__get_major(self._module.params['compatibility_version']),
minor=self.__get_minor(self._module.params['compatibility_version']),
) if self._module.params['compatibility_version'] else None,
)
def update_check(self, entity):
minor = self.__get_minor(self._module.params.get('compatibility_version'))
major = self.__get_major(self._module.params.get('compatibility_version'))
return (
equal(getattr(self._get_mac_pool(), 'id', None), getattr(entity.mac_pool, 'id', None)) and
equal(self._module.params.get('comment'), entity.comment) and
equal(self._module.params.get('description'), entity.description) and
equal(self._module.params.get('quota_mode'), str(entity.quota_mode)) and
equal(self._module.params.get('local'), entity.local) and
equal(minor, self.__get_minor(entity.version)) and
equal(major, self.__get_major(entity.version))
)
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(
choices=['present', 'absent'],
default='present',
),
name=dict(default=None, required=True),
description=dict(default=None),
local=dict(type='bool'),
compatibility_version=dict(default=None),
quota_mode=dict(choices=['disabled', 'audit', 'enabled']),
comment=dict(default=None),
mac_pool=dict(default=None),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
)
check_sdk(module)
check_params(module)
try:
connection = create_connection(module.params.pop('auth'))
data_centers_service = connection.system_service().data_centers_service()
clusters_module = DatacentersModule(
connection=connection,
module=module,
service=data_centers_service,
)
state = module.params['state']
if state == 'present':
ret = clusters_module.create()
elif state == 'absent':
ret = clusters_module.remove()
module.exit_json(**ret)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=False)
if __name__ == "__main__":
main()

View file

@ -0,0 +1,102 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_full_argument_spec,
)
ANSIBLE_METADATA = {'status': 'preview',
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_datacenters_facts
short_description: Retrieve facts about one or more oVirt datacenters
author: "Ondra Machacek (@machacekondra)"
version_added: "2.3"
description:
- "Retrieve facts about one or more oVirt datacenters."
notes:
- "This module creates a new top-level C(ovirt_datacenters) fact, which
contains a list of datacenters."
options:
pattern:
description:
- "Search term which is accepted by oVirt search backend."
- "For example to search datacenter I(X) use following pattern: I(name=X)"
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather facts about all data centers which names start with C(production):
- ovirt_datacenters_facts:
pattern: name=production*
- debug:
var: ovirt_datacenters
'''
RETURN = '''
ovirt_datacenters:
description: "List of dictionaries describing the datacenters. Datacenter attribues are mapped to dictionary keys,
all datacenters attributes can be found at following url: https://ovirt.example.com/ovirt-engine/api/model#types/data_center."
returned: On success.
type: list
'''
def main():
argument_spec = ovirt_full_argument_spec(
pattern=dict(default='', required=False),
)
module = AnsibleModule(argument_spec)
check_sdk(module)
try:
connection = create_connection(module.params.pop('auth'))
datacenters_service = connection.system_service().data_centers_service()
datacenters = datacenters_service.list(search=module.params['pattern'])
module.exit_json(
changed=False,
ansible_facts=dict(
ovirt_datacenters=[
get_dict_of_struct(c) for c in datacenters
],
),
)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=False)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,322 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
try:
import ovirtsdk4 as sdk
import ovirtsdk4.types as otypes
except ImportError:
pass
from ansible.module_utils.ovirt import *
ANSIBLE_METADATA = {'status': ['preview'],
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_disks
short_description: "Module to manage Virtual Machine and floating disks in oVirt."
version_added: "2.2"
author: "Ondra Machacek (@machacekondra)"
description:
- "Module to manage Virtual Machine and floating disks in oVirt."
options:
id:
description:
- "ID of the disk to manage. Either C(id) or C(name) is required."
name:
description:
- "Name of the disk to manage. Either C(id) or C(name)/C(alias) is required."
aliases: ['alias']
vm_name:
description:
- "Name of the Virtual Machine to manage. Either C(vm_id) or C(vm_name) is required if C(state) is I(attached) or I(detached)."
vm_id:
description:
- "ID of the Virtual Machine to manage. Either C(vm_id) or C(vm_name) is required if C(state) is I(attached) or I(detached)."
state:
description:
- "Should the Virtual Machine disk be present/absent/attached/detached."
choices: ['present', 'absent', 'attached', 'detached']
default: 'present'
size:
description:
- "Size of the disk. Size should be specified using IEC standard units. For example 10GiB, 1024MiB, etc."
interface:
description:
- "Driver of the storage interface."
choices: ['virtio', 'ide', 'virtio_scsi']
default: 'virtio'
format:
description:
- Specify format of the disk.
- If (cow) format is used, disk will by created as sparse, so space will be allocated for the volume as needed, also known as I(thin provision).
- If (raw) format is used, disk storage will be allocated right away, also known as I(preallocated).
- Note that this option isn't idempotent as it's not currently possible to change format of the disk via API.
choices: ['raw', 'cow']
storage_domain:
description:
- "Storage domain name where disk should be created. By default storage is chosen by oVirt engine."
profile:
description:
- "Disk profile name to be attached to disk. By default profile is chosen by oVirt engine."
bootable:
description:
- "I(True) if the disk should be bootable. By default when disk is created it isn't bootable."
shareable:
description:
- "I(True) if the disk should be shareable. By default when disk is created it isn't shareable."
logical_unit:
description:
- "Dictionary which describes LUN to be directly attached to VM:"
- "C(address) - Address of the storage server. Used by iSCSI."
- "C(port) - Port of the storage server. Used by iSCSI."
- "C(target) - iSCSI target."
- "C(lun_id) - LUN id."
- "C(username) - CHAP Username to be used to access storage server. Used by iSCSI."
- "C(password) - CHAP Password of the user to be used to access storage server. Used by iSCSI."
- "C(storage_type) - Storage type either I(fcp) or I(iscsi)."
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Create and attach new disk to VM
- ovirt_disks:
name: myvm_disk
vm_name: rhel7
size: 10GiB
format: cow
interface: virtio
# Attach logical unit to VM rhel7
- ovirt_disks:
vm_name: rhel7
logical_unit:
target: iqn.2016-08-09.brq.str-01:omachace
id: 1IET_000d0001
address: 10.34.63.204
interface: virtio
# Detach disk from VM
- ovirt_disks:
state: detached
name: myvm_disk
vm_name: rhel7
size: 10GiB
format: cow
interface: virtio
'''
RETURN = '''
id:
description: "ID of the managed disk"
returned: "On success if disk is found."
type: str
sample: 7de90f31-222c-436c-a1ca-7e655bd5b60c
disk:
description: "Dictionary of all the disk attributes. Disk attributes can be found on your oVirt instance
at following url: https://ovirt.example.com/ovirt-engine/api/model#types/disk."
returned: "On success if disk is found and C(vm_id) or C(vm_name) wasn't passed."
disk_attachment:
description: "Dictionary of all the disk attachment attributes. Disk attachment attributes can be found
on your oVirt instance at following url:
https://ovirt.example.com/ovirt-engine/api/model#types/disk_attachment."
returned: "On success if disk is found and C(vm_id) or C(vm_name) was passed and VM was found."
'''
def _search_by_lun(disks_service, lun_id):
"""
Find disk by LUN ID.
"""
res = [
disk for disk in disks_service.list(search='disk_type=lun') if (
disk.lun_storage.id == lun_id
)
]
return res[0] if res else None
class DisksModule(BaseModule):
def build_entity(self):
logical_unit = self._module.params.get('logical_unit')
return otypes.Disk(
id=self._module.params.get('id'),
name=self._module.params.get('name'),
description=self._module.params.get('description'),
format=otypes.DiskFormat(
self._module.params.get('format')
) if self._module.params.get('format') else None,
sparse=False if self._module.params.get('format') == 'raw' else True,
provisioned_size=convert_to_bytes(
self._module.params.get('size')
),
storage_domains=[
otypes.StorageDomain(
name=self._module.params.get('storage_domain'),
),
],
shareable=self._module.params.get('shareable'),
lun_storage=otypes.HostStorage(
type=otypes.StorageType(
logical_unit.get('storage_type', 'iscsi')
),
logical_units=[
otypes.LogicalUnit(
address=logical_unit.get('address'),
port=logical_unit.get('port', 3260),
target=logical_unit.get('target'),
id=logical_unit.get('id'),
username=logical_unit.get('username'),
password=logical_unit.get('password'),
)
],
) if logical_unit else None,
)
def update_check(self, entity):
return (
equal(self._module.params.get('description'), entity.description) and
equal(convert_to_bytes(self._module.params.get('size')), entity.provisioned_size) and
equal(self._module.params.get('shareable'), entity.shareable)
)
class DiskAttachmentsModule(DisksModule):
def build_entity(self):
return otypes.DiskAttachment(
disk=super(DiskAttachmentsModule, self).build_entity(),
interface=otypes.DiskInterface(
self._module.params.get('interface')
) if self._module.params.get('interface') else None,
bootable=self._module.params.get('bootable'),
active=True,
)
def update_check(self, entity):
return (
equal(self._module.params.get('interface'), str(entity.interface)) and
equal(self._module.params.get('bootable'), entity.bootable)
)
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(
choices=['present', 'absent', 'attached', 'detached'],
default='present'
),
id=dict(default=None),
name=dict(default=None, aliases=['alias']),
vm_name=dict(default=None),
vm_id=dict(default=None),
size=dict(default=None),
interface=dict(default=None,),
storage_domain=dict(default=None),
profile=dict(default=None),
format=dict(default=None, choices=['raw', 'cow']),
bootable=dict(default=None, type='bool'),
shareable=dict(default=None, type='bool'),
logical_unit=dict(default=None, type='dict'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
)
check_sdk(module)
check_params(module)
try:
disk = None
state = module.params['state']
connection = create_connection(module.params.pop('auth'))
disks_service = connection.system_service().disks_service()
disks_module = DisksModule(
connection=connection,
module=module,
service=disks_service,
)
lun = module.params.get('logical_unit')
if lun:
disk = _search_by_lun(disks_service, lun.get('id'))
ret = None
# First take care of creating the VM, if needed:
if state == 'present' or state == 'detached' or state == 'attached':
ret = disks_module.create(
entity=disk,
result_state=otypes.DiskStatus.OK if lun is None else None,
)
# We need to pass ID to the module, so in case we want detach/attach disk
# we have this ID specified to attach/detach method:
module.params['id'] = ret['id'] if disk is None else disk.id
elif state == 'absent':
ret = disks_module.remove()
# If VM was passed attach/detach disks to/from the VM:
if module.params.get('vm_id') is not None or module.params.get('vm_name') is not None and state != 'absent':
vms_service = connection.system_service().vms_service()
# If `vm_id` isn't specified, find VM by name:
vm_id = module.params['vm_id']
if vm_id is None:
vm_id = getattr(search_by_name(vms_service, module.params['vm_name']), 'id', None)
if vm_id is None:
module.fail_json(
msg="VM don't exists, please create it first."
)
disk_attachments_service = vms_service.vm_service(vm_id).disk_attachments_service()
disk_attachments_module = DiskAttachmentsModule(
connection=connection,
module=module,
service=disk_attachments_service,
changed=ret['changed'] if ret else False,
)
if state == 'present' or state == 'attached':
ret = disk_attachments_module.create()
elif state == 'detached':
ret = disk_attachments_module.remove()
module.exit_json(**ret)
except Exception as e:
module.fail_json(msg=str(e))
finally:
connection.close(logout=False)
from ansible.module_utils.basic import *
if __name__ == "__main__":
main()

View file

@ -0,0 +1,248 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
import traceback
try:
import ovirtsdk4.types as otypes
except ImportError:
pass
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
BaseModule,
check_params,
check_sdk,
create_connection,
equal,
ovirt_full_argument_spec,
)
ANSIBLE_METADATA = {'status': 'preview',
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_external_providers
short_description: Module to manage external providers in oVirt
version_added: "2.3"
author: "Ondra Machacek (@machacekondra)"
description:
- "Module to manage external providers in oVirt"
options:
name:
description:
- "Name of the the external provider to manage."
state:
description:
- "Should the external be present or absent"
choices: ['present', 'absent']
default: present
description:
description:
- "Description of the external provider."
type:
description:
- "Type of the external provider."
choices: ['os_image', 'os_network', 'os_volume', 'foreman']
url:
description:
- "URL where external provider is hosted."
- "Applicable for those types: I(os_image), I(os_volume), I(os_network) and I(foreman)."
username:
description:
- "Username to be used for login to external provider."
- "Applicable for all types."
password:
description:
- "Password of the user specified in C(username) parameter."
- "Applicable for all types."
tenant_name:
description:
- "Name of the tenant."
- "Applicable for those types: I(os_image), I(os_volume) and I(os_network)."
aliases: ['tenant']
authentication_url:
description:
- "Keystone authentication URL of the openstack provider."
- "Applicable for those types: I(os_image), I(os_volume) and I(os_network)."
aliases: ['auth_url']
data_center:
description:
- "Name of the data center where provider should be attached."
- "Applicable for those type: I(os_volume)."
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Add image external provider:
- ovirt_external_providers:
name: image_provider
type: os_image
url: http://10.34.63.71:9292
username: admin
password: 123456
tenant: admin
auth_url: http://10.34.63.71:35357/v2.0/
# Add foreman provider:
- ovirt_external_providers:
name: foreman_provider
type: foreman
url: https://foreman.example.com
username: admin
password: 123456
# Remove image external provider:
- ovirt_external_providers:
state: absent
name: image_provider
type: os_image
'''
RETURN = '''
id:
description: ID of the external provider which is managed
returned: On success if external provider is found.
type: str
sample: 7de90f31-222c-436c-a1ca-7e655bd5b60c
external_host_provider:
description: "Dictionary of all the external_host_provider attributes. External provider attributes can be found on your oVirt instance
at following url: https://ovirt.example.com/ovirt-engine/api/model#types/external_host_provider."
returned: "On success and if parameter 'type: foreman' is used."
type: dictionary
openstack_image_provider:
description: "Dictionary of all the openstack_image_provider attributes. External provider attributes can be found on your oVirt instance
at following url: https://ovirt.example.com/ovirt-engine/api/model#types/openstack_image_provider."
returned: "On success and if parameter 'type: os_image' is used."
type: dictionary
openstack_volume_provider:
description: "Dictionary of all the openstack_volume_provider attributes. External provider attributes can be found on your oVirt instance
at following url: https://ovirt.example.com/ovirt-engine/api/model#types/openstack_volume_provider."
returned: "On success and if parameter 'type: os_volume' is used."
type: dictionary
openstack_network_provider:
description: "Dictionary of all the openstack_network_provider attributes. External provider attributes can be found on your oVirt instance
at following url: https://ovirt.example.com/ovirt-engine/api/model#types/openstack_network_provider."
returned: "On success and if parameter 'type: os_network' is used."
type: dictionary
'''
class ExternalProviderModule(BaseModule):
def provider_type(self, provider_type):
self._provider_type = provider_type
def build_entity(self):
provider_type = self._provider_type(
requires_authentication='username' in self._module.params,
)
for key, value in self._module.params.items():
if hasattr(provider_type, key):
setattr(provider_type, key, value)
return provider_type
def update_check(self, entity):
return (
equal(self._module.params.get('description'), entity.description) and
equal(self._module.params.get('url'), entity.url) and
equal(self._module.params.get('authentication_url'), entity.authentication_url) and
equal(self._module.params.get('tenant_name'), getattr(entity, 'tenant_name', None)) and
equal(self._module.params.get('username'), entity.username)
)
def _external_provider_service(provider_type, system_service):
if provider_type == 'os_image':
return otypes.OpenStackImageProvider, system_service.openstack_image_providers_service()
elif provider_type == 'os_network':
return otypes.OpenStackNetworkProvider, system_service.openstack_network_providers_service()
elif provider_type == 'os_volume':
return otypes.OpenStackVolumeProvider, system_service.openstack_volume_providers_service()
elif provider_type == 'foreman':
return otypes.ExternalHostProvider, system_service.external_host_providers_service()
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(
choices=['present', 'absent'],
default='present',
),
name=dict(default=None),
description=dict(default=None),
type=dict(
default=None,
required=True,
choices=[
'os_image', 'os_network', 'os_volume', 'foreman',
],
aliases=['provider'],
),
url=dict(default=None),
username=dict(default=None),
password=dict(default=None, no_log=True),
tenant_name=dict(default=None, aliases=['tenant']),
authentication_url=dict(default=None, aliases=['auth_url']),
data_center=dict(default=None, aliases=['data_center']),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
)
check_sdk(module)
check_params(module)
try:
connection = create_connection(module.params.pop('auth'))
provider_type, external_providers_service = _external_provider_service(
provider_type=module.params.pop('type'),
system_service=connection.system_service(),
)
external_providers_module = ExternalProviderModule(
connection=connection,
module=module,
service=external_providers_service,
)
external_providers_module.provider_type(provider_type)
state = module.params.pop('state')
if state == 'absent':
ret = external_providers_module.remove()
elif state == 'present':
ret = external_providers_module.create()
module.exit_json(**ret)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=False)
if __name__ == "__main__":
main()

View file

@ -0,0 +1,151 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
import fnmatch
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_full_argument_spec,
)
ANSIBLE_METADATA = {'status': 'preview',
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_external_providers_facts
short_description: Retrieve facts about one or more oVirt external_providers
version_added: "2.3"
description:
- "Retrieve facts about one or more oVirt external_providers."
notes:
- "This module creates a new top-level C(ovirt_external_providers) fact, which
contains a list of external_providers."
options:
type:
description:
- "Type of the external provider."
choices: ['os_image', 'os_network', 'os_volume', 'foreman']
required: true
name:
description:
- "Name of the external provider, can be used as glob expression."
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather facts about all image external providers named C<glance>:
- ovirt_external_providers_facts:
type: os_image
name: glance
- debug:
var: ovirt_external_providers
'''
RETURN = '''
external_host_providers:
description: "List of dictionaries of all the external_host_provider attributes. External provider attributes can be found on your oVirt instance
at following url: https://ovirt.example.com/ovirt-engine/api/model#types/external_host_provider."
returned: "On success and if parameter 'type: foreman' is used."
type: list
openstack_image_providers:
description: "List of dictionaries of all the openstack_image_provider attributes. External provider attributes can be found on your oVirt instance
at following url: https://ovirt.example.com/ovirt-engine/api/model#types/openstack_image_provider."
returned: "On success and if parameter 'type: os_image' is used."
type: list
openstack_volume_providers:
description: "List of dictionaries of all the openstack_volume_provider attributes. External provider attributes can be found on your oVirt instance
at following url: https://ovirt.example.com/ovirt-engine/api/model#types/openstack_volume_provider."
returned: "On success and if parameter 'type: os_volume' is used."
type: list
openstack_network_providers:
description: "List of dictionaries of all the openstack_network_provider attributes. External provider attributes can be found on your oVirt instance
at following url: https://ovirt.example.com/ovirt-engine/api/model#types/openstack_network_provider."
returned: "On success and if parameter 'type: os_network' is used."
type: list
'''
def _external_provider_service(provider_type, system_service):
if provider_type == 'os_image':
return system_service.openstack_image_providers_service()
elif provider_type == 'os_network':
return system_service.openstack_network_providers_service()
elif provider_type == 'os_volume':
return system_service.openstack_volume_providers_service()
elif provider_type == 'foreman':
return system_service.external_host_providers_service()
def main():
argument_spec = ovirt_full_argument_spec(
name=dict(default=None, required=False),
type=dict(
default=None,
required=True,
choices=[
'os_image', 'os_network', 'os_volume', 'foreman',
],
aliases=['provider'],
),
)
module = AnsibleModule(argument_spec)
check_sdk(module)
try:
connection = create_connection(module.params.pop('auth'))
external_providers_service = _external_provider_service(
provider_type=module.params.pop('type'),
system_service=connection.system_service(),
)
if module.params['name']:
external_providers = [
e for e in external_providers_service.list()
if fnmatch.fnmatch(e.name, module.params['name'])
]
else:
external_providers = external_providers_service.list()
module.exit_json(
changed=False,
ansible_facts=dict(
ovirt_external_providers=[
get_dict_of_struct(c) for c in external_providers
],
),
)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=False)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,182 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
import traceback
try:
import ovirtsdk4.types as otypes
except ImportError:
pass
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
BaseModule,
check_sdk,
check_params,
create_connection,
equal,
ovirt_full_argument_spec,
)
ANSIBLE_METADATA = {'status': 'preview',
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_groups
short_description: Module to manage groups in oVirt
version_added: "2.3"
author: "Ondra Machacek (@machacekondra)"
description:
- "Module to manage groups in oVirt"
options:
name:
description:
- "Name of the the group to manage."
required: true
state:
description:
- "Should the group be present/absent."
choices: ['present', 'absent']
default: present
authz_name:
description:
- "Authorization provider of the group. In previous versions of oVirt known as domain."
required: true
aliases: ['domain']
namespace:
description:
- "Namespace of the authorization provider, where group resides."
required: false
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Add group group1 from authorization provider example.com-authz
ovirt_groups:
name: group1
domain: example.com-authz
# Add group group1 from authorization provider example.com-authz
# In case of multi-domain Active Directory setup, you should pass
# also namespace, so it adds correct group:
ovirt_groups:
name: group1
namespace: dc=ad2,dc=example,dc=com
domain: example.com-authz
# Remove group group1 with authorization provider example.com-authz
ovirt_groups:
state: absent
name: group1
domain: example.com-authz
'''
RETURN = '''
id:
description: ID of the group which is managed
returned: On success if group is found.
type: str
sample: 7de90f31-222c-436c-a1ca-7e655bd5b60c
group:
description: "Dictionary of all the group attributes. Group attributes can be found on your oVirt instance
at following url: https://ovirt.example.com/ovirt-engine/api/model#types/group."
returned: On success if group is found.
'''
def _group(connection, module):
groups = connection.system_service().groups_service().list(
search="name={name}".format(
name=module.params['name'],
)
)
# If found more groups, filter them by namespace and authz name:
# (filtering here, as oVirt backend doesn't support it)
if len(groups) > 1:
groups = [
g for g in groups if (
equal(module.params['namespace'], g.namespace) and
equal(module.params['authz_name'], g.domain.name)
)
]
return groups[0] if groups else None
class GroupsModule(BaseModule):
def build_entity(self):
return otypes.Group(
domain=otypes.Domain(
name=self._module.params['authz_name']
),
name=self._module.params['name'],
namespace=self._module.params['namespace'],
)
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(
choices=['present', 'absent'],
default='present',
),
name=dict(required=True),
authz_name=dict(required=True, aliases=['domain']),
namespace=dict(default=None),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
)
check_sdk(module)
check_params(module)
try:
connection = create_connection(module.params.pop('auth'))
groups_service = connection.system_service().groups_service()
groups_module = GroupsModule(
connection=connection,
module=module,
service=groups_service,
)
group = _group(connection, module)
state = module.params['state']
if state == 'present':
ret = groups_module.create(entity=group)
elif state == 'absent':
ret = groups_module.remove(entity=group)
module.exit_json(**ret)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=False)
if __name__ == "__main__":
main()

View file

@ -0,0 +1,102 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_full_argument_spec,
)
ANSIBLE_METADATA = {'status': 'preview',
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_groups_facts
short_description: Retrieve facts about one or more oVirt groups
author: "Ondra Machacek (@machacekondra)"
version_added: "2.3"
description:
- "Retrieve facts about one or more oVirt groups."
notes:
- "This module creates a new top-level C(ovirt_groups) fact, which
contains a list of groups."
options:
pattern:
description:
- "Search term which is accepted by oVirt search backend."
- "For example to search group X use following pattern: name=X"
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather facts about all groups which names start with C(admin):
- ovirt_groups_facts:
pattern: name=admin*
- debug:
var: ovirt_groups
'''
RETURN = '''
ovirt_groups:
description: "List of dictionaries describing the groups. Group attribues are mapped to dictionary keys,
all groups attributes can be found at following url: https://ovirt.example.com/ovirt-engine/api/model#types/group."
returned: On success.
type: list
'''
def main():
argument_spec = ovirt_full_argument_spec(
pattern=dict(default='', required=False),
)
module = AnsibleModule(argument_spec)
check_sdk(module)
try:
connection = create_connection(module.params.pop('auth'))
groups_service = connection.system_service().groups_service()
groups = groups_service.list(search=module.params['pattern'])
module.exit_json(
changed=False,
ansible_facts=dict(
ovirt_groups=[
get_dict_of_struct(c) for c in groups
],
),
)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=False)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,368 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
try:
import ovirtsdk4 as sdk
import ovirtsdk4.types as otypes
except ImportError:
pass
from ansible.module_utils.ovirt import *
ANSIBLE_METADATA = {'status': ['preview'],
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_host_networks
short_description: Module to manage host networks in oVirt
version_added: "2.3"
author: "Ondra Machacek (@machacekondra)"
description:
- "Module to manage host networks in oVirt."
options:
name:
description:
- "Name of the the host to manage networks for."
required: true
state:
description:
- "Should the host be present/absent."
choices: ['present', 'absent']
default: present
bond:
description:
- "Dictionary describing network bond:"
- "C(name) - Bond name."
- "C(mode) - Bonding mode."
- "C(interfaces) - List of interfaces to create a bond."
interface:
description:
- "Name of the network interface where logical network should be attached."
networks:
description:
- "List of dictionary describing networks to be attached to interface or bond:"
- "C(name) - Name of the logical network to be assigned to bond or interface."
- "C(boot_protocol) - Boot protocol one of the I(none), I(static) or I(dhcp)."
- "C(address) - IP address in case of I(static) boot protocol is used."
- "C(prefix) - Routing prefix in case of I(static) boot protocol is used."
- "C(gateway) - Gateway in case of I(static) boot protocol is used."
- "C(version) - IP version. Either v4 or v6."
labels:
description:
- "List of names of the network label to be assigned to bond or interface."
check:
description:
- "If I(true) verify connectivity between host and engine."
- "Network configuration changes will be rolled back if connectivity between
engine and the host is lost after changing network configuration."
save:
description:
- "If I(true) network configuration will be persistent, by default they are temporary."
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Create bond on eth0 and eth1 interface, and put 'myvlan' network on top of it:
- name: Bonds
ovirt_host_networks:
name: myhost
bond:
name: bond0
mode: 2
interfaces:
- eth1
- eth2
networks:
- name: myvlan
boot_protocol: static
address: 1.2.3.4
prefix: 24
gateway: 1.2.3.4
version: v4
# Remove bond0 bond from host interfaces:
- ovirt_host_networks:
state: absent
name: myhost
bond:
name: bond0
# Assign myvlan1 and myvlan2 vlans to host eth0 interface:
- ovirt_host_networks:
name: myhost
interface: eth0
networks:
- name: myvlan1
- name: myvlan2
# Remove myvlan2 vlan from host eth0 interface:
- ovirt_host_networks:
state: absent
name: myhost
interface: eth0
networks:
- name: myvlan2
# Remove all networks/vlans from host eth0 interface:
- ovirt_host_networks:
state: absent
name: myhost
interface: eth0
'''
RETURN = '''
id:
description: ID of the host NIC which is managed
returned: On success if host NIC is found.
type: str
sample: 7de90f31-222c-436c-a1ca-7e655bd5b60c
host_nic:
description: "Dictionary of all the host NIC attributes. Host NIC attributes can be found on your oVirt instance
at following url: https://ovirt.example.com/ovirt-engine/api/model#types/host_nic."
returned: On success if host NIC is found.
'''
class HostNetworksModule(BaseModule):
def build_entity(self):
return otypes.Host()
def update_address(self, attachment, network):
# Check if there is any change in address assignenmts and
# update it if needed:
for ip in attachment.ip_address_assignments:
if str(ip.ip.version) == network.get('version'):
changed = False
if not equal(network.get('boot_protocol'), str(ip.assignment_method)):
ip.assignment_method = otypes.BootProtocol(network.get('boot_protocol'))
changed = True
if not equal(network.get('address'), ip.ip.address):
ip.ip.address = network.get('address')
changed = True
if not equal(network.get('gateway'), ip.ip.gateway):
ip.ip.gateway = network.get('gateway')
changed = True
if not equal(network.get('prefix'), int(ip.ip.netmask)):
ip.ip.netmask = str(network.get('prefix'))
changed = True
if changed:
attachments_service.service(attachment.id).update(attachment)
self.changed = True
break
def has_update(self, nic_service):
update = False
bond = self._module.params['bond']
networks = self._module.params['networks']
nic = nic_service.get()
if nic is None:
return update
# Check if bond configuration should be updated:
if bond:
update = not (
equal(str(bond.get('mode')), nic.bonding.options[0].value) and
equal(
sorted(bond.get('interfaces')) if bond.get('interfaces') else None,
sorted(get_link_name(self._connection, s) for s in nic.bonding.slaves)
)
)
if not networks:
return update
# Check if networks attachments configuration should be updated:
attachments_service = nic_service.network_attachments_service()
network_names = [network.get('name') for network in networks]
attachments = {}
for attachment in attachments_service.list():
name = get_link_name(self._connection, attachment.network)
if name in network_names:
attachments[name] = attachment
for network in networks:
attachment = attachments.get(network.get('name'))
# If attachment don't exsits, we need to create it:
if attachment is None:
return True
self.update_address(attachment, network)
return update
def _action_save_configuration(self, entity):
if self._module.params['save']:
if not self._module.check_mode:
self._service.service(entity.id).commit_net_config()
self.changed = True
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(
choices=['present', 'absent'],
default='present',
),
name=dict(default=None, aliases=['host'], required=True),
bond=dict(default=None, type='dict'),
interface=dict(default=None),
networks=dict(default=None, type='list'),
labels=dict(default=None, type='list'),
check=dict(default=None, type='bool'),
save=dict(default=None, type='bool'),
)
module = AnsibleModule(argument_spec=argument_spec)
check_sdk(module)
try:
connection = create_connection(module.params.pop('auth'))
hosts_service = connection.system_service().hosts_service()
host_networks_module = HostNetworksModule(
connection=connection,
module=module,
service=hosts_service,
)
host = host_networks_module.search_entity()
if host is None:
raise Exception("Host '%s' was not found." % module.params['name'])
bond = module.params['bond']
interface = module.params['interface']
networks = module.params['networks']
labels = module.params['labels']
nic_name = bond.get('name') if bond else module.params['interface']
nics_service = hosts_service.host_service(host.id).nics_service()
nic = search_by_name(nics_service, nic_name)
state = module.params['state']
if (
state == 'present' and
(nic is None or host_networks_module.has_update(nics_service.service(nic.id)))
):
host_networks_module.action(
entity=host,
action='setup_networks',
post_action=host_networks_module._action_save_configuration,
check_connectivity=module.params['check'],
modified_bonds=[
otypes.HostNic(
name=bond.get('name'),
bonding=otypes.Bonding(
options=[
otypes.Option(
name="mode",
value=str(bond.get('mode')),
)
],
slaves=[
otypes.HostNic(name=i) for i in bond.get('interfaces', [])
],
),
),
] if bond else None,
modified_labels=[
otypes.NetworkLabel(
name=str(name),
host_nic=otypes.HostNic(
name=bond.get('name') if bond else interface
),
) for name in labels
] if labels else None,
modified_network_attachments=[
otypes.NetworkAttachment(
network=otypes.Network(
name=network['name']
) if network['name'] else None,
host_nic=otypes.HostNic(
name=bond.get('name') if bond else interface
),
ip_address_assignments=[
otypes.IpAddressAssignment(
assignment_method=otypes.BootProtocol(
network.get('boot_protocol', 'none')
),
ip=otypes.Ip(
address=network.get('address'),
gateway=network.get('gateway'),
netmask=network.get('netmask'),
version=otypes.IpVersion(
network.get('version')
) if network.get('version') else None,
),
),
],
) for network in networks
] if networks else None,
)
elif state == 'absent' and nic:
attachments_service = nics_service.nic_service(nic.id).network_attachments_service()
attachments = attachments_service.list()
if networks:
network_names = [network['name'] for network in networks]
attachments = [
attachment for attachment in attachments
if get_link_name(connection, attachment.network) in network_names
]
if labels or bond or attachments:
host_networks_module.action(
entity=host,
action='setup_networks',
post_action=host_networks_module._action_save_configuration,
check_connectivity=module.params['check'],
removed_bonds=[
otypes.HostNic(
name=bond.get('name'),
),
] if bond else None,
removed_labels=[
otypes.NetworkLabel(
name=str(name),
) for name in labels
] if labels else None,
removed_network_attachments=list(attachments),
)
nic = search_by_name(nics_service, nic_name)
module.exit_json(**{
'changed': host_networks_module.changed,
'id': nic.id if nic else None,
'host_nic': get_dict_of_struct(nic),
})
except Exception as e:
module.fail_json(msg=str(e))
finally:
connection.close(logout=False)
from ansible.module_utils.basic import *
if __name__ == "__main__":
main()

View file

@ -0,0 +1,236 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
try:
import ovirtsdk4 as sdk
import ovirtsdk4.types as otypes
except ImportError:
pass
from ansible.module_utils.ovirt import *
ANSIBLE_METADATA = {'status': ['preview'],
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_host_pm
short_description: Module to manage power management of hosts in oVirt
version_added: "2.3"
author: "Ondra Machacek (@machacekondra)"
description:
- "Module to manage power management of hosts in oVirt."
options:
name:
description:
- "Name of the the host to manage."
required: true
aliases: ['host']
state:
description:
- "Should the host be present/absent."
choices: ['present', 'absent']
default: present
address:
description:
- "Address of the power management interface."
username:
description:
- "Username to be used to connect to power management interface."
password:
description:
- "Password of the user specified in C(username) parameter."
type:
description:
- "Type of the power management. oVirt predefined values are I(drac5), I(ipmilan), I(rsa),
I(bladecenter), I(alom), I(apc), I(apc_snmp), I(eps), I(wti), I(rsb), I(cisco_ucs),
I(drac7), I(hpblade), I(ilo), I(ilo2), I(ilo3), I(ilo4), I(ilo_ssh),
but user can have defined custom type."
port:
description:
- "Power management interface port."
slot:
description:
- "Power management slot."
options:
description:
- "Dictionary of additional fence agent options."
- "Additional information about options can be found at U(https://fedorahosted.org/cluster/wiki/FenceArguments)."
encrypt_options:
description:
- "If (true) options will be encrypted when send to agent."
aliases: ['encrypt']
order:
description:
- "Integer value specifying, by default it's added at the end."
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Add fence agent to host 'myhost'
- ovirt_host_pm:
name: myhost
address: 1.2.3.4
options:
myoption1: x
myoption2: y
username: admin
password: admin
port: 3333
type: ipmilan
# Remove ipmilan fence agent with address 1.2.3.4 on host 'myhost'
- ovirt_host_pm:
state: absent
name: myhost
address: 1.2.3.4
type: ipmilan
'''
RETURN = '''
id:
description: ID of the agent which is managed
returned: On success if agent is found.
type: str
sample: 7de90f31-222c-436c-a1ca-7e655bd5b60c
agent:
description: "Dictionary of all the agent attributes. Agent attributes can be found on your oVirt instance
at following url: https://ovirt.example.com/ovirt-engine/api/model#types/agent."
returned: On success if agent is found.
'''
class HostModule(BaseModule):
def build_entity(self):
return otypes.Host(
power_management=otypes.PowerManagement(
enabled=True,
),
)
def update_check(self, entity):
return equal(True, entity.power_management.enabled)
class HostPmModule(BaseModule):
def build_entity(self):
return otypes.Agent(
address=self._module.params['address'],
encrypt_options=self._module.params['encrypt_options'],
options=[
otypes.Option(
name=name,
value=value,
) for name, value in self._module.params['options'].items()
] if self._module.params['options'] else None,
password=self._module.params['password'],
port=self._module.params['port'],
type=self._module.params['type'],
username=self._module.params['username'],
order=self._module.params.get('order', 100),
)
def update_check(self, entity):
return (
equal(self._module.params.get('address'), entity.address) and
equal(self._module.params.get('encrypt_options'), entity.encrypt_options) and
equal(self._module.params.get('password'), entity.password) and
equal(self._module.params.get('username'), entity.username) and
equal(self._module.params.get('port'), entity.port) and
equal(self._module.params.get('type'), entity.type)
)
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(
choices=['present', 'absent'],
default='present',
),
name=dict(default=None, required=True, aliases=['host']),
address=dict(default=None),
username=dict(default=None),
password=dict(default=None),
type=dict(default=None),
port=dict(default=None, type='int'),
slot=dict(default=None),
options=dict(default=None, type='dict'),
encrypt_options=dict(default=None, type='bool', aliases=['encrypt']),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
)
check_sdk(module)
try:
connection = create_connection(module.params.pop('auth'))
hosts_service = connection.system_service().hosts_service()
host = search_by_name(hosts_service, module.params['name'])
fence_agents_service = hosts_service.host_service(host.id).fence_agents_service()
host_pm_module = HostPmModule(
connection=connection,
module=module,
service=fence_agents_service,
)
host_module = HostModule(
connection=connection,
module=module,
service=hosts_service,
)
state = module.params['state']
if state == 'present':
agent = host_pm_module.search_entity(
search_params={
'address': module.params['address'],
'type': module.params['type'],
}
)
ret = host_pm_module.create(entity=agent)
# Enable Power Management, if it's not enabled:
host_module.create(entity=host)
elif state == 'absent':
agent = host_pm_module.search_entity(
search_params={
'address': module.params['address'],
'type': module.params['type'],
}
)
ret = host_pm_module.remove(entity=agent)
module.exit_json(**ret)
except Exception as e:
module.fail_json(msg=str(e))
finally:
connection.close(logout=False)
from ansible.module_utils.basic import *
if __name__ == "__main__":
main()

View file

@ -0,0 +1,326 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
try:
import ovirtsdk4 as sdk
import ovirtsdk4.types as otypes
from ovirtsdk4.types import HostStatus as hoststate
except ImportError:
pass
from ansible.module_utils.ovirt import *
ANSIBLE_METADATA = {'status': ['preview'],
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_hosts
short_description: Module to manage hosts in oVirt
version_added: "2.3"
author: "Ondra Machacek (@machacekondra)"
description:
- "Module to manage hosts in oVirt"
options:
name:
description:
- "Name of the the host to manage."
required: true
state:
description:
- "State which should a host to be in after successful completion."
choices: ['present', 'absent', 'maintenance', 'upgraded', 'started', 'restarted', 'stopped']
default: present
comment:
description:
- "Description of the host."
cluster:
description:
- "Name of the cluster, where host should be created."
address:
description:
- "Host address. It can be either FQDN (preferred) or IP address."
password:
description:
- "Password of the root. It's required in case C(public_key) is set to I(False)."
public_key:
description:
- "I(True) if the public key should be used to authenticate to host."
- "It's required in case C(password) is not set."
default: False
aliases: ['ssh_public_key']
kdump_integration:
description:
- "Specify if host will have enabled Kdump integration."
choices: ['enabled', 'disabled']
default: enabled
spm_priority:
description:
- "SPM priority of the host. Integer value from 1 to 10, where higher number means higher priority."
override_iptables:
description:
- "If True host iptables will be overridden by host deploy script."
force:
description:
- "If True host will be forcibly moved to desired state."
default: False
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Add host with username/password
- ovirt_hosts:
cluster: Default
name: myhost
address: 10.34.61.145
password: secret
# Add host using public key
- ovirt_hosts:
public_key: true
cluster: Default
name: myhost2
address: 10.34.61.145
# Maintenance
- ovirt_hosts:
state: maintenance
name: myhost
# Restart host using power management:
- ovirt_hosts:
state: restarted
name: myhost
# Upgrade host
- ovirt_hosts:
state: upgraded
name: myhost
# Remove host
- ovirt_hosts:
state: absent
name: myhost
force: True
'''
RETURN = '''
id:
description: ID of the host which is managed
returned: On success if host is found.
type: str
sample: 7de90f31-222c-436c-a1ca-7e655bd5b60c
host:
description: "Dictionary of all the host attributes. Host attributes can be found on your oVirt instance
at following url: https://ovirt.example.com/ovirt-engine/api/model#types/host."
returned: On success if host is found.
'''
class HostsModule(BaseModule):
def build_entity(self):
return otypes.Host(
name=self._module.params['name'],
cluster=otypes.Cluster(
name=self._module.params['cluster']
) if self._module.params['cluster'] else None,
comment=self._module.params['comment'],
address=self._module.params['address'],
root_password=self._module.params['password'],
ssh=otypes.Ssh(
authentication_method='publickey',
) if self._module.params['public_key'] else None,
kdump_status=otypes.KdumpStatus(
self._module.params['kdump_integration']
) if self._module.params['kdump_integration'] else None,
spm=otypes.Spm(
priority=self._module.params['spm_priority'],
) if self._module.params['spm_priority'] else None,
override_iptables=self._module.params['override_iptables'],
)
def update_check(self, entity):
return (
equal(self._module.params.get('comment'), entity.comment) and
equal(self._module.params.get('kdump_integration'), entity.kdump_status) and
equal(self._module.params.get('spm_priority'), entity.spm.priority)
)
def pre_remove(self, entity):
self.action(
entity=entity,
action='deactivate',
action_condition=lambda h: h.status != hoststate.MAINTENANCE,
wait_condition=lambda h: h.status == hoststate.MAINTENANCE,
)
def post_update(self, entity):
if entity.status != hoststate.UP:
if not self._module.check_mode:
self._service.host_service(entity.id).activate()
self.changed = True
def failed_state(host):
return host.status in [
hoststate.ERROR,
hoststate.INSTALL_FAILED,
hoststate.NON_RESPONSIVE,
hoststate.NON_OPERATIONAL,
]
def control_state(host_module):
host = host_module.search_entity()
if host is None:
return
state = host_module._module.params['state']
host_service = host_module._service.service(host.id)
if failed_state(host):
raise Exception("Not possible to manage host '%s'." % host.name)
elif host.status in [
hoststate.REBOOT,
hoststate.CONNECTING,
hoststate.INITIALIZING,
hoststate.INSTALLING,
hoststate.INSTALLING_OS,
]:
wait(
service=host_service,
condition=lambda host: host.status == hoststate.UP,
fail_condition=failed_state,
)
elif host.status == hoststate.PREPARING_FOR_MAINTENANCE:
wait(
service=host_service,
condition=lambda host: host.status == hoststate.MAINTENANCE,
fail_condition=failed_state,
)
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(
choices=['present', 'absent', 'maintenance', 'upgraded', 'started', 'restarted', 'stopped'],
default='present',
),
name=dict(required=True),
comment=dict(default=None),
cluster=dict(default=None),
address=dict(default=None),
password=dict(default=None),
public_key=dict(default=False, type='bool', aliases=['ssh_public_key']),
kdump_integration=dict(default=None, choices=['enabled', 'disabled']),
spm_priority=dict(default=None, type='int'),
override_iptables=dict(default=None, type='bool'),
force=dict(default=False, type='bool'),
timeout=dict(default=600, type='int'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
)
check_sdk(module)
try:
connection = create_connection(module.params.pop('auth'))
hosts_service = connection.system_service().hosts_service()
hosts_module = HostsModule(
connection=connection,
module=module,
service=hosts_service,
)
state = module.params['state']
control_state(hosts_module)
if state == 'present':
ret = hosts_module.create()
hosts_module.action(
action='activate',
action_condition=lambda h: h.status == hoststate.MAINTENANCE,
wait_condition=lambda h: h.status == hoststate.UP,
fail_condition=failed_state,
)
elif state == 'absent':
ret = hosts_module.remove()
elif state == 'maintenance':
ret = hosts_module.action(
action='deactivate',
action_condition=lambda h: h.status != hoststate.MAINTENANCE,
wait_condition=lambda h: h.status == hoststate.MAINTENANCE,
fail_condition=failed_state,
)
elif state == 'upgraded':
ret = hosts_module.action(
action='upgrade',
action_condition=lambda h: h.update_available,
wait_condition=lambda h: h.status == hoststate.UP,
fail_condition=failed_state,
)
elif state == 'started':
ret = hosts_module.action(
action='fence',
action_condition=lambda h: h.status == hoststate.DOWN,
wait_condition=lambda h: h.status in [hoststate.UP, hoststate.MAINTENANCE],
fail_condition=failed_state,
fence_type='start',
)
elif state == 'stopped':
hosts_module.action(
action='deactivate',
action_condition=lambda h: h.status not in [hoststate.MAINTENANCE, hoststate.DOWN],
wait_condition=lambda h: h.status in [hoststate.MAINTENANCE, hoststate.DOWN],
fail_condition=failed_state,
)
ret = hosts_module.action(
action='fence',
action_condition=lambda h: h.status != hoststate.DOWN,
wait_condition=lambda h: h.status == hoststate.DOWN,
fail_condition=failed_state,
fence_type='stop',
)
elif state == 'restarted':
ret = hosts_module.action(
action='fence',
wait_condition=lambda h: h.status == hoststate.UP,
fail_condition=failed_state,
fence_type='restart',
)
module.exit_json(**ret)
except Exception as e:
module.fail_json(msg=str(e))
finally:
connection.close(logout=False)
from ansible.module_utils.basic import *
if __name__ == "__main__":
main()

View file

@ -0,0 +1,99 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
try:
import ovirtsdk4 as sdk
except ImportError:
pass
from ansible.module_utils.ovirt import *
ANSIBLE_METADATA = {'status': ['preview'],
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_hosts_facts
short_description: Retrieve facts about one or more oVirt hosts
author: "Ondra Machacek (@machacekondra)"
version_added: "2.3"
description:
- "Retrieve facts about one or more oVirt hosts."
notes:
- "This module creates a new top-level C(ovirt_hosts) fact, which
contains a list of hosts."
options:
pattern:
description:
- "Search term which is accepted by oVirt search backend."
- "For example to search host X from datacenter Y use following pattern:
name=X and datacenter=Y"
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather facts about all hosts which names start with C(host) and
# belong to data center C(west):
- ovirt_hosts_facts:
pattern: name=host* and datacenter=west
- debug:
var: ovirt_hosts
'''
RETURN = '''
ovirt_hosts:
description: "List of dictionaries describing the hosts. Host attribues are mapped to dictionary keys,
all hosts attributes can be found at following url: https://ovirt.example.com/ovirt-engine/api/model#types/host."
returned: On success.
type: list
'''
def main():
argument_spec = ovirt_full_argument_spec(
pattern=dict(default='', required=False),
)
module = AnsibleModule(argument_spec)
check_sdk(module)
try:
connection = create_connection(module.params.pop('auth'))
hosts_service = connection.system_service().hosts_service()
hosts = hosts_service.list(search=module.params['pattern'])
module.exit_json(
changed=False,
ansible_facts=dict(
ovirt_hosts=[
get_dict_of_struct(c) for c in hosts
],
),
)
except Exception as e:
module.fail_json(msg=str(e))
from ansible.module_utils.basic import *
if __name__ == '__main__':
main()

View file

@ -0,0 +1,180 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
import traceback
try:
import ovirtsdk4.types as otypes
except ImportError:
pass
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
BaseModule,
check_sdk,
equal,
create_connection,
ovirt_full_argument_spec,
)
ANSIBLE_METADATA = {'status': 'preview',
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_mac_pools
short_description: Module to manage MAC pools in oVirt
version_added: "2.3"
author: "Ondra Machacek (@machacekondra)"
description:
- "This module manage MAC pools in oVirt."
options:
name:
description:
- "Name of the the MAC pool to manage."
required: true
description:
description:
- "Description of the MAC pool."
state:
description:
- "Should the mac pool be present or absent."
choices: ['present', 'absent']
default: present
allow_duplicates:
description:
- "If (true) allow a MAC address to be used multiple times in a pool."
- "Default value is set by oVirt engine to I(false)."
ranges:
description:
- "List of MAC ranges. The from and to should be splitted by comma."
- "For example: 00:1a:4a:16:01:51,00:1a:4a:16:01:61"
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Create MAC pool:
- ovirt_mac_pools:
name: mymacpool
allow_duplicates: false
ranges:
- 00:1a:4a:16:01:51,00:1a:4a:16:01:61
- 00:1a:4a:16:02:51,00:1a:4a:16:02:61
# Remove MAC pool:
- ovirt_mac_pools:
state: absent
name: mymacpool
'''
RETURN = '''
id:
description: ID of the MAC pool which is managed
returned: On success if MAC pool is found.
type: str
sample: 7de90f31-222c-436c-a1ca-7e655bd5b60c
template:
description: "Dictionary of all the MAC pool attributes. MAC pool attributes can be found on your oVirt instance
at following url: https://ovirt.example.com/ovirt-engine/api/model#types/mac_pool."
returned: On success if MAC pool is found.
'''
class MACPoolModule(BaseModule):
def build_entity(self):
return otypes.MacPool(
name=self._module.params['name'],
allow_duplicates=self._module.params['allow_duplicates'],
description=self._module.params['description'],
ranges=[
otypes.Range(
from_=mac_range.split(',')[0],
to=mac_range.split(',')[1],
)
for mac_range in self._module.params['ranges']
],
)
def _compare_ranges(self, entity):
if self._module.params['ranges'] is not None:
ranges = sorted([
'%s,%s' % (mac_range.from_, mac_range.to)
for mac_range in entity.ranges
])
return equal(sorted(self._module.params['ranges']), ranges)
return True
def update_check(self, entity):
return (
self._compare_ranges(entity) and
equal(self._module.params['allow_duplicates'], entity.allow_duplicates) and
equal(self._module.params['description'], entity.description)
)
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(
choices=['present', 'absent'],
default='present',
),
name=dict(default=None, required=True),
allow_duplicates=dict(default=None, type='bool'),
description=dict(default=None),
ranges=dict(default=None, type='list'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
)
check_sdk(module)
try:
connection = create_connection(module.params.pop('auth'))
mac_pools_service = connection.system_service().mac_pools_service()
mac_pools_module = MACPoolModule(
connection=connection,
module=module,
service=mac_pools_service,
)
state = module.params['state']
if state == 'present':
ret = mac_pools_module.create()
elif state == 'absent':
ret = mac_pools_module.remove()
module.exit_json(**ret)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=False)
if __name__ == "__main__":
main()

View file

@ -0,0 +1,268 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
import traceback
try:
import ovirtsdk4.types as otypes
except ImportError:
pass
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
BaseModule,
check_sdk,
check_params,
create_connection,
equal,
ovirt_full_argument_spec,
search_by_name,
)
ANSIBLE_METADATA = {'status': 'preview',
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_networks
short_description: Module to manage logical networks in oVirt
version_added: "2.3"
author: "Ondra Machacek (@machacekondra)"
description:
- "Module to manage logical networks in oVirt"
options:
name:
description:
- "Name of the the network to manage."
required: true
state:
description:
- "Should the network be present or absent"
choices: ['present', 'absent']
default: present
datacenter:
description:
- "Datacenter name where network reside."
description:
description:
- "Description of the network."
comment:
description:
- "Comment of the network."
vlan_tag:
description:
- "Specify VLAN tag."
vm_network:
description:
- "If I(True) network will be marked as network for VM."
- "VM network carries traffic relevant to the virtual machine."
mtu:
description:
- "Maximum transmission unit (MTU) of the network."
clusters:
description:
- "List of dictionaries describing how the network is managed in specific cluster."
- "C(name) - Cluster name."
- "C(assigned) - I(true) if the network should be assigned to cluster. Default is I(true)."
- "C(required) - I(true) if the network must remain operational for all hosts associated with this network."
- "C(display) - I(true) if the network should marked as display network."
- "C(migration) - I(true) if the network should marked as migration network."
- "C(gluster) - I(true) if the network should marked as gluster network."
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Create network
- ovirt_networks:
datacenter: mydatacenter
name: mynetwork
vlan_tag: 1
vm_network: true
# Remove network
- ovirt_networks:
state: absent
name: mynetwork
'''
RETURN = '''
id:
description: "ID of the managed network"
returned: "On success if network is found."
type: str
sample: 7de90f31-222c-436c-a1ca-7e655bd5b60c
network:
description: "Dictionary of all the network attributes. Network attributes can be found on your oVirt instance
at following url: https://ovirt.example.com/ovirt-engine/api/model#types/network."
returned: "On success if network is found."
'''
class NetworksModule(BaseModule):
def build_entity(self):
return otypes.Network(
name=self._module.params['name'],
comment=self._module.params['comment'],
description=self._module.params['description'],
data_center=otypes.DataCenter(
name=self._module.params['datacenter'],
) if self._module.params['datacenter'] else None,
vlan=otypes.Vlan(
self._module.params['vlan_tag'],
) if self._module.params['vlan_tag'] else None,
usages=[
otypes.NetworkUsage.VM if self._module.params['vm_network'] else None
] if self._module.params['vm_network'] is not None else None,
mtu=self._module.params['mtu'],
)
def update_check(self, entity):
return (
equal(self._module.params.get('comment'), entity.comment) and
equal(self._module.params.get('description'), entity.description) and
equal(self._module.params.get('vlan_tag'), getattr(entity.vlan, 'id', None)) and
equal(self._module.params.get('vm_network'), True if entity.usages else False) and
equal(self._module.params.get('mtu'), entity.mtu)
)
class ClusterNetworksModule(BaseModule):
def __init__(self, network_id, cluster_network, *args, **kwargs):
super(ClusterNetworksModule, self).__init__(*args, **kwargs)
self._network_id = network_id
self._cluster_network = cluster_network
def build_entity(self):
return otypes.Network(
id=self._network_id,
name=self._module.params['name'],
required=self._cluster_network.get('required'),
display=self._cluster_network.get('display'),
usages=[
otypes.NetworkUsage(usage)
for usage in ['display', 'gluster', 'migration']
if self._cluster_network.get(usage, False)
] if (
self._cluster_network.get('display') is not None or
self._cluster_network.get('gluster') is not None or
self._cluster_network.get('migration') is not None
) else None,
)
def update_check(self, entity):
return (
equal(self._cluster_network.get('required'), entity.required) and
equal(self._cluster_network.get('display'), entity.display) and
equal(
sorted([
usage
for usage in ['display', 'gluster', 'migration']
if self._cluster_network.get(usage, False)
]),
sorted([
str(usage)
for usage in getattr(entity, 'usages', [])
# VM + MANAGEMENT is part of root network
if usage != otypes.NetworkUsage.VM and usage != otypes.NetworkUsage.MANAGEMENT
]),
)
)
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(
choices=['present', 'absent'],
default='present',
),
datacenter=dict(default=None, required=True),
name=dict(default=None, required=True),
description=dict(default=None),
comment=dict(default=None),
vlan_tag=dict(default=None, type='int'),
vm_network=dict(default=None, type='bool'),
mtu=dict(default=None, type='int'),
clusters=dict(default=None, type='list'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
)
check_sdk(module)
check_params(module)
try:
connection = create_connection(module.params.pop('auth'))
clusters_service = connection.system_service().clusters_service()
networks_service = connection.system_service().networks_service()
networks_module = NetworksModule(
connection=connection,
module=module,
service=networks_service,
)
state = module.params['state']
network = networks_module.search_entity(
search_params={
'name': module.params['name'],
'datacenter': module.params['datacenter'],
},
)
if state == 'present':
ret = networks_module.create(entity=network)
# Update clusters networks:
for param_cluster in module.params.get('clusters', []):
cluster = search_by_name(clusters_service, param_cluster.get('name', None))
if cluster is None:
raise Exception("Cluster '%s' was not found." % cluster_name)
cluster_networks_service = clusters_service.service(cluster.id).networks_service()
cluster_networks_module = ClusterNetworksModule(
network_id=ret['id'],
cluster_network=param_cluster,
connection=connection,
module=module,
service=cluster_networks_service,
)
if param_cluster.get('assigned', True):
ret = cluster_networks_module.create()
else:
ret = cluster_networks_module.remove()
elif state == 'absent':
ret = networks_module.remove(entity=network)
module.exit_json(**ret)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=False)
if __name__ == "__main__":
main()

View file

@ -0,0 +1,104 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_full_argument_spec,
)
ANSIBLE_METADATA = {'status': 'preview',
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_networks_facts
short_description: Retrieve facts about one or more oVirt networks
author: "Ondra Machacek (@machacekondra)"
version_added: "2.3"
description:
- "Retrieve facts about one or more oVirt networks."
notes:
- "This module creates a new top-level C(ovirt_networks) fact, which
contains a list of networks."
options:
pattern:
description:
- "Search term which is accepted by oVirt search backend."
- "For example to search network starting with string vlan1 use: name=vlan1*"
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather facts about all networks which names start with C(vlan1):
- ovirt_networks_facts:
pattern: name=vlan1*
- debug:
var: ovirt_networks
'''
RETURN = '''
ovirt_networks:
description: "List of dictionaries describing the networks. Network attribues are mapped to dictionary keys,
all networks attributes can be found at following url: https://ovirt.example.com/ovirt-engine/api/model#types/network."
returned: On success.
type: list
'''
def main():
argument_spec = ovirt_full_argument_spec(
pattern=dict(default='', required=False),
)
module = AnsibleModule(argument_spec)
check_sdk(module)
try:
connection = create_connection(module.params.pop('auth'))
networks_service = connection.system_service().networks_service()
networks = networks_service.list(search=module.params['pattern'])
module.exit_json(
changed=False,
ansible_facts=dict(
ovirt_networks=[
get_dict_of_struct(c) for c in networks
],
),
)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=False)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,247 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
try:
import ovirtsdk4.types as otypes
except ImportError:
pass
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
BaseModule,
check_sdk,
create_connection,
equal,
get_link_name,
ovirt_full_argument_spec,
search_by_name,
)
ANSIBLE_METADATA = {'status': 'preview',
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_nics
short_description: Module to manage network interfaces of Virtual Machines in oVirt
version_added: "2.3"
author: "Ondra Machacek (@machacekondra)"
description:
- "Module to manage network interfaces of Virtual Machines in oVirt."
options:
name:
description:
- "Name of the network interface to manage."
required: true
vm:
description:
- "Name of the Virtual Machine to manage."
required: true
state:
description:
- "Should the Virtual Machine NIC be present/absent/plugged/unplugged."
choices: ['present', 'absent', 'plugged', 'unplugged']
default: present
network:
description:
- "Logical network to which the VM network interface should use,
by default Empty network is used if network is not specified."
profile:
description:
- "Virtual network interface profile to be attached to VM network interface."
interface:
description:
- "Type of the network interface."
choices: ['virtio', 'e1000', 'rtl8139', 'pci_passthrough', 'rtl8139_virtio', 'spapr_vlan']
default: 'virtio'
mac_address:
description:
- "Custom MAC address of the network interface, by default it's obtained from MAC pool."
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Add NIC to VM
- ovirt_nics:
state: present
vm: myvm
name: mynic
interface: e1000
mac_address: 00:1a:4a:16:01:56
profile: ovirtmgmt
network: ovirtmgmt
# Plug NIC to VM
- ovirt_nics:
state: plugged
vm: myvm
name: mynic
# Unplug NIC from VM
- ovirt_nics:
state: unplugged
vm: myvm
name: mynic
# Remove NIC from VM
- ovirt_nics:
state: absent
vm: myvm
name: mynic
'''
RETURN = '''
id:
description: ID of the network interface which is managed
returned: On success if network interface is found.
type: str
sample: 7de90f31-222c-436c-a1ca-7e655bd5b60c
nic:
description: "Dictionary of all the network interface attributes. Network interface attributes can be found on your oVirt instance
at following url: https://ovirt.example.com/ovirt-engine/api/model#types/nic."
returned: On success if network interface is found.
'''
class VmNicsModule(BaseModule):
def __init__(self, *args, **kwargs):
super(VmNicsModule, self).__init__(*args, **kwargs)
self.vnic_id = None
@property
def vnic_id(self):
return self._vnic_id
@vnic_id.setter
def vnic_id(self, vnic_id):
self._vnic_id = vnic_id
def build_entity(self):
return otypes.Nic(
name=self._module.params.get('name'),
interface=otypes.NicInterface(
self._module.params.get('interface')
) if self._module.params.get('interface') else None,
vnic_profile=otypes.VnicProfile(
id=self.vnic_id,
) if self.vnic_id else None,
mac=otypes.Mac(
address=self._module.params.get('mac_address')
) if self._module.params.get('mac_address') else None,
)
def update_check(self, entity):
return (
equal(self._module.params.get('interface'), str(entity.interface)) and
equal(self._module.params.get('profile'), get_link_name(self._connection, entity.vnic_profile)) and
equal(self._module.params.get('mac_address'), entity.mac.address)
)
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(
choices=['present', 'absent', 'plugged', 'unplugged'],
default='present'
),
vm=dict(required=True),
name=dict(required=True),
interface=dict(default=None),
profile=dict(default=None),
network=dict(default=None),
mac_address=dict(default=None),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
)
check_sdk(module)
try:
# Locate the service that manages the virtual machines and use it to
# search for the NIC:
connection = create_connection(module.params.pop('auth'))
vms_service = connection.system_service().vms_service()
# Locate the VM, where we will manage NICs:
vm_name = module.params.get('vm')
vm = search_by_name(vms_service, vm_name)
if vm is None:
raise Exception("VM '%s' was not found." % vm_name)
# Locate the service that manages the virtual machines NICs:
vm_service = vms_service.vm_service(vm.id)
nics_service = vm_service.nics_service()
vmnics_module = VmNicsModule(
connection=connection,
module=module,
service=nics_service,
)
# Find vNIC id of the network interface (if any):
profile = module.params.get('profile')
if profile and module.params['network']:
cluster_name = get_link_name(connection, vm.cluster)
dcs_service = connection.system_service().data_centers_service()
dc = dcs_service.list(search='Clusters.name=%s' % cluster_name)[0]
networks_service = dcs_service.service(dc.id).networks_service()
network = search_by_name(networks_service, module.params['network'])
for vnic in connection.system_service().vnic_profiles_service().list():
if vnic.name == profile and vnic.network.id == network.id:
vmnics_module.vnic_id = vnic.id
# Handle appropriate action:
state = module.params['state']
if state == 'present':
ret = vmnics_module.create()
elif state == 'absent':
ret = vmnics_module.remove()
elif state == 'plugged':
vmnics_module.create()
ret = vmnics_module.action(
action='activate',
action_condition=lambda nic: not nic.plugged,
wait_condition=lambda nic: nic.plugged,
)
elif state == 'unplugged':
vmnics_module.create()
ret = vmnics_module.action(
action='deactivate',
action_condition=lambda nic: nic.plugged,
wait_condition=lambda nic: not nic.plugged,
)
module.exit_json(**ret)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=False)
if __name__ == "__main__":
main()

View file

@ -0,0 +1,122 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
import fnmatch
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_full_argument_spec,
search_by_name,
)
ANSIBLE_METADATA = {'status': 'preview',
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_nics_facts
short_description: Retrieve facts about one or more oVirt virtual machine network interfaces
author: "Ondra Machacek (@machacekondra)"
version_added: "2.3"
description:
- "Retrieve facts about one or more oVirt virtual machine network interfaces."
notes:
- "This module creates a new top-level C(ovirt_nics) fact, which
contains a list of NICs."
options:
vm:
description:
- "Name of the VM where NIC is attached."
required: true
name:
description:
- "Name of the NIC, can be used as glob expression."
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather facts about all NICs which names start with C(eth) for VM named C(centos7):
- ovirt_nics_facts:
vm: centos7
name: eth*
- debug:
var: ovirt_nics
'''
RETURN = '''
ovirt_nics:
description: "List of dictionaries describing the network interfaces. NIC attribues are mapped to dictionary keys,
all NICs attributes can be found at following url: https://ovirt.example.com/ovirt-engine/api/model#types/nic."
returned: On success.
type: list
'''
def main():
argument_spec = ovirt_full_argument_spec(
vm=dict(required=True),
name=dict(default=None),
)
module = AnsibleModule(argument_spec)
check_sdk(module)
try:
connection = create_connection(module.params.pop('auth'))
vms_service = connection.system_service().vms_service()
vm_name = module.params['vm']
vm = search_by_name(vms_service, vm_name)
if vm is None:
raise Exception("VM '%s' was not found." % vm_name)
nics_service = vms_service.service(vm.id).nics_service()
if module.params['name']:
nics = [
e for e in nics_service.list()
if fnmatch.fnmatch(e.name, module.params['name'])
]
else:
nics = nics_service.list()
module.exit_json(
changed=False,
ansible_facts=dict(
ovirt_nics=[
get_dict_of_struct(c) for c in nics
],
),
)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=False)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,291 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
try:
import ovirtsdk4.types as otypes
except ImportError:
pass
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
BaseModule,
check_sdk,
create_connection,
equal,
follow_link,
get_link_name,
ovirt_full_argument_spec,
search_by_attributes,
search_by_name,
)
ANSIBLE_METADATA = {'status': 'preview',
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_permissions
short_description: "Module to manage permissions of users/groups in oVirt"
version_added: "2.3"
author: "Ondra Machacek (@machacekondra)"
description:
- "Module to manage permissions of users/groups in oVirt"
options:
role:
description:
- "Name of the the role to be assigned to user/group on specific object."
default: UserRole
state:
description:
- "Should the permission be present/absent."
choices: ['present', 'absent']
default: present
object_id:
description:
- "ID of the object where the permissions should be managed."
object_name:
description:
- "Name of the object where the permissions should be managed."
object_type:
description:
- "The object where the permissions should be managed."
default: 'virtual_machine'
choices: [
'data_center',
'cluster',
'host',
'storage_domain',
'network',
'disk',
'vm',
'vm_pool',
'template',
]
user_name:
description:
- "Username of the the user to manage. In most LDAPs it's I(uid) of the user, but in Active Directory you must specify I(UPN) of the user."
group_name:
description:
- "Name of the the group to manage."
authz_name:
description:
- "Authorization provider of the user/group. In previous versions of oVirt known as domain."
required: true
aliases: ['domain']
namespace:
description:
- "Namespace of the authorization provider, where user/group resides."
required: false
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Add user user1 from authorization provider example.com-authz
- ovirt_permissions:
user_name: user1
authz_name: example.com-authz
object_type: vm
object_name: myvm
role: UserVmManager
# Remove permission from user
- ovirt_permissions:
state: absent
user_name: user1
authz_name: example.com-authz
object_type: cluster
object_name: mycluster
role: ClusterAdmin
'''
RETURN = '''
id:
description: ID of the permission which is managed
returned: On success if permission is found.
type: str
sample: 7de90f31-222c-436c-a1ca-7e655bd5b60c
permission:
description: "Dictionary of all the permission attributes. Permission attributes can be found on your oVirt instance
at following url: https://ovirt.example.com/ovirt-engine/api/model#types/permission."
returned: On success if permission is found.
'''
def _objects_service(connection, object_type):
return getattr(
connection.system_service(),
'%ss_service' % object_type,
None,
)()
def _object_service(connection, module):
object_type = module.params['object_type']
objects_service = _objects_service(connection, object_type)
object_id = module.params['object_id']
if object_id is None:
sdk_object = search_by_name(objects_service, module.params['object_name'])
if sdk_object is None:
raise Exception(
"'%s' object '%s' was not found." % (
module.params['object_type'],
module.params['object_name']
)
)
object_id = sdk_object.id
return objects_service.service(object_id)
def _permission(module, permissions_service, connection):
for permission in permissions_service.list():
user = follow_link(connection, permission.user)
if (
equal(module.params['user_name'], user.principal if user else None) and
equal(module.params['group_name'], get_link_name(connection, permission.group)) and
equal(module.params['role'], get_link_name(connection, permission.role))
):
return permission
class PermissionsModule(BaseModule):
def _user(self):
user = search_by_attributes(
self._connection.system_service().users_service(),
usrname="{name}@{authz_name}".format(
name=self._module.params['user_name'],
authz_name=self._module.params['authz_name'],
),
)
if user is None:
raise Exception("User '%s' was not found." % self._module.params['user_name'])
return user
def _group(self):
groups = self._connection.system_service().groups_service().list(
search="name={name}".format(
name=self._module.params['group_name'],
)
)
# If found more groups, filter them by namespace and authz name:
# (filtering here, as oVirt backend doesn't support it)
if len(groups) > 1:
groups = [
g for g in groups if (
equal(self._module.params['namespace'], g.namespace) and
equal(self._module.params['authz_name'], g.domain.name)
)
]
if not groups:
raise Exception("Group '%s' was not found." % self._module.params['group_name'])
return groups[0]
def build_entity(self):
entity = self._group() if self._module.params['group_name'] else self._user()
return otypes.Permission(
user=otypes.User(
id=entity.id
) if self._module.params['user_name'] else None,
group=otypes.Group(
id=entity.id
) if self._module.params['group_name'] else None,
role=otypes.Role(
name=self._module.params['role']
),
)
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(
choices=['present', 'absent'],
default='present',
),
role=dict(default='UserRole'),
object_type=dict(
default='virtual_machine',
choices=[
'data_center',
'cluster',
'host',
'storage_domain',
'network',
'disk',
'vm',
'vm_pool',
'template',
]
),
authz_name=dict(required=True, aliases=['domain']),
object_id=dict(default=None),
object_name=dict(default=None),
user_name=dict(rdefault=None),
group_name=dict(default=None),
namespace=dict(default=None),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
)
check_sdk(module)
if module.params['object_name'] is None and module.params['object_id'] is None:
module.fail_json(msg='"object_name" or "object_id" is required')
if module.params['user_name'] is None and module.params['group_name'] is None:
module.fail_json(msg='"user_name" or "group_name" is required')
try:
connection = create_connection(module.params.pop('auth'))
permissions_service = _object_service(connection, module).permissions_service()
permissions_module = PermissionsModule(
connection=connection,
module=module,
service=permissions_service,
)
permission = _permission(module, permissions_service, connection)
state = module.params['state']
if state == 'present':
ret = permissions_module.create(entity=permission)
elif state == 'absent':
ret = permissions_module.remove(entity=permission)
module.exit_json(**ret)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=False)
if __name__ == "__main__":
main()

View file

@ -0,0 +1,140 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
import traceback
try:
import ovirtsdk4 as sdk
except ImportError:
pass
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
check_sdk,
create_connection,
get_link_name,
ovirt_full_argument_spec,
search_by_name,
)
ANSIBLE_METADATA = {'status': 'preview',
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_permissions_facts
short_description: Retrieve facts about one or more oVirt permissions
author: "Ondra Machacek (@machacekondra)"
version_added: "2.3"
description:
- "Retrieve facts about one or more oVirt permissions."
notes:
- "This module creates a new top-level C(ovirt_permissions) fact, which
contains a list of permissions."
options:
user_name:
description:
- "Username of the the user to manage. In most LDAPs it's I(uid) of the user, but in Active Directory you must specify I(UPN) of the user."
group_name:
description:
- "Name of the the group to manage."
authz_name:
description:
- "Authorization provider of the user/group. In previous versions of oVirt known as domain."
required: true
aliases: ['domain']
namespace:
description:
- "Namespace of the authorization provider, where user/group resides."
required: false
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather facts about all permissions of user with username C(john):
- ovirt_permissions_facts:
user_name: john
authz_name: example.com-authz
- debug:
var: ovirt_permissions
'''
RETURN = '''
ovirt_permissions:
description: "List of dictionaries describing the permissions. Permission attribues are mapped to dictionary keys,
all permissions attributes can be found at following url: https://ovirt.example.com/ovirt-engine/api/model#types/permission."
returned: On success.
type: list
'''
def _permissions_service(connection, module):
if module.params['user_name']:
service = connection.system_service().users_service()
entity = search_by_name(service, module.params['user_name'])
else:
service = connection.system_service().groups_service()
entity = search_by_name(service, module.params['group_name'])
if entity is None:
raise Exception("User/Group wasn't found.")
return service.service(entity.id).permissions_service()
def main():
argument_spec = ovirt_full_argument_spec(
authz_name=dict(required=True, aliases=['domain']),
user_name=dict(rdefault=None),
group_name=dict(default=None),
namespace=dict(default=None),
)
module = AnsibleModule(argument_spec)
check_sdk(module)
try:
connection = create_connection(module.params.pop('auth'))
permissions_service = _permissions_service(connection, module)
permissions = []
for p in permissions_service.list():
newperm = dict()
for key, value in p.__dict__.items():
if value and isinstance(value, sdk.Struct):
newperm[key[1:]] = get_link_name(connection, value)
permissions.append(newperm)
module.exit_json(
changed=False,
ansible_facts=dict(ovirt_permissions=permissions),
)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=False)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,298 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
try:
import ovirtsdk4.types as otypes
except ImportError:
pass
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
BaseModule,
check_sdk,
create_connection,
equal,
get_link_name,
ovirt_full_argument_spec,
search_by_name,
)
ANSIBLE_METADATA = {'status': 'preview',
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_quotas
short_description: Module to manage datacenter quotas in oVirt
version_added: "2.3"
author: "Ondra Machacek (@machacekondra)"
description:
- "Module to manage datacenter quotas in oVirt"
options:
name:
description:
- "Name of the the quota to manage."
required: true
state:
description:
- "Should the quota be present/absent."
choices: ['present', 'absent']
default: present
datacenter:
description:
- "Name of the datacenter where quota should be managed."
required: true
description:
description:
- "Description of the the quota to manage."
cluster_threshold:
description:
- "Cluster threshold(soft limit) defined in percentage (0-100)."
cluster_grace:
description:
- "Cluster grace(hard limit) defined in percentage (1-100)."
storage_threshold:
description:
- "Storage threshold(soft limit) defined in percentage (0-100)."
storage_grace:
description:
- "Storage grace(hard limit) defined in percentage (1-100)."
clusters:
description:
- "List of dictionary of cluster limits, which is valid to specific cluster."
- "If cluster isn't spefied it's valid to all clusters in system:"
- "C(cluster) - Name of the cluster."
- "C(memory) - Memory limit (in GiB)."
- "C(cpu) - CPU limit."
storages:
description:
- "List of dictionary of storage limits, which is valid to specific storage."
- "If storage isn't spefied it's valid to all storages in system:"
- "C(storage) - Name of the storage."
- "C(size) - Size limit (in GiB)."
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Add cluster quota to cluster cluster1 with memory limit 20GiB and CPU limit to 10:
ovirt_quotas:
name: quota1
datacenter: dcX
clusters:
- name: cluster1
memory: 20
cpu: 10
# Add cluster quota to all clusters with memory limit 30GiB and CPU limit to 15:
ovirt_quotas:
name: quota2
datacenter: dcX
clusters:
- memory: 30
cpu: 15
# Add storage quota to storage data1 with size limit to 100GiB
ovirt_quotas:
name: quota3
datacenter: dcX
storage_grace: 40
storage_threshold: 60
storages:
- name: data1
size: 100
# Remove quota quota1 (Note the quota must not be assigned to any VM/disk):
ovirt_quotas:
state: absent
datacenter: dcX
name: quota1
'''
RETURN = '''
id:
description: ID of the quota which is managed
returned: On success if quota is found.
type: str
sample: 7de90f31-222c-436c-a1ca-7e655bd5b60c
quota:
description: "Dictionary of all the quota attributes. Quota attributes can be found on your oVirt instance
at following url: https://ovirt.example.com/ovirt-engine/api/model#types/quota."
returned: On success if quota is found.
'''
class QuotasModule(BaseModule):
def build_entity(self):
return otypes.Quota(
description=self._module.params['description'],
name=self._module.params['name'],
storage_hard_limit_pct=self._module.params.get('storage_grace'),
storage_soft_limit_pct=self._module.params.get('storage_threshold'),
cluster_hard_limit_pct=self._module.params.get('cluster_grace'),
cluster_soft_limit_pct=self._module.params.get('cluster_threshold'),
)
def update_storage_limits(self, entity):
new_limits = {}
for storage in self._module.params.get('storages'):
new_limits[storage.get('name', '')] = {
'size': storage.get('size'),
}
old_limits = {}
sd_limit_service = self._service.service(entity.id).quota_storage_limits_service()
for limit in sd_limit_service.list():
storage = get_link_name(self._connection, limit.storage_domain) if limit.storage_domain else ''
old_limits[storage] = {
'size': limit.limit,
}
sd_limit_service.service(limit.id).remove()
return new_limits == old_limits
def update_cluster_limits(self, entity):
new_limits = {}
for cluster in self._module.params.get('clusters'):
new_limits[cluster.get('name', '')] = {
'cpu': cluster.get('cpu'),
'memory': float(cluster.get('memory')),
}
old_limits = {}
cl_limit_service = self._service.service(entity.id).quota_cluster_limits_service()
for limit in cl_limit_service.list():
cluster = get_link_name(self._connection, limit.cluster) if limit.cluster else ''
old_limits[cluster] = {
'cpu': limit.vcpu_limit,
'memory': limit.memory_limit,
}
cl_limit_service.service(limit.id).remove()
return new_limits == old_limits
def update_check(self, entity):
# -- FIXME --
# Note that we here always remove all cluster/storage limits, because
# it's not currently possible to update them and then re-create the limits
# appropriatelly, this shouldn't have any side-effects, but it's not considered
# as a correct approach.
# This feature is tracked here: https://bugzilla.redhat.com/show_bug.cgi?id=1398576
#
return (
self.update_storage_limits(entity) and
self.update_cluster_limits(entity) and
equal(self._module.params.get('description'), entity.description) and
equal(self._module.params.get('storage_grace'), entity.storage_hard_limit_pct) and
equal(self._module.params.get('storage_threshold'), entity.storage_soft_limit_pct) and
equal(self._module.params.get('cluster_grace'), entity.cluster_hard_limit_pct) and
equal(self._module.params.get('cluster_threshold'), entity.cluster_soft_limit_pct)
)
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(
choices=['present', 'absent'],
default='present',
),
name=dict(required=True),
datacenter=dict(required=True),
description=dict(default=None),
cluster_threshold=dict(default=None, type='int', aliases=['cluster_soft_limit']),
cluster_grace=dict(default=None, type='int', aliases=['cluster_hard_limit']),
storage_threshold=dict(default=None, type='int', aliases=['storage_soft_limit']),
storage_grace=dict(default=None, type='int', aliases=['storage_hard_limit']),
clusters=dict(default=[], type='list'),
storages=dict(default=[], type='list'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
)
check_sdk(module)
try:
connection = create_connection(module.params.pop('auth'))
datacenters_service = connection.system_service().data_centers_service()
dc_name = module.params['datacenter']
dc_id = getattr(search_by_name(datacenters_service, dc_name), 'id', None)
if dc_id is None:
raise Exception("Datacenter '%s' was not found." % dc_name)
quotas_service = datacenters_service.service(dc_id).quotas_service()
quotas_module = QuotasModule(
connection=connection,
module=module,
service=quotas_service,
)
state = module.params['state']
if state == 'present':
ret = quotas_module.create()
# Manage cluster limits:
cl_limit_service = quotas_service.service(ret['id']).quota_cluster_limits_service()
for cluster in module.params.get('clusters'):
cl_limit_service.add(
limit=otypes.QuotaClusterLimit(
memory_limit=float(cluster.get('memory')),
vcpu_limit=cluster.get('cpu'),
cluster=search_by_name(
connection.system_service().clusters_service(),
cluster.get('name')
),
),
)
# Manage storage limits:
sd_limit_service = quotas_service.service(ret['id']).quota_storage_limits_service()
for storage in module.params.get('storages'):
sd_limit_service.add(
limit=otypes.QuotaStorageLimit(
limit=storage.get('size'),
storage_domain=search_by_name(
connection.system_service().storage_domains_service(),
storage.get('name')
),
)
)
elif state == 'absent':
ret = quotas_module.remove()
module.exit_json(**ret)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=False)
if __name__ == "__main__":
main()

View file

@ -0,0 +1,121 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
import fnmatch
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_full_argument_spec,
search_by_name,
)
ANSIBLE_METADATA = {'status': 'preview',
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_quotas_facts
short_description: Retrieve facts about one or more oVirt quotas
version_added: "2.3"
description:
- "Retrieve facts about one or more oVirt quotas."
notes:
- "This module creates a new top-level C(ovirt_quotas) fact, which
contains a list of quotas."
options:
datacenter:
description:
- "Name of the datacenter where quota resides."
required: true
name:
description:
- "Name of the quota, can be used as glob expression."
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather facts about quota named C<myquota> in Default datacenter:
- ovirt_quotas_facts:
datacenter: Default
name: myquota
- debug:
var: ovirt_quotas
'''
RETURN = '''
ovirt_quotas:
description: "List of dictionaries describing the quotas. Quota attribues are mapped to dictionary keys,
all quotas attributes can be found at following url: https://ovirt.example.com/ovirt-engine/api/model#types/quota."
returned: On success.
type: list
'''
def main():
argument_spec = ovirt_full_argument_spec(
datacenter=dict(required=True),
name=dict(default=None),
)
module = AnsibleModule(argument_spec)
check_sdk(module)
try:
connection = create_connection(module.params.pop('auth'))
datacenters_service = connection.system_service().data_centers_service()
dc_name = module.params['datacenter']
dc = search_by_name(datacenters_service, dc_name)
if dc is None:
raise Exception("Datacenter '%s' was not found." % dc_name)
quotas_service = datacenters_service.service(dc.id).quotas_service()
if module.params['name']:
quotas = [
e for e in quotas_service.list()
if fnmatch.fnmatch(e.name, module.params['name'])
]
else:
quotas = quotas_service.list()
module.exit_json(
changed=False,
ansible_facts=dict(
ovirt_quotas=[
get_dict_of_struct(c) for c in quotas
],
),
)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=False)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,444 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
try:
import ovirtsdk4.types as otypes
from ovirtsdk4.types import StorageDomainStatus as sdstate
except ImportError:
pass
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
BaseModule,
check_sdk,
create_connection,
ovirt_full_argument_spec,
search_by_name,
wait,
)
ANSIBLE_METADATA = {'status': 'preview',
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_storage_domains
short_description: Module to manage storage domains in oVirt
version_added: "2.3"
author: "Ondra Machacek (@machacekondra)"
description:
- "Module to manage storage domains in oVirt"
options:
name:
description:
- "Name of the the storage domain to manage."
state:
description:
- "Should the storage domain be present/absent/maintenance/unattached"
choices: ['present', 'absent', 'maintenance', 'unattached']
default: present
description:
description:
- "Description of the storage domain."
comment:
description:
- "Comment of the storage domain."
data_center:
description:
- "Data center name where storage domain should be attached."
domain_function:
description:
- "Function of the storage domain."
choices: ['data', 'iso', 'export']
default: 'data'
aliases: ['type']
host:
description:
- "Host to be used to mount storage."
nfs:
description:
- "Dictionary with values for NFS storage type:"
- "C(address) - Address of the NFS server. E.g.: myserver.mydomain.com"
- "C(path) - Path of the mount point. E.g.: /path/to/my/data"
iscsi:
description:
- "Dictionary with values for iSCSI storage type:"
- "C(address) - Address of the iSCSI storage server."
- "C(port) - Port of the iSCSI storage server."
- "C(target) - iSCSI target."
- "C(lun_id) - LUN id."
- "C(username) - Username to be used to access storage server."
- "C(password) - Password of the user to be used to access storage server."
posixfs:
description:
- "Dictionary with values for PosixFS storage type:"
- "C(path) - Path of the mount point. E.g.: /path/to/my/data"
- "C(vfs_type) - Virtual File System type."
- "C(mount_options) - Option which will be passed when mounting storage."
glusterfs:
description:
- "Dictionary with values for GlusterFS storage type:"
- "C(address) - Address of the NFS server. E.g.: myserver.mydomain.com"
- "C(path) - Path of the mount point. E.g.: /path/to/my/data"
- "C(mount_options) - Option which will be passed when mounting storage."
fcp:
description:
- "Dictionary with values for fibre channel storage type:"
- "C(address) - Address of the fibre channel storage server."
- "C(port) - Port of the fibre channel storage server."
- "C(lun_id) - LUN id."
destroy:
description:
- "If I(True) storage domain metadata won't be cleaned, and user have to clean them manually."
- "This parameter is relevant only when C(state) is I(absent)."
format:
description:
- "If I(True) storage domain will be removed after removing it from oVirt."
- "This parameter is relevant only when C(state) is I(absent)."
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Add data NFS storage domain
- ovirt_storage_domains:
name: data_nfs
host: myhost
data_center: mydatacenter
nfs:
address: 10.34.63.199
path: /path/data
# Add data iSCSI storage domain:
- ovirt_storage_domains:
name: data_iscsi
host: myhost
data_center: mydatacenter
iscsi:
target: iqn.2016-08-09.domain-01:nickname
lun_id: 1IET_000d0002
address: 10.34.63.204
# Import export NFS storage domain:
- ovirt_storage_domains:
domain_function: export
host: myhost
data_center: mydatacenter
nfs:
address: 10.34.63.199
path: /path/export
# Create ISO NFS storage domain
- ovirt_storage_domains:
name: myiso
domain_function: iso
host: myhost
data_center: mydatacenter
nfs:
address: 10.34.63.199
path: /path/iso
# Remove storage domain
- ovirt_storage_domains:
state: absent
name: mystorage_domain
format: true
'''
RETURN = '''
id:
description: ID of the storage domain which is managed
returned: On success if storage domain is found.
type: str
sample: 7de90f31-222c-436c-a1ca-7e655bd5b60c
storage domain:
description: "Dictionary of all the storage domain attributes. Storage domain attributes can be found on your oVirt instance
at following url: https://ovirt.example.com/ovirt-engine/api/model#types/storage_domain."
returned: On success if storage domain is found.
'''
class StorageDomainModule(BaseModule):
def _get_storage_type(self):
for sd_type in ['nfs', 'iscsi', 'posixfs', 'glusterfs', 'fcp']:
if self._module.params.get(sd_type) is not None:
return sd_type
def _get_storage(self):
for sd_type in ['nfs', 'iscsi', 'posixfs', 'glusterfs', 'fcp']:
if self._module.params.get(sd_type) is not None:
return self._module.params.get(sd_type)
def _login(self, storage_type, storage):
if storage_type == 'iscsi':
hosts_service = self._connection.system_service().hosts_service()
host = search_by_name(hosts_service, self._module.params['host'])
hosts_service.host_service(host.id).iscsi_login(
iscsi=otypes.IscsiDetails(
username=storage.get('username'),
password=storage.get('password'),
address=storage.get('address'),
target=storage.get('target'),
),
)
def build_entity(self):
storage_type = self._get_storage_type()
storage = self._get_storage()
self._login(storage_type, storage)
return otypes.StorageDomain(
name=self._module.params['name'],
description=self._module.params['description'],
comment=self._module.params['comment'],
type=otypes.StorageDomainType(
self._module.params['domain_function']
),
host=otypes.Host(
name=self._module.params['host'],
),
storage=otypes.HostStorage(
type=otypes.StorageType(storage_type),
logical_units=[
otypes.LogicalUnit(
id=storage.get('lun_id'),
address=storage.get('address'),
port=storage.get('port', 3260),
target=storage.get('target'),
username=storage.get('username'),
password=storage.get('password'),
),
] if storage_type in ['iscsi', 'fcp'] else None,
mount_options=storage.get('mount_options'),
vfs_type=storage.get('vfs_type'),
address=storage.get('address'),
path=storage.get('path'),
)
)
def _attached_sds_service(self):
# Get data center object of the storage domain:
dcs_service = self._connection.system_service().data_centers_service()
dc = search_by_name(dcs_service, self._module.params['data_center'])
if dc is None:
return
dc_service = dcs_service.data_center_service(dc.id)
return dc_service.storage_domains_service()
def _maintenance(self, storage_domain):
attached_sds_service = self._attached_sds_service()
if attached_sds_service is None:
return
attached_sd_service = attached_sds_service.storage_domain_service(storage_domain.id)
attached_sd = attached_sd_service.get()
if attached_sd and attached_sd.status != sdstate.MAINTENANCE:
if not self._module.check_mode:
attached_sd_service.deactivate()
self.changed = True
wait(
service=attached_sd_service,
condition=lambda sd: sd.status == sdstate.MAINTENANCE,
wait=self._module.params['wait'],
timeout=self._module.params['timeout'],
)
def _unattach(self, storage_domain):
attached_sds_service = self._attached_sds_service()
if attached_sds_service is None:
return
attached_sd_service = attached_sds_service.storage_domain_service(storage_domain.id)
attached_sd = attached_sd_service.get()
if attached_sd and attached_sd.status == sdstate.MAINTENANCE:
if not self._module.check_mode:
# Detach the storage domain:
attached_sd_service.remove()
self.changed = True
# Wait until storage domain is detached:
wait(
service=attached_sd_service,
condition=lambda sd: sd is None,
wait=self._module.params['wait'],
timeout=self._module.params['timeout'],
)
def pre_remove(self, storage_domain):
# Before removing storage domain we need to put it into maintenance state:
self._maintenance(storage_domain)
# Before removing storage domain we need to detach it from data center:
self._unattach(storage_domain)
def post_create_check(self, sd_id):
storage_domain = self._service.service(sd_id).get()
self._service = self._attached_sds_service()
# If storage domain isn't attached, attach it:
attached_sd_service = self._service.service(storage_domain.id)
if attached_sd_service.get() is None:
self._service.add(
otypes.StorageDomain(
id=storage_domain.id,
),
)
self.changed = True
# Wait until storage domain is in maintenance:
wait(
service=attached_sd_service,
condition=lambda sd: sd.status == sdstate.ACTIVE,
wait=self._module.params['wait'],
timeout=self._module.params['timeout'],
)
def unattached_pre_action(self, storage_domain):
self._service = self._attached_sds_service(storage_domain)
self._maintenance(self._service, storage_domain)
def failed_state(sd):
return sd.status in [sdstate.UNKNOWN, sdstate.INACTIVE]
def control_state(sd_module):
sd = sd_module.search_entity()
if sd is None:
return
sd_service = sd_module._service.service(sd.id)
if sd.status == sdstate.LOCKED:
wait(
service=sd_service,
condition=lambda sd: sd.status != sdstate.LOCKED,
fail_condition=failed_state,
)
if failed_state(sd):
raise Exception("Not possible to manage storage domain '%s'." % sd.name)
elif sd.status == sdstate.ACTIVATING:
wait(
service=sd_service,
condition=lambda sd: sd.status == sdstate.ACTIVE,
fail_condition=failed_state,
)
elif sd.status == sdstate.DETACHING:
wait(
service=sd_service,
condition=lambda sd: sd.status == sdstate.UNATTACHED,
fail_condition=failed_state,
)
elif sd.status == sdstate.PREPARING_FOR_MAINTENANCE:
wait(
service=sd_service,
condition=lambda sd: sd.status == sdstate.MAINTENANCE,
fail_condition=failed_state,
)
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(
choices=['present', 'absent', 'maintenance', 'unattached'],
default='present',
),
name=dict(required=True),
description=dict(default=None),
comment=dict(default=None),
data_center=dict(required=True),
domain_function=dict(choices=['data', 'iso', 'export'], default='data', aliases=['type']),
host=dict(default=None),
nfs=dict(default=None, type='dict'),
iscsi=dict(default=None, type='dict'),
posixfs=dict(default=None, type='dict'),
glusterfs=dict(default=None, type='dict'),
fcp=dict(default=None, type='dict'),
destroy=dict(type='bool', default=False),
format=dict(type='bool', default=False),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
)
check_sdk(module)
try:
connection = create_connection(module.params.pop('auth'))
storage_domains_service = connection.system_service().storage_domains_service()
storage_domains_module = StorageDomainModule(
connection=connection,
module=module,
service=storage_domains_service,
)
state = module.params['state']
control_state(storage_domains_module)
if state == 'absent':
ret = storage_domains_module.remove(
destroy=module.params['destroy'],
format=module.params['format'],
host=module.params['host'],
)
elif state == 'present':
sd_id = storage_domains_module.create()['id']
storage_domains_module.post_create_check(sd_id)
ret = storage_domains_module.action(
action='activate',
action_condition=lambda s: s.status == sdstate.MAINTENANCE,
wait_condition=lambda s: s.status == sdstate.ACTIVE,
fail_condition=failed_state,
)
elif state == 'maintenance':
sd_id = storage_domains_module.create()['id']
storage_domains_module.post_create_check(sd_id)
ret = storage_domains_module.action(
action='deactivate',
action_condition=lambda s: s.status == sdstate.ACTIVE,
wait_condition=lambda s: s.status == sdstate.MAINTENANCE,
fail_condition=failed_state,
)
elif state == 'unattached':
ret = storage_domains_module.create()
storage_domains_module.pre_remove(
storage_domain=storage_domains_service.service(ret['id']).get()
)
ret['changed'] = storage_domains_module.changed
module.exit_json(**ret)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=False)
if __name__ == "__main__":
main()

View file

@ -0,0 +1,104 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_full_argument_spec,
)
ANSIBLE_METADATA = {'status': 'preview',
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_storage_domains_facts
short_description: Retrieve facts about one or more oVirt storage domains
author: "Ondra Machacek (@machacekondra)"
version_added: "2.3"
description:
- "Retrieve facts about one or more oVirt storage domains."
notes:
- "This module creates a new top-level C(ovirt_storage_domains) fact, which
contains a list of storage domains."
options:
pattern:
description:
- "Search term which is accepted by oVirt search backend."
- "For example to search storage domain X from datacenter Y use following pattern:
name=X and datacenter=Y"
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather facts about all storage domains which names start with C(data) and
# belong to data center C(west):
- ovirt_storage_domains_facts:
pattern: name=data* and datacenter=west
- debug:
var: ovirt_storage_domains
'''
RETURN = '''
ovirt_storage_domains:
description: "List of dictionaries describing the storage domains. Storage_domain attribues are mapped to dictionary keys,
all storage domains attributes can be found at following url: https://ovirt.example.com/ovirt-engine/api/model#types/storage_domain."
returned: On success.
type: list
'''
def main():
argument_spec = ovirt_full_argument_spec(
pattern=dict(default='', required=False),
)
module = AnsibleModule(argument_spec)
check_sdk(module)
try:
connection = create_connection(module.params.pop('auth'))
storage_domains_service = connection.system_service().storage_domains_service()
storage_domains = storage_domains_service.list(search=module.params['pattern'])
module.exit_json(
changed=False,
ansible_facts=dict(
ovirt_storage_domains=[
get_dict_of_struct(c) for c in storage_domains
],
),
)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=False)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,314 @@
#!/usr/bin/pythonapi/
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
import time
import traceback
try:
import ovirtsdk4.types as otypes
except ImportError:
pass
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
BaseModule,
check_sdk,
create_connection,
equal,
get_dict_of_struct,
get_link_name,
ovirt_full_argument_spec,
search_by_attributes,
search_by_name,
)
ANSIBLE_METADATA = {'status': 'preview',
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_templates
short_description: Module to manage virtual machine templates in oVirt
version_added: "2.3"
author: "Ondra Machacek (@machacekondra)"
description:
- "Module to manage virtual machine templates in oVirt."
options:
name:
description:
- "Name of the the template to manage."
required: true
state:
description:
- "Should the template be present/absent/exported/imported"
choices: ['present', 'absent', 'exported', 'imported']
default: present
vm:
description:
- "Name of the VM, which will be used to create template."
description:
description:
- "Description of the template."
cpu_profile:
description:
- "CPU profile to be set to template."
cluster:
description:
- "Name of the cluster, where template should be created/imported."
exclusive:
description:
- "When C(state) is I(exported) this parameter indicates if the existing templates with the
same name should be overwritten."
export_domain:
description:
- "When C(state) is I(exported) or I(imported) this parameter specifies the name of the
export storage domain."
image_provider:
description:
- "When C(state) is I(imported) this parameter specifies the name of the image provider to be used."
image_disk:
description:
- "When C(state) is I(imported) and C(image_provider) is used this parameter specifies the name of disk
to be imported as template."
storage_domain:
description:
- "When C(state) is I(imported) this parameter specifies the name of the destination data storage domain."
clone_permissions:
description:
- "If I(True) then the permissions of the VM (only the direct ones, not the inherited ones)
will be copied to the created template."
- "This parameter is used only when C(state) I(present)."
default: False
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Create template from vm
- ovirt_templates:
cluster: Default
name: mytemplate
vm: rhel7
cpu_profile: Default
description: Test
# Import template
- ovirt_templates:
state: imported
name: mytemplate
export_domain: myexport
storage_domain: mystorage
cluster: mycluster
# Remove template
- ovirt_templates:
state: absent
name: mytemplate
'''
RETURN = '''
id:
description: ID of the template which is managed
returned: On success if template is found.
type: str
sample: 7de90f31-222c-436c-a1ca-7e655bd5b60c
template:
description: "Dictionary of all the template attributes. Template attributes can be found on your oVirt instance
at following url: https://ovirt.example.com/ovirt-engine/api/model#types/template."
returned: On success if template is found.
'''
class TemplatesModule(BaseModule):
def build_entity(self):
return otypes.Template(
name=self._module.params['name'],
cluster=otypes.Cluster(
name=self._module.params['cluster']
) if self._module.params['cluster'] else None,
vm=otypes.Vm(
name=self._module.params['vm']
) if self._module.params['vm'] else None,
description=self._module.params['description'],
cpu_profile=otypes.CpuProfile(
id=search_by_name(
self._connection.system_service().cpu_profiles_service(),
self._module.params['cpu_profile'],
).id
) if self._module.params['cpu_profile'] else None,
)
def update_check(self, entity):
return (
equal(self._module.params.get('cluster'), get_link_name(self._connection, entity.cluster)) and
equal(self._module.params.get('description'), entity.description) and
equal(self._module.params.get('cpu_profile'), get_link_name(self._connection, entity.cpu_profile))
)
def _get_export_domain_service(self):
provider_name = self._module.params['export_domain'] or self._module.params['image_provider']
export_sds_service = self._connection.system_service().storage_domains_service()
export_sd = search_by_name(export_sds_service, provider_name)
if export_sd is None:
raise ValueError(
"Export storage domain/Image Provider '%s' wasn't found." % provider_name
)
return export_sds_service.service(export_sd.id)
def post_export_action(self, entity):
self._service = self._get_export_domain_service().templates_service()
def post_import_action(self, entity):
self._service = self._connection.system_service().templates_service()
def wait_for_import(module, templates_service):
if module.params['wait']:
start = time.time()
timeout = module.params['timeout']
poll_interval = module.params['poll_interval']
while time.time() < start + timeout:
template = search_by_name(templates_service, module.params['name'])
if template:
return template
time.sleep(poll_interval)
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(
choices=['present', 'absent', 'exported', 'imported'],
default='present',
),
name=dict(default=None, required=True),
vm=dict(default=None),
description=dict(default=None),
cluster=dict(default=None),
cpu_profile=dict(default=None),
disks=dict(default=[], type='list'),
clone_permissions=dict(type='bool'),
export_domain=dict(default=None),
storage_domain=dict(default=None),
exclusive=dict(type='bool'),
image_provider=dict(default=None),
image_disk=dict(default=None),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
)
check_sdk(module)
try:
connection = create_connection(module.params.pop('auth'))
templates_service = connection.system_service().templates_service()
templates_module = TemplatesModule(
connection=connection,
module=module,
service=templates_service,
)
state = module.params['state']
if state == 'present':
ret = templates_module.create(
result_state=otypes.TemplateStatus.OK,
clone_permissions=module.params['clone_permissions'],
)
elif state == 'absent':
ret = templates_module.remove()
elif state == 'exported':
template = templates_module.search_entity()
export_service = templates_module._get_export_domain_service()
export_template = search_by_attributes(export_service.templates_service(), id=template.id)
ret = templates_module.action(
entity=template,
action='export',
action_condition=lambda t: export_template is None,
wait_condition=lambda t: t is not None,
post_action=templates_module.post_export_action,
storage_domain=otypes.StorageDomain(id=export_service.get().id),
exclusive=module.params['exclusive'],
)
elif state == 'imported':
template = templates_module.search_entity()
if template:
ret = templates_module.create(
result_state=otypes.TemplateStatus.OK,
)
else:
kwargs = {}
if module.params['image_provider']:
kwargs.update(
disk=otypes.Disk(
name=module.params['image_disk']
),
template=otypes.Template(
name=module.params['name'],
),
import_as_template=True,
)
if module.params['image_disk']:
# We need to refresh storage domain to get list of images:
templates_module._get_export_domain_service().images_service().list()
glance_service = connection.system_service().openstack_image_providers_service()
image_provider = search_by_name(glance_service, module.params['image_provider'])
images_service = glance_service.service(image_provider.id).images_service()
else:
images_service = templates_module._get_export_domain_service().templates_service()
template_name = module.params['image_disk'] or module.params['name']
entity = search_by_name(images_service, template_name)
if entity is None:
raise Exception("Image/template '%s' was not found." % template_name)
images_service.service(entity.id).import_(
storage_domain=otypes.StorageDomain(
name=module.params['storage_domain']
) if module.params['storage_domain'] else None,
cluster=otypes.Cluster(
name=module.params['cluster']
) if module.params['cluster'] else None,
**kwargs
)
template = wait_for_import(module, templates_service)
ret = {
'changed': True,
'id': template.id,
'template': get_dict_of_struct(template),
}
module.exit_json(**ret)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=False)
if __name__ == "__main__":
main()

View file

@ -0,0 +1,104 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_full_argument_spec,
)
ANSIBLE_METADATA = {'status': 'preview',
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_templates_facts
short_description: Retrieve facts about one or more oVirt templates
author: "Ondra Machacek (@machacekondra)"
version_added: "2.3"
description:
- "Retrieve facts about one or more oVirt templates."
notes:
- "This module creates a new top-level C(ovirt_templates) fact, which
contains a list of templates."
options:
pattern:
description:
- "Search term which is accepted by oVirt search backend."
- "For example to search template X from datacenter Y use following pattern:
name=X and datacenter=Y"
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather facts about all templates which names start with C(centos) and
# belongs to data center C(west):
- ovirt_templates_facts:
pattern: name=centos* and datacenter=west
- debug:
var: ovirt_templates
'''
RETURN = '''
ovirt_templates:
description: "List of dictionaries describing the templates. Template attribues are mapped to dictionary keys,
all templates attributes can be found at following url: https://ovirt.example.com/ovirt-engine/api/model#types/template."
returned: On success.
type: list
'''
def main():
argument_spec = ovirt_full_argument_spec(
pattern=dict(default='', required=False),
)
module = AnsibleModule(argument_spec)
check_sdk(module)
try:
connection = create_connection(module.params.pop('auth'))
templates_service = connection.system_service().templates_service()
templates = templates_service.list(search=module.params['pattern'])
module.exit_json(
changed=False,
ansible_facts=dict(
ovirt_templates=[
get_dict_of_struct(c) for c in templates
],
),
)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=False)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,169 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
import traceback
try:
import ovirtsdk4.types as otypes
except ImportError:
pass
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
BaseModule,
check_sdk,
check_params,
create_connection,
ovirt_full_argument_spec,
)
ANSIBLE_METADATA = {'status': 'preview',
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_users
short_description: Module to manage users in oVirt
version_added: "2.3"
author: "Ondra Machacek (@machacekondra)"
description:
- "Module to manage users in oVirt."
options:
name:
description:
- "Name of the the user to manage. In most LDAPs it's I(uid) of the user, but in Active Directory you must specify I(UPN) of the user."
required: true
state:
description:
- "Should the user be present/absent."
choices: ['present', 'absent']
default: present
authz_name:
description:
- "Authorization provider of the user. In previous versions of oVirt known as domain."
required: true
aliases: ['domain']
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Add user user1 from authorization provider example.com-authz
ovirt_users:
name: user1
domain: example.com-authz
# Add user user1 from authorization provider example.com-authz
# In case of Active Directory specify UPN:
ovirt_users:
name: user1@ad2.example.com
domain: example.com-authz
# Remove user user1 with authorization provider example.com-authz
ovirt_users:
state: absent
name: user1
authz_name: example.com-authz
'''
RETURN = '''
id:
description: ID of the user which is managed
returned: On success if user is found.
type: str
sample: 7de90f31-222c-436c-a1ca-7e655bd5b60c
user:
description: "Dictionary of all the user attributes. User attributes can be found on your oVirt instance
at following url: https://ovirt.example.com/ovirt-engine/api/model#types/user."
returned: On success if user is found.
'''
def username(module):
return '{}@{}'.format(module.params['name'], module.params['authz_name'])
class UsersModule(BaseModule):
def build_entity(self):
return otypes.User(
domain=otypes.Domain(
name=self._module.params['authz_name']
),
user_name=username(self._module),
principal=self._module.params['name'],
namespace=self._module.params['namespace'],
)
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(
choices=['present', 'absent'],
default='present',
),
name=dict(required=True),
authz_name=dict(required=True, aliases=['domain']),
namespace=dict(default=None),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
)
check_sdk(module)
check_params(module)
try:
connection = create_connection(module.params.pop('auth'))
users_service = connection.system_service().users_service()
users_module = UsersModule(
connection=connection,
module=module,
service=users_service,
)
state = module.params['state']
if state == 'present':
ret = users_module.create(
search_params={
'usrname': username(module),
}
)
elif state == 'absent':
ret = users_module.remove(
search_params={
'usrname': username(module),
}
)
module.exit_json(**ret)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=False)
if __name__ == "__main__":
main()

View file

@ -0,0 +1,102 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_full_argument_spec,
)
ANSIBLE_METADATA = {'status': 'preview',
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_users_facts
short_description: Retrieve facts about one or more oVirt users
author: "Ondra Machacek (@machacekondra)"
version_added: "2.3"
description:
- "Retrieve facts about one or more oVirt users."
notes:
- "This module creates a new top-level C(ovirt_users) fact, which
contains a list of users."
options:
pattern:
description:
- "Search term which is accepted by oVirt search backend."
- "For example to search user X use following pattern: name=X"
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather facts about all users which first names start with C(john):
- ovirt_users_facts:
pattern: name=john*
- debug:
var: ovirt_users
'''
RETURN = '''
ovirt_users:
description: "List of dictionaries describing the users. User attribues are mapped to dictionary keys,
all users attributes can be found at following url: https://ovirt.example.com/ovirt-engine/api/model#types/user."
returned: On success.
type: list
'''
def main():
argument_spec = ovirt_full_argument_spec(
pattern=dict(default='', required=False),
)
module = AnsibleModule(argument_spec)
check_sdk(module)
try:
connection = create_connection(module.params.pop('auth'))
users_service = connection.system_service().users_service()
users = users_service.list(search=module.params['pattern'])
module.exit_json(
changed=False,
ansible_facts=dict(
ovirt_users=[
get_dict_of_struct(c) for c in users
],
),
)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=False)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,220 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
try:
import ovirtsdk4.types as otypes
except ImportError:
pass
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
BaseModule,
check_params,
check_sdk,
create_connection,
equal,
get_link_name,
ovirt_full_argument_spec,
wait,
)
ANSIBLE_METADATA = {'status': 'preview',
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_vmpools
short_description: Module to manage VM pools in oVirt
version_added: "2.3"
author: "Ondra Machacek (@machacekondra)"
description:
- "Module to manage VM pools in oVirt."
options:
name:
description:
- "Name of the the VM pool to manage."
required: true
state:
description:
- "Should the VM pool be present/absent."
- "Note that when C(state) is I(absent) all VMs in VM pool are stopped and removed."
choices: ['present', 'absent']
default: present
template:
description:
- "Name of the template, which will be used to create VM pool."
description:
description:
- "Description of the VM pool."
cluster:
description:
- "Name of the cluster, where VM pool should be created."
type:
description:
- "Type of the VM pool. Either manual or automatic."
- "C(manual) - The administrator is responsible for explicitly returning the virtual machine to the pool.
The virtual machine reverts to the original base image after the administrator returns it to the pool."
- "C(Automatic) - When the virtual machine is shut down, it automatically reverts to its base image and
is returned to the virtual machine pool."
- "Default value is set by engine."
choices: ['manual', 'automatic']
vm_per_user:
description:
- "Maximum number of VMs a single user can attach to from this pool."
- "Default value is set by engine."
prestarted:
description:
- "Number of pre-started VMs defines the number of VMs in run state, that are waiting
to be attached to Users."
- "Default value is set by engine."
vm_count:
description:
- "Number of VMs in the pool."
- "Default value is set by engine."
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Create VM pool from template
- ovirt_vmpools:
cluster: mycluster
name: myvmpool
template: rhel7
vm_count: 2
prestarted: 2
vm_per_user: 1
# Remove vmpool, note that all VMs in pool will be stopped and removed:
- ovirt_vmpools:
state: absent
name: myvmpool
'''
RETURN = '''
id:
description: ID of the VM pool which is managed
returned: On success if VM pool is found.
type: str
sample: 7de90f31-222c-436c-a1ca-7e655bd5b60c
vm_pool:
description: "Dictionary of all the VM pool attributes. VM pool attributes can be found on your oVirt instance
at following url: https://ovirt.example.com/ovirt-engine/api/model#types/vm_pool."
returned: On success if VM pool is found.
'''
class VmPoolsModule(BaseModule):
def build_entity(self):
return otypes.VmPool(
name=self._module.params['name'],
description=self._module.params['description'],
comment=self._module.params['comment'],
cluster=otypes.Cluster(
name=self._module.params['cluster']
) if self._module.params['cluster'] else None,
template=otypes.Template(
name=self._module.params['template']
) if self._module.params['template'] else None,
max_user_vms=self._module.params['vm_per_user'],
prestarted_vms=self._module.params['prestarted'],
size=self._module.params['vm_count'],
type=otypes.VmPoolType(
self._module.params['type']
) if self._module.params['type'] else None,
)
def update_check(self, entity):
return (
equal(self._module.params.get('cluster'), get_link_name(self._connection, entity.cluster)) and
equal(self._module.params.get('description'), entity.description) and
equal(self._module.params.get('comment'), entity.comment) and
equal(self._module.params.get('vm_per_user'), entity.max_user_vms) and
equal(self._module.params.get('prestarted'), entity.prestarted_vms) and
equal(self._module.params.get('vm_count'), entity.size)
)
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(
choices=['present', 'absent'],
default='present',
),
name=dict(default=None, required=True),
template=dict(default=None),
cluster=dict(default=None),
description=dict(default=None),
comment=dict(default=None),
vm_per_user=dict(default=None, type='int'),
prestarted=dict(default=None, type='int'),
vm_count=dict(default=None, type='int'),
type=dict(default=None, choices=['automatic', 'manual']),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
)
check_sdk(module)
check_params(module)
try:
connection = create_connection(module.params.pop('auth'))
vm_pools_service = connection.system_service().vm_pools_service()
vm_pools_module = VmPoolsModule(
connection=connection,
module=module,
service=vm_pools_service,
)
state = module.params['state']
if state == 'present':
ret = vm_pools_module.create()
# Wait for all VM pool VMs to be created:
if module.params['wait']:
vms_service = connection.system_service().vms_service()
for vm in vms_service.list(search='pool=%s' % module.params['name']):
wait(
service=vms_service.service(vm.id),
condition=lambda vm: vm.status in [otypes.VmStatus.DOWN, otypes.VmStatus.UP],
timeout=module.params['timeout'],
)
elif state == 'absent':
ret = vm_pools_module.remove()
module.exit_json(**ret)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=False)
if __name__ == "__main__":
main()

View file

@ -0,0 +1,101 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_full_argument_spec,
)
ANSIBLE_METADATA = {'status': 'preview',
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_vmpools_facts
short_description: Retrieve facts about one or more oVirt vmpools
author: "Ondra Machacek (@machacekondra)"
version_added: "2.3"
description:
- "Retrieve facts about one or more oVirt vmpools."
notes:
- "This module creates a new top-level C(ovirt_vmpools) fact, which
contains a list of vmpools."
options:
pattern:
description:
- "Search term which is accepted by oVirt search backend."
- "For example to search vmpool X: name=X"
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather facts about all vm pools which names start with C(centos):
- ovirt_vmpools_facts:
pattern: name=centos*
- debug:
var: ovirt_vmpools
'''
RETURN = '''
ovirt_vm_pools:
description: "List of dictionaries describing the vmpools. Vm pool attribues are mapped to dictionary keys,
all vmpools attributes can be found at following url: https://ovirt.example.com/ovirt-engine/api/model#types/vm_pool."
returned: On success.
type: list
'''
def main():
argument_spec = ovirt_full_argument_spec(
pattern=dict(default='', required=False),
)
module = AnsibleModule(argument_spec)
check_sdk(module)
try:
connection = create_connection(module.params.pop('auth'))
vmpools_service = connection.system_service().vm_pools_service()
vmpools = vmpools_service.list(search=module.params['pattern'])
module.exit_json(
changed=False,
ansible_facts=dict(
ovirt_vm_pools=[
get_dict_of_struct(c) for c in vmpools
],
),
)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=False)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,887 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
try:
import ovirtsdk4 as sdk
import ovirtsdk4.types as otypes
except ImportError:
pass
from ansible.module_utils.ovirt import *
ANSIBLE_METADATA = {'status': ['preview'],
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_vms
short_description: "Module to manage Virtual Machines in oVirt."
version_added: "2.2"
author: "Ondra Machacek (@machacekondra)"
description:
- "This module manages whole lifecycle of the Virtual Machine(VM) in oVirt. Since VM can hold many states in oVirt,
this see notes to see how the states of the VM are handled."
options:
name:
description:
- "Name of the the Virtual Machine to manage. If VM don't exists C(name) is required.
Otherwise C(id) or C(name) can be used."
id:
description:
- "ID of the the Virtual Machine to manage."
state:
description:
- "Should the Virtual Machine be running/stopped/present/absent/suspended/next_run."
- "I(present) and I(running) are equal states."
- "I(next_run) state updates the VM and if the VM has next run configuration it will be rebooted."
- "Please check I(notes) to more detailed description of states."
choices: ['running', 'stopped', 'present', 'absent', 'suspended', 'next_run']
default: present
cluster:
description:
- "Name of the cluster, where Virtual Machine should be created. Required if creating VM."
template:
description:
- "Name of the template, which should be used to create Virtual Machine. Required if creating VM."
- "If template is not specified and VM doesn't exist, VM will be created from I(Blank) template."
template_version:
description:
- "Version number of the template to be used for VM."
- "By default the latest available version of the template is used."
version_added: "2.3"
use_latest_template_version:
description:
- "Specify if latest template version should be used, when running a stateless VM."
- "If this parameter is set to I(true) stateless VM is created."
version_added: "2.3"
memory:
description:
- "Amount of memory of the Virtual Machine. Prefix uses IEC 60027-2 standard (for example 1GiB, 1024MiB)."
- "Default value is set by engine."
memory_guaranteed:
description:
- "Amount of minimal guaranteed memory of the Virtual Machine.
Prefix uses IEC 60027-2 standard (for example 1GiB, 1024MiB)."
- "C(memory_guaranteed) parameter can't be lower than C(memory) parameter. Default value is set by engine."
cpu_shares:
description:
- "Set a CPU shares for this Virtual Machine. Default value is set by oVirt engine."
cpu_cores:
description:
- "Number of virtual CPUs cores of the Virtual Machine. Default value is set by oVirt engine."
cpu_sockets:
description:
- "Number of virtual CPUs sockets of the Virtual Machine. Default value is set by oVirt engine."
type:
description:
- "Type of the Virtual Machine. Default value is set by oVirt engine."
choices: [server, desktop]
operating_system:
description:
- "Operating system of the Virtual Machine. Default value is set by oVirt engine."
choices: [
rhel_6_ppc64, other, freebsd, windows_2003x64, windows_10, rhel_6x64, rhel_4x64, windows_2008x64,
windows_2008R2x64, debian_7, windows_2012x64, ubuntu_14_04, ubuntu_12_04, ubuntu_13_10, windows_8x64,
other_linux_ppc64, windows_2003, other_linux, windows_10x64, windows_2008, rhel_3, rhel_5, rhel_4,
other_ppc64, sles_11, rhel_6, windows_xp, rhel_7x64, freebsdx64, rhel_7_ppc64, windows_7, rhel_5x64,
ubuntu_14_04_ppc64, sles_11_ppc64, windows_8, windows_2012R2x64, windows_2008r2x64, ubuntu_13_04,
ubuntu_12_10, windows_7x64
]
boot_devices:
description:
- "List of boot devices which should be used to boot. Choices I(network), I(hd) and I(cdrom)."
- "For example: ['cdrom', 'hd']. Default value is set by oVirt engine."
host:
description:
- "Specify host where Virtual Machine should be running. By default the host is chosen by engine scheduler."
- "This parameter is used only when C(state) is I(running) or I(present)."
high_availability:
description:
- "If I(True) Virtual Machine will be set as highly available."
- "If I(False) Virtual Machine won't be set as highly available."
- "If no value is passed, default value is set by oVirt engine."
delete_protected:
description:
- "If I(True) Virtual Machine will be set as delete protected."
- "If I(False) Virtual Machine won't be set as delete protected."
- "If no value is passed, default value is set by oVirt engine."
stateless:
description:
- "If I(True) Virtual Machine will be set as stateless."
- "If I(False) Virtual Machine will be unset as stateless."
- "If no value is passed, default value is set by oVirt engine."
clone:
description:
- "If I(True) then the disks of the created virtual machine will be cloned and independent of the template."
- "This parameter is used only when C(state) is I(running) or I(present) and VM didn't exist before."
default: False
clone_permissions:
description:
- "If I(True) then the permissions of the template (only the direct ones, not the inherited ones)
will be copied to the created virtual machine."
- "This parameter is used only when C(state) is I(running) or I(present) and VM didn't exist before."
default: False
cd_iso:
description:
- "ISO file from ISO storage domain which should be attached to Virtual Machine."
- "If you pass empty string the CD will be ejected from VM."
- "If used with C(state) I(running) or I(present) and VM is running the CD will be attached to VM."
- "If used with C(state) I(running) or I(present) and VM is down the CD will be attached to VM persistently."
force:
description:
- "Please check to I(Synopsis) to more detailed description of force parameter, it can behave differently
in different situations."
default: False
nics:
description:
- "List of NICs, which should be attached to Virtual Machine. NIC is described by following dictionary:"
- "C(name) - Name of the NIC."
- "C(profile_name) - Profile name where NIC should be attached."
- "C(interface) - Type of the network interface. One of following: I(virtio), I(e1000), I(rtl8139), default is I(virtio)."
- "C(mac_address) - Custom MAC address of the network interface, by default it's obtained from MAC pool."
- "C(Note:)"
- "This parameter is used only when C(state) is I(running) or I(present) and is able to only create NICs.
To manage NICs of the VM in more depth please use M(ovirt_nics) module instead."
disks:
description:
- "List of disks, which should be attached to Virtual Machine. Disk is described by following dictionary:"
- "C(name) - Name of the disk. Either C(name) or C(id) is reuqired."
- "C(id) - ID of the disk. Either C(name) or C(id) is reuqired."
- "C(interface) - Interface of the disk, either I(virtio) or I(IDE), default is I(virtio)."
- "C(bootable) - I(True) if the disk should be bootable, default is non bootable."
- "C(activate) - I(True) if the disk should be activated, default is activated."
- "C(Note:)"
- "This parameter is used only when C(state) is I(running) or I(present) and is able to only attach disks.
To manage disks of the VM in more depth please use M(ovirt_disks) module instead."
sysprep:
description:
- "Dictionary with values for Windows Virtual Machine initialization using sysprep:"
- "C(host_name) - Hostname to be set to Virtual Machine when deployed."
- "C(active_directory_ou) - Active Directory Organizational Unit, to be used for login of user."
- "C(org_name) - Organization name to be set to Windows Virtual Machine."
- "C(domain) - Domain to be set to Windows Virtual Machine."
- "C(timezone) - Timezone to be set to Windows Virtual Machine."
- "C(ui_language) - UI language of the Windows Virtual Machine."
- "C(system_locale) - System localization of the Windows Virtual Machine."
- "C(input_locale) - Input localization of the Windows Virtual Machine."
- "C(windows_license_key) - License key to be set to Windows Virtual Machine."
- "C(user_name) - Username to be used for set password to Windows Virtual Machine."
- "C(root_password) - Password to be set for username to Windows Virtual Machine."
cloud_init:
description:
- "Dictionary with values for Unix-like Virtual Machine initialization using cloud init:"
- "C(host_name) - Hostname to be set to Virtual Machine when deployed."
- "C(timezone) - Timezone to be set to Virtual Machine when deployed."
- "C(user_name) - Username to be used to set password to Virtual Machine when deployed."
- "C(root_password) - Password to be set for user specified by C(user_name) parameter."
- "C(authorized_ssh_keys) - Use this SSH keys to login to Virtual Machine."
- "C(regenerate_ssh_keys) - If I(True) SSH keys will be regenerated on Virtual Machine."
- "C(custom_script) - Cloud-init script which will be executed on Virtual Machine when deployed."
- "C(dns_servers) - DNS servers to be configured on Virtual Machine."
- "C(dns_search) - DNS search domains to be configured on Virtual Machine."
- "C(nic_boot_protocol) - Set boot protocol of the network interface of Virtual Machine. Can be one of none, dhcp or static."
- "C(nic_ip_address) - If boot protocol is static, set this IP address to network interface of Virtual Machine."
- "C(nic_netmask) - If boot protocol is static, set this netmask to network interface of Virtual Machine."
- "C(nic_gateway) - If boot protocol is static, set this gateway to network interface of Virtual Machine."
- "C(nic_name) - Set name to network interface of Virtual Machine."
- "C(nic_on_boot) - If I(True) network interface will be set to start on boot."
cloud_init_nics:
description:
- "List of dictionaries representing network interafaces to be setup by cloud init."
- "This option is used, when user needs to setup more network interfaces via cloud init."
- "If one network interface is enough, user should use C(cloud_init) I(nic_*) parameters. C(cloud_init) I(nic_*) parameters
are merged with C(cloud_init_nics) parameters."
- "Dictionary can contain following values:"
- "C(nic_boot_protocol) - Set boot protocol of the network interface of Virtual Machine. Can be one of none, dhcp or static."
- "C(nic_ip_address) - If boot protocol is static, set this IP address to network interface of Virtual Machine."
- "C(nic_netmask) - If boot protocol is static, set this netmask to network interface of Virtual Machine."
- "C(nic_gateway) - If boot protocol is static, set this gateway to network interface of Virtual Machine."
- "C(nic_name) - Set name to network interface of Virtual Machine."
- "C(nic_on_boot) - If I(True) network interface will be set to start on boot."
version_added: "2.3"
notes:
- "If VM is in I(UNASSIGNED) or I(UNKNOWN) state before any operation, the module will fail.
If VM is in I(IMAGE_LOCKED) state before any operation, we try to wait for VM to be I(DOWN).
If VM is in I(SAVING_STATE) state before any operation, we try to wait for VM to be I(SUSPENDED).
If VM is in I(POWERING_DOWN) state before any operation, we try to wait for VM to be I(UP) or I(DOWN). VM can
get into I(UP) state from I(POWERING_DOWN) state, when there is no ACPI or guest agent running inside VM, or
if the shutdown operation fails.
When user specify I(UP) C(state), we always wait to VM to be in I(UP) state in case VM is I(MIGRATING),
I(REBOOTING), I(POWERING_UP), I(RESTORING_STATE), I(WAIT_FOR_LAUNCH). In other states we run start operation on VM.
When user specify I(stopped) C(state), and If user pass C(force) parameter set to I(true) we forcibly stop the VM in
any state. If user don't pass C(force) parameter, we always wait to VM to be in UP state in case VM is
I(MIGRATING), I(REBOOTING), I(POWERING_UP), I(RESTORING_STATE), I(WAIT_FOR_LAUNCH). If VM is in I(PAUSED) or
I(SUSPENDED) state, we start the VM. Then we gracefully shutdown the VM.
When user specify I(suspended) C(state), we always wait to VM to be in UP state in case VM is I(MIGRATING),
I(REBOOTING), I(POWERING_UP), I(RESTORING_STATE), I(WAIT_FOR_LAUNCH). If VM is in I(PAUSED) or I(DOWN) state,
we start the VM. Then we suspend the VM.
When user specify I(absent) C(state), we forcibly stop the VM in any state and remove it."
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Creates a new Virtual Machine from template named 'rhel7_template'
ovirt_vms:
state: present
name: myvm
template: rhel7_template
# Creates a stateless VM which will always use latest template version:
ovirt_vms:
name: myvm
template: rhel7
cluster: mycluster
use_latest_template_version: true
# Creates a new server rhel7 Virtual Machine from Blank template
# on brq01 cluster with 2GiB memory and 2 vcpu cores/sockets
# and attach bootable disk with name rhel7_disk and attach virtio NIC
ovirt_vms:
state: present
cluster: brq01
name: myvm
memory: 2GiB
cpu_cores: 2
cpu_sockets: 2
cpu_shares: 1024
type: server
operating_system: rhel_7x64
disks:
- name: rhel7_disk
bootable: True
nics:
- name: nic1
# Run VM with cloud init:
ovirt_vms:
name: rhel7
template: rhel7
cluster: Default
memory: 1GiB
high_availability: true
cloud_init:
nic_boot_protocol: static
nic_ip_address: 10.34.60.86
nic_netmask: 255.255.252.0
nic_gateway: 10.34.63.254
nic_name: eth1
nic_on_boot: true
host_name: example.com
custom_script: |
write_files:
- content: |
Hello, world!
path: /tmp/greeting.txt
permissions: '0644'
user_name: root
root_password: super_password
# Run VM with cloud init, with multiple network interfaces:
ovirt_vms:
name: rhel7_4
template: rhel7
cluster: mycluster
cloud_init_nics:
- nic_name: eth0
nic_boot_protocol: dhcp
nic_on_boot: true
- nic_name: eth1
nic_boot_protocol: static
nic_ip_address: 10.34.60.86
nic_netmask: 255.255.252.0
nic_gateway: 10.34.63.254
nic_on_boot: true
# Run VM with sysprep:
ovirt_vms:
name: windows2012R2_AD
template: windows2012R2
cluster: Default
memory: 3GiB
high_availability: true
sysprep:
host_name: windowsad.example.com
user_name: Administrator
root_password: SuperPassword123
# Migrate/Run VM to/on host named 'host1'
ovirt_vms:
state: running
name: myvm
host: host1
# Change Vm's CD:
ovirt_vms:
name: myvm
cd_iso: drivers.iso
# Eject Vm's CD:
ovirt_vms:
name: myvm
cd_iso: ''
# Boot VM from CD:
ovirt_vms:
name: myvm
cd_iso: centos7_x64.iso
boot_devices:
- cdrom
# Stop vm:
ovirt_vms:
state: stopped
name: myvm
# Upgrade memory to already created VM:
ovirt_vms:
name: myvm
memory: 4GiB
# Hot plug memory to already created and running VM:
# (VM won't be restarted)
ovirt_vms:
name: myvm
memory: 4GiB
# When change on the VM needs restart of the VM, use next_run state,
# The VM will be updated and rebooted if there are any changes.
# If present state would be used, VM won't be restarted.
ovirt_vms:
state: next_run
name: myvm
boot_devices:
- network
# Remove VM, if VM is running it will be stopped:
ovirt_vms:
state: absent
name: myvm
'''
RETURN = '''
id:
description: ID of the VM which is managed
returned: On success if VM is found.
type: str
sample: 7de90f31-222c-436c-a1ca-7e655bd5b60c
vm:
description: "Dictionary of all the VM attributes. VM attributes can be found on your oVirt instance
at following url: https://ovirt.example.com/ovirt-engine/api/model#types/vm."
returned: On success if VM is found.
'''
class VmsModule(BaseModule):
def __get_template_with_version(self):
"""
oVirt in version 4.1 doesn't support search by template+version_number,
so we need to list all templates with specific name and then iterate
throught it's version until we find the version we look for.
"""
template = None
if self._module.params['template']:
templates_service = self._connection.system_service().templates_service()
templates = templates_service.list(search='name=%s' % self._module.params['template'])
if self._module.params['template_version']:
templates = [
t for t in templates
if t.version.version_number == self._module.params['template_version']
]
if templates:
template = templates[0]
return template
def build_entity(self):
template = self.__get_template_with_version()
return otypes.Vm(
name=self._module.params['name'],
cluster=otypes.Cluster(
name=self._module.params['cluster']
) if self._module.params['cluster'] else None,
template=otypes.Template(
id=template.id,
) if template else None,
use_latest_template_version=self._module.params['use_latest_template_version'],
stateless=self._module.params['stateless'] or self._module.params['use_latest_template_version'],
delete_protected=self._module.params['delete_protected'],
high_availability=otypes.HighAvailability(
enabled=self._module.params['high_availability']
) if self._module.params['high_availability'] is not None else None,
cpu=otypes.Cpu(
topology=otypes.CpuTopology(
cores=self._module.params['cpu_cores'],
sockets=self._module.params['cpu_sockets'],
)
) if (
self._module.params['cpu_cores'] or self._module.params['cpu_sockets']
) else None,
cpu_shares=self._module.params['cpu_shares'],
os=otypes.OperatingSystem(
type=self._module.params['operating_system'],
boot=otypes.Boot(
devices=[
otypes.BootDevice(dev) for dev in self._module.params['boot_devices']
],
) if self._module.params['boot_devices'] else None,
) if (
self._module.params['operating_system'] or self._module.params['boot_devices']
) else None,
type=otypes.VmType(
self._module.params['type']
) if self._module.params['type'] else None,
memory=convert_to_bytes(
self._module.params['memory']
) if self._module.params['memory'] else None,
memory_policy=otypes.MemoryPolicy(
guaranteed=convert_to_bytes(self._module.params['memory_guaranteed']),
) if self._module.params['memory_guaranteed'] else None,
)
def update_check(self, entity):
return (
equal(self._module.params.get('cluster'), get_link_name(self._connection, entity.cluster)) and
equal(convert_to_bytes(self._module.params['memory']), entity.memory) and
equal(convert_to_bytes(self._module.params['memory_guaranteed']), entity.memory_policy.guaranteed) and
equal(self._module.params.get('cpu_cores'), entity.cpu.topology.cores) and
equal(self._module.params.get('cpu_sockets'), entity.cpu.topology.sockets) and
equal(self._module.params.get('type'), str(entity.type)) and
equal(self._module.params.get('operating_system'), str(entity.os.type)) and
equal(self._module.params.get('high_availability'), entity.high_availability.enabled) and
equal(self._module.params.get('stateless'), entity.stateless) and
equal(self._module.params.get('cpu_shares'), entity.cpu_shares) and
equal(self._module.params.get('delete_protected'), entity.delete_protected) and
equal(self._module.params.get('use_latest_template_version'), entity.use_latest_template_version) and
equal(self._module.params.get('boot_devices'), [str(dev) for dev in getattr(entity.os, 'devices', [])])
)
def pre_create(self, entity):
# If VM don't exists, and template is not specified, set it to Blank:
if entity is None:
if self._module.params.get('template') is None:
self._module.params['template'] = 'Blank'
def post_update(self, entity):
self.post_create(entity)
def post_create(self, entity):
# After creation of the VM, attach disks and NICs:
self.changed = self.__attach_disks(entity)
self.changed = self.__attach_nics(entity)
def pre_remove(self, entity):
# Forcibly stop the VM, if it's not in DOWN state:
if entity.status != otypes.VmStatus.DOWN:
if not self._module.check_mode:
self.changed = self.action(
action='stop',
action_condition=lambda vm: vm.status != otypes.VmStatus.DOWN,
wait_condition=lambda vm: vm.status == otypes.VmStatus.DOWN,
)['changed']
def __suspend_shutdown_common(self, vm_service):
if vm_service.get().status in [
otypes.VmStatus.MIGRATING,
otypes.VmStatus.POWERING_UP,
otypes.VmStatus.REBOOT_IN_PROGRESS,
otypes.VmStatus.WAIT_FOR_LAUNCH,
otypes.VmStatus.UP,
otypes.VmStatus.RESTORING_STATE,
]:
self._wait_for_UP(vm_service)
def _pre_shutdown_action(self, entity):
vm_service = self._service.vm_service(entity.id)
self.__suspend_shutdown_common(vm_service)
if entity.status in [otypes.VmStatus.SUSPENDED, otypes.VmStatus.PAUSED]:
vm_service.start()
self._wait_for_UP(vm_service)
return vm_service.get()
def _pre_suspend_action(self, entity):
vm_service = self._service.vm_service(entity.id)
self.__suspend_shutdown_common(vm_service)
if entity.status in [otypes.VmStatus.PAUSED, otypes.VmStatus.DOWN]:
vm_service.start()
self._wait_for_UP(vm_service)
return vm_service.get()
def _post_start_action(self, entity):
vm_service = self._service.service(entity.id)
self._wait_for_UP(vm_service)
self._attach_cd(vm_service.get())
self._migrate_vm(vm_service.get())
def _attach_cd(self, entity):
cd_iso = self._module.params['cd_iso']
if cd_iso is not None:
vm_service = self._service.service(entity.id)
current = vm_service.get().status == otypes.VmStatus.UP
cdroms_service = vm_service.cdroms_service()
cdrom_device = cdroms_service.list()[0]
cdrom_service = cdroms_service.cdrom_service(cdrom_device.id)
cdrom = cdrom_service.get(current=current)
if getattr(cdrom.file, 'id', '') != cd_iso:
if not self._module.check_mode:
cdrom_service.update(
cdrom=otypes.Cdrom(
file=otypes.File(id=cd_iso)
),
current=current,
)
self.changed = True
return entity
def _migrate_vm(self, entity):
vm_host = self._module.params['host']
vm_service = self._service.vm_service(entity.id)
if vm_host is not None:
# In case VM is preparing to be UP, wait to be up, to migrate it:
if entity.status == otypes.VmStatus.UP:
hosts_service = self._connection.system_service().hosts_service()
current_vm_host = hosts_service.host_service(entity.host.id).get().name
if vm_host != current_vm_host:
if not self._module.check_mode:
vm_service.migrate(host=otypes.Host(name=vm_host))
self._wait_for_UP(vm_service)
self.changed = True
return entity
def _wait_for_UP(self, vm_service):
wait(
service=vm_service,
condition=lambda vm: vm.status == otypes.VmStatus.UP,
wait=self._module.params['wait'],
timeout=self._module.params['timeout'],
)
def __attach_disks(self, entity):
disks_service = self._connection.system_service().disks_service()
for disk in self._module.params['disks']:
# If disk ID is not specified, find disk by name:
disk_id = disk.get('id')
if disk_id is None:
disk_id = getattr(
search_by_name(
service=disks_service,
name=disk.get('name')
),
'id',
None
)
# Attach disk to VM:
disk_attachments_service = self._service.service(entity.id).disk_attachments_service()
if disk_attachments_service.attachment_service(disk_id).get() is None:
if not self._module.check_mode:
disk_attachments_service.add(
otypes.DiskAttachment(
disk=otypes.Disk(
id=disk_id,
),
active=disk.get('activate', True),
interface=otypes.DiskInterface(
disk.get('interface', 'virtio')
),
bootable=disk.get('bootable', False),
)
)
self.changed = True
def __attach_nics(self, entity):
# Attach NICs to VM, if specified:
vnic_profiles_service = self._connection.system_service().vnic_profiles_service()
nics_service = self._service.service(entity.id).nics_service()
for nic in self._module.params['nics']:
if search_by_name(nics_service, nic.get('name')) is None:
if not self._module.check_mode:
nics_service.add(
otypes.Nic(
name=nic.get('name'),
interface=otypes.NicInterface(
nic.get('interface', 'virtio')
),
vnic_profile=otypes.VnicProfile(
id=search_by_name(
vnic_profiles_service,
nic.get('profile_name'),
).id
) if nic.get('profile_name') else None,
mac=otypes.Mac(
address=nic.get('mac_address')
) if nic.get('mac_address') else None,
)
)
self.changed = True
def _get_initialization(sysprep, cloud_init, cloud_init_nics):
initialization = None
if cloud_init or cloud_init_nics:
initialization = otypes.Initialization(
nic_configurations=[
otypes.NicConfiguration(
boot_protocol=otypes.BootProtocol(
nic.pop('nic_boot_protocol').lower()
) if nic.get('nic_boot_protocol') else None,
name=nic.pop('nic_name', None),
on_boot=nic.pop('nic_on_boot', None),
ip=otypes.Ip(
address=nic.pop('nic_ip_address', None),
netmask=nic.pop('nic_netmask', None),
gateway=nic.pop('nic_gateway', None),
) if (
nic.get('nic_gateway') is not None or
nic.get('nic_netmask') is not None or
nic.get('nic_ip_address') is not None
) else None,
)
for nic in cloud_init_nics
if (
nic.get('nic_gateway') is not None or
nic.get('nic_netmask') is not None or
nic.get('nic_ip_address') is not None or
nic.get('nic_boot_protocol') is not None or
nic.get('nic_on_boot') is not None
)
] if cloud_init_nics else None,
**cloud_init
)
elif sysprep:
initialization = otypes.Initialization(
**sysprep
)
return initialization
def control_state(vm, vms_service, module):
if vm is None:
return
force = module.params['force']
state = module.params['state']
vm_service = vms_service.vm_service(vm.id)
if vm.status == otypes.VmStatus.IMAGE_LOCKED:
wait(
service=vm_service,
condition=lambda vm: vm.status == otypes.VmStatus.DOWN,
)
elif vm.status == otypes.VmStatus.SAVING_STATE:
# Result state is SUSPENDED, we should wait to be suspended:
wait(
service=vm_service,
condition=lambda vm: vm.status == otypes.VmStatus.SUSPENDED,
)
elif (
vm.status == otypes.VmStatus.UNASSIGNED or
vm.status == otypes.VmStatus.UNKNOWN
):
# Invalid states:
module.fail_json("Not possible to control VM, if it's in '{}' status".format(vm.status))
elif vm.status == otypes.VmStatus.POWERING_DOWN:
if (force and state == 'stopped') or state == 'absent':
vm_service.stop()
wait(
service=vm_service,
condition=lambda vm: vm.status == otypes.VmStatus.DOWN,
)
else:
# If VM is powering down, wait to be DOWN or UP.
# VM can end in UP state in case there is no GA
# or ACPI on the VM or shutdown operation crashed:
wait(
service=vm_service,
condition=lambda vm: vm.status in [otypes.VmStatus.DOWN, otypes.VmStatus.UP],
)
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(
choices=['running', 'stopped', 'present', 'absent', 'suspended', 'next_run'],
default='present',
),
name=dict(default=None),
id=dict(default=None),
cluster=dict(default=None),
template=dict(default=None),
template_version=dict(default=None, type='int'),
use_latest_template_version=dict(default=None, type='bool'),
disks=dict(default=[], type='list'),
memory=dict(default=None),
memory_guaranteed=dict(default=None),
cpu_sockets=dict(default=None, type='int'),
cpu_cores=dict(default=None, type='int'),
cpu_shares=dict(default=None, type='int'),
type=dict(choices=['server', 'desktop']),
operating_system=dict(
default=None,
choices=[
'rhel_6_ppc64', 'other', 'freebsd', 'windows_2003x64', 'windows_10',
'rhel_6x64', 'rhel_4x64', 'windows_2008x64', 'windows_2008R2x64',
'debian_7', 'windows_2012x64', 'ubuntu_14_04', 'ubuntu_12_04',
'ubuntu_13_10', 'windows_8x64', 'other_linux_ppc64', 'windows_2003',
'other_linux', 'windows_10x64', 'windows_2008', 'rhel_3', 'rhel_5',
'rhel_4', 'other_ppc64', 'sles_11', 'rhel_6', 'windows_xp', 'rhel_7x64',
'freebsdx64', 'rhel_7_ppc64', 'windows_7', 'rhel_5x64',
'ubuntu_14_04_ppc64', 'sles_11_ppc64', 'windows_8',
'windows_2012R2x64', 'windows_2008r2x64', 'ubuntu_13_04',
'ubuntu_12_10', 'windows_7x64',
],
),
cd_iso=dict(default=None),
boot_devices=dict(default=None, type='list'),
high_availability=dict(type='bool'),
stateless=dict(type='bool'),
delete_protected=dict(type='bool'),
force=dict(type='bool', default=False),
nics=dict(default=[], type='list'),
cloud_init=dict(type='dict'),
cloud_init_nics=dict(defaul=[], type='list'),
sysprep=dict(type='dict'),
host=dict(default=None),
clone=dict(type='bool', default=False),
clone_permissions=dict(type='bool', default=False),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
)
check_sdk(module)
check_params(module)
try:
state = module.params['state']
connection = create_connection(module.params.pop('auth'))
vms_service = connection.system_service().vms_service()
vms_module = VmsModule(
connection=connection,
module=module,
service=vms_service,
)
vm = vms_module.search_entity()
control_state(vm, vms_service, module)
if state == 'present' or state == 'running' or state == 'next_run':
sysprep = module.params['sysprep']
cloud_init = module.params['cloud_init']
cloud_init_nics = module.params['cloud_init_nics']
cloud_init_nics.append(cloud_init)
# In case VM don't exist, wait for VM DOWN state,
# otherwise don't wait for any state, just update VM:
vms_module.create(
entity=vm,
result_state=otypes.VmStatus.DOWN if vm is None else None,
clone=module.params['clone'],
clone_permissions=module.params['clone_permissions'],
)
ret = vms_module.action(
action='start',
post_action=vms_module._post_start_action,
action_condition=lambda vm: (
vm.status not in [
otypes.VmStatus.MIGRATING,
otypes.VmStatus.POWERING_UP,
otypes.VmStatus.REBOOT_IN_PROGRESS,
otypes.VmStatus.WAIT_FOR_LAUNCH,
otypes.VmStatus.UP,
otypes.VmStatus.RESTORING_STATE,
]
),
wait_condition=lambda vm: vm.status == otypes.VmStatus.UP,
# Start action kwargs:
use_cloud_init=cloud_init is not None or len(cloud_init_nics) > 0,
use_sysprep=sysprep is not None,
vm=otypes.Vm(
placement_policy=otypes.VmPlacementPolicy(
hosts=[otypes.Host(name=module.params['host'])]
) if module.params['host'] else None,
initialization=_get_initialization(sysprep, cloud_init, cloud_init_nics),
),
)
if state == 'next_run':
# Apply next run configuration, if needed:
vm = vms_service.vm_service(ret['id']).get()
if vm.next_run_configuration_exists:
ret = vms_module.action(
action='reboot',
entity=vm,
action_condition=lambda vm: vm.status == otypes.VmStatus.UP,
wait_condition=lambda vm: vm.status == otypes.VmStatus.UP,
)
elif state == 'stopped':
vms_module.create(
result_state=otypes.VmStatus.DOWN if vm is None else None,
clone=module.params['clone'],
clone_permissions=module.params['clone_permissions'],
)
if module.params['force']:
ret = vms_module.action(
action='stop',
post_action=vms_module._attach_cd,
action_condition=lambda vm: vm.status != otypes.VmStatus.DOWN,
wait_condition=lambda vm: vm.status == otypes.VmStatus.DOWN,
)
else:
ret = vms_module.action(
action='shutdown',
pre_action=vms_module._pre_shutdown_action,
post_action=vms_module._attach_cd,
action_condition=lambda vm: vm.status != otypes.VmStatus.DOWN,
wait_condition=lambda vm: vm.status == otypes.VmStatus.DOWN,
)
elif state == 'suspended':
vms_module.create(
result_state=otypes.VmStatus.DOWN if vm is None else None,
clone=module.params['clone'],
clone_permissions=module.params['clone_permissions'],
)
ret = vms_module.action(
action='suspend',
pre_action=vms_module._pre_suspend_action,
action_condition=lambda vm: vm.status != otypes.VmStatus.SUSPENDED,
wait_condition=lambda vm: vm.status == otypes.VmStatus.SUSPENDED,
)
elif state == 'absent':
ret = vms_module.remove()
module.exit_json(**ret)
except Exception as e:
module.fail_json(msg=str(e))
finally:
connection.close(logout=False)
from ansible.module_utils.basic import *
if __name__ == "__main__":
main()

View file

@ -0,0 +1,104 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# 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/>.
#
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_full_argument_spec,
)
ANSIBLE_METADATA = {'status': 'preview',
'supported_by': 'community',
'version': '1.0'}
DOCUMENTATION = '''
---
module: ovirt_vms_facts
short_description: Retrieve facts about one or more oVirt virtual machines
author: "Ondra Machacek (@machacekondra)"
version_added: "2.3"
description:
- "Retrieve facts about one or more oVirt virtual machines."
notes:
- "This module creates a new top-level C(ovirt_vms) fact, which
contains a list of virtual machines."
options:
pattern:
description:
- "Search term which is accepted by oVirt search backend."
- "For example to search VM X from cluster Y use following pattern:
name=X and cluster=Y"
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather facts about all VMs which names start with C(centos) and
# belong to cluster C(west):
- ovirt_vms_facts:
pattern: name=centos* and cluster=west
- debug:
var: ovirt_vms
'''
RETURN = '''
ovirt_vms:
description: "List of dictionaries describing the VMs. VM attribues are mapped to dictionary keys,
all VMs attributes can be found at following url: https://ovirt.example.com/ovirt-engine/api/model#types/vm."
returned: On success.
type: list
'''
def main():
argument_spec = ovirt_full_argument_spec(
pattern=dict(default='', required=False),
)
module = AnsibleModule(argument_spec)
check_sdk(module)
try:
connection = create_connection(module.params.pop('auth'))
vms_service = connection.system_service().vms_service()
vms = vms_service.list(search=module.params['pattern'])
module.exit_json(
changed=False,
ansible_facts=dict(
ovirt_vms=[
get_dict_of_struct(c) for c in vms
],
),
)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=False)
if __name__ == '__main__':
main()