mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-07-22 12:50:22 -07:00
Relocating extras into lib/ansible/modules/ after merge
This commit is contained in:
parent
c65ba07d2c
commit
011ea55a8f
596 changed files with 0 additions and 266 deletions
0
lib/ansible/modules/cloud/ovirt/__init__.py
Normal file
0
lib/ansible/modules/cloud/ovirt/__init__.py
Normal file
207
lib/ansible/modules/cloud/ovirt/ovirt_affinity_labels.py
Normal file
207
lib/ansible/modules/cloud/ovirt/ovirt_affinity_labels.py
Normal 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()
|
158
lib/ansible/modules/cloud/ovirt/ovirt_affinity_labels_facts.py
Normal file
158
lib/ansible/modules/cloud/ovirt/ovirt_affinity_labels_facts.py
Normal 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()
|
234
lib/ansible/modules/cloud/ovirt/ovirt_auth.py
Normal file
234
lib/ansible/modules/cloud/ovirt/ovirt_auth.py
Normal 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()
|
564
lib/ansible/modules/cloud/ovirt/ovirt_clusters.py
Normal file
564
lib/ansible/modules/cloud/ovirt/ovirt_clusters.py
Normal 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()
|
103
lib/ansible/modules/cloud/ovirt/ovirt_clusters_facts.py
Normal file
103
lib/ansible/modules/cloud/ovirt/ovirt_clusters_facts.py
Normal 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()
|
221
lib/ansible/modules/cloud/ovirt/ovirt_datacenters.py
Normal file
221
lib/ansible/modules/cloud/ovirt/ovirt_datacenters.py
Normal 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()
|
102
lib/ansible/modules/cloud/ovirt/ovirt_datacenters_facts.py
Normal file
102
lib/ansible/modules/cloud/ovirt/ovirt_datacenters_facts.py
Normal 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()
|
322
lib/ansible/modules/cloud/ovirt/ovirt_disks.py
Normal file
322
lib/ansible/modules/cloud/ovirt/ovirt_disks.py
Normal 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()
|
248
lib/ansible/modules/cloud/ovirt/ovirt_external_providers.py
Normal file
248
lib/ansible/modules/cloud/ovirt/ovirt_external_providers.py
Normal 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()
|
|
@ -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()
|
182
lib/ansible/modules/cloud/ovirt/ovirt_groups.py
Normal file
182
lib/ansible/modules/cloud/ovirt/ovirt_groups.py
Normal 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()
|
102
lib/ansible/modules/cloud/ovirt/ovirt_groups_facts.py
Normal file
102
lib/ansible/modules/cloud/ovirt/ovirt_groups_facts.py
Normal 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()
|
368
lib/ansible/modules/cloud/ovirt/ovirt_host_networks.py
Normal file
368
lib/ansible/modules/cloud/ovirt/ovirt_host_networks.py
Normal 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()
|
236
lib/ansible/modules/cloud/ovirt/ovirt_host_pm.py
Normal file
236
lib/ansible/modules/cloud/ovirt/ovirt_host_pm.py
Normal 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()
|
326
lib/ansible/modules/cloud/ovirt/ovirt_hosts.py
Normal file
326
lib/ansible/modules/cloud/ovirt/ovirt_hosts.py
Normal 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()
|
99
lib/ansible/modules/cloud/ovirt/ovirt_hosts_facts.py
Normal file
99
lib/ansible/modules/cloud/ovirt/ovirt_hosts_facts.py
Normal 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()
|
180
lib/ansible/modules/cloud/ovirt/ovirt_mac_pools.py
Normal file
180
lib/ansible/modules/cloud/ovirt/ovirt_mac_pools.py
Normal 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()
|
268
lib/ansible/modules/cloud/ovirt/ovirt_networks.py
Normal file
268
lib/ansible/modules/cloud/ovirt/ovirt_networks.py
Normal 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()
|
104
lib/ansible/modules/cloud/ovirt/ovirt_networks_facts.py
Normal file
104
lib/ansible/modules/cloud/ovirt/ovirt_networks_facts.py
Normal 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()
|
247
lib/ansible/modules/cloud/ovirt/ovirt_nics.py
Normal file
247
lib/ansible/modules/cloud/ovirt/ovirt_nics.py
Normal 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()
|
122
lib/ansible/modules/cloud/ovirt/ovirt_nics_facts.py
Normal file
122
lib/ansible/modules/cloud/ovirt/ovirt_nics_facts.py
Normal 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()
|
291
lib/ansible/modules/cloud/ovirt/ovirt_permissions.py
Normal file
291
lib/ansible/modules/cloud/ovirt/ovirt_permissions.py
Normal 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()
|
140
lib/ansible/modules/cloud/ovirt/ovirt_permissions_facts.py
Normal file
140
lib/ansible/modules/cloud/ovirt/ovirt_permissions_facts.py
Normal 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()
|
298
lib/ansible/modules/cloud/ovirt/ovirt_quotas.py
Normal file
298
lib/ansible/modules/cloud/ovirt/ovirt_quotas.py
Normal 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()
|
121
lib/ansible/modules/cloud/ovirt/ovirt_quotas_facts.py
Normal file
121
lib/ansible/modules/cloud/ovirt/ovirt_quotas_facts.py
Normal 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()
|
444
lib/ansible/modules/cloud/ovirt/ovirt_storage_domains.py
Normal file
444
lib/ansible/modules/cloud/ovirt/ovirt_storage_domains.py
Normal 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()
|
104
lib/ansible/modules/cloud/ovirt/ovirt_storage_domains_facts.py
Normal file
104
lib/ansible/modules/cloud/ovirt/ovirt_storage_domains_facts.py
Normal 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()
|
314
lib/ansible/modules/cloud/ovirt/ovirt_templates.py
Normal file
314
lib/ansible/modules/cloud/ovirt/ovirt_templates.py
Normal 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()
|
104
lib/ansible/modules/cloud/ovirt/ovirt_templates_facts.py
Normal file
104
lib/ansible/modules/cloud/ovirt/ovirt_templates_facts.py
Normal 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()
|
169
lib/ansible/modules/cloud/ovirt/ovirt_users.py
Normal file
169
lib/ansible/modules/cloud/ovirt/ovirt_users.py
Normal 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()
|
102
lib/ansible/modules/cloud/ovirt/ovirt_users_facts.py
Normal file
102
lib/ansible/modules/cloud/ovirt/ovirt_users_facts.py
Normal 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()
|
220
lib/ansible/modules/cloud/ovirt/ovirt_vmpools.py
Normal file
220
lib/ansible/modules/cloud/ovirt/ovirt_vmpools.py
Normal 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()
|
101
lib/ansible/modules/cloud/ovirt/ovirt_vmpools_facts.py
Normal file
101
lib/ansible/modules/cloud/ovirt/ovirt_vmpools_facts.py
Normal 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()
|
887
lib/ansible/modules/cloud/ovirt/ovirt_vms.py
Normal file
887
lib/ansible/modules/cloud/ovirt/ovirt_vms.py
Normal 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()
|
104
lib/ansible/modules/cloud/ovirt/ovirt_vms_facts.py
Normal file
104
lib/ansible/modules/cloud/ovirt/ovirt_vms_facts.py
Normal 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()
|
Loading…
Add table
Add a link
Reference in a new issue