Migrated to ovirt.ovirt

pull/68298/head
Ansible Core Team 5 years ago committed by Matt Martz
parent 02541a15b2
commit d1f86d7151

@ -1,868 +0,0 @@
# -*- 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 inspect
import os
import time
from abc import ABCMeta, abstractmethod
from datetime import datetime
from distutils.version import LooseVersion
from ansible.module_utils.cloud import CloudRetry
from ansible.module_utils.common._collections_compat import Mapping
try:
from enum import Enum # enum is a ovirtsdk4 requirement
import ovirtsdk4 as sdk
import ovirtsdk4.version as sdk_version
import ovirtsdk4.types as otypes
HAS_SDK = LooseVersion(sdk_version.VERSION) >= LooseVersion('4.3.0')
except ImportError:
HAS_SDK = False
BYTES_MAP = {
'kib': 2**10,
'mib': 2**20,
'gib': 2**30,
'tib': 2**40,
'pib': 2**50,
}
def check_sdk(module):
if not HAS_SDK:
module.fail_json(
msg='ovirtsdk4 version 4.3.0 or higher is required for this module'
)
def get_dict_of_struct(struct, connection=None, fetch_nested=False, attributes=None):
"""
Convert SDK Struct type into dictionary.
"""
res = {}
def resolve_href(value):
# Fetch nested values of struct:
try:
value = connection.follow_link(value)
except sdk.Error:
value = None
nested_obj = dict(
(attr, convert_value(getattr(value, attr)))
for attr in attributes if getattr(value, attr, None) is not None
)
nested_obj['id'] = getattr(value, 'id', None)
nested_obj['href'] = getattr(value, 'href', None)
return nested_obj
def remove_underscore(val):
if val.startswith('_'):
val = val[1:]
remove_underscore(val)
return val
def convert_value(value):
nested = False
if isinstance(value, sdk.Struct):
if not fetch_nested or not value.href:
return get_dict_of_struct(value)
return resolve_href(value)
elif isinstance(value, Enum) or isinstance(value, datetime):
return str(value)
elif isinstance(value, list) or isinstance(value, sdk.List):
if isinstance(value, sdk.List) and fetch_nested and value.href:
try:
value = connection.follow_link(value)
nested = True
except sdk.Error:
value = []
ret = []
for i in value:
if isinstance(i, sdk.Struct):
if not nested and fetch_nested and i.href:
ret.append(resolve_href(i))
elif not nested:
ret.append(get_dict_of_struct(i))
else:
nested_obj = dict(
(attr, convert_value(getattr(i, attr)))
for attr in attributes if getattr(i, attr, None)
)
nested_obj['id'] = getattr(i, 'id', None)
ret.append(nested_obj)
elif isinstance(i, Enum):
ret.append(str(i))
else:
ret.append(i)
return ret
else:
return value
if struct is not None:
for key, value in struct.__dict__.items():
if value is None:
continue
key = remove_underscore(key)
res[key] = convert_value(value)
return res
def engine_version(connection):
"""
Return string representation of oVirt engine version.
"""
engine_api = connection.system_service().get()
engine_version = engine_api.product_info.version
return '%s.%s' % (engine_version.major, engine_version.minor)
def create_connection(auth):
"""
Create a connection to Python SDK, from task `auth` parameter.
If user doesnt't have SSO token the `auth` dictionary has following parameters mandatory:
url, username, password
If user has SSO token the `auth` dictionary has following parameters mandatory:
url, token
The `ca_file` parameter is mandatory in case user want to use secure connection,
in case user want to use insecure connection, it's mandatory to send insecure=True.
:param auth: dictionary which contains needed values for connection creation
:return: Python SDK connection
"""
url = auth.get('url')
if url is None and auth.get('hostname') is not None:
url = 'https://{0}/ovirt-engine/api'.format(auth.get('hostname'))
return sdk.Connection(
url=url,
username=auth.get('username'),
password=auth.get('password'),
ca_file=auth.get('ca_file', None),
insecure=auth.get('insecure', False),
token=auth.get('token', None),
kerberos=auth.get('kerberos', None),
headers=auth.get('headers', None),
)
def convert_to_bytes(param):
"""
This method convert units to bytes, which follow IEC standard.
:param param: value to be converted
"""
if param is None:
return None
# Get rid of whitespaces:
param = ''.join(param.split())
# Convert to bytes:
if len(param) > 3 and param[-3].lower() in ['k', 'm', 'g', 't', 'p']:
return int(param[:-3]) * BYTES_MAP.get(param[-3:].lower(), 1)
elif param.isdigit():
return int(param) * 2**10
else:
raise ValueError(
"Unsupported value(IEC supported): '{value}'".format(value=param)
)
def follow_link(connection, link):
"""
This method returns the entity of the element which link points to.
:param connection: connection to the Python SDK
:param link: link of the entity
:return: entity which link points to
"""
if link:
return connection.follow_link(link)
else:
return None
def get_link_name(connection, link):
"""
This method returns the name of the element which link points to.
:param connection: connection to the Python SDK
:param link: link of the entity
:return: name of the entity, which link points to
"""
if link:
return connection.follow_link(link).name
else:
return None
def equal(param1, param2, ignore_case=False):
"""
Compare two parameters and return if they are equal.
This parameter doesn't run equal operation if first parameter is None.
With this approach we don't run equal operation in case user don't
specify parameter in their task.
:param param1: user inputted parameter
:param param2: value of entity parameter
:return: True if parameters are equal or first parameter is None, otherwise False
"""
if param1 is not None:
if ignore_case:
return param1.lower() == param2.lower()
return param1 == param2
return True
def search_by_attributes(service, list_params=None, **kwargs):
"""
Search for the entity by attributes. Nested entities don't support search
via REST, so in case using search for nested entity we return all entities
and filter them by specified attributes.
"""
list_params = list_params or {}
# Check if 'list' method support search(look for search parameter):
if 'search' in inspect.getargspec(service.list)[0]:
res = service.list(
# There must be double quotes around name, because some oVirt resources it's possible to create then with space in name.
search=' and '.join('{0}="{1}"'.format(k, v) for k, v in kwargs.items()),
**list_params
)
else:
res = [
e for e in service.list(**list_params) if len([
k for k, v in kwargs.items() if getattr(e, k, None) == v
]) == len(kwargs)
]
res = res or [None]
return res[0]
def search_by_name(service, name, **kwargs):
"""
Search for the entity by its name. Nested entities don't support search
via REST, so in case using search for nested entity we return all entities
and filter them by name.
:param service: service of the entity
:param name: name of the entity
:return: Entity object returned by Python SDK
"""
# Check if 'list' method support search(look for search parameter):
if 'search' in inspect.getargspec(service.list)[0]:
res = service.list(
# There must be double quotes around name, because some oVirt resources it's possible to create then with space in name.
search='name="{name}"'.format(name=name)
)
else:
res = [e for e in service.list() if e.name == name]
if kwargs:
res = [
e for e in service.list() if len([
k for k, v in kwargs.items() if getattr(e, k, None) == v
]) == len(kwargs)
]
res = res or [None]
return res[0]
def get_entity(service, get_params=None):
"""
Ignore SDK Error in case of getting an entity from service.
"""
entity = None
try:
if get_params is not None:
entity = service.get(**get_params)
else:
entity = service.get()
except sdk.Error:
# We can get here 404, we should ignore it, in case
# of removing entity for example.
pass
return entity
def get_id_by_name(service, name, raise_error=True, ignore_case=False):
"""
Search an entity ID by it's name.
"""
entity = search_by_name(service, name)
if entity is not None:
return entity.id
if raise_error:
raise Exception("Entity '%s' was not found." % name)
def wait(
service,
condition,
fail_condition=lambda e: False,
timeout=180,
wait=True,
poll_interval=3,
):
"""
Wait until entity fulfill expected condition.
:param service: service of the entity
:param condition: condition to be fulfilled
:param fail_condition: if this condition is true, raise Exception
:param timeout: max time to wait in seconds
:param wait: if True wait for condition, if False don't wait
:param poll_interval: Number of seconds we should wait until next condition check
"""
# Wait until the desired state of the entity:
if wait:
start = time.time()
while time.time() < start + timeout:
# Exit if the condition of entity is valid:
entity = get_entity(service)
if condition(entity):
return
elif fail_condition(entity):
raise Exception("Error while waiting on result state of the entity.")
# Sleep for `poll_interval` seconds if none of the conditions apply:
time.sleep(float(poll_interval))
raise Exception("Timeout exceed while waiting on result state of the entity.")
def __get_auth_dict():
OVIRT_URL = os.environ.get('OVIRT_URL')
OVIRT_HOSTNAME = os.environ.get('OVIRT_HOSTNAME')
OVIRT_USERNAME = os.environ.get('OVIRT_USERNAME')
OVIRT_PASSWORD = os.environ.get('OVIRT_PASSWORD')
OVIRT_TOKEN = os.environ.get('OVIRT_TOKEN')
OVIRT_CAFILE = os.environ.get('OVIRT_CAFILE')
OVIRT_INSECURE = OVIRT_CAFILE is None
env_vars = None
if OVIRT_URL is None and OVIRT_HOSTNAME is not None:
OVIRT_URL = 'https://{0}/ovirt-engine/api'.format(OVIRT_HOSTNAME)
if OVIRT_URL and ((OVIRT_USERNAME and OVIRT_PASSWORD) or OVIRT_TOKEN):
env_vars = {
'url': OVIRT_URL,
'username': OVIRT_USERNAME,
'password': OVIRT_PASSWORD,
'insecure': OVIRT_INSECURE,
'token': OVIRT_TOKEN,
'ca_file': OVIRT_CAFILE,
}
if env_vars is not None:
auth = dict(default=env_vars, type='dict')
else:
auth = dict(required=True, type='dict')
return auth
def ovirt_info_full_argument_spec(**kwargs):
"""
Extend parameters of info module with parameters which are common to all
oVirt info modules.
:param kwargs: kwargs to be extended
:return: extended dictionary with common parameters
"""
spec = dict(
auth=__get_auth_dict(),
fetch_nested=dict(default=False, type='bool'),
nested_attributes=dict(type='list', default=list()),
)
spec.update(kwargs)
return spec
# Left for third-party module compatibility
def ovirt_facts_full_argument_spec(**kwargs):
"""
This is deprecated. Please use ovirt_info_full_argument_spec instead!
:param kwargs: kwargs to be extended
:return: extended dictionary with common parameters
"""
return ovirt_info_full_argument_spec(**kwargs)
def ovirt_full_argument_spec(**kwargs):
"""
Extend parameters of module with parameters which are common to all oVirt modules.
:param kwargs: kwargs to be extended
:return: extended dictionary with common parameters
"""
spec = dict(
auth=__get_auth_dict(),
timeout=dict(default=180, type='int'),
wait=dict(default=True, type='bool'),
poll_interval=dict(default=3, type='int'),
fetch_nested=dict(default=False, type='bool'),
nested_attributes=dict(type='list', default=list()),
)
spec.update(kwargs)
return spec
def check_params(module):
"""
Most modules must have either `name` or `id` specified.
"""
if module.params.get('name') is None and module.params.get('id') is None:
module.fail_json(msg='"name" or "id" is required')
def engine_supported(connection, version):
return LooseVersion(engine_version(connection)) >= LooseVersion(version)
def check_support(version, connection, module, params):
"""
Check if parameters used by user are supported by oVirt Python SDK
and oVirt engine.
"""
api_version = LooseVersion(engine_version(connection))
version = LooseVersion(version)
for param in params:
if module.params.get(param) is not None:
return LooseVersion(sdk_version.VERSION) >= version and api_version >= version
return True
class BaseModule(object):
"""
This is base class for oVirt modules. oVirt modules should inherit this
class and override method to customize specific needs of the module.
The only abstract method of this class is `build_entity`, which must
to be implemented in child class.
"""
__metaclass__ = ABCMeta
def __init__(self, connection, module, service, changed=False):
self._connection = connection
self._module = module
self._service = service
self._changed = changed
self._diff = {'after': dict(), 'before': dict()}
@property
def changed(self):
return self._changed
@changed.setter
def changed(self, changed):
if not self._changed:
self._changed = changed
@abstractmethod
def build_entity(self):
"""
This method should return oVirt Python SDK type, which we want to
create or update, initialized by values passed by Ansible module.
For example if we want to create VM, we will return following:
types.Vm(name=self._module.params['vm_name'])
:return: Specific instance of sdk.Struct.
"""
pass
def param(self, name, default=None):
"""
Return a module parameter specified by it's name.
"""
return self._module.params.get(name, default)
def update_check(self, entity):
"""
This method handle checks whether the entity values are same as values
passed to ansible module. By default we don't compare any values.
:param entity: Entity we want to compare with Ansible module values.
:return: True if values are same, so we don't need to update the entity.
"""
return True
def pre_create(self, entity):
"""
This method is called right before entity is created.
:param entity: Entity to be created or updated.
"""
pass
def post_create(self, entity):
"""
This method is called right after entity is created.
:param entity: Entity which was created.
"""
pass
def post_update(self, entity):
"""
This method is called right after entity is updated.
:param entity: Entity which was updated.
"""
pass
def diff_update(self, after, update):
for k, v in update.items():
if isinstance(v, Mapping):
after[k] = self.diff_update(after.get(k, dict()), v)
else:
after[k] = update[k]
return after
def create(
self,
entity=None,
result_state=None,
fail_condition=lambda e: False,
search_params=None,
update_params=None,
_wait=None,
force_create=False,
**kwargs
):
"""
Method which is called when state of the entity is 'present'. If user
don't provide `entity` parameter the entity is searched using
`search_params` parameter. If entity is found it's updated, whether
the entity should be updated is checked by `update_check` method.
The corresponding updated entity is build by `build_entity` method.
Function executed after entity is created can optionally be specified
in `post_create` parameter. Function executed after entity is updated
can optionally be specified in `post_update` parameter.
:param entity: Entity we want to update, if exists.
:param result_state: State which should entity has in order to finish task.
:param fail_condition: Function which checks incorrect state of entity, if it returns `True` Exception is raised.
:param search_params: Dictionary of parameters to be used for search.
:param update_params: The params which should be passed to update method.
:param kwargs: Additional parameters passed when creating entity.
:return: Dictionary with values returned by Ansible module.
"""
if entity is None and not force_create:
entity = self.search_entity(search_params)
self.pre_create(entity)
if entity:
# Entity exists, so update it:
entity_service = self._service.service(entity.id)
if not self.update_check(entity):
new_entity = self.build_entity()
if not self._module.check_mode:
update_params = update_params or {}
updated_entity = entity_service.update(
new_entity,
**update_params
)
self.post_update(entity)
# Update diffs only if user specified --diff parameter,
# so we don't useless overload API:
if self._module._diff:
before = get_dict_of_struct(
entity,
self._connection,
fetch_nested=True,
attributes=['name'],
)
after = before.copy()
self.diff_update(after, get_dict_of_struct(new_entity))
self._diff['before'] = before
self._diff['after'] = after
self.changed = True
else:
# Entity don't exists, so create it:
if not self._module.check_mode:
entity = self._service.add(
self.build_entity(),
**kwargs
)
self.post_create(entity)
self.changed = True
if not self._module.check_mode:
# Wait for the entity to be created and to be in the defined state:
entity_service = self._service.service(entity.id)
def state_condition(entity):
return entity
if result_state:
def state_condition(entity):
return entity and entity.status == result_state
wait(
service=entity_service,
condition=state_condition,
fail_condition=fail_condition,
wait=_wait if _wait is not None else self._module.params['wait'],
timeout=self._module.params['timeout'],
poll_interval=self._module.params['poll_interval'],
)
return {
'changed': self.changed,
'id': getattr(entity, 'id', None),
type(entity).__name__.lower(): get_dict_of_struct(
struct=entity,
connection=self._connection,
fetch_nested=self._module.params.get('fetch_nested'),
attributes=self._module.params.get('nested_attributes'),
),
'diff': self._diff,
}
def pre_remove(self, entity):
"""
This method is called right before entity is removed.
:param entity: Entity which we want to remove.
"""
pass
def entity_name(self, entity):
return "{e_type} '{e_name}'".format(
e_type=type(entity).__name__.lower(),
e_name=getattr(entity, 'name', None),
)
def remove(self, entity=None, search_params=None, **kwargs):
"""
Method which is called when state of the entity is 'absent'. If user
don't provide `entity` parameter the entity is searched using
`search_params` parameter. If entity is found it's removed.
Function executed before remove is executed can optionally be specified
in `pre_remove` parameter.
:param entity: Entity we want to remove.
:param search_params: Dictionary of parameters to be used for search.
:param kwargs: Additional parameters passed when removing entity.
:return: Dictionary with values returned by Ansible module.
"""
if entity is None:
entity = self.search_entity(search_params)
if entity is None:
return {
'changed': self.changed,
'msg': "Entity wasn't found."
}
self.pre_remove(entity)
entity_service = self._service.service(entity.id)
if not self._module.check_mode:
entity_service.remove(**kwargs)
wait(
service=entity_service,
condition=lambda entity: not entity,
wait=self._module.params['wait'],
timeout=self._module.params['timeout'],
poll_interval=self._module.params['poll_interval'],
)
self.changed = True
return {
'changed': self.changed,
'id': entity.id,
type(entity).__name__.lower(): get_dict_of_struct(
struct=entity,
connection=self._connection,
fetch_nested=self._module.params.get('fetch_nested'),
attributes=self._module.params.get('nested_attributes'),
),
}
def action(
self,
action,
entity=None,
action_condition=lambda e: e,
wait_condition=lambda e: e,
fail_condition=lambda e: False,
pre_action=lambda e: e,
post_action=lambda e: None,
search_params=None,
**kwargs
):
"""
This method is executed when we want to change the state of some oVirt
entity. The action to be executed on oVirt service is specified by
`action` parameter. Whether the action should be executed can be
specified by passing `action_condition` parameter. State which the
entity should be in after execution of the action can be specified
by `wait_condition` parameter.
Function executed before an action on entity can optionally be specified
in `pre_action` parameter. Function executed after an action on entity can
optionally be specified in `post_action` parameter.
:param action: Action which should be executed by service on entity.
:param entity: Entity we want to run action on.
:param action_condition: Function which is executed when checking if action should be executed.
:param fail_condition: Function which checks incorrect state of entity, if it returns `True` Exception is raised.
:param wait_condition: Function which is executed when waiting on result state.
:param pre_action: Function which is executed before running the action.
:param post_action: Function which is executed after running the action.
:param search_params: Dictionary of parameters to be used for search.
:param kwargs: Additional parameters passed to action.
:return: Dictionary with values returned by Ansible module.
"""
if entity is None:
entity = self.search_entity(search_params)
entity = pre_action(entity)
if entity is None:
self._module.fail_json(
msg="Entity not found, can't run action '{0}'.".format(
action
)
)
entity_service = self._service.service(entity.id)
entity = entity_service.get()
if action_condition(entity):
if not self._module.check_mode:
getattr(entity_service, action)(**kwargs)
self.changed = True
post_action(entity)
wait(
service=self._service.service(entity.id),
condition=wait_condition,
fail_condition=fail_condition,
wait=self._module.params['wait'],
timeout=self._module.params['timeout'],
poll_interval=self._module.params['poll_interval'],
)
return {
'changed': self.changed,
'id': entity.id,
type(entity).__name__.lower(): get_dict_of_struct(
struct=entity,
connection=self._connection,
fetch_nested=self._module.params.get('fetch_nested'),
attributes=self._module.params.get('nested_attributes'),
),
'diff': self._diff,
}
def wait_for_import(self, condition=lambda e: True):
if self._module.params['wait']:
start = time.time()
timeout = self._module.params['timeout']
poll_interval = self._module.params['poll_interval']
while time.time() < start + timeout:
entity = self.search_entity()
if entity and condition(entity):
return entity
time.sleep(poll_interval)
def search_entity(self, search_params=None, list_params=None):
"""
Always first try to search by `ID`, if ID isn't specified,
check if user constructed special search in `search_params`,
if not search by `name`.
"""
entity = None
if 'id' in self._module.params and self._module.params['id'] is not None:
entity = get_entity(self._service.service(self._module.params['id']), get_params=list_params)
elif search_params is not None:
entity = search_by_attributes(self._service, list_params=list_params, **search_params)
elif self._module.params.get('name') is not None:
entity = search_by_attributes(self._service, list_params=list_params, name=self._module.params['name'])
return entity
def _get_major(self, full_version):
if full_version is None or full_version == "":
return None
if isinstance(full_version, otypes.Version):
return int(full_version.major)
return int(full_version.split('.')[0])
def _get_minor(self, full_version):
if full_version is None or full_version == "":
return None
if isinstance(full_version, otypes.Version):
return int(full_version.minor)
return int(full_version.split('.')[1])
def _sdk4_error_maybe():
"""
Allow for ovirtsdk4 not being installed.
"""
if HAS_SDK:
return sdk.Error
return type(None)
class OvirtRetry(CloudRetry):
base_class = _sdk4_error_maybe()
@staticmethod
def status_code_from_exception(error):
return error.code
@staticmethod
def found(response_code, catch_extra_error_codes=None):
# This is a list of error codes to retry.
retry_on = [
# HTTP status: Conflict
409,
]
if catch_extra_error_codes:
retry_on.extend(catch_extra_error_codes)
return response_code in retry_on

@ -1,329 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2017, Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_affinity_group
short_description: Module to manage affinity groups in oVirt/RHV
version_added: "2.3"
author:
- Ondra Machacek (@machacekondra)
description:
- "This module manage affinity groups in oVirt/RHV. It can also manage assignments
of those groups to VMs."
options:
name:
description:
- Name of the affinity group to manage.
required: true
state:
description:
- Should the affinity group be present or absent.
choices: [ absent, present ]
default: present
cluster:
description:
- Name of the cluster of the affinity group.
description:
description:
- Description of the affinity group.
host_enforcing:
description:
- If I(yes) VM cannot start on host if it does not satisfy the C(host_rule).
- This parameter is support since oVirt/RHV 4.1 version.
type: bool
host_rule:
description:
- If I(positive) I(all) VMs in this group should run on the this host.
- If I(negative) I(no) VMs in this group should run on the this host.
- If I(disabled) this affinity group doesn't take effect.
- This parameter is support since oVirt/RHV 4.1 version.
choices: [ disabled, negative, positive ]
vm_enforcing:
description:
- If I(yes) VM cannot start if it does not satisfy the C(vm_rule).
type: bool
vm_rule:
description:
- If I(positive) I(all) VMs in this group should run on the host defined by C(host_rule).
- If I(negative) I(no) VMs in this group should run on the host defined by C(host_rule).
- If I(disabled) this affinity group doesn't take effect.
choices: [ disabled, negative, positive ]
vms:
description:
- List of the VMs names, which should have assigned this affinity group.
hosts:
description:
- List of the hosts names, which should have assigned this affinity group.
- This parameter is support since oVirt/RHV 4.1 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:
- name: Create(if not exists) and assign affinity group to VMs vm1 and vm2 and host host1
ovirt_affinity_group:
name: mygroup
cluster: mycluster
vm_enforcing: true
vm_rule: positive
host_enforcing: true
host_rule: positive
vms:
- vm1
- vm2
hosts:
- host1
- name: Detach VMs from affinity group and disable VM rule
ovirt_affinity_group:
name: mygroup
cluster: mycluster
vm_enforcing: false
vm_rule: disabled
host_enforcing: true
host_rule: positive
vms: []
hosts:
- host1
- host2
- name: Remove affinity group
ovirt_affinity_group:
state: absent
cluster: mycluster
name: mygroup
'''
RETURN = '''
id:
description: ID of the affinity group which is managed
returned: On success if affinity group is found.
type: str
sample: 7de90f31-222c-436c-a1ca-7e655bd5b60c
affinity_group:
description: "Dictionary of all the affinity group attributes. Affinity group attributes can be found on your oVirt/RHV instance
at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/affinity_group."
returned: On success if affinity group is found.
type: str
'''
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_support,
create_connection,
get_id_by_name,
equal,
engine_supported,
ovirt_full_argument_spec,
search_by_name,
)
class AffinityGroupsModule(BaseModule):
def __init__(self, vm_ids, host_ids, *args, **kwargs):
super(AffinityGroupsModule, self).__init__(*args, **kwargs)
self._vm_ids = vm_ids
self._host_ids = host_ids
def update_vms(self, affinity_group):
"""
This method iterate via the affinity VM assignments and datech the VMs
which should not be attached to affinity and attach VMs which should be
attached to affinity.
"""
assigned_vms = self.assigned_vms(affinity_group)
to_remove = [vm for vm in assigned_vms if vm not in self._vm_ids]
to_add = [vm for vm in self._vm_ids if vm not in assigned_vms]
ag_service = self._service.group_service(affinity_group.id)
for vm in to_remove:
ag_service.vms_service().vm_service(vm).remove()
for vm in to_add:
# API return <action> element instead of VM element, so we
# need to WA this issue, for oVirt/RHV versions having this bug:
try:
ag_service.vms_service().add(otypes.Vm(id=vm))
except ValueError as ex:
if 'complete' not in str(ex):
raise ex
def post_create(self, affinity_group):
self.update_vms(affinity_group)
def post_update(self, affinity_group):
self.update_vms(affinity_group)
def build_entity(self):
affinity_group = otypes.AffinityGroup(
name=self._module.params['name'],
description=self._module.params['description'],
positive=(
self._module.params['vm_rule'] == 'positive'
) if self._module.params['vm_rule'] is not None else None,
enforcing=(
self._module.params['vm_enforcing']
) if self._module.params['vm_enforcing'] is not None else None,
)
# Those attributes are Supported since 4.1:
if not engine_supported(self._connection, '4.1'):
return affinity_group
affinity_group.hosts_rule = otypes.AffinityRule(
positive=(
self.param('host_rule') == 'positive'
) if self.param('host_rule') is not None else None,
enforcing=self.param('host_enforcing'),
) if (
self.param('host_enforcing') is not None or
self.param('host_rule') is not None
) else None
affinity_group.vms_rule = otypes.AffinityRule(
positive=(
self.param('vm_rule') == 'positive'
) if self.param('vm_rule') is not None else None,
enforcing=self.param('vm_enforcing'),
enabled=(
self.param('vm_rule') in ['negative', 'positive']
) if self.param('vm_rule') is not None else None,
) if (
self.param('vm_enforcing') is not None or
self.param('vm_rule') is not None
) else None
affinity_group.hosts = [
otypes.Host(id=host_id) for host_id in self._host_ids
] if self._host_ids is not None else None
return affinity_group
def assigned_vms(self, affinity_group):
if getattr(affinity_group.vms, 'href', None):
return sorted([
vm.id for vm in self._connection.follow_link(affinity_group.vms)
])
else:
return sorted([vm.id for vm in affinity_group.vms])
def update_check(self, entity):
assigned_vms = self.assigned_vms(entity)
do_update = (
equal(self.param('description'), entity.description) and equal(self.param('vm_enforcing'), entity.enforcing) and equal(
self.param('vm_rule') == 'positive' if self.param('vm_rule') else None,
entity.positive
) and equal(self._vm_ids, assigned_vms)
)
# Following attributes is supported since 4.1,
# so return if it doesn't exist:
if not engine_supported(self._connection, '4.1'):
return do_update
# Following is supported since 4.1:
return do_update and (
equal(
self.param('host_rule') == 'positive' if self.param('host_rule') else None,
entity.hosts_rule.positive) and equal(self.param('host_enforcing'), entity.hosts_rule.enforcing) and equal(
self.param('vm_rule') in ['negative', 'positive'] if self.param('vm_rule') else None,
entity.vms_rule.enabled) and equal(self._host_ids, sorted([host.id for host in entity.hosts]))
)
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(type='str', default='present', choices=['absent', 'present']),
cluster=dict(type='str', required=True),
name=dict(type='str', required=True),
description=dict(type='str'),
vm_enforcing=dict(type='bool'),
vm_rule=dict(type='str', choices=['disabled', 'negative', 'positive']),
host_enforcing=dict(type='bool'),
host_rule=dict(type='str', choices=['disabled', 'negative', 'positive']),
vms=dict(type='list'),
hosts=dict(type='list'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
)
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
# Check if unsupported parameters were passed:
supported_41 = ('host_enforcing', 'host_rule', 'hosts')
if not check_support(
version='4.1',
connection=connection,
module=module,
params=supported_41,
):
module.fail_json(
msg='Following parameters are supported since 4.1: {params}'.format(
params=supported_41,
)
)
clusters_service = connection.system_service().clusters_service()
vms_service = connection.system_service().vms_service()
hosts_service = connection.system_service().hosts_service()
cluster_name = module.params['cluster']
cluster = search_by_name(clusters_service, cluster_name)
if cluster is None:
raise Exception("Cluster '%s' was not found." % cluster_name)
cluster_service = clusters_service.cluster_service(cluster.id)
affinity_groups_service = cluster_service.affinity_groups_service()
# Fetch VM ids which should be assigned to affinity group:
vm_ids = sorted([
get_id_by_name(vms_service, vm_name)
for vm_name in module.params['vms']
]) if module.params['vms'] is not None else None
# Fetch host ids which should be assigned to affinity group:
host_ids = sorted([
get_id_by_name(hosts_service, host_name)
for host_name in module.params['hosts']
]) if module.params['hosts'] is not None else None
affinity_groups_module = AffinityGroupsModule(
connection=connection,
module=module,
service=affinity_groups_service,
vm_ids=vm_ids,
host_ids=host_ids,
)
state = module.params['state']
if state == 'present':
ret = affinity_groups_module.create()
elif state == 'absent':
ret = affinity_groups_module.remove()
module.exit_json(**ret)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == "__main__":
main()

@ -1,210 +0,0 @@
#!/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/>.
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_affinity_label
short_description: Module to manage affinity labels in oVirt/RHV
version_added: "2.3"
author: "Ondra Machacek (@machacekondra)"
description:
- "This module manage affinity labels in oVirt/RHV. It can also manage assignments
of those labels to hosts and VMs."
options:
name:
description:
- "Name of 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_label:
name: mylabel
cluster: mycluster
vms:
- vm1
- vm2
hosts:
- host1
# To detach all VMs from label
- ovirt_affinity_label:
name: mylabel
cluster: mycluster
vms: []
# Remove affinity label
- ovirt_affinity_label:
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
affinity_label:
description: "Dictionary of all the affinity label attributes. Affinity label attributes can be found on your oVirt/RHV instance
at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/affinity_label."
type: dict
returned: On success if affinity label is found.
'''
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,
)
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:
auth = module.params.pop('auth')
connection = create_connection(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=auth.get('token') is None)
if __name__ == "__main__":
main()

@ -1,182 +0,0 @@
#!/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/>.
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_affinity_label_info
short_description: Retrieve information about one or more oVirt/RHV affinity labels
author: "Ondra Machacek (@machacekondra)"
version_added: "2.3"
description:
- "Retrieve information about one or more oVirt/RHV affinity labels."
- This module was called C(ovirt_affinity_label_facts) before Ansible 2.9, returning C(ansible_facts).
Note that the M(ovirt_affinity_label_info) module no longer returns C(ansible_facts)!
notes:
- "This module returns a variable C(ovirt_affinity_labels), which
contains a list of affinity labels. You need to register the result with
the I(register) keyword to use it."
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_info
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather information about all affinity labels, which names start with C(label):
- ovirt_affinity_label_info:
name: label*
register: result
- debug:
msg: "{{ result.ovirt_affinity_labels }}"
# Gather information about all affinity labels, which are assigned to VMs
# which names start with C(postgres):
- ovirt_affinity_label_info:
vm: postgres*
register: result
- debug:
msg: "{{ result.ovirt_affinity_labels }}"
# Gather information about all affinity labels, which are assigned to hosts
# which names start with C(west):
- ovirt_affinity_label_info:
host: west*
register: result
- debug:
msg: "{{ result.ovirt_affinity_labels }}"
# Gather information 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_label_info:
host: west*
vm: postgres*
register: result
- debug:
msg: "{{ result.ovirt_affinity_labels }}"
'''
RETURN = '''
ovirt_affinity_labels:
description: "List of dictionaries describing the affinity labels. Affinity labels attributes are mapped to dictionary keys,
all affinity labels attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/affinity_label."
returned: On success.
type: list
'''
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_info_full_argument_spec,
search_by_name,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
name=dict(default=None),
host=dict(default=None),
vm=dict(default=None),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name == 'ovirt_affinity_label_facts'
if is_old_facts:
module.deprecate("The 'ovirt_affinity_label_facts' module has been renamed to 'ovirt_affinity_label_info', "
"and the renamed one no longer returns ansible_facts", version='2.13')
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(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()
if search_by_name(hosts_service, module.params['host']) is None:
raise Exception("Host '%s' was not found." % module.params['host'])
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()
if search_by_name(vms_service, module.params['vm']) is None:
raise Exception("Vm '%s' was not found." % module.params['vm'])
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
result = dict(
ovirt_affinity_labels=[
get_dict_of_struct(
struct=l,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for l in labels
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

@ -1,98 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'
}
DOCUMENTATION = '''
---
module: ovirt_api_info
short_description: Retrieve information about the oVirt/RHV API
author: "Ondra Machacek (@machacekondra)"
version_added: "2.5"
description:
- "Retrieve information about the oVirt/RHV API."
- This module was called C(ovirt_api_facts) before Ansible 2.9, returning C(ansible_facts).
Note that the M(ovirt_api_info) module no longer returns C(ansible_facts)!
notes:
- "This module returns a variable C(ovirt_api),
which contains a information about oVirt/RHV API. You need to register the result with
the I(register) keyword to use it."
extends_documentation_fragment: ovirt_info
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather information oVirt API:
- ovirt_api_info:
register: result
- debug:
msg: "{{ result.ovirt_api }}"
'''
RETURN = '''
ovirt_api:
description: "Dictionary describing the oVirt API information.
Api attributes are mapped to dictionary keys,
all API attributes can be found at following
url: https://ovirt.example.com/ovirt-engine/api/model#types/api."
returned: On success.
type: dict
'''
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
)
def main():
argument_spec = ovirt_info_full_argument_spec()
module = AnsibleModule(argument_spec)
is_old_facts = module._name == 'ovirt_api_facts'
if is_old_facts:
module.deprecate("The 'ovirt_api_facts' module has been renamed to 'ovirt_api_info', "
"and the renamed one no longer returns ansible_facts", version='2.13')
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
api = connection.system_service().get()
result = dict(
ovirt_api=get_dict_of_struct(
struct=api,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
)
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

@ -1,300 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_auth
short_description: "Module to manage authentication to oVirt/RHV"
author: "Ondra Machacek (@machacekondra)"
version_added: "2.2"
description:
- "This module authenticates to oVirt/RHV engine and creates SSO token, which should be later used in
all other oVirt/RHV 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: False
description:
- "The name of the user. For example: I(admin@internal)
Default value is set by I(OVIRT_USERNAME) environment variable."
password:
required: False
description:
- "The password of the user. Default value is set by I(OVIRT_PASSWORD) environment variable."
token:
required: False
description:
- "SSO token to be used instead of login with username/password.
Default value is set by I(OVIRT_TOKEN) environment variable."
version_added: 2.5
url:
required: False
description:
- "A string containing the API URL of the server.
For example: I(https://server.example.com/ovirt-engine/api).
Default value is set by I(OVIRT_URL) environment variable."
- "Either C(url) or C(hostname) is required."
hostname:
required: False
description:
- "A string containing the hostname of the server.
For example: I(server.example.com).
Default value is set by I(OVIRT_HOSTNAME) environment variable."
- "Either C(url) or C(hostname) is required."
version_added: "2.6"
insecure:
required: False
description:
- "A boolean flag that indicates if the server TLS certificate and host name should be checked."
type: bool
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.
Default value is set by I(OVIRT_CAFILE) environment variable."
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)."
type: bool
kerberos:
required: False
description:
- "A boolean flag indicating if Kerberos authentication
should be used instead of the default basic authentication."
type: bool
headers:
required: False
description:
- "A dictionary of HTTP headers to be added to each API call."
version_added: "2.4"
requirements:
- python >= 2.7
- ovirt-engine-sdk-python >= 4.3.0
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."
- "In order to use this module you have to install oVirt/RHV Python SDK.
To ensure it's installed with correct version you can create the following task:
I(pip: name=ovirt-engine-sdk-python version=4.3.0)"
- "Note that in oVirt/RHV 4.1 if you want to use a user which is not administrator
you must enable the I(ENGINE_API_FILTER_BY_DEFAULT) variable in engine. In
oVirt/RHV 4.2 and later it's enabled by default."
'''
EXAMPLES = '''
- block:
# Create a vault with `ovirt_password` variable which store your
# oVirt/RHV 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_vm:
auth: "{{ ovirt_auth }}"
state: absent
name: myvm
always:
- name: Always revoke the SSO token
ovirt_auth:
state: absent
ovirt_auth: "{{ ovirt_auth }}"
# When user will set following environment variables:
# OVIRT_URL = https://fqdn/ovirt-engine/api
# OVIRT_USERNAME = admin@internal
# OVIRT_PASSWORD = the_password
# User can login the oVirt using environment variable instead of variables
# in yaml file.
# This is mainly useful when using Ansible Tower or AWX, as it will work
# for Red Hat Virtualization credentials type.
- name: Obtain SSO token
ovirt_auth:
state: present
'''
RETURN = '''
ovirt_auth:
description: Authentication facts, needed to perform authentication to oVirt/RHV.
returned: success
type: complex
contains:
token:
description: SSO token which is used for connection to oVirt/RHV engine.
returned: success
type: str
sample: "kdfVWp9ZgeewBXV-iq3Js1-xQJZPSEQ334FLb3eksoEPRaab07DhZ8ED8ghz9lJd-MQ2GqtRIeqhvhCkrUWQPw"
url:
description: URL of the oVirt/RHV engine API endpoint.
returned: success
type: str
sample: "https://ovirt.example.com/ovirt-engine/api"
ca_file:
description: CA file, which is used to verify SSL/TLS connection.
returned: success
type: str
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
headers:
description: Dictionary of HTTP headers to be added to each API call.
returned: success
type: dict
'''
import os
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
def main():
module = AnsibleModule(
argument_spec=dict(
url=dict(default=None),
hostname=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=None),
timeout=dict(required=False, type='int', default=0),
compress=dict(required=False, type='bool', default=True),
kerberos=dict(required=False, type='bool', default=False),
headers=dict(required=False, type='dict'),
state=dict(default='present', choices=['present', 'absent']),
token=dict(default=None),
ovirt_auth=dict(required=None, type='dict'),
),
required_if=[
('state', 'absent', ['ovirt_auth']),
],
supports_check_mode=True,
)
check_sdk(module)
state = module.params.get('state')
if state == 'present':
params = module.params
elif state == 'absent':
params = module.params['ovirt_auth']
def get_required_parameter(param, env_var, required=False):
var = params.get(param) or os.environ.get(env_var)
if not var and required and state == 'present':
module.fail_json(msg="'%s' is a required parameter." % param)
return var
url = get_required_parameter('url', 'OVIRT_URL', required=False)
hostname = get_required_parameter('hostname', 'OVIRT_HOSTNAME', required=False)
if url is None and hostname is None:
module.fail_json(msg="You must specify either 'url' or 'hostname'.")
if url is None and hostname is not None:
url = 'https://{0}/ovirt-engine/api'.format(hostname)
username = get_required_parameter('username', 'OVIRT_USERNAME')
password = get_required_parameter('password', 'OVIRT_PASSWORD')
token = get_required_parameter('token', 'OVIRT_TOKEN')
ca_file = get_required_parameter('ca_file', 'OVIRT_CAFILE')
insecure = params.get('insecure') if params.get('insecure') is not None else not bool(ca_file)
connection = sdk.Connection(
url=url,
username=username,
password=password,
ca_file=ca_file,
insecure=insecure,
timeout=params.get('timeout'),
compress=params.get('compress'),
kerberos=params.get('kerberos'),
headers=params.get('headers'),
token=token,
)
try:
token = connection.authenticate()
module.exit_json(
changed=False,
ansible_facts=dict(
ovirt_auth=dict(
token=token,
url=url,
ca_file=ca_file,
insecure=insecure,
timeout=params.get('timeout'),
compress=params.get('compress'),
kerberos=params.get('kerberos'),
headers=params.get('headers'),
) if state == 'present' else dict()
)
)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
# Close the connection, but don't revoke token
connection.close(logout=state == 'absent')
if __name__ == "__main__":
main()

@ -1,745 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_cluster
short_description: Module to manage clusters in oVirt/RHV
version_added: "2.3"
author: "Ondra Machacek (@machacekondra)"
description:
- "Module to manage clusters in oVirt/RHV"
options:
id:
description:
- "ID of the cluster to manage."
version_added: "2.8"
name:
description:
- "Name of the cluster to manage."
required: true
state:
description:
- "Should the cluster be present or absent."
choices: ['present', 'absent']
default: present
data_center:
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 I(True) enable memory balloon optimization. Memory balloon is used to
re-distribute / reclaim the host memory based on VM needs
in a dynamic way."
type: bool
virt:
description:
- "If I(True), hosts in this cluster will be used to run virtual machines."
type: bool
gluster:
description:
- "If I(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."
type: bool
threads_as_cores:
description:
- "If I(True) the exposed host threads would be treated as cores
which can be utilized by virtual machines."
type: bool
ksm:
description:
- "I I(True) MoM enables to run Kernel Same-page Merging I(KSM) when
necessary and when it can yield a memory saving benefit that
outweighs its CPU cost."
type: bool
ksm_numa:
description:
- "If I(True) enables KSM C(ksm) for best performance inside NUMA nodes."
type: bool
ha_reservation:
description:
- "If I(True) enables the oVirt/RHV to monitor cluster capacity for highly
available virtual machines."
type: bool
trusted_service:
description:
- "If I(True) enables integration with an OpenAttestation server."
type: bool
vm_reason:
description:
- "If I(True) enables an optional reason field when a virtual machine
is shut down from the Manager, allowing the administrator to
provide an explanation for the maintenance."
type: bool
host_reason:
description:
- "If I(True) enables 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."
type: bool
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 I(True) enables fencing on the cluster."
- "Fencing is enabled by default."
type: bool
fence_skip_if_gluster_bricks_up:
description:
- "A flag indicating if fencing should be skipped if Gluster bricks are up and running in the host being fenced."
- "This flag is optional, and the default value is `false`."
type: bool
version_added: "2.8"
fence_skip_if_gluster_quorum_not_met:
description:
- "A flag indicating if fencing should be skipped if Gluster bricks are up and running and Gluster quorum will not
be met without those bricks."
- "This flag is optional, and the default value is `false`."
type: bool
version_added: "2.8"
fence_skip_if_sd_active:
description:
- "If I(True) any hosts in the cluster that are Non Responsive
and still connected to storage will not be fenced."
type: bool
fence_skip_if_connectivity_broken:
description:
- "If I(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)."
type: bool
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 bandwidth 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 I(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 I(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."
- "C(post_copy) - Virtual machines should not experience any significant downtime.
If the VM migration is not converging for a long time, the migration will be switched to post-copy.
Added in version I(2.4)."
choices: ['legacy', 'minimal_downtime', 'suspend_workload', 'post_copy']
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."
scheduling_policy_properties:
description:
- "Custom scheduling policy properties of the cluster."
- "These optional properties override the properties of the
scheduling policy specified by the C(scheduling_policy) parameter."
version_added: "2.6"
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 bridge 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."
mac_pool:
description:
- "MAC pool to be used by this cluster."
- "C(Note:)"
- "This is supported since oVirt version 4.1."
version_added: 2.4
external_network_providers:
description:
- "List of references to the external network providers available
in the cluster. If the automatic deployment of the external
network provider is supported, the networks of the referenced
network provider are available on every host in the cluster."
- "This is supported since oVirt version 4.2."
suboptions:
name:
description:
- Name of the external network provider. Either C(name) or C(id) is required.
id:
description:
- ID of the external network provider. Either C(name) or C(id) is required.
version_added: 2.5
firewall_type:
description:
- "The type of firewall to be used on hosts in this cluster."
- "Up to version 4.1, it was always I(iptables). Since version 4.2, you can choose between I(iptables) and I(firewalld).
For clusters with a compatibility version of 4.2 and higher, the default firewall type is I(firewalld)."
type: str
version_added: 2.8
choices: ['firewalld', 'iptables']
gluster_tuned_profile:
description:
- "The name of the U(https://fedorahosted.org/tuned) to set on all the hosts in the cluster. This is not mandatory
and relevant only for clusters with Gluster service."
- "Could be for example I(virtual-host), I(rhgs-sequential-io), I(rhgs-random-io)"
version_added: 2.8
type: str
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_cluster:
data_center: mydatacenter
name: mycluster
cpu_type: Intel SandyBridge Family
description: mycluster
compatibility_version: 4.0
# Create virt service cluster:
- ovirt_cluster:
data_center: 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
# Create cluster with default network provider
- ovirt_cluster:
name: mycluster
data_center: Default
cpu_type: Intel SandyBridge Family
external_network_providers:
- name: ovirt-provider-ovn
# Remove cluster
- ovirt_cluster:
state: absent
name: mycluster
# Change cluster Name
- ovirt_cluster:
id: 00000000-0000-0000-0000-000000000000
name: "new_cluster_name"
'''
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/RHV instance
at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/cluster."
type: dict
returned: On success if cluster is found.
'''
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,
get_id_by_name,
)
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
# post copy - a7aeedb2-8d66-4e51-bb22-32595027ce71
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'
elif migration_policy == 'post_copy':
return 'a7aeedb2-8d66-4e51-bb22-32595027ce71'
def _get_sched_policy(self):
sched_policy = None
if self.param('scheduling_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 _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 _get_external_network_providers(self):
return self.param('external_network_providers') or []
def _get_external_network_provider_id(self, external_provider):
return external_provider.get('id') or get_id_by_name(
self._connection.system_service().openstack_network_providers_service(),
external_provider.get('name')
)
def _get_external_network_providers_entity(self):
if self.param('external_network_providers') is not None:
return [otypes.ExternalProvider(id=self._get_external_network_provider_id(external_provider))
for external_provider in self.param('external_network_providers')]
def build_entity(self):
sched_policy = self._get_sched_policy()
return otypes.Cluster(
id=self.param('id'),
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'),
skip_if_gluster_bricks_up=self.param('fence_skip_if_gluster_bricks_up'),
skip_if_gluster_quorum_not_met=self.param('fence_skip_if_gluster_quorum_not_met'),
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') is not None 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_skip_if_gluster_bricks_up') is not None or
self.param('fence_skip_if_gluster_quorum_not_met') 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'),
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('data_center'),
) if self.param('data_center') else None,
management_network=otypes.Network(
name=self.param('network'),
) if self.param('network') else None,
cpu=otypes.Cpu(
architecture=otypes.Architecture(
self.param('cpu_arch')
) if self.param('cpu_arch') else None,
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,
mac_pool=otypes.MacPool(
id=get_id_by_name(self._connection.system_service().mac_pools_service(), self.param('mac_pool'))
) if self.param('mac_pool') else None,
external_network_providers=self._get_external_network_providers_entity(),
custom_scheduling_policy_properties=[
otypes.Property(
name=sp.get('name'),
value=str(sp.get('value')),
) for sp in self.param('scheduling_policy_properties') if sp
] if self.param('scheduling_policy_properties') is not None else None,
firewall_type=otypes.FirewallType(
self.param('firewall_type')
) if self.param('firewall_type') else None,
gluster_tuned_profile=self.param('gluster_tuned_profile'),
)
def _matches_entity(self, item, entity):
return equal(item.get('id'), entity.id) and equal(item.get('name'), entity.name)
def _update_check_external_network_providers(self, entity):
if self.param('external_network_providers') is None:
return True
if entity.external_network_providers is None:
return not self.param('external_network_providers')
entity_providers = self._connection.follow_link(entity.external_network_providers)
entity_provider_ids = [provider.id for provider in entity_providers]
entity_provider_names = [provider.name for provider in entity_providers]
for provider in self._get_external_network_providers():
if provider.get('id'):
if provider.get('id') not in entity_provider_ids:
return False
elif provider.get('name') and provider.get('name') not in entity_provider_names:
return False
for entity_provider in entity_providers:
if not any([self._matches_entity(provider, entity_provider)
for provider in self._get_external_network_providers()]):
return False
return True
def update_check(self, entity):
sched_policy = self._get_sched_policy()
migration_policy = getattr(entity.migration, 'policy', None)
cluster_cpu = getattr(entity, 'cpu', dict())
def check_custom_scheduling_policy_properties():
if self.param('scheduling_policy_properties'):
current = []
if entity.custom_scheduling_policy_properties:
current = [(sp.name, str(sp.value)) for sp in entity.custom_scheduling_policy_properties]
passed = [(sp.get('name'), str(sp.get('value'))) for sp in self.param('scheduling_policy_properties') if sp]
for p in passed:
if p not in current:
return False
return True
return (
check_custom_scheduling_policy_properties() and
equal(self.param('name'), entity.name) and
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(getattr(cluster_cpu, 'architecture', None))) and
equal(self.param('cpu_type'), getattr(cluster_cpu, 'type', None)) 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
equal(self.param('ksm'), 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_gluster_bricks_up'), entity.fencing_policy.skip_if_gluster_bricks_up) and
equal(self.param('fence_skip_if_gluster_quorum_not_met'), entity.fencing_policy.skip_if_gluster_quorum_not_met) 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(getattr(entity.serial_number, 'policy', None))) and
equal(self.param('serial_policy_value'), getattr(entity.serial_number, 'value', None)) and
equal(self.param('scheduling_policy'), getattr(self._connection.follow_link(entity.scheduling_policy), 'name', None)) and
equal(self.param('firewall_type'), str(entity.firewall_type)) and
equal(self.param('gluster_tuned_profile'), getattr(entity, 'gluster_tuned_profile', None)) and
equal(self._get_policy_id(), getattr(migration_policy, 'id', None)) 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
])
) and
equal(
get_id_by_name(self._connection.system_service().mac_pools_service(), self.param('mac_pool'), raise_error=False),
entity.mac_pool.id
) and
self._update_check_external_network_providers(entity)
)
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(
choices=['present', 'absent'],
default='present',
),
name=dict(default=None, required=True),
id=dict(default=None),
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'], aliases=['performance_preset']),
rng_sources=dict(default=None, type='list'),
spice_proxy=dict(default=None),
fence_enabled=dict(default=None, type='bool'),
fence_skip_if_gluster_bricks_up=dict(default=None, type='bool'),
fence_skip_if_gluster_quorum_not_met=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', 'post_copy']
),
serial_policy=dict(default=None, choices=['vm', 'host', 'custom']),
serial_policy_value=dict(default=None),
scheduling_policy=dict(default=None),
data_center=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),
mac_pool=dict(default=None),
external_network_providers=dict(default=None, type='list'),
scheduling_policy_properties=dict(type='list'),
firewall_type=dict(choices=['iptables', 'firewalld'], default=None),
gluster_tuned_profile=dict(default=None),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
)
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(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=auth.get('token') is None)
if __name__ == "__main__":
main()

@ -1,120 +0,0 @@
#!/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/>.
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_cluster_info
short_description: Retrieve information about one or more oVirt/RHV clusters
author: "Ondra Machacek (@machacekondra)"
version_added: "2.3"
description:
- "Retrieve information about one or more oVirt/RHV clusters."
- This module was called C(ovirt_cluster_facts) before Ansible 2.9, returning C(ansible_facts).
Note that the M(ovirt_cluster_info) module no longer returns C(ansible_facts)!
notes:
- "This module returns a variable C(ovirt_clusters), which
contains a list of clusters. You need to register the result with
the I(register) keyword to use it."
options:
pattern:
description:
- "Search term which is accepted by oVirt/RHV search backend."
- "For example to search cluster X from datacenter Y use following pattern:
name=X and datacenter=Y"
extends_documentation_fragment: ovirt_info
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather information about all clusters which names start with C<production>:
- ovirt_cluster_info:
pattern:
name: 'production*'
register: result
- debug:
msg: "{{ result.ovirt_clusters }}"
'''
RETURN = '''
ovirt_clusters:
description: "List of dictionaries describing the clusters. Cluster attributes are mapped to dictionary keys,
all clusters attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/cluster."
returned: On success.
type: list
'''
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
pattern=dict(default='', required=False),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name == 'ovirt_cluster_facts'
if is_old_facts:
module.deprecate("The 'ovirt_cluster_facts' module has been renamed to 'ovirt_cluster_info', "
"and the renamed one no longer returns ansible_facts", version='2.13')
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
clusters_service = connection.system_service().clusters_service()
clusters = clusters_service.list(search=module.params['pattern'])
result = dict(
ovirt_clusters=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in clusters
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

@ -1,233 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_datacenter
short_description: Module to manage data centers in oVirt/RHV
version_added: "2.3"
author: "Ondra Machacek (@machacekondra)"
description:
- "Module to manage data centers in oVirt/RHV"
options:
id:
description:
- "ID of the datacenter to manage."
version_added: "2.8"
name:
description:
- "Name of 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."
type: bool
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/RHV 4.1. You should
use C(mac_pool) in C(ovirt_clusters) module, as MAC pools are
set per cluster since 4.1."
force:
description:
- "This parameter can be used only when removing a data center.
If I(True) data center will be forcibly removed, even though it
contains some clusters. Default value is I(False), which means
that only empty data center can be removed."
version_added: "2.5"
default: False
type: bool
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_datacenter:
name: mydatacenter
local: True
compatibility_version: 4.0
quota_mode: enabled
# Remove datacenter
- ovirt_datacenter:
state: absent
name: mydatacenter
# Change Datacenter Name
- ovirt_datacenter:
id: 00000000-0000-0000-0000-000000000000
name: "new_datacenter_name"
'''
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/RHV instance
at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/datacenter."
returned: "On success if datacenter is found."
type: dict
'''
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,
)
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'],
id=self._module.params['id'],
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('name'), entity.name) 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'),
id=dict(default=None),
compatibility_version=dict(default=None),
quota_mode=dict(choices=['disabled', 'audit', 'enabled']),
comment=dict(default=None),
mac_pool=dict(default=None),
force=dict(default=None, type='bool'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
)
check_sdk(module)
check_params(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
data_centers_service = connection.system_service().data_centers_service()
data_centers_module = DatacentersModule(
connection=connection,
module=module,
service=data_centers_service,
)
state = module.params['state']
if state == 'present':
ret = data_centers_module.create()
elif state == 'absent':
ret = data_centers_module.remove(force=module.params['force'])
module.exit_json(**ret)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == "__main__":
main()

@ -1,103 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_datacenter_info
short_description: Retrieve information about one or more oVirt/RHV datacenters
author: "Ondra Machacek (@machacekondra)"
version_added: "2.3"
description:
- "Retrieve information about one or more oVirt/RHV datacenters."
- This module was called C(ovirt_datacenter_facts) before Ansible 2.9, returning C(ansible_facts).
Note that the M(ovirt_datacenter_info) module no longer returns C(ansible_facts)!
notes:
- "This module returns a variable C(ovirt_datacenters), which
contains a list of datacenters. You need to register the result with
the I(register) keyword to use it."
options:
pattern:
description:
- "Search term which is accepted by oVirt/RHV search backend."
- "For example to search datacenter I(X) use following pattern: I(name=X)"
extends_documentation_fragment: ovirt_info
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather information about all data centers which names start with C(production):
- ovirt_datacenter_info:
pattern: name=production*
register: result
- debug:
msg: "{{ result.ovirt_datacenters }}"
'''
RETURN = '''
ovirt_datacenters:
description: "List of dictionaries describing the datacenters. Datacenter attributes are mapped to dictionary keys,
all datacenters attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/data_center."
returned: On success.
type: list
'''
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
pattern=dict(default='', required=False),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name == 'ovirt_datacenter_facts'
if is_old_facts:
module.deprecate("The 'ovirt_datacenter_facts' module has been renamed to 'ovirt_datacenter_info', "
"and the renamed one no longer returns ansible_facts", version='2.13')
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
datacenters_service = connection.system_service().data_centers_service()
datacenters = datacenters_service.list(search=module.params['pattern'])
result = dict(
ovirt_datacenters=[
get_dict_of_struct(
struct=d,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for d in datacenters
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

@ -1,838 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_disk
short_description: "Module to manage Virtual Machine and floating disks in oVirt/RHV"
version_added: "2.2"
author: "Ondra Machacek (@machacekondra)"
description:
- "Module to manage Virtual Machine and floating disks in oVirt/RHV."
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']
description:
description:
- "Description of the disk image to manage."
version_added: "2.5"
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/exported/imported."
choices: ['present', 'absent', 'attached', 'detached', 'exported', 'imported']
default: 'present'
download_image_path:
description:
- "Path on a file system where disk should be downloaded."
- "Note that you must have an valid oVirt/RHV engine CA in your system trust store
or you must provide it in C(ca_file) parameter."
- "Note that the disk is not downloaded when the file already exists,
but you can forcibly download the disk when using C(force) I (true)."
version_added: "2.3"
upload_image_path:
description:
- "Path to disk image, which should be uploaded."
- "Note that currently we support only compatibility version 0.10 of the qcow disk."
- "Note that you must have an valid oVirt/RHV engine CA in your system trust store
or you must provide it in C(ca_file) parameter."
- "Note that there is no reliable way to achieve idempotency, so
if you want to upload the disk even if the disk with C(id) or C(name) exists,
then please use C(force) I(true). If you will use C(force) I(false), which
is default, then the disk image won't be uploaded."
version_added: "2.3"
size:
description:
- "Size of the disk. Size should be specified using IEC standard units.
For example 10GiB, 1024MiB, etc."
- "Size can be only increased, not decreased."
interface:
description:
- "Driver of the storage interface."
- "It's required parameter when creating the new disk."
choices: ['virtio', 'ide', 'virtio_scsi']
format:
description:
- Specify format of the disk.
- Note that this option isn't idempotent as it's not currently possible to change format of the disk via API.
choices: ['raw', 'cow']
content_type:
description:
- Specify if the disk is a data disk or ISO image or a one of a the Hosted Engine disk types
- The Hosted Engine disk content types are available with Engine 4.3+ and Ansible 2.8
choices: ['data', 'iso', 'hosted_engine', 'hosted_engine_sanlock', 'hosted_engine_metadata', 'hosted_engine_configuration']
default: 'data'
version_added: "2.8"
sparse:
required: False
type: bool
version_added: "2.5"
description:
- "I(True) if the disk should be sparse (also known as I(thin provision)).
If the parameter is omitted, cow disks will be created as sparse and raw disks as I(preallocated)"
- Note that this option isn't idempotent as it's not currently possible to change sparseness of the disk via API.
storage_domain:
description:
- "Storage domain name where disk should be created."
storage_domains:
description:
- "Storage domain names where disk should be copied."
- "C(**IMPORTANT**)"
- "There is no reliable way to achieve idempotency, so every time
you specify this parameter the disks are copied, so please handle
your playbook accordingly to not copy the disks all the time. This
is valid only for VM and floating disks, template disks works
as expected."
version_added: "2.3"
force:
description:
- "Please take a look at C(image_path) documentation to see the correct
usage of this parameter."
version_added: "2.3"
type: bool
profile:
description:
- "Disk profile name to be attached to disk. By default profile is chosen by oVirt/RHV engine."
quota_id:
description:
- "Disk quota ID to be used for disk. By default quota is chosen by oVirt/RHV engine."
version_added: "2.5"
bootable:
description:
- "I(True) if the disk should be bootable. By default when disk is created it isn't bootable."
type: bool
default: 'no'
shareable:
description:
- "I(True) if the disk should be shareable. By default when disk is created it isn't shareable."
type: bool
logical_unit:
description:
- "Dictionary which describes LUN to be directly attached to VM:"
suboptions:
address:
description:
- Address of the storage server. Used by iSCSI.
port:
description:
- Port of the storage server. Used by iSCSI.
target:
description:
- iSCSI target.
lun_id:
description:
- LUN id.
username:
description:
- CHAP Username to be used to access storage server. Used by iSCSI.
password:
description:
- CHAP Password of the user to be used to access storage server. Used by iSCSI.
storage_type:
description:
- Storage type either I(fcp) or I(iscsi).
sparsify:
description:
- "I(True) if the disk should be sparsified."
- "Sparsification frees space in the disk image that is not used by
its filesystem. As a result, the image will occupy less space on
the storage."
- "Note that this parameter isn't idempotent, as it's not possible
to check if the disk should be or should not be sparsified."
version_added: "2.4"
type: bool
openstack_volume_type:
description:
- "Name of the openstack volume type. This is valid when working
with cinder."
version_added: "2.4"
image_provider:
description:
- "When C(state) is I(exported) disk is exported to given Glance image provider."
- "When C(state) is I(imported) disk is imported from given Glance image provider."
- "C(**IMPORTANT**)"
- "There is no reliable way to achieve idempotency, so every time
you specify this parameter the disk is exported, so please handle
your playbook accordingly to not export the disk all the time.
This option is valid only for template disks."
version_added: "2.4"
host:
description:
- "When the hypervisor name is specified the newly created disk or
an existing disk will refresh its information about the
underlying storage( Disk size, Serial, Product ID, Vendor ID ...)
The specified host will be used for gathering the storage
related information. This option is only valid for passthrough
disks. This option requires at least the logical_unit.id to be
specified"
version_added: "2.8"
wipe_after_delete:
description:
- "If the disk's Wipe After Delete is enabled, then the disk is first wiped."
type: bool
activate:
description:
- I(True) if the disk should be activated.
- When creating disk of virtual machine it is set to I(True).
version_added: "2.8"
type: bool
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_disk:
name: myvm_disk
vm_name: rhel7
size: 10GiB
format: cow
interface: virtio
storage_domain: data
# Attach logical unit to VM rhel7
- ovirt_disk:
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_disk:
state: detached
name: myvm_disk
vm_name: rhel7
size: 10GiB
format: cow
interface: virtio
# Change Disk Name
- ovirt_disk:
id: 00000000-0000-0000-0000-000000000000
storage_domain: data
name: "new_disk_name"
vm_name: rhel7
# Upload local image to disk and attach it to vm:
# Since Ansible 2.3
- ovirt_disk:
name: mydisk
vm_name: myvm
interface: virtio
size: 10GiB
format: cow
image_path: /path/to/mydisk.qcow2
storage_domain: data
# Download disk to local file system:
# Since Ansible 2.3
- ovirt_disk:
id: 7de90f31-222c-436c-a1ca-7e655bd5b60c
download_image_path: /home/user/mydisk.qcow2
# Export disk as image to Glance domain
# Since Ansible 2.4
- ovirt_disk:
id: 7de90f31-222c-436c-a1ca-7e655bd5b60c
image_provider: myglance
state: exported
# Defining a specific quota while creating a disk image:
# Since Ansible 2.5
- ovirt_quotas_facts:
data_center: Default
name: myquota
- ovirt_disk:
name: mydisk
size: 10GiB
storage_domain: data
description: somedescriptionhere
quota_id: "{{ ovirt_quotas[0]['id'] }}"
# Upload an ISO image
# Since Ansible 2.8
- ovirt_disk:
name: myiso
upload_image_path: /path/to/iso/image
storage_domain: data
size: 4 GiB
wait: true
bootable: true
format: raw
content_type: iso
# Add fiber chanel disk
- name: Create disk
ovirt_disk:
name: fcp_disk
host: my_host
logical_unit:
id: 3600a09803830447a4f244c4657597777
storage_type: fcp
'''
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/RHV instance
at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/disk."
returned: "On success if disk is found and C(vm_id) or C(vm_name) wasn't passed."
type: dict
disk_attachment:
description: "Dictionary of all the disk attachment attributes. Disk attachment attributes can be found
on your oVirt/RHV instance at following url:
http://ovirt.github.io/ovirt-engine-api-model/master/#types/disk_attachment."
returned: "On success if disk is found and C(vm_id) or C(vm_name) was passed and VM was found."
type: dict
'''
import os
import time
import traceback
import ssl
from ansible.module_utils.six.moves.http_client import HTTPSConnection, IncompleteRead
from ansible.module_utils.six.moves.urllib.parse import urlparse
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,
convert_to_bytes,
equal,
follow_link,
get_id_by_name,
ovirt_full_argument_spec,
get_dict_of_struct,
search_by_name,
wait,
)
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
def transfer(connection, module, direction, transfer_func):
transfers_service = connection.system_service().image_transfers_service()
transfer = transfers_service.add(
otypes.ImageTransfer(
image=otypes.Image(
id=module.params['id'],
),
direction=direction,
)
)
transfer_service = transfers_service.image_transfer_service(transfer.id)
try:
# After adding a new transfer for the disk, the transfer's status will be INITIALIZING.
# Wait until the init phase is over. The actual transfer can start when its status is "Transferring".
while transfer.phase == otypes.ImageTransferPhase.INITIALIZING:
time.sleep(module.params['poll_interval'])
transfer = transfer_service.get()
proxy_url = urlparse(transfer.proxy_url)
context = ssl.create_default_context()
auth = module.params['auth']
if auth.get('insecure'):
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
elif auth.get('ca_file'):
context.load_verify_locations(cafile=auth.get('ca_file'))
proxy_connection = HTTPSConnection(
proxy_url.hostname,
proxy_url.port,
context=context,
)
transfer_func(
transfer_service,
proxy_connection,
proxy_url,
transfer.signed_ticket
)
return True
finally:
transfer_service.finalize()
while transfer.phase in [
otypes.ImageTransferPhase.TRANSFERRING,
otypes.ImageTransferPhase.FINALIZING_SUCCESS,
]:
time.sleep(module.params['poll_interval'])
transfer = transfer_service.get()
if transfer.phase in [
otypes.ImageTransferPhase.UNKNOWN,
otypes.ImageTransferPhase.FINISHED_FAILURE,
otypes.ImageTransferPhase.FINALIZING_FAILURE,
otypes.ImageTransferPhase.CANCELLED,
]:
raise Exception(
"Error occurred while uploading image. The transfer is in %s" % transfer.phase
)
if not module.params.get('logical_unit'):
disks_service = connection.system_service().disks_service()
wait(
service=disks_service.service(module.params['id']),
condition=lambda d: d.status == otypes.DiskStatus.OK,
wait=module.params['wait'],
timeout=module.params['timeout'],
)
def download_disk_image(connection, module):
def _transfer(transfer_service, proxy_connection, proxy_url, transfer_ticket):
BUF_SIZE = 128 * 1024
transfer_headers = {
'Authorization': transfer_ticket,
}
proxy_connection.request(
'GET',
proxy_url.path,
headers=transfer_headers,
)
r = proxy_connection.getresponse()
path = module.params["download_image_path"]
image_size = int(r.getheader('Content-Length'))
with open(path, "wb") as mydisk:
pos = 0
while pos < image_size:
to_read = min(image_size - pos, BUF_SIZE)
chunk = r.read(to_read)
if not chunk:
raise RuntimeError("Socket disconnected")
mydisk.write(chunk)
pos += len(chunk)
return transfer(
connection,
module,
otypes.ImageTransferDirection.DOWNLOAD,
transfer_func=_transfer,
)
def upload_disk_image(connection, module):
def _transfer(transfer_service, proxy_connection, proxy_url, transfer_ticket):
BUF_SIZE = 128 * 1024
path = module.params['upload_image_path']
image_size = os.path.getsize(path)
proxy_connection.putrequest("PUT", proxy_url.path)
proxy_connection.putheader('Content-Length', "%d" % (image_size,))
proxy_connection.endheaders()
with open(path, "rb") as disk:
pos = 0
while pos < image_size:
to_read = min(image_size - pos, BUF_SIZE)
chunk = disk.read(to_read)
if not chunk:
transfer_service.pause()
raise RuntimeError("Unexpected end of file at pos=%d" % pos)
proxy_connection.send(chunk)
pos += len(chunk)
return transfer(
connection,
module,
otypes.ImageTransferDirection.UPLOAD,
transfer_func=_transfer,
)
class DisksModule(BaseModule):
def build_entity(self):
hosts_service = self._connection.system_service().hosts_service()
logical_unit = self._module.params.get('logical_unit')
disk = 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,
content_type=otypes.DiskContentType(
self._module.params.get('content_type')
) if self._module.params.get('content_type') else None,
sparse=self._module.params.get(
'sparse'
) if self._module.params.get(
'sparse'
) is not None else self._module.params.get('format') != 'raw',
openstack_volume_type=otypes.OpenStackVolumeType(
name=self.param('openstack_volume_type')
) if self.param('openstack_volume_type') else None,
provisioned_size=convert_to_bytes(
self._module.params.get('size')
),
storage_domains=[
otypes.StorageDomain(
name=self._module.params.get('storage_domain'),
),
],
quota=otypes.Quota(id=self._module.params.get('quota_id')) if self.param('quota_id') else None,
shareable=self._module.params.get('shareable'),
wipe_after_delete=self.param('wipe_after_delete'),
lun_storage=otypes.HostStorage(
host=otypes.Host(
id=get_id_by_name(hosts_service, self._module.params.get('host'))
) if self.param('host') else None,
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,
)
if hasattr(disk, 'initial_size') and self._module.params['upload_image_path']:
disk.initial_size = convert_to_bytes(
self._module.params.get('size')
)
return disk
def update_storage_domains(self, disk_id):
changed = False
disk_service = self._service.service(disk_id)
disk = disk_service.get()
sds_service = self._connection.system_service().storage_domains_service()
# We don't support move&copy for non file based storages:
if disk.storage_type != otypes.DiskStorageType.IMAGE:
return changed
# Initiate move:
if self._module.params['storage_domain']:
new_disk_storage_id = get_id_by_name(sds_service, self._module.params['storage_domain'])
changed = self.action(
action='move',
entity=disk,
action_condition=lambda d: new_disk_storage_id != d.storage_domains[0].id,
wait_condition=lambda d: d.status == otypes.DiskStatus.OK,
storage_domain=otypes.StorageDomain(
id=new_disk_storage_id,
),
post_action=lambda _: time.sleep(self._module.params['poll_interval']),
)['changed']
if self._module.params['storage_domains']:
for sd in self._module.params['storage_domains']:
new_disk_storage = search_by_name(sds_service, sd)
changed = changed or self.action(
action='copy',
entity=disk,
action_condition=(
lambda disk: new_disk_storage.id not in [sd.id for sd in disk.storage_domains]
),
wait_condition=lambda disk: disk.status == otypes.DiskStatus.OK,
storage_domain=otypes.StorageDomain(
id=new_disk_storage.id,
),
)['changed']
return changed
def _update_check(self, entity):
return (
equal(self._module.params.get('name'), entity.name) and
equal(self._module.params.get('description'), entity.description) and
equal(self.param('quota_id'), getattr(entity.quota, 'id', None)) and
equal(convert_to_bytes(self._module.params.get('size')), entity.provisioned_size) and
equal(self._module.params.get('shareable'), entity.shareable) and
equal(self.param('wipe_after_delete'), entity.wipe_after_delete)
)
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=self.param('activate'),
)
def update_check(self, entity):
return (
super(DiskAttachmentsModule, self)._update_check(follow_link(self._connection, entity.disk)) and
equal(self._module.params.get('interface'), str(entity.interface)) and
equal(self._module.params.get('bootable'), entity.bootable) and
equal(self.param('activate'), entity.active)
)
def searchable_attributes(module):
"""
Return all searchable disk attributes passed to module.
"""
attributes = {
'name': module.params.get('name'),
'Storage.name': module.params.get('storage_domain'),
'vm_names': module.params.get('vm_name'),
}
return dict((k, v) for k, v in attributes.items() if v is not None)
def get_vm_service(connection, module):
if module.params.get('vm_id') is not None or module.params.get('vm_name') is not None and module.params['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 = get_id_by_name(vms_service, module.params['vm_name'])
if vm_id is None:
module.fail_json(
msg="VM don't exists, please create it first."
)
return vms_service.vm_service(vm_id)
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(
choices=['present', 'absent', 'attached', 'detached', 'exported', 'imported'],
default='present'
),
id=dict(default=None),
name=dict(default=None, aliases=['alias']),
description=dict(default=None),
vm_name=dict(default=None),
vm_id=dict(default=None),
size=dict(default=None),
interface=dict(default=None,),
storage_domain=dict(default=None),
storage_domains=dict(default=None, type='list'),
profile=dict(default=None),
quota_id=dict(default=None),
format=dict(default='cow', choices=['raw', 'cow']),
content_type=dict(
default='data',
choices=['data', 'iso', 'hosted_engine', 'hosted_engine_sanlock', 'hosted_engine_metadata', 'hosted_engine_configuration']
),
sparse=dict(default=None, type='bool'),
bootable=dict(default=None, type='bool'),
shareable=dict(default=None, type='bool'),
logical_unit=dict(default=None, type='dict'),
download_image_path=dict(default=None),
upload_image_path=dict(default=None, aliases=['image_path']),
force=dict(default=False, type='bool'),
sparsify=dict(default=None, type='bool'),
openstack_volume_type=dict(default=None),
image_provider=dict(default=None),
host=dict(default=None),
wipe_after_delete=dict(type='bool', default=None),
activate=dict(default=None, type='bool'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
)
lun = module.params.get('logical_unit')
host = module.params['host']
# Fail when host is specified with the LUN id. Lun id is needed to identify
# an existing disk if already available inthe environment.
if (host and lun is None) or (host and lun.get("id") is None):
module.fail_json(
msg="Can not use parameter host ({0!s}) without "
"specifying the logical_unit id".format(host)
)
check_sdk(module)
check_params(module)
try:
disk = None
state = module.params['state']
auth = module.params.get('auth')
connection = create_connection(auth)
disks_service = connection.system_service().disks_service()
disks_module = DisksModule(
connection=connection,
module=module,
service=disks_service,
)
force_create = False
vm_service = get_vm_service(connection, module)
if lun:
disk = _search_by_lun(disks_service, lun.get('id'))
else:
disk = disks_module.search_entity(search_params=searchable_attributes(module))
if vm_service and disk:
# If the VM don't exist in VMs disks, but still it's found it means it was found
# for template with same name as VM, so we should force create the VM disk.
force_create = disk.id not in [a.disk.id for a in vm_service.disk_attachments_service().list() if a.disk]
ret = None
# First take care of creating the VM, if needed:
if state in ('present', 'detached', 'attached'):
# Always activate disk when its being created
if vm_service is not None and disk is None:
module.params['activate'] = True
ret = disks_module.create(
entity=disk if not force_create else None,
result_state=otypes.DiskStatus.OK if lun is None else None,
fail_condition=lambda d: d.status == otypes.DiskStatus.ILLEGAL if lun is None else False,
force_create=force_create,
)
is_new_disk = ret['changed']
ret['changed'] = ret['changed'] or disks_module.update_storage_domains(ret['id'])
# 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']
# Upload disk image in case it's new disk or force parameter is passed:
if module.params['upload_image_path'] and (is_new_disk or module.params['force']):
uploaded = upload_disk_image(connection, module)
ret['changed'] = ret['changed'] or uploaded
# Download disk image in case it's file don't exist or force parameter is passed:
if (
module.params['download_image_path'] and (not os.path.isfile(module.params['download_image_path']) or module.params['force'])
):
downloaded = download_disk_image(connection, module)
ret['changed'] = ret['changed'] or downloaded
# Disk sparsify, only if disk is of image type:
if not module.check_mode:
disk = disks_service.disk_service(module.params['id']).get()
if disk.storage_type == otypes.DiskStorageType.IMAGE:
ret = disks_module.action(
action='sparsify',
action_condition=lambda d: module.params['sparsify'],
wait_condition=lambda d: d.status == otypes.DiskStatus.OK,
)
# Export disk as image to glance domain
elif state == 'exported':
disk = disks_module.search_entity()
if disk is None:
module.fail_json(
msg="Can not export given disk '%s', it doesn't exist" %
module.params.get('name') or module.params.get('id')
)
if disk.storage_type == otypes.DiskStorageType.IMAGE:
ret = disks_module.action(
action='export',
action_condition=lambda d: module.params['image_provider'],
wait_condition=lambda d: d.status == otypes.DiskStatus.OK,
storage_domain=otypes.StorageDomain(name=module.params['image_provider']),
)
elif state == 'imported':
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()
entity_id = get_id_by_name(images_service, module.params['name'])
images_service.service(entity_id).import_(
storage_domain=otypes.StorageDomain(
name=module.params['storage_domain']
) if module.params['storage_domain'] else None,
disk=otypes.Disk(
name=module.params['name']
),
import_as_template=False,
)
# Wait for disk to appear in system:
disk = disks_module.wait_for_import(
condition=lambda t: t.status == otypes.DiskStatus.OK
)
ret = disks_module.create(result_state=otypes.DiskStatus.OK)
elif state == 'absent':
ret = disks_module.remove()
# If VM was passed attach/detach disks to/from the VM:
if vm_service:
disk_attachments_service = vm_service.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()
if lun is None:
wait(
service=disk_attachments_service.service(ret['id']),
condition=lambda d: follow_link(connection, d.disk).status == otypes.DiskStatus.OK,
wait=module.params['wait'],
timeout=module.params['timeout'],
)
elif state == 'detached':
ret = disk_attachments_module.remove()
# When the host parameter is specified and the disk is not being
# removed, refresh the information about the LUN.
if state != 'absent' and host:
hosts_service = connection.system_service().hosts_service()
host_id = get_id_by_name(hosts_service, host)
disks_service.disk_service(disk.id).refresh_lun(otypes.Host(id=host_id))
module.exit_json(**ret)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == "__main__":
main()

@ -1,120 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2017 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/>.
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_disk_info
short_description: Retrieve information about one or more oVirt/RHV disks
author: "Katerina Koukiou (@KKoukiou)"
version_added: "2.5"
description:
- "Retrieve information about one or more oVirt/RHV disks."
- This module was called C(ovirt_disk_facts) before Ansible 2.9, returning C(ansible_facts).
Note that the M(ovirt_disk_info) module no longer returns C(ansible_facts)!
notes:
- "This module returns a variable C(ovirt_disks), which
contains a list of disks. You need to register the result with
the I(register) keyword to use it."
options:
pattern:
description:
- "Search term which is accepted by oVirt/RHV search backend."
- "For example to search Disk X from storage Y use following pattern:
name=X and storage.name=Y"
extends_documentation_fragment: ovirt_info
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather information about all Disks which names start with C(centos)
- ovirt_disk_info:
pattern: name=centos*
register: result
- debug:
msg: "{{ result.ovirt_disks }}"
'''
RETURN = '''
ovirt_disks:
description: "List of dictionaries describing the Disks. Disk attributes are mapped to dictionary keys,
all Disks attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/disk."
returned: On success.
type: list
'''
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
pattern=dict(default='', required=False),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name == 'ovirt_disk_facts'
if is_old_facts:
module.deprecate("The 'ovirt_disk_facts' module has been renamed to 'ovirt_disk_info', "
"and the renamed one no longer returns ansible_facts", version='2.13')
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
disks_service = connection.system_service().disks_service()
disks = disks_service.list(
search=module.params['pattern'],
)
result = dict(
ovirt_disks=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in disks
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

@ -1,249 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright: (c) 2019, Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_event
short_description: Create or delete an event in oVirt/RHV
author: "Chris Keller (@nasx)"
version_added: "2.8"
description:
- "This module can be used to create or delete an event in oVirt/RHV."
options:
state:
description:
- "Should the event be present/absent."
- "The C(wait) option must be set to false when state is absent."
choices: ['present', 'absent']
type: str
default: present
description:
description:
- "Message for the event."
- "Required when state is present."
type: str
severity:
description:
- "Severity of the event."
- "Required when state is present."
choices: ['error', 'normal', 'warning']
default: normal
type: str
origin:
description:
- "Originator of the event."
- "Required when state is present."
type: str
custom_id:
description:
- "Custom ID for the event. This ID must be unique for each event."
- "Required when state is present."
type: int
id:
description:
- "The event ID in the oVirt/RHV audit_log table. This ID is not the same as custom_id and is only used when state is absent."
- "Required when state is absent."
type: str
cluster:
description:
- "The id of the cluster associated with this event."
type: str
data_center:
description:
- "The id of the data center associated with this event."
type: str
host:
description:
- "The id of the host associated with this event."
type: str
storage_domain:
description:
- "The id of the storage domain associated with this event."
type: str
template:
description:
- "The id of the template associated with this event."
type: str
user:
description:
- "The id of the user associated with this event."
type: str
vm:
description:
- "The id of the VM associated with this event."
type: str
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain the auth parameter for simplicity,
# look at the ovirt_auth module to see how to reuse authentication.
- name: Create an event
ovirt_event:
state: present
description: "The file system /home on host xyz is almost full!"
origin: "mymonitor"
custom_id: 123456789
severity: warning
- name: Create an event and link it to a specific object
ovirt_event:
state: present
description: "The file system /home is almost full!"
origin: "mymonitor"
custom_id: 123456789
severity: warning
vm: "c79db183-46ef-44d1-95f9-1a368c516c19"
- name: Remove an event
ovirt_event:
state: absent
id: 123456789
wait: false
'''
RETURN = '''
id:
description: "ID of the event that was created."
returned: "On success."
type: str
event:
description: "Dictionary of all the Event attributes. All event attributes can be found at the following url:
http://ovirt.github.io/ovirt-engine-api-model/master/#types/event"
returned: "On success."
type: dict
'''
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,
get_dict_of_struct,
ovirt_full_argument_spec,
)
class EventsModule(BaseModule):
def build_entity(self):
return otypes.Event(
description=self._module.params['description'],
severity=otypes.LogSeverity(self._module.params['severity']),
origin=self._module.params['origin'],
custom_id=self._module.params['custom_id'],
id=self._module.params['id'],
cluster=otypes.Cluster(
id=self._module.params['cluster']
) if self._module.params['cluster'] is not None else None,
data_center=otypes.DataCenter(
id=self._module.params['data_center']
) if self._module.params['data_center'] is not None else None,
host=otypes.Host(
id=self._module.params['host']
) if self._module.params['host'] is not None else None,
storage_domain=otypes.StorageDomain(
id=self._module.params['storage_domain']
) if self._module.params['storage_domain'] is not None else None,
template=otypes.Template(
id=self._module.params['template']
) if self._module.params['template'] is not None else None,
user=otypes.User(
id=self._module.params['user']
) if self._module.params['user'] is not None else None,
vm=otypes.Vm(
id=self._module.params['vm']
) if self._module.params['vm'] is not None else None,
)
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(
choices=['present', 'absent'],
default='present',
),
description=dict(default=None),
severity=dict(
choices=['error', 'normal', 'warning'],
default='normal',
),
origin=dict(default=None),
custom_id=dict(default=None, type='int'),
id=dict(default=None),
cluster=dict(default=None),
data_center=dict(default=None),
host=dict(default=None),
storage_domain=dict(default=None),
template=dict(default=None),
user=dict(default=None),
vm=dict(default=None),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True
)
check_sdk(module)
# Wait must be set to false if state == absent
if module.params['state'] == 'absent' and module.params['wait'] is not False:
module.fail_json(msg='When "state" is absent, "wait" must be set to false.')
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
events_service = connection.system_service().events_service()
events_module = EventsModule(
connection=connection,
module=module,
service=events_service,
)
state = module.params['state']
if state == 'present':
ret = events_module.create()
elif state == 'absent':
ret = events_module.remove()
module.exit_json(**ret)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == "__main__":
main()

@ -1,170 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright: (c) 2019, Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_event_info
short_description: This module can be used to retrieve information about one or more oVirt/RHV events
author: "Chris Keller (@nasx)"
version_added: "2.8"
description:
- "Retrieve information about one or more oVirt/RHV events."
- This module was called C(ovirt_event_facts) before Ansible 2.9, returning C(ansible_facts).
Note that the M(ovirt_event_info) module no longer returns C(ansible_facts)!
options:
case_sensitive:
description:
- "Indicates if the search performed using the search parameter should be performed taking case
into account. The default value is true, which means that case is taken into account. If you
want to search ignoring case set it to false."
required: false
default: true
type: bool
from_:
description:
- "Indicates the event index after which events should be returned. The indexes of events are
strictly increasing, so when this parameter is used only the events with greater indexes
will be returned."
required: false
type: int
max:
description:
- "Sets the maximum number of events to return. If not specified all the events are returned."
required: false
type: int
search:
description:
- "Search term which is accepted by the oVirt/RHV API."
- "For example to search for events of severity alert use the following pattern: severity=alert"
required: false
type: str
headers:
description:
- "Additional HTTP headers."
required: false
type: str
query:
description:
- "Additional URL query parameters."
required: false
type: str
wait:
description:
- "If True wait for the response."
required: false
default: true
type: bool
extends_documentation_fragment: ovirt_info
'''
EXAMPLES = '''
# Examples don't contain the auth parameter for simplicity,
# look at the ovirt_auth module to see how to reuse authentication.
- name: Return all events
ovirt_event_info:
register: result
- name: Return the last 10 events
ovirt_event_info:
max: 10
register: result
- name: Return all events of type alert
ovirt_event_info:
search: "severity=alert"
register: result
- debug:
msg: "{{ result.ovirt_events }}"
'''
RETURN = '''
ovirt_events:
description: "List of dictionaries describing the events. Event attributes are mapped to dictionary keys.
All event attributes can be found at the following url:
http://ovirt.github.io/ovirt-engine-api-model/master/#types/event"
returned: On success."
type: list
'''
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
case_sensitive=dict(default=True, type='bool', required=False),
from_=dict(default=None, type='int', required=False),
max=dict(default=None, type='int', required=False),
search=dict(default='', required=False),
headers=dict(default='', required=False),
query=dict(default='', required=False),
wait=dict(default=True, type='bool', required=False)
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name == 'ovirt_event_facts'
if is_old_facts:
module.deprecate("The 'ovirt_event_facts' module has been renamed to 'ovirt_event_info', "
"and the renamed one no longer returns ansible_facts", version='2.13')
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
events_service = connection.system_service().events_service()
events = events_service.list(
case_sensitive=module.params['case_sensitive'],
from_=module.params['from_'],
max=module.params['max'],
search=module.params['search'],
headers=module.params['headers'],
query=module.params['query'],
wait=module.params['wait']
)
result = dict(
ovirt_events=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in events
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

@ -1,406 +0,0 @@
#!/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/>.
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_external_provider
short_description: Module to manage external providers in oVirt/RHV
version_added: "2.3"
author: "Ondra Machacek (@machacekondra)"
description:
- "Module to manage external providers in oVirt/RHV"
options:
name:
description:
- "Name of the external provider to manage."
state:
description:
- "Should the external be present or absent"
- "When you are using absent for I(os_volume), you need to make
sure that SD is not attached to the data center!"
choices: ['present', 'absent']
default: present
description:
description:
- "Description of the external provider."
type:
description:
- "Type of the external provider."
choices: ['os_image', 'network', 'os_volume', 'foreman']
url:
description:
- "URL where external provider is hosted."
- "Applicable for those types: I(os_image), I(os_volume), I(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(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(network)."
aliases: ['auth_url']
data_center:
description:
- "Name of the data center where provider should be attached."
- "Applicable for those type: I(os_volume)."
read_only:
description:
- "Specify if the network should be read only."
- "Applicable if C(type) is I(network)."
type: bool
network_type:
description:
- "Type of the external network provider either external (for example OVN) or neutron."
- "Applicable if C(type) is I(network)."
choices: ['external', 'neutron']
default: ['external']
authentication_keys:
description:
- "List of authentication keys. Each key is represented by dict
like {'uuid': 'our-uuid', 'value': 'YourSecretValue=='}"
- "When you will not pass these keys and there are already some
of them defined in the system they will be removed."
- "Applicable for I(os_volume)."
default: []
version_added: "2.6"
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_provider:
name: image_provider
type: os_image
url: http://1.2.3.4:9292
username: admin
password: 123456
tenant: admin
auth_url: http://1.2.3.4:35357/v2.0
# Add volume external provider:
- ovirt_external_provider:
name: image_provider
type: os_volume
url: http://1.2.3.4:9292
username: admin
password: 123456
tenant: admin
auth_url: http://1.2.3.4:5000/v2.0
authentication_keys:
-
uuid: "1234567-a1234-12a3-a234-123abc45678"
value: "ABCD00000000111111222333445w=="
# Add foreman provider:
- ovirt_external_provider:
name: foreman_provider
type: foreman
url: https://foreman.example.com
username: admin
password: 123456
# Add external network provider for OVN:
- ovirt_external_provider:
name: ovn_provider
type: network
network_type: external
url: http://1.2.3.4:9696
# Remove image external provider:
- ovirt_external_provider:
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/RHV instance
at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/external_host_provider."
returned: "On success and if parameter 'type: foreman' is used."
type: dict
openstack_image_provider:
description: "Dictionary of all the openstack_image_provider attributes. External provider attributes can be found on your oVirt/RHV instance
at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/openstack_image_provider."
returned: "On success and if parameter 'type: os_image' is used."
type: dict
openstack_volume_provider:
description: "Dictionary of all the openstack_volume_provider attributes. External provider attributes can be found on your oVirt/RHV instance
at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/openstack_volume_provider."
returned: "On success and if parameter 'type: os_volume' is used."
type: dict
openstack_network_provider:
description: "Dictionary of all the openstack_network_provider attributes. External provider attributes can be found on your oVirt/RHV instance
at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/openstack_network_provider."
returned: "On success and if parameter 'type: network' is used."
type: dict
'''
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,
)
OS_VOLUME = 'os_volume'
OS_IMAGE = 'os_image'
NETWORK = 'network'
FOREMAN = 'foreman'
class ExternalProviderModule(BaseModule):
non_provider_params = ['type', 'authentication_keys', 'data_center']
def provider_type(self, provider_type):
self._provider_type = provider_type
def provider_module_params(self):
provider_params = [
(key, value) for key, value in self._module.params.items() if key
not in self.non_provider_params
]
provider_params.append(('data_center', self.get_data_center()))
return provider_params
def get_data_center(self):
dc_name = self._module.params.get("data_center", None)
if dc_name:
system_service = self._connection.system_service()
data_centers_service = system_service.data_centers_service()
return data_centers_service.list(
search='name=%s' % dc_name,
)[0]
return dc_name
def build_entity(self):
provider_type = self._provider_type(
requires_authentication=self._module.params.get('username') is not None,
)
if self._module.params.pop('type') == NETWORK:
setattr(
provider_type,
'type',
otypes.OpenStackNetworkProviderType(self._module.params.pop('network_type'))
)
for key, value in self.provider_module_params():
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 update_volume_provider_auth_keys(
self, provider, providers_service, keys
):
"""
Update auth keys for volume provider, if not exist add them or remove
if they are not specified and there are already defined in the external
volume provider.
Args:
provider (dict): Volume provider details.
providers_service (openstack_volume_providers_service): Provider
service.
keys (list): Keys to be updated/added to volume provider, each key
is represented as dict with keys: uuid, value.
"""
provider_service = providers_service.provider_service(provider['id'])
auth_keys_service = provider_service.authentication_keys_service()
provider_keys = auth_keys_service.list()
# removing keys which are not defined
for key in [
k.id for k in provider_keys if k.uuid not in [
defined_key['uuid'] for defined_key in keys
]
]:
self.changed = True
if not self._module.check_mode:
auth_keys_service.key_service(key).remove()
if not (provider_keys or keys):
# Nothing need to do when both are empty.
return
for key in keys:
key_id_for_update = None
for existing_key in provider_keys:
if key['uuid'] == existing_key.uuid:
key_id_for_update = existing_key.id
auth_key_usage_type = (
otypes.OpenstackVolumeAuthenticationKeyUsageType("ceph")
)
auth_key = otypes.OpenstackVolumeAuthenticationKey(
usage_type=auth_key_usage_type,
uuid=key['uuid'],
value=key['value'],
)
if not key_id_for_update:
self.changed = True
if not self._module.check_mode:
auth_keys_service.add(auth_key)
else:
# We cannot really distinguish here if it was really updated cause
# we cannot take key value to check if it was changed or not. So
# for sure we update here always.
self.changed = True
if not self._module.check_mode:
auth_key_service = (
auth_keys_service.key_service(key_id_for_update)
)
auth_key_service.update(auth_key)
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 == 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, 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),
read_only=dict(default=None, type='bool'),
network_type=dict(
default='external',
choices=['external', 'neutron'],
),
authentication_keys=dict(
default=[], aliases=['auth_keys'], type='list', no_log=True,
),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
)
check_sdk(module)
check_params(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
provider_type_param = module.params.get('type')
provider_type, external_providers_service = _external_provider_service(
provider_type=provider_type_param,
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()
openstack_volume_provider_id = ret.get('id')
if (
provider_type_param == OS_VOLUME and
openstack_volume_provider_id
):
external_providers_module.update_volume_provider_auth_keys(
ret, external_providers_service,
module.params.get('authentication_keys'),
)
module.exit_json(**ret)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == "__main__":
main()

@ -1,161 +0,0 @@
#!/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/>.
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_external_provider_info
short_description: Retrieve information about one or more oVirt/RHV external providers
author: "Ondra Machacek (@machacekondra)"
version_added: "2.3"
description:
- "Retrieve information about one or more oVirt/RHV external providers."
- This module was called C(ovirt_external_provider_facts) before Ansible 2.9, returning C(ansible_facts).
Note that the M(ovirt_external_provider_info) module no longer returns C(ansible_facts)!
notes:
- "This module returns a variable C(ovirt_external_providers), which
contains a list of external_providers. You need to register the result with
the I(register) keyword to use it."
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_info
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather information about all image external providers named C<glance>:
- ovirt_external_provider_info:
type: os_image
name: glance
register: result
- debug:
msg: "{{ result.ovirt_external_providers }}"
'''
RETURN = '''
ovirt_external_providers:
description:
- "List of dictionaries. Content depends on I(type)."
- "For type C(foreman), attributes appearing in the dictionary can be found on your oVirt/RHV instance
at the following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/external_host_provider."
- "For type C(os_image), attributes appearing in the dictionary can be found on your oVirt/RHV instance
at the following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/openstack_image_provider."
- "For type C(os_volume), attributes appearing in the dictionary can be found on your oVirt/RHV instance
at the following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/openstack_volume_provider."
- "For type C(os_network), attributes appearing in the dictionary can be found on your oVirt/RHV instance
at the following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/openstack_network_provider."
returned: On success
type: list
'''
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_info_full_argument_spec,
)
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_info_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)
is_old_facts = module._name == 'ovirt_external_provider_facts'
if is_old_facts:
module.deprecate("The 'ovirt_external_provider_facts' module has been renamed to 'ovirt_external_provider_info', "
"and the renamed one no longer returns ansible_facts", version='2.13')
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(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()
result = dict(
ovirt_external_providers=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in external_providers
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

@ -1,185 +0,0 @@
#!/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/>.
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_group
short_description: Module to manage groups in oVirt/RHV
version_added: "2.3"
author: "Ondra Machacek (@machacekondra)"
description:
- "Module to manage groups in oVirt/RHV"
options:
name:
description:
- "Name of 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/RHV 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_group:
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_group:
name: group1
namespace: dc=ad2,dc=example,dc=com
domain: example.com-authz
# Remove group group1 with authorization provider example.com-authz
- ovirt_group:
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/RHV instance
at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/group."
returned: On success if group is found.
type: dict
'''
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,
)
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/RHV 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:
auth = module.params.pop('auth')
connection = create_connection(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=auth.get('token') is None)
if __name__ == "__main__":
main()

@ -1,118 +0,0 @@
#!/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/>.
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_group_info
short_description: Retrieve information about one or more oVirt/RHV groups
author: "Ondra Machacek (@machacekondra)"
version_added: "2.3"
description:
- "Retrieve information about one or more oVirt/RHV groups."
- This module was called C(ovirt_group_facts) before Ansible 2.9, returning C(ansible_facts).
Note that the M(ovirt_group_info) module no longer returns C(ansible_facts)!
notes:
- "This module returns a variable C(ovirt_groups), which
contains a list of groups. You need to register the result with
the I(register) keyword to use it."
options:
pattern:
description:
- "Search term which is accepted by oVirt/RHV search backend."
- "For example to search group X use following pattern: name=X"
extends_documentation_fragment: ovirt_info
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather information about all groups which names start with C(admin):
- ovirt_group_info:
pattern: name=admin*
register: result
- debug:
msg: "{{ result.ovirt_groups }}"
'''
RETURN = '''
ovirt_groups:
description: "List of dictionaries describing the groups. Group attributes are mapped to dictionary keys,
all groups attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/group."
returned: On success.
type: list
'''
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
pattern=dict(default='', required=False),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name == 'ovirt_group_facts'
if is_old_facts:
module.deprecate("The 'ovirt_group_facts' module has been renamed to 'ovirt_group_info', "
"and the renamed one no longer returns ansible_facts", version='2.13')
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
groups_service = connection.system_service().groups_service()
groups = groups_service.list(search=module.params['pattern'])
result = dict(
ovirt_groups=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in groups
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

@ -1,701 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_host
short_description: Module to manage hosts in oVirt/RHV
version_added: "2.3"
author: "Ondra Machacek (@machacekondra)"
description:
- "Module to manage hosts in oVirt/RHV"
options:
id:
description:
- "ID of the host to manage."
version_added: "2.8"
name:
description:
- "Name of the host to manage."
required: true
state:
description:
- "State which should a host to be in after successful completion."
- "I(iscsilogin) and I(iscsidiscover) are supported since version 2.4."
choices: [
'present', 'absent', 'maintenance', 'upgraded', 'started',
'restarted', 'stopped', 'reinstalled', 'iscsidiscover', 'iscsilogin'
]
default: present
comment:
description:
- "Description of the host."
timeout:
description:
- "The amount of time in seconds the module should wait for the host to
get into desired state."
default: 600
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
type: bool
aliases: ['ssh_public_key']
kdump_integration:
description:
- "Specify if host will have enabled Kdump integration."
choices: ['enabled', 'disabled']
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."
- "Note that C(override_iptables) is I(false) by default in oVirt/RHV."
type: bool
force:
description:
- "Indicates that the host should be removed even if it is non-responsive,
or if it is part of a Gluster Storage cluster and has volume bricks on it."
- "WARNING: It doesn't forcibly remove the host if another host related operation is being executed on the host at the same time."
default: False
type: bool
override_display:
description:
- "Override the display address of all VMs on this host with specified address."
type: bool
kernel_params:
description:
- "List of kernel boot parameters."
- "Following are most common kernel parameters used for host:"
- "Hostdev Passthrough & SR-IOV: intel_iommu=on"
- "Nested Virtualization: kvm-intel.nested=1"
- "Unsafe Interrupts: vfio_iommu_type1.allow_unsafe_interrupts=1"
- "PCI Reallocation: pci=realloc"
- "C(Note:)"
- "Modifying kernel boot parameters settings can lead to a host boot failure.
Please consult the product documentation before doing any changes."
- "Kernel boot parameters changes require host deploy and restart. The host needs
to be I(reinstalled) successfully and then to be I(rebooted) for kernel boot parameters
to be applied."
hosted_engine:
description:
- "If I(deploy) it means this host should deploy also hosted engine
components."
- "If I(undeploy) it means this host should un-deploy hosted engine
components and this host will not function as part of the High
Availability cluster."
choices:
- 'deploy'
- 'undeploy'
power_management_enabled:
description:
- "Enable or disable power management of the host."
- "For more comprehensive setup of PM use C(ovirt_host_pm) module."
version_added: 2.4
type: bool
activate:
description:
- "If C(state) is I(present) activate the host."
- "This parameter is good to disable, when you don't want to change
the state of host when using I(present) C(state)."
default: True
type: bool
version_added: 2.4
iscsi:
description:
- "If C(state) is I(iscsidiscover) it means that the iscsi attribute is being
used to discover targets"
- "If C(state) is I(iscsilogin) it means that the iscsi attribute is being
used to login to the specified targets passed as part of the iscsi attribute"
suboptions:
username:
description:
- "A CHAP user name for logging into a target."
password:
description:
- "A CHAP password for logging into a target."
address:
description:
- "Address of the iSCSI storage server."
target:
description:
- "The target IQN for the storage device."
port:
description:
- "The port being used to connect with iscsi."
portal:
description:
- "The portal being used to connect with iscsi."
version_added: 2.10
version_added: 2.4
check_upgrade:
description:
- "If I(true) and C(state) is I(upgraded) run check for upgrade
action before executing upgrade action."
default: True
type: bool
version_added: 2.4
reboot_after_upgrade:
description:
- "If I(true) and C(state) is I(upgraded) reboot host after successful upgrade."
default: True
type: bool
version_added: 2.6
vgpu_placement:
description:
- If I(consolidated), each vGPU is placed on the first physical card with
available space. This is the default placement, utilizing all available
space on the physical cards.
- If I(separated), each vGPU is placed on a separate physical card, if
possible. This can be useful for improving vGPU performance.
choices: ['consolidated', 'separated']
version_added: 2.8
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 supporting SR-IOV.
# Note that override_iptables is false by default in oVirt/RHV:
- ovirt_host:
cluster: Default
name: myhost
address: 10.34.61.145
password: secret
override_iptables: true
kernel_params:
- intel_iommu=on
# Add host using public key
- ovirt_host:
public_key: true
cluster: Default
name: myhost2
address: 10.34.61.145
override_iptables: true
# Deploy hosted engine host
- ovirt_host:
cluster: Default
name: myhost2
password: secret
address: 10.34.61.145
override_iptables: true
hosted_engine: deploy
# Maintenance
- ovirt_host:
state: maintenance
name: myhost
# Restart host using power management:
- ovirt_host:
state: restarted
name: myhost
# Upgrade host
- ovirt_host:
state: upgraded
name: myhost
# discover iscsi targets
- ovirt_host:
state: iscsidiscover
name: myhost
iscsi:
username: iscsi_user
password: secret
address: 10.34.61.145
port: 3260
# login to iscsi targets
- ovirt_host:
state: iscsilogin
name: myhost
iscsi:
username: iscsi_user
password: secret
address: 10.34.61.145
target: "iqn.2015-07.com.mlipchuk2.redhat:444"
port: 3260
# Reinstall host using public key
- ovirt_host:
state: reinstalled
name: myhost
public_key: true
# Remove host
- ovirt_host:
state: absent
name: myhost
force: True
# Retry removing host when failed (https://bugzilla.redhat.com/show_bug.cgi?id=1719271)
- ovirt_host:
state: absent
name: myhost
register: result
until: not result.failed
retries: 6
delay: 20
# Change host Name
- ovirt_host:
id: 00000000-0000-0000-0000-000000000000
name: "new host name"
'''
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/RHV instance
at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/host."
returned: On success if host is found.
type: dict
iscsi_targets:
description: "List of host iscsi targets"
returned: On success if host is found and state is iscsidiscover.
type: list
'''
import time
import traceback
try:
import ovirtsdk4.types as otypes
from ovirtsdk4.types import HostStatus as hoststate
except ImportError:
pass
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
BaseModule,
check_sdk,
create_connection,
equal,
get_id_by_name,
ovirt_full_argument_spec,
wait,
)
class HostsModule(BaseModule):
def __init__(self, start_event=None, *args, **kwargs):
super(HostsModule, self).__init__(*args, **kwargs)
self.start_event = start_event
def build_entity(self):
return otypes.Host(
id=self._module.params.get('id'),
name=self.param('name'),
cluster=otypes.Cluster(
name=self.param('cluster')
) if self.param('cluster') else None,
comment=self.param('comment'),
address=self.param('address'),
root_password=self.param('password'),
ssh=otypes.Ssh(
authentication_method=otypes.SshAuthenticationMethod.PUBLICKEY,
) if self.param('public_key') else None,
spm=otypes.Spm(
priority=self.param('spm_priority'),
) if self.param('spm_priority') else None,
override_iptables=self.param('override_iptables'),
display=otypes.Display(
address=self.param('override_display'),
) if self.param('override_display') else None,
os=otypes.OperatingSystem(
custom_kernel_cmdline=' '.join(self.param('kernel_params')),
) if self.param('kernel_params') else None,
power_management=otypes.PowerManagement(
enabled=self.param('power_management_enabled'),
kdump_detection=self.param('kdump_integration') == 'enabled',
) if self.param('power_management_enabled') is not None or self.param('kdump_integration') else None,
vgpu_placement=otypes.VgpuPlacement(
self.param('vgpu_placement')
) if self.param('vgpu_placement') is not None else None,
)
def update_check(self, entity):
kernel_params = self.param('kernel_params')
return (
equal(self.param('comment'), entity.comment) and
equal(self.param('kdump_integration'), 'enabled' if entity.power_management.kdump_detection else 'disabled') and
equal(self.param('spm_priority'), entity.spm.priority) and
equal(self.param('name'), entity.name) and
equal(self.param('power_management_enabled'), entity.power_management.enabled) and
equal(self.param('override_display'), getattr(entity.display, 'address', None)) and
equal(self.param('vgpu_placement'), str(entity.vgpu_placement)) and
equal(
sorted(kernel_params) if kernel_params else None,
sorted(entity.os.custom_kernel_cmdline.split(' '))
)
)
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_reinstall(self, host):
wait(
service=self._service.service(host.id),
condition=lambda h: h.status != hoststate.MAINTENANCE,
fail_condition=failed_state,
wait=self.param('wait'),
timeout=self.param('timeout'),
)
def raise_host_exception(self):
events = self._connection.system_service().events_service().list(from_=int(self.start_event.index))
error_events = [
event.description for event in events
if event.host is not None and (event.host.id == self.param('id') or event.host.name == self.param('name')) and
event.severity in [otypes.LogSeverity.WARNING, otypes.LogSeverity.ERROR]
]
if error_events:
raise Exception("Error message: %s" % error_events)
return True
def failed_state_after_reinstall(self, host, count=0):
if host.status in [
hoststate.ERROR,
hoststate.INSTALL_FAILED,
hoststate.NON_OPERATIONAL,
]:
return self.raise_host_exception()
# If host is in non-responsive state after upgrade/install
# let's wait for few seconds and re-check again the state:
if host.status == hoststate.NON_RESPONSIVE:
if count <= 3:
time.sleep(20)
return self.failed_state_after_reinstall(
self._service.service(host.id).get(),
count + 1,
)
else:
return self.raise_host_exception()
return False
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):
# In case host is in INSTALL_FAILED status, we can reinstall it:
if hoststate.INSTALL_FAILED == host.status and state != 'reinstalled':
raise Exception(
"Not possible to manage host '%s' in state '%s'." % (
host.name,
host.status
)
)
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,
)
return host
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(
choices=[
'present', 'absent', 'maintenance', 'upgraded', 'started',
'restarted', 'stopped', 'reinstalled', 'iscsidiscover', 'iscsilogin'
],
default='present',
),
name=dict(required=True),
id=dict(default=None),
comment=dict(default=None),
cluster=dict(default=None),
address=dict(default=None),
password=dict(default=None, no_log=True),
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'),
override_display=dict(default=None),
kernel_params=dict(default=None, type='list'),
hosted_engine=dict(default=None, choices=['deploy', 'undeploy']),
power_management_enabled=dict(default=None, type='bool'),
activate=dict(default=True, type='bool'),
iscsi=dict(default=None, type='dict'),
check_upgrade=dict(default=True, type='bool'),
reboot_after_upgrade=dict(default=True, type='bool'),
vgpu_placement=dict(default=None, choices=['consolidated', 'separated']),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'iscsidiscover', ['iscsi']],
['state', 'iscsilogin', ['iscsi']]
]
)
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
hosts_service = connection.system_service().hosts_service()
start_event = connection.system_service().events_service().list(max=1)[0]
hosts_module = HostsModule(
connection=connection,
module=module,
service=hosts_service,
start_event=start_event,
)
state = module.params['state']
host = control_state(hosts_module)
if state == 'present':
ret = hosts_module.create(
deploy_hosted_engine=(
module.params.get('hosted_engine') == 'deploy'
) if module.params.get('hosted_engine') is not None else None,
activate=module.params['activate'],
result_state=(hoststate.MAINTENANCE if module.params['activate'] is False else hoststate.UP) if host is None else None,
fail_condition=hosts_module.failed_state_after_reinstall if host is None else lambda h: False,
)
if module.params['activate'] and host is not None:
ret = hosts_module.action(
action='activate',
action_condition=lambda h: h.status != hoststate.UP,
wait_condition=lambda h: h.status == hoststate.UP,
fail_condition=failed_state,
)
elif state == 'absent':
ret = hosts_module.remove()
elif state == 'maintenance':
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,
)
ret = hosts_module.create()
elif state == 'upgraded':
result_state = hoststate.MAINTENANCE if host.status == hoststate.MAINTENANCE else hoststate.UP
events_service = connection.system_service().events_service()
last_event = events_service.list(max=1)[0]
if module.params['check_upgrade']:
hosts_module.action(
action='upgrade_check',
action_condition=lambda host: not host.update_available,
wait_condition=lambda host: host.update_available or (
len([
event
for event in events_service.list(
from_=int(last_event.id),
search='type=885',
# Uncomment when 4.1 is EOL, and remove the cond:
# if host.name in event.description
# search='type=885 and host.name=%s' % host.name,
) if host.name in event.description
]) > 0
),
fail_condition=lambda host: len([
event
for event in events_service.list(
from_=int(last_event.id),
search='type=839 or type=887 and host.name=%s' % host.name,
)
]) > 0,
)
# Set to False, because upgrade_check isn't 'changing' action:
hosts_module._changed = False
ret = hosts_module.action(
action='upgrade',
action_condition=lambda h: h.update_available,
wait_condition=lambda h: h.status == result_state,
post_action=lambda h: time.sleep(module.params['poll_interval']),
fail_condition=lambda h: hosts_module.failed_state_after_reinstall(h) or (
len([
event
for event in events_service.list(
from_=int(last_event.id),
# Fail upgrade if migration fails:
# 17: Failed to switch Host to Maintenance mode
# 65, 140: Migration failed
# 166: No available host was found to migrate VM
search='type=65 or type=140 or type=166 or type=17',
) if host.name in event.description
]) > 0
),
reboot=module.params['reboot_after_upgrade'],
)
elif state == 'iscsidiscover':
host_id = get_id_by_name(hosts_service, module.params['name'])
iscsi_param = module.params['iscsi']
iscsi_targets = hosts_service.service(host_id).iscsi_discover(
iscsi=otypes.IscsiDetails(
port=int(iscsi_param.get('port', 3260)),
username=iscsi_param.get('username'),
password=iscsi_param.get('password'),
address=iscsi_param.get('address'),
portal=iscsi_param.get('portal'),
),
)
ret = {
'changed': False,
'id': host_id,
'iscsi_targets': iscsi_targets,
}
elif state == 'iscsilogin':
host_id = get_id_by_name(hosts_service, module.params['name'])
iscsi_param = module.params['iscsi']
ret = hosts_module.action(
action='iscsi_login',
iscsi=otypes.IscsiDetails(
port=int(iscsi_param.get('port', 3260)),
username=iscsi_param.get('username'),
password=iscsi_param.get('password'),
address=iscsi_param.get('address'),
target=iscsi_param.get('target'),
portal=iscsi_param.get('portal'),
),
)
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=hosts_module.failed_state_after_reinstall,
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 if module.params['wait'] else True,
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=hosts_module.failed_state_after_reinstall,
fence_type='restart',
)
elif state == 'reinstalled':
# Deactivate host if not in maintanence:
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,
)
# Reinstall host:
hosts_module.action(
action='install',
action_condition=lambda h: h.status == hoststate.MAINTENANCE,
post_action=hosts_module.post_reinstall,
wait_condition=lambda h: h.status == hoststate.MAINTENANCE,
fail_condition=hosts_module.failed_state_after_reinstall,
host=otypes.Host(
override_iptables=module.params['override_iptables'],
) if module.params['override_iptables'] else None,
root_password=module.params['password'],
ssh=otypes.Ssh(
authentication_method=otypes.SshAuthenticationMethod.PUBLICKEY,
) if module.params['public_key'] else None,
deploy_hosted_engine=(
module.params.get('hosted_engine') == 'deploy'
) if module.params.get('hosted_engine') is not None else None,
undeploy_hosted_engine=(
module.params.get('hosted_engine') == 'undeploy'
) if module.params.get('hosted_engine') is not None else None,
)
# Activate host after reinstall:
ret = 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,
)
module.exit_json(**ret)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == "__main__":
main()

@ -1,144 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_host_info
short_description: Retrieve information about one or more oVirt/RHV hosts
author: "Ondra Machacek (@machacekondra)"
version_added: "2.3"
description:
- "Retrieve information about one or more oVirt/RHV hosts."
- This module was called C(ovirt_host_facts) before Ansible 2.9, returning C(ansible_facts).
Note that the M(ovirt_host_info) module no longer returns C(ansible_facts)!
notes:
- "This module returns a variable C(ovirt_hosts), which
contains a list of hosts. You need to register the result with
the I(register) keyword to use it."
options:
pattern:
description:
- "Search term which is accepted by oVirt/RHV search backend."
- "For example to search host X from datacenter Y use following pattern:
name=X and datacenter=Y"
all_content:
description:
- "If I(true) all the attributes of the hosts should be
included in the response."
default: False
version_added: "2.7"
type: bool
cluster_version:
description:
- "Filter the hosts based on the cluster version."
type: str
version_added: "2.8"
extends_documentation_fragment: ovirt_info
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather information about all hosts which names start with C(host) and
# belong to data center C(west):
- ovirt_host_info:
pattern: name=host* and datacenter=west
register: result
- debug:
msg: "{{ result.ovirt_hosts }}"
# All hosts with cluster version 4.2:
- ovirt_host_info:
pattern: name=host*
cluster_version: "4.2"
register: result
- debug:
msg: "{{ result.ovirt_hosts }}"
'''
RETURN = '''
ovirt_hosts:
description: "List of dictionaries describing the hosts. Host attributes are mapped to dictionary keys,
all hosts attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/host."
returned: On success.
type: list
'''
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
)
def get_filtered_hosts(cluster_version, hosts, connection):
# Filtering by cluster version returns only those which have same cluster version as input
filtered_hosts = []
for host in hosts:
cluster = connection.follow_link(host.cluster)
cluster_version_host = str(cluster.version.major) + '.' + str(cluster.version.minor)
if cluster_version_host == cluster_version:
filtered_hosts.append(host)
return filtered_hosts
def main():
argument_spec = ovirt_info_full_argument_spec(
pattern=dict(default='', required=False),
all_content=dict(default=False, type='bool'),
cluster_version=dict(default=None, type='str'),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name == 'ovirt_host_facts'
if is_old_facts:
module.deprecate("The 'ovirt_host_facts' module has been renamed to 'ovirt_host_info', "
"and the renamed one no longer returns ansible_facts", version='2.13')
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
hosts_service = connection.system_service().hosts_service()
hosts = hosts_service.list(
search=module.params['pattern'],
all_content=module.params['all_content']
)
cluster_version = module.params.get('cluster_version')
if cluster_version is not None:
hosts = get_filtered_hosts(cluster_version, hosts, connection)
result = dict(
ovirt_hosts=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in hosts
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

@ -1,601 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016, 2018 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/>.
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_host_network
short_description: Module to manage host networks in oVirt/RHV
version_added: "2.3"
author: "Ondra Machacek (@machacekondra)"
description:
- "Module to manage host networks in oVirt/RHV."
options:
name:
description:
- "Name of the host to manage networks for."
required: true
aliases:
- 'host'
state:
description:
- "Should the host be present/absent."
choices: ['present', 'absent']
default: present
bond:
description:
- "Dictionary describing network bond:"
suboptions:
name:
description:
- Bond name.
mode:
description:
- Bonding mode.
options:
description:
- Bonding options.
interfaces:
description:
- 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:"
suboptions:
name:
description:
- Name of the logical network to be assigned to bond or interface.
boot_protocol:
description:
- Boot protocol.
choices: ['none', 'static', 'dhcp']
address:
description:
- IP address in case of I(static) boot protocol is used.
netmask:
description:
- Subnet mask in case of I(static) boot protocol is used.
gateway:
description:
- Gateway in case of I(static) boot protocol is used.
version:
description:
- IP version. Either v4 or v6. Default is v4.
custom_properties:
description:
- "Custom properties applied to the host network."
- "Custom properties is a list of dictionary which can have following values."
suboptions:
name:
description:
- Name of custom property.
value:
description:
- Value of custom property.
version_added: 2.10
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."
type: bool
save:
description:
- "If I(true) network configuration will be persistent, otherwise it is temporary. Default I(true) since Ansible 2.8."
type: bool
default: True
sync_networks:
description:
- "If I(true) all networks will be synchronized before modification"
type: bool
default: false
version_added: 2.8
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# In all examples the durability of the configuration created is dependent on the 'save' option value:
# Create bond on eth0 and eth1 interface, and put 'myvlan' network on top of it and persist the new configuration:
- name: Bonds
ovirt_host_network:
name: myhost
save: yes
bond:
name: bond0
mode: 2
interfaces:
- eth1
- eth2
networks:
- name: myvlan
boot_protocol: static
address: 1.2.3.4
netmask: 255.255.255.0
gateway: 1.2.3.4
version: v4
# Create bond on eth1 and eth2 interface, specifying both mode and miimon:
- name: Bonds
ovirt_host_network:
name: myhost
bond:
name: bond0
mode: 1
options:
miimon: 200
interfaces:
- eth1
- eth2
# Remove bond0 bond from host interfaces:
- ovirt_host_network:
state: absent
name: myhost
bond:
name: bond0
# Assign myvlan1 and myvlan2 vlans to host eth0 interface:
- ovirt_host_network:
name: myhost
interface: eth0
networks:
- name: myvlan1
- name: myvlan2
# Remove myvlan2 vlan from host eth0 interface:
- ovirt_host_network:
state: absent
name: myhost
interface: eth0
networks:
- name: myvlan2
# Remove all networks/vlans from host eth0 interface:
- ovirt_host_network:
state: absent
name: myhost
interface: eth0
# Add custom_properties to network:
- ovirt_host_network:
name: myhost
interface: eth0
networks:
- name: myvlan1
custom_properties:
- name: bridge_opts
value: gc_timer=10
'''
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/RHV instance
at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/host_nic."
returned: On success if host NIC is found.
type: dict
'''
import traceback
try:
import ovirtsdk4.types as otypes
except ImportError:
pass
from ansible.module_utils import six
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
BaseModule,
check_sdk,
create_connection,
equal,
get_dict_of_struct,
get_entity,
get_link_name,
ovirt_full_argument_spec,
search_by_name,
engine_supported
)
def get_bond_options(mode, usr_opts):
MIIMON_100 = dict(miimon='100')
DEFAULT_MODE_OPTS = {
'1': MIIMON_100,
'2': MIIMON_100,
'3': MIIMON_100,
'4': dict(xmit_hash_policy='2', **MIIMON_100)
}
options = []
if mode is None:
return options
def get_type_name(mode_number):
"""
We need to maintain this type strings, for the __compare_options method,
for easier comparision.
"""
modes = [
'Active-Backup',
'Load balance (balance-xor)',
None,
'Dynamic link aggregation (802.3ad)',
]
if (not 0 < mode_number <= len(modes)):
return None
return modes[mode_number - 1]
try:
mode_number = int(mode)
except ValueError:
raise Exception('Bond mode must be a number.')
options.append(
otypes.Option(
name='mode',
type=get_type_name(mode_number),
value=str(mode_number)
)
)
opts_dict = DEFAULT_MODE_OPTS.get(str(mode), {})
if usr_opts is not None:
opts_dict.update(**usr_opts)
options.extend(
[otypes.Option(name=opt, value=str(value))
for opt, value in six.iteritems(opts_dict)]
)
return options
class HostNetworksModule(BaseModule):
def __compare_options(self, new_options, old_options):
return sorted((get_dict_of_struct(opt) for opt in new_options),
key=lambda x: x["name"]) != sorted((get_dict_of_struct(opt) for opt in old_options),
key=lambda x: x["name"])
def build_entity(self):
return otypes.Host()
def update_custom_properties(self, attachments_service, attachment, network):
if network.get('custom_properties'):
current = []
if attachment.properties:
current = [(cp.name, str(cp.value)) for cp in attachment.properties]
passed = [(cp.get('name'), str(cp.get('value'))) for cp in network.get('custom_properties') if cp]
if sorted(current) != sorted(passed):
attachment.properties = [
otypes.Property(
name=prop.get('name'),
value=prop.get('value')
) for prop in network.get('custom_properties')
]
if not self._module.check_mode:
attachments_service.service(attachment.id).update(attachment)
self.changed = True
def update_address(self, attachments_service, attachment, network):
# Check if there is any change in address assignments and
# update it if needed:
for ip in attachment.ip_address_assignments:
if str(ip.ip.version) == network.get('version', 'v4'):
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('netmask'), ip.ip.netmask):
ip.ip.netmask = network.get('netmask')
changed = True
if changed:
if not self._module.check_mode:
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']
labels = self._module.params['labels']
nic = get_entity(nic_service)
if nic is None:
return update
# Check if bond configuration should be updated:
if bond:
update = self.__compare_options(get_bond_options(bond.get('mode'), bond.get('options')), getattr(nic.bonding, 'options', []))
update = update or not equal(
sorted(bond.get('interfaces')) if bond.get('interfaces') else None,
sorted(get_link_name(self._connection, s) for s in nic.bonding.slaves)
)
# Check if labels need to be updated on interface/bond:
if labels:
net_labels = nic_service.network_labels_service().list()
# If any labels which user passed aren't assigned, relabel the interface:
if sorted(labels) != sorted([lbl.id for lbl in net_labels]):
return True
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 exists, we need to create it:
if attachment is None:
return True
self.update_custom_properties(attachments_service, attachment, network)
self.update_address(attachments_service, attachment, network)
return update
def _action_save_configuration(self, entity):
if not self._module.check_mode:
self._service.service(entity.id).commit_net_config()
self.changed = True
def needs_sync(nics_service):
nics = nics_service.list()
for nic in nics:
nic_service = nics_service.nic_service(nic.id)
for network_attachment_service in nic_service.network_attachments_service().list():
if not network_attachment_service.in_sync:
return True
return False
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(
choices=['present', 'absent'],
default='present',
),
name=dict(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=True, type='bool'),
sync_networks=dict(default=False, type='bool'),
)
module = AnsibleModule(argument_spec=argument_spec)
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(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']
host_service = hosts_service.host_service(host.id)
nics_service = host_service.nics_service()
nic = search_by_name(nics_service, nic_name)
if module.params["sync_networks"]:
if needs_sync(nics_service):
if not module.check_mode:
host_service.sync_all_networks()
host_networks_module.changed = True
network_names = [network['name'] for network in networks or []]
state = module.params['state']
if (
state == 'present' and
(nic is None or host_networks_module.has_update(nics_service.service(nic.id)))
):
# Remove networks which are attached to different interface then user want:
attachments_service = host_service.network_attachments_service()
# Append attachment ID to network if needs update:
for a in attachments_service.list():
current_network_name = get_link_name(connection, a.network)
if current_network_name in network_names:
for n in networks:
if n['name'] == current_network_name:
n['id'] = a.id
# Check if we have to break some bonds:
removed_bonds = []
if nic is not None:
for host_nic in nics_service.list():
if host_nic.bonding and nic.id in [slave.id for slave in host_nic.bonding.slaves]:
removed_bonds.append(otypes.HostNic(id=host_nic.id))
# Assign the networks:
setup_params = dict(
entity=host,
action='setup_networks',
check_connectivity=module.params['check'],
removed_bonds=removed_bonds if removed_bonds else None,
modified_bonds=[
otypes.HostNic(
name=bond.get('name'),
bonding=otypes.Bonding(
options=get_bond_options(bond.get('mode'), bond.get('options')),
slaves=[
otypes.HostNic(name=i) for i in bond.get('interfaces', [])
],
),
),
] if bond else None,
modified_labels=[
otypes.NetworkLabel(
id=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(
id=network.get('id'),
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,
),
),
],
properties=[
otypes.Property(
name=prop.get('name'),
value=prop.get('value')
) for prop in network.get('custom_properties')
]
) for network in networks
] if networks else None,
)
if engine_supported(connection, '4.3'):
setup_params['commit_on_success'] = module.params['save']
elif module.params['save']:
setup_params['post_action'] = host_networks_module._action_save_configuration
host_networks_module.action(**setup_params)
elif state == 'absent' and nic:
attachments = []
nic_service = nics_service.nic_service(nic.id)
attached_labels = set([str(lbl.id) for lbl in nic_service.network_labels_service().list()])
if networks:
attachments_service = nic_service.network_attachments_service()
attachments = attachments_service.list()
attachments = [
attachment for attachment in attachments
if get_link_name(connection, attachment.network) in network_names
]
# Remove unmanaged networks:
unmanaged_networks_service = host_service.unmanaged_networks_service()
unmanaged_networks = [(u.id, u.name) for u in unmanaged_networks_service.list()]
for net_id, net_name in unmanaged_networks:
if net_name in network_names:
if not module.check_mode:
unmanaged_networks_service.unmanaged_network_service(net_id).remove()
host_networks_module.changed = True
# Need to check if there are any labels to be removed, as backend fail
# if we try to send remove non existing label, for bond and attachments it's OK:
if (labels and set(labels).intersection(attached_labels)) or bond or attachments:
setup_params = dict(
entity=host,
action='setup_networks',
check_connectivity=module.params['check'],
removed_bonds=[
otypes.HostNic(
name=bond.get('name'),
),
] if bond else None,
removed_labels=[
otypes.NetworkLabel(id=str(name)) for name in labels
] if labels else None,
removed_network_attachments=attachments if attachments else None,
)
if engine_supported(connection, '4.3'):
setup_params['commit_on_success'] = module.params['save']
elif module.params['save']:
setup_params['post_action'] = host_networks_module._action_save_configuration
host_networks_module.action(**setup_params)
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), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == "__main__":
main()

@ -1,261 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_host_pm
short_description: Module to manage power management of hosts in oVirt/RHV
version_added: "2.3"
author: "Ondra Machacek (@machacekondra)"
description:
- "Module to manage power management of hosts in oVirt/RHV."
options:
name:
description:
- "Name of 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/RHV 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."
options:
description:
- "Dictionary of additional fence agent options (including Power Management slot)."
- "Additional information about options can be found at U(https://github.com/ClusterLabs/fence-agents/blob/master/doc/FenceAgentAPI.md)."
encrypt_options:
description:
- "If I(true) options will be encrypted when send to agent."
aliases: ['encrypt']
type: bool
order:
description:
- "Integer value specifying, by default it's added at the end."
version_added: "2.5"
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
# Add fence agent to host 'myhost' using 'slot' option
- ovirt_host_pm:
name: myhost
address: 1.2.3.4
options:
myoption1: x
myoption2: y
slot: myslot
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/RHV instance
at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/agent."
returned: On success if agent is found.
type: dict
'''
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,
)
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 pre_create(self, entity):
# Save the entity, so we know if Agent already existed
self.entity = entity
def build_entity(self):
last = next((s for s in sorted([a.order for a in self._service.list()])), 0)
order = self.param('order') if self.param('order') is not None else self.entity.order if self.entity else last + 1
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=order,
)
def update_check(self, entity):
def check_options():
if self.param('options'):
current = []
if entity.options:
current = [(opt.name, str(opt.value)) for opt in entity.options]
passed = [(k, str(v)) for k, v in self.param('options').items()]
return sorted(current) == sorted(passed)
return True
return (
check_options() and
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('username'), entity.username) and
equal(self._module.params.get('port'), entity.port) and
equal(self._module.params.get('type'), entity.type) and
equal(self._module.params.get('order'), entity.order)
)
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, no_log=True),
type=dict(default=None),
port=dict(default=None, type='int'),
order=dict(default=None, type='int'),
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:
auth = module.params.pop('auth')
connection = create_connection(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), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == "__main__":
main()

@ -1,182 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2017 Red Hat, Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_host_storage_info
short_description: Retrieve information about one or more oVirt/RHV HostStorages (applicable only for block storage)
author: "Daniel Erez (@derez)"
version_added: "2.4"
description:
- "Retrieve information about one or more oVirt/RHV HostStorages (applicable only for block storage)."
- This module was called C(ovirt_host_storage_facts) before Ansible 2.9, returning C(ansible_facts).
Note that the M(ovirt_host_storage_info) module no longer returns C(ansible_facts)!
options:
host:
description:
- "Host to get device list from."
required: true
iscsi:
description:
- "Dictionary with values for iSCSI storage type:"
suboptions:
address:
description:
- "Address of the iSCSI storage server."
target:
description:
- "The target IQN for the storage device."
username:
description:
- "A CHAP user name for logging into a target."
password:
description:
- "A CHAP password for logging into a target."
portal:
description:
- "The portal being used to connect with iscsi."
version_added: 2.10
fcp:
description:
- "Dictionary with values for fibre channel storage type:"
suboptions:
address:
description:
- "Address of the fibre channel storage server."
port:
description:
- "Port of the fibre channel storage server."
lun_id:
description:
- "LUN id."
extends_documentation_fragment: ovirt_info
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather information about HostStorages with specified target and address:
- ovirt_host_storage_info:
host: myhost
iscsi:
target: iqn.2016-08-09.domain-01:nickname
address: 10.34.63.204
register: result
- debug:
msg: "{{ result.ovirt_host_storages }}"
'''
RETURN = '''
ovirt_host_storages:
description: "List of dictionaries describing the HostStorage. HostStorage attributes are mapped to dictionary keys,
all HostStorage attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/host_storage."
returned: On success.
type: list
'''
import traceback
try:
import ovirtsdk4.types as otypes
except ImportError:
pass
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
get_id_by_name,
)
def _login(host_service, iscsi):
host_service.iscsi_login(
iscsi=otypes.IscsiDetails(
username=iscsi.get('username'),
password=iscsi.get('password'),
address=iscsi.get('address'),
target=iscsi.get('target'),
portal=iscsi.get('portal')
),
)
def _get_storage_type(params):
for sd_type in ['iscsi', 'fcp']:
if params.get(sd_type) is not None:
return sd_type
def main():
argument_spec = ovirt_info_full_argument_spec(
host=dict(required=True),
iscsi=dict(default=None, type='dict'),
fcp=dict(default=None, type='dict'),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name == 'ovirt_host_storage_facts'
if is_old_facts:
module.deprecate("The 'ovirt_host_storage_facts' module has been renamed to 'ovirt_host_storage_info', "
"and the renamed one no longer returns ansible_facts", version='2.13')
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
# Get Host
hosts_service = connection.system_service().hosts_service()
host_id = get_id_by_name(hosts_service, module.params['host'])
storage_type = _get_storage_type(module.params)
host_service = hosts_service.host_service(host_id)
if storage_type == 'iscsi':
# Login
iscsi = module.params.get('iscsi')
_login(host_service, iscsi)
# Get LUNs exposed from the specified target
host_storages = host_service.storage_service().list()
if storage_type == 'iscsi':
filterred_host_storages = [host_storage for host_storage in host_storages
if host_storage.type == otypes.StorageType.ISCSI]
if 'target' in iscsi:
filterred_host_storages = [host_storage for host_storage in filterred_host_storages
if iscsi.get('target') == host_storage.logical_units[0].target]
elif storage_type == 'fcp':
filterred_host_storages = [host_storage for host_storage in host_storages
if host_storage.type == otypes.StorageType.FCP]
result = dict(
ovirt_host_storages=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in filterred_host_storages
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

@ -1,592 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2017, Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_instance_type
short_description: Module to manage Instance Types in oVirt/RHV
version_added: "2.8"
author:
- Martin Necas (@mnecas)
- Ondra Machacek (@machacekondra)
description:
- This module manages whole lifecycle of the Instance Type in oVirt/RHV.
options:
name:
description:
- Name of the Instance Type to manage.
- If instance type don't exists C(name) is required. Otherwise C(id) or C(name) can be used.
id:
description:
- ID of the Instance Type to manage.
state:
description:
- Should the Instance Type be present/absent.
- I(present) state will create/update instance type and don't change its state if it already exists.
choices: [ absent, present ]
default: present
memory:
description:
- Amount of memory of the Instance Type. 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 Instance Type.
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.
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.
- 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 instance type in more depth please use M(ovirt_nic) module instead.
memory_max:
description:
- Upper bound of instance type memory up to which memory hot-plug can be performed.
Prefix uses IEC 60027-2 standard (for example 1GiB, 1024MiB).
- Default value is set by engine.
cpu_cores:
description:
- Number of virtual CPUs cores of the Instance Type.
- Default value is set by oVirt/RHV engine.
cpu_sockets:
description:
- Number of virtual CPUs sockets of the Instance Type.
- Default value is set by oVirt/RHV engine.
cpu_threads:
description:
- Number of virtual CPUs sockets of the Instance Type.
- Default value is set by oVirt/RHV engine.
operating_system:
description:
- Operating system of the Instance Type.
- Default value is set by oVirt/RHV engine.
- "Possible values: debian_7, freebsd, freebsdx64, other, other_linux,
other_linux_ppc64, other_ppc64, rhel_3, rhel_4, rhel_4x64, rhel_5, rhel_5x64,
rhel_6, rhel_6x64, rhel_6_ppc64, rhel_7x64, rhel_7_ppc64, sles_11, sles_11_ppc64,
ubuntu_12_04, ubuntu_12_10, ubuntu_13_04, ubuntu_13_10, ubuntu_14_04, ubuntu_14_04_ppc64,
windows_10, windows_10x64, windows_2003, windows_2003x64, windows_2008, windows_2008x64,
windows_2008r2x64, windows_2008R2x64, windows_2012x64, windows_2012R2x64, windows_7,
windows_7x64, windows_8, windows_8x64, windows_xp"
boot_devices:
description:
- List of boot devices which should be used to boot. For example C([ cdrom, hd ]).
- Default value is set by oVirt/RHV engine.
choices: [ cdrom, hd, network ]
serial_console:
description:
- "I(True) enable VirtIO serial console, I(False) to disable it. By default is chosen by oVirt/RHV engine."
type: bool
usb_support:
description:
- "I(True) enable USB support, I(False) to disable it. By default is chosen by oVirt/RHV engine."
type: bool
high_availability:
description:
- If I(yes) Instance Type will be set as highly available.
- If I(no) Instance Type won't be set as highly available.
- If no value is passed, default value is set by oVirt/RHV engine.
type: bool
high_availability_priority:
description:
- Indicates the priority of the instance type inside the run and migration queues.
Instance Type with higher priorities will be started and migrated before instance types with lower
priorities. The value is an integer between 0 and 100. The higher the value, the higher the priority.
- If no value is passed, default value is set by oVirt/RHV engine.
watchdog:
description:
- "Assign watchdog device for the instance type."
- "Watchdogs is a dictionary which can have following values:"
- "C(model) - Model of the watchdog device. For example: I(i6300esb), I(diag288) or I(null)."
- "C(action) - Watchdog action to be performed when watchdog is triggered. For example: I(none), I(reset), I(poweroff), I(pause) or I(dump)."
host:
description:
- Specify host where Instance Type 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).
graphical_console:
description:
- "Assign graphical console to the instance type."
- "Graphical console is a dictionary which can have following values:"
- "C(headless_mode) - If I(true) disable the graphics console for this instance type."
- "C(protocol) - Graphical protocol, a list of I(spice), I(vnc), or both."
description:
description:
- "Description of the instance type."
cpu_mode:
description:
- "CPU mode of the instance type. It can be some of the following: I(host_passthrough), I(host_model) or I(custom)."
- "For I(host_passthrough) CPU type you need to set C(placement_policy) to I(pinned)."
- "If no value is passed, default value is set by oVirt/RHV engine."
rng_device:
description:
- "Random number generator (RNG). You can choose of one the following devices I(urandom), I(random) or I(hwrng)."
- "In order to select I(hwrng), you must have it enabled on cluster first."
- "/dev/urandom is used for cluster version >= 4.1, and /dev/random for cluster version <= 4.0"
rng_bytes:
description:
- "Number of bytes allowed to consume per period."
rng_period:
description:
- "Duration of one period in milliseconds."
placement_policy:
description:
- "The configuration of the instance type's placement policy."
- "Placement policy can be one of the following values:"
- "C(migratable) - Allow manual and automatic migration."
- "C(pinned) - Do not allow migration."
- "C(user_migratable) - Allow manual migration only."
- "If no value is passed, default value is set by oVirt/RHV engine."
cpu_pinning:
description:
- "CPU Pinning topology to map instance type CPU to host CPU."
- "CPU Pinning topology is a list of dictionary which can have following values:"
- "C(cpu) - Number of the host CPU."
- "C(vcpu) - Number of the instance type CPU."
soundcard_enabled:
description:
- "If I(true), the sound card is added to the instance type."
type: bool
smartcard_enabled:
description:
- "If I(true), use smart card authentication."
type: bool
virtio_scsi:
description:
- "If I(true), virtio scsi will be enabled."
type: bool
io_threads:
description:
- "Number of IO threads used by instance type. I(0) means IO threading disabled."
ballooning_enabled:
description:
- "If I(true), use memory ballooning."
- "Memory balloon is a guest device, which may be used to re-distribute / reclaim the host memory
based on instance type needs in a dynamic way. In this way it's possible to create memory over commitment states."
type: bool
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 instance type
- name: Create instance type
ovirt_instance_type:
state: present
name: myit
rng_device: hwrng
rng_bytes: 200
rng_period: 200
soundcard_enabled: true
virtio_scsi: true
boot_devices:
- network
# Remove instance type
- ovirt_instance_type:
state: absent
name: myit
# Create instance type with predefined memory and cpu limits.
- ovirt_instance_type:
state: present
name: myit
memory: 2GiB
cpu_cores: 2
cpu_sockets: 2
nics:
- name: nic1
# Enable usb support and serial console
- ovirt_instance_type:
name: myit
usb_support: True
serial_console: True
# Use graphical console with spice and vnc
- name: Create a instance type that has the console configured for both Spice and VNC
ovirt_instance_type:
name: myit
graphical_console:
protocol:
- spice
- vnc
'''
RETURN = '''
id:
description: ID of the instance type which is managed
returned: On success if instance type is found.
type: str
sample: 7de90f31-222c-436c-a1ca-7e655bd5b60c
instancetype:
description: "Dictionary of all the instance type attributes. instance type attributes can be found on your oVirt/RHV instance
at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/instance_type."
returned: On success if instance type is found.
type: dict
'''
from ansible.module_utils.basic import AnsibleModule
import traceback
from ansible.module_utils.ovirt import (
BaseModule,
check_params,
check_sdk,
convert_to_bytes,
create_connection,
equal,
get_dict_of_struct,
get_entity,
get_link_name,
get_id_by_name,
ovirt_full_argument_spec,
search_by_attributes,
search_by_name,
wait,
)
try:
import ovirtsdk4.types as otypes
except ImportError:
pass
class InstanceTypeModule(BaseModule):
def build_entity(self):
return otypes.InstanceType(
id=self.param('id'),
name=self.param('name'),
console=(
otypes.Console(enabled=self.param('serial_console'))
) if self.param('serial_console') is not None else None,
usb=(
otypes.Usb(enabled=self.param('usb_support'))
) if self.param('usb_support') is not None else None,
high_availability=otypes.HighAvailability(
enabled=self.param('high_availability'),
priority=self.param('high_availability_priority'),
) if self.param('high_availability') is not None or self.param('high_availability_priority') else None,
cpu=otypes.Cpu(
topology=otypes.CpuTopology(
cores=self.param('cpu_cores'),
sockets=self.param('cpu_sockets'),
threads=self.param('cpu_threads'),
) if any((
self.param('cpu_cores'),
self.param('cpu_sockets'),
self.param('cpu_threads')
)) else None,
cpu_tune=otypes.CpuTune(
vcpu_pins=[
otypes.VcpuPin(vcpu=int(pin['vcpu']), cpu_set=str(pin['cpu'])) for pin in self.param('cpu_pinning')
],
) if self.param('cpu_pinning') else None,
mode=otypes.CpuMode(self.param('cpu_mode')) if self.param(
'cpu_mode') else None,
) if any((
self.param('cpu_cores'),
self.param('cpu_sockets'),
self.param('cpu_threads'),
self.param('cpu_mode'),
self.param('cpu_pinning')
)) else None,
os=otypes.OperatingSystem(
type=self.param('operating_system'),
boot=otypes.Boot(
devices=[
otypes.BootDevice(dev) for dev in self.param('boot_devices')
],
) if self.param('boot_devices') else None
),
rng_device=otypes.RngDevice(
source=otypes.RngSource(self.param('rng_device')),
rate=otypes.Rate(
bytes=self.param('rng_bytes'),
period=self.param('rng_period')
)
) if self.param('rng_device') else None,
memory=convert_to_bytes(
self.param('memory')
) if self.param('memory') else None,
virtio_scsi=otypes.VirtioScsi(
enabled=self.param('virtio_scsi')
) if self.param('virtio_scsi') else None,
memory_policy=otypes.MemoryPolicy(
guaranteed=convert_to_bytes(self.param('memory_guaranteed')),
ballooning=self.param('ballooning_enabled'),
max=convert_to_bytes(self.param('memory_max')),
) if any((
self.param('memory_guaranteed'),
self.param('ballooning_enabled') is not None,
self.param('memory_max')
)) else None,
description=self.param('description'),
placement_policy=otypes.VmPlacementPolicy(
affinity=otypes.VmAffinity(self.param('placement_policy')),
hosts=[
otypes.Host(name=self.param('host')),
] if self.param('host') else None,
) if self.param('placement_policy') else None,
soundcard_enabled=self.param('soundcard_enabled'),
display=otypes.Display(
smartcard_enabled=self.param('smartcard_enabled')
) if self.param('smartcard_enabled') is not None else None,
io=otypes.Io(
threads=self.param('io_threads'),
) if self.param('io_threads') is not None else None,
)
def __attach_watchdog(self, entity):
watchdogs_service = self._service.service(entity.id).watchdogs_service()
watchdog = self.param('watchdog')
if watchdog is not None:
current_watchdog = next(iter(watchdogs_service.list()), None)
if watchdog.get('model') is None and current_watchdog:
watchdogs_service.watchdog_service(current_watchdog.id).remove()
return True
elif watchdog.get('model') is not None and current_watchdog is None:
watchdogs_service.add(
otypes.Watchdog(
model=otypes.WatchdogModel(watchdog.get('model').lower()),
action=otypes.WatchdogAction(watchdog.get('action')),
)
)
return True
elif current_watchdog is not None:
if (
str(current_watchdog.model).lower() != watchdog.get('model').lower() or
str(current_watchdog.action).lower() != watchdog.get('action').lower()
):
watchdogs_service.watchdog_service(current_watchdog.id).update(
otypes.Watchdog(
model=otypes.WatchdogModel(watchdog.get('model')),
action=otypes.WatchdogAction(watchdog.get('action')),
)
)
return True
return False
def __get_vnic_profile_id(self, nic):
"""
Return VNIC profile ID looked up by it's name, because there can be
more VNIC profiles with same name, other criteria of filter is cluster.
"""
vnics_service = self._connection.system_service().vnic_profiles_service()
clusters_service = self._connection.system_service().clusters_service()
cluster = search_by_name(clusters_service, self.param('cluster'))
profiles = [
profile for profile in vnics_service.list()
if profile.name == nic.get('profile_name')
]
cluster_networks = [
net.id for net in self._connection.follow_link(cluster.networks)
]
try:
return next(
profile.id for profile in profiles
if profile.network.id in cluster_networks
)
except StopIteration:
raise Exception(
"Profile '%s' was not found in cluster '%s'" % (
nic.get('profile_name'),
self.param('cluster')
)
)
def __attach_nics(self, entity):
# Attach NICs to instance type, if specified:
nics_service = self._service.service(entity.id).nics_service()
for nic in self.param('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=self.__get_vnic_profile_id(nic),
) 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 __attach_graphical_console(self, entity):
graphical_console = self.param('graphical_console')
if not graphical_console:
return False
it_service = self._service.instance_type_service(entity.id)
gcs_service = it_service.graphics_consoles_service()
graphical_consoles = gcs_service.list()
# Remove all graphical consoles if there are any:
if bool(graphical_console.get('headless_mode')):
if not self._module.check_mode:
for gc in graphical_consoles:
gcs_service.console_service(gc.id).remove()
return len(graphical_consoles) > 0
# If there are not gc add any gc to be added:
protocol = graphical_console.get('protocol')
if isinstance(protocol, str):
protocol = [protocol]
current_protocols = [str(gc.protocol) for gc in graphical_consoles]
if not current_protocols:
if not self._module.check_mode:
for p in protocol:
gcs_service.add(
otypes.GraphicsConsole(
protocol=otypes.GraphicsType(p),
)
)
return True
# Update consoles:
if sorted(protocol) != sorted(current_protocols):
if not self._module.check_mode:
for gc in graphical_consoles:
gcs_service.console_service(gc.id).remove()
for p in protocol:
gcs_service.add(
otypes.GraphicsConsole(
protocol=otypes.GraphicsType(p),
)
)
return True
def post_update(self, entity):
self.post_present(entity.id)
def post_present(self, entity_id):
entity = self._service.service(entity_id).get()
self.changed = self.__attach_nics(entity)
self.changed = self.__attach_watchdog(entity)
self.changed = self.__attach_graphical_console(entity)
def update_check(self, entity):
cpu_mode = getattr(entity.cpu, 'mode')
it_display = entity.display
return (
not self.param('kernel_params_persist') and
equal(convert_to_bytes(self.param('memory_guaranteed')), entity.memory_policy.guaranteed) and
equal(convert_to_bytes(self.param('memory_max')), entity.memory_policy.max) and
equal(self.param('cpu_cores'), entity.cpu.topology.cores) and
equal(self.param('cpu_sockets'), entity.cpu.topology.sockets) and
equal(self.param('cpu_threads'), entity.cpu.topology.threads) and
equal(self.param('cpu_mode'), str(cpu_mode) if cpu_mode else None) and
equal(self.param('type'), str(entity.type)) and
equal(self.param('name'), str(entity.name)) and
equal(self.param('operating_system'), str(entity.os.type)) and
equal(self.param('soundcard_enabled'), entity.soundcard_enabled) and
equal(self.param('smartcard_enabled'), getattr(it_display, 'smartcard_enabled', False)) and
equal(self.param('io_threads'), entity.io.threads) and
equal(self.param('ballooning_enabled'), entity.memory_policy.ballooning) and
equal(self.param('serial_console'), getattr(entity.console, 'enabled', None)) and
equal(self.param('usb_support'), entity.usb.enabled) and
equal(self.param('virtio_scsi'), getattr(entity, 'smartcard_enabled', False)) and
equal(self.param('high_availability'), entity.high_availability.enabled) and
equal(self.param('high_availability_priority'), entity.high_availability.priority) and
equal(self.param('boot_devices'), [str(dev) for dev in getattr(entity.os.boot, 'devices', [])]) and
equal(self.param('description'), entity.description) and
equal(self.param('rng_device'), str(entity.rng_device.source) if entity.rng_device else None) and
equal(self.param('rng_bytes'), entity.rng_device.rate.bytes if entity.rng_device else None) and
equal(self.param('rng_period'), entity.rng_device.rate.period if entity.rng_device else None) and
equal(self.param('placement_policy'), str(entity.placement_policy.affinity) if entity.placement_policy else None)
)
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(type='str', default='present',
choices=['absent', 'present']),
name=dict(type='str'),
id=dict(type='str'),
memory=dict(type='str'),
memory_guaranteed=dict(type='str'),
memory_max=dict(type='str'),
cpu_sockets=dict(type='int'),
cpu_cores=dict(type='int'),
cpu_threads=dict(type='int'),
operating_system=dict(type='str'),
boot_devices=dict(type='list', choices=['cdrom', 'hd', 'network']),
serial_console=dict(type='bool'),
usb_support=dict(type='bool'),
high_availability=dict(type='bool'),
high_availability_priority=dict(type='int'),
watchdog=dict(type='dict'),
host=dict(type='str'),
graphical_console=dict(type='dict'),
description=dict(type='str'),
cpu_mode=dict(type='str'),
rng_device=dict(type='str'),
rng_bytes=dict(type='int', default=None),
rng_period=dict(type='int', default=None),
placement_policy=dict(type='str'),
cpu_pinning=dict(type='list'),
soundcard_enabled=dict(type='bool', default=None),
virtio_scsi=dict(type='bool', default=None),
smartcard_enabled=dict(type='bool', default=None),
io_threads=dict(type='int', default=None),
nics=dict(type='list', default=[]),
ballooning_enabled=dict(type='bool', default=None),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_one_of=[['id', 'name']],
)
check_sdk(module)
check_params(module)
try:
state = module.params['state']
auth = module.params.pop('auth')
connection = create_connection(auth)
its_service = connection.system_service().instance_types_service()
its_module = InstanceTypeModule(
connection=connection,
module=module,
service=its_service,
)
it = its_module.search_entity()
if state == 'present':
ret = its_module.create(
entity=it
)
its_module.post_present(ret['id'])
ret['changed'] = its_module.changed
elif state == 'absent':
ret = its_module.remove()
module.exit_json(**ret)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == "__main__":
main()

@ -1,236 +0,0 @@
#!/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/>.
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_job
short_description: Module to manage jobs in oVirt/RHV
version_added: "2.9"
author: "Martin Necas (@mnecas)"
description:
- "This module manage jobs in oVirt/RHV. It can also manage steps of the job."
options:
description:
description:
- "Description of the job."
- "When task with same description has already finished and you rerun taks it will create new job."
required: true
state:
description:
- "Should the job be C(present)/C(absent)/C(failed)."
- "C(started) is alias for C(present). C(finished) is alias for C(absent). Same in the steps."
- "Note when C(finished)/C(failed) it will finish/fail all steps."
choices: ['present', 'absent', 'started', 'finished', 'failed']
default: present
steps:
description:
- "The steps of the job."
suboptions:
description:
description:
- "Description of the step."
required: true
state:
description:
- "Should the step be present/absent/failed."
- "Note when one step fail whole job will fail"
- "Note when all steps are finished it will finish job."
choices: ['present', 'absent', 'started', 'finished', 'failed']
default: present
type: list
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
- name: Create job with two steps
ovirt_job:
description: job_name
steps:
- description: step_name_A
- description: step_name_B
- name: Finish one step
ovirt_job:
description: job_name
steps:
- description: step_name_A
state: finished
- name: When you fail one step whole job will stop
ovirt_job:
description: job_name
steps:
- description: step_name_B
state: failed
- name: Finish all steps
ovirt_job:
description: job_name
state: finished
'''
RETURN = '''
id:
description: ID of the job which is managed
returned: On success if job is found.
type: str
sample: 7de90f31-222c-436c-a1ca-7e655bd5b60c
job:
description: "Dictionary of all the job attributes. Job attributes can be found on your oVirt/RHV instance
at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/job."
returned: On success if job is found.
type: dict
'''
import traceback
try:
import ovirtsdk4.types as otypes
except ImportError:
pass
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
check_sdk,
create_connection,
equal,
get_id_by_name,
ovirt_full_argument_spec,
get_dict_of_struct,
)
def build_job(description):
return otypes.Job(
description=description,
status=otypes.JobStatus.STARTED,
external=True,
auto_cleared=True
)
def build_step(description, job_id):
return otypes.Step(
description=description,
type=otypes.StepEnum.UNKNOWN,
job=otypes.Job(
id=job_id
),
status=otypes.StepStatus.STARTED,
external=True,
)
def attach_steps(module, job_id, jobs_service):
changed = False
steps_service = jobs_service.job_service(job_id).steps_service()
if module.params.get('steps'):
for step in module.params.get('steps'):
step_entity = get_entity(steps_service, step.get('description'))
step_state = step.get('state', 'present')
if step_state in ['present', 'started']:
if step_entity is None:
steps_service.add(build_step(step.get('description'), job_id))
changed = True
if step_entity is not None and step_entity.status not in [otypes.StepStatus.FINISHED, otypes.StepStatus.FAILED]:
if step_state in ['absent', 'finished']:
steps_service.step_service(step_entity.id).end(succeeded=True)
changed = True
elif step_state == 'failed':
steps_service.step_service(step_entity.id).end(succeeded=False)
changed = True
return changed
def get_entity(service, description):
all_entities = service.list()
for entity in all_entities:
if entity.description == description and entity.status not in [otypes.StepStatus.FINISHED, otypes.JobStatus.FINISHED]:
return entity
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(
choices=['present', 'absent', 'started', 'finished', 'failed'],
default='present',
),
description=dict(default=None),
steps=dict(default=None, type='list'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=False,
)
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
jobs_service = connection.system_service().jobs_service()
state = module.params['state']
job = get_entity(jobs_service, module.params['description'])
changed = False
if state in ['present', 'started']:
if job is None or job.status in [otypes.JobStatus.FINISHED, otypes.JobStatus.FAILED]:
job = jobs_service.add(build_job(module.params['description']))
changed = True
changed = attach_steps(module, job.id, jobs_service) or changed
if job is not None and job.status not in [otypes.JobStatus.FINISHED, otypes.JobStatus.FAILED]:
if state in ['absent', 'finished']:
jobs_service.job_service(job.id).end(succeeded=True)
changed = True
elif state == 'failed':
jobs_service.job_service(job.id).end(succeeded=False)
changed = True
ret = {
'changed': changed,
'id': getattr(job, 'id', None),
'job': get_dict_of_struct(
struct=job,
connection=connection,
fetch_nested=True,
attributes=module.params.get('nested_attributes'),
),
}
module.exit_json(**ret)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == "__main__":
main()

@ -1,181 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_mac_pool
short_description: Module to manage MAC pools in oVirt/RHV
version_added: "2.3"
author: "Ondra Machacek (@machacekondra)"
description:
- "This module manage MAC pools in oVirt/RHV."
options:
id:
description:
- "ID of the mac pool to manage."
version_added: "2.8"
name:
description:
- "Name of 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 I(true) allow a MAC address to be used multiple times in a pool."
- "Default value is set by oVirt/RHV engine to I(false)."
type: bool
ranges:
description:
- "List of MAC ranges. The from and to should be split 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_pool:
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_pool:
state: absent
name: mymacpool
# Change MAC pool Name
- ovirt_nic:
id: 00000000-0000-0000-0000-000000000000
name: "new_mac_pool_name"
'''
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/RHV instance
at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/mac_pool."
returned: On success if MAC pool is found.
type: dict
'''
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,
)
class MACPoolModule(BaseModule):
def build_entity(self):
return otypes.MacPool(
name=self._module.params['name'],
id=self._module.params['id'],
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']
] if self._module.params['ranges'] else None,
)
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) and
equal(self._module.params['name'], entity.name)
)
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(
choices=['present', 'absent'],
default='present',
),
name=dict(required=True),
id=dict(default=None),
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:
auth = module.params.pop('auth')
connection = create_connection(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=auth.get('token') is None)
if __name__ == "__main__":
main()

@ -1,360 +0,0 @@
#!/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/>.
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_network
short_description: Module to manage logical networks in oVirt/RHV
version_added: "2.3"
author: "Ondra Machacek (@machacekondra)"
description:
- "Module to manage logical networks in oVirt/RHV"
options:
id:
description:
- "ID of the network to manage."
version_added: "2.8"
name:
description:
- "Name of the network to manage."
required: true
state:
description:
- "Should the network be present or absent"
choices: ['present', 'absent']
default: present
data_center:
description:
- "Datacenter name where network reside."
description:
description:
- "Description of the network."
comment:
description:
- "Comment of the network."
vlan_tag:
description:
- "Specify VLAN tag."
external_provider:
description:
- "Name of external network provider."
- "At first it tries to import the network when not found it will create network in external provider."
version_added: 2.8
vm_network:
description:
- "If I(True) network will be marked as network for VM."
- "VM network carries traffic relevant to the virtual machine."
type: bool
mtu:
description:
- "Maximum transmission unit (MTU) of the network."
clusters:
description:
- "List of dictionaries describing how the network is managed in specific cluster."
suboptions:
name:
description:
- Cluster name.
assigned:
description:
- I(true) if the network should be assigned to cluster. Default is I(true).
type: bool
required:
description:
- I(true) if the network must remain operational for all hosts associated with this network.
type: bool
display:
description:
- I(true) if the network should marked as display network.
type: bool
migration:
description:
- I(true) if the network should marked as migration network.
type: bool
gluster:
description:
- I(true) if the network should marked as gluster network.
type: bool
label:
description:
- "Name of the label to assign to the network."
version_added: "2.5"
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_network:
data_center: mydatacenter
name: mynetwork
vlan_tag: 1
vm_network: true
# Remove network
- ovirt_network:
state: absent
name: mynetwork
# Change Network Name
- ovirt_network:
id: 00000000-0000-0000-0000-000000000000
name: "new_network_name"
data_center: mydatacenter
# Add network from external provider
- ovirt_network:
data_center: mydatacenter
name: mynetwork
external_provider: ovirt-provider-ovn
'''
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/RHV instance
at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/network."
returned: "On success if network is found."
type: dict
'''
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,
get_id_by_name,
get_dict_of_struct,
get_entity
)
class NetworksModule(BaseModule):
def build_entity(self):
if self.param('external_provider'):
ons_service = self._connection.system_service().openstack_network_providers_service()
on_service = ons_service.provider_service(get_id_by_name(ons_service, self.param('external_provider')))
return otypes.Network(
name=self._module.params['name'],
comment=self._module.params['comment'],
description=self._module.params['description'],
id=self._module.params['id'],
data_center=otypes.DataCenter(
name=self._module.params['data_center'],
) if self._module.params['data_center'] 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'],
external_provider=otypes.OpenStackNetworkProvider(id=on_service.get().id)
if self.param('external_provider') else None,
)
def post_create(self, entity):
self._update_label_assignments(entity)
def _update_label_assignments(self, entity):
if self.param('label') is None:
return
labels_service = self._service.service(entity.id).network_labels_service()
labels = [lbl.id for lbl in labels_service.list()]
if not self.param('label') in labels:
if not self._module.check_mode:
if labels:
labels_service.label_service(labels[0]).remove()
labels_service.add(
label=otypes.NetworkLabel(id=self.param('label'))
)
self.changed = True
def update_check(self, entity):
self._update_label_assignments(entity)
return (
equal(self._module.params.get('comment'), entity.comment) and
equal(self._module.params.get('name'), entity.name) 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
self._old_usages = []
self._cluster_network_entity = get_entity(self._service.network_service(network_id))
if self._cluster_network_entity is not None:
self._old_usages = self._cluster_network_entity.usages
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=list(set([
otypes.NetworkUsage(usage)
for usage in ['display', 'gluster', 'migration']
if self._cluster_network.get(usage, False)
] + self._old_usages))
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
all(
x in [
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
]
for x in [
usage
for usage in ['display', 'gluster', 'migration']
if self._cluster_network.get(usage, False)
]
)
)
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(
choices=['present', 'absent'],
default='present',
),
data_center=dict(required=True),
id=dict(default=None),
name=dict(required=True),
description=dict(default=None),
comment=dict(default=None),
external_provider=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'),
label=dict(default=None),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
)
check_sdk(module)
check_params(module)
try:
auth = module.params.pop('auth')
connection = create_connection(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']
search_params = {
'name': module.params['name'],
'datacenter': module.params['data_center'],
}
if state == 'present':
imported = False
if module.params.get('external_provider') and module.params.get('name') not in [net.name for net in networks_service.list()]:
# Try to import network
ons_service = connection.system_service().openstack_network_providers_service()
on_service = ons_service.provider_service(get_id_by_name(ons_service, module.params.get('external_provider')))
on_networks_service = on_service.networks_service()
if module.params.get('name') in [net.name for net in on_networks_service.list()]:
network_service = on_networks_service.network_service(get_id_by_name(on_networks_service, module.params.get('name')))
network_service.import_(data_center=otypes.DataCenter(name=module.params.get('data_center')))
imported = True
ret = networks_module.create(search_params=search_params)
ret['changed'] = ret['changed'] or imported
# Update clusters networks:
if module.params.get('clusters') is not None:
for param_cluster in module.params.get('clusters'):
cluster = search_by_name(clusters_service, param_cluster.get('name'))
if cluster is None:
raise Exception("Cluster '%s' was not found." % param_cluster.get('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(search_params=search_params)
module.exit_json(**ret)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == "__main__":
main()

@ -1,120 +0,0 @@
#!/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/>.
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_network_info
short_description: Retrieve information about one or more oVirt/RHV networks
author: "Ondra Machacek (@machacekondra)"
version_added: "2.3"
description:
- "Retrieve information about one or more oVirt/RHV networks."
- This module was called C(ovirt_network_facts) before Ansible 2.9, returning C(ansible_facts).
Note that the M(ovirt_network_info) module no longer returns C(ansible_facts)!
notes:
- "This module returns a variable C(ovirt_networks), which
contains a list of networks. You need to register the result with
the I(register) keyword to use it."
options:
pattern:
description:
- "Search term which is accepted by oVirt/RHV search backend."
- "For example to search network starting with string vlan1 use: name=vlan1*"
extends_documentation_fragment: ovirt_info
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather information about all networks which names start with C(vlan1):
- ovirt_network_info:
pattern: name=vlan1*
register: result
- debug:
msg: "{{ result.ovirt_networks }}"
'''
RETURN = '''
ovirt_networks:
description: "List of dictionaries describing the networks. Network attributes are mapped to dictionary keys,
all networks attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/network."
returned: On success.
type: list
'''
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
pattern=dict(default='', required=False),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name == 'ovirt_network_facts'
if is_old_facts:
module.deprecate("The 'ovirt_network_facts' module has been renamed to 'ovirt_network_info', "
"and the renamed one no longer returns ansible_facts", version='2.13')
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
networks_service = connection.system_service().networks_service()
networks = networks_service.list(search=module.params['pattern'])
result = dict(
ovirt_networks=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in networks
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

@ -1,318 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2017, Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_nic
short_description: Module to manage network interfaces of Virtual Machines in oVirt/RHV
version_added: "2.3"
author:
- Ondra Machacek (@machacekondra)
description:
- Module to manage network interfaces of Virtual Machines in oVirt/RHV.
options:
id:
description:
- "ID of the nic to manage."
version_added: "2.8"
name:
description:
- Name of the network interface to manage.
required: true
vm:
description:
- Name of the Virtual Machine to manage.
- You must provide either C(vm) parameter or C(template) parameter.
template:
description:
- Name of the template to manage.
- You must provide either C(vm) parameter or C(template) parameter.
version_added: "2.4"
state:
description:
- Should the Virtual Machine NIC be present/absent/plugged/unplugged.
choices: [ absent, plugged, present, 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.
- When not specified and network has only single profile it will be auto-selected, otherwise you must specify profile.
interface:
description:
- "Type of the network interface. For example e1000, pci_passthrough, rtl8139, rtl8139_virtio, spapr_vlan or virtio."
- "It's required parameter when creating the new NIC."
mac_address:
description:
- Custom MAC address of the network interface, by default it's obtained from MAC pool.
linked:
description:
- Defines if the NIC is linked to the virtual machine.
type: bool
version_added: "2.9"
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
- name: Add NIC to VM
ovirt_nic:
state: present
vm: myvm
name: mynic
interface: e1000
mac_address: 00:1a:4a:16:01:56
profile: ovirtmgmt
network: ovirtmgmt
- name: Plug NIC to VM
ovirt_nic:
state: plugged
vm: myvm
name: mynic
- name: Unplug NIC from VM
ovirt_nic:
state: unplugged
linked: false
vm: myvm
name: mynic
- name: Add NIC to template
ovirt_nic:
auth: "{{ ovirt_auth }}"
state: present
template: my_template
name: nic1
interface: virtio
profile: ovirtmgmt
network: ovirtmgmt
- name: Remove NIC from VM
ovirt_nic:
state: absent
vm: myvm
name: mynic
# Change NIC Name
- ovirt_nic:
id: 00000000-0000-0000-0000-000000000000
name: "new_nic_name"
vm: myvm
'''
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/RHV instance
at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/nic."
returned: On success if network interface is found.
type: dict
'''
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,
)
class EntityNicsModule(BaseModule):
def __init__(self, *args, **kwargs):
super(EntityNicsModule, 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(
id=self._module.params.get('id'),
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,
linked=self.param('linked') if self.param('linked') is not None else None,
)
def update_check(self, entity):
if self._module.params.get('vm'):
return (
equal(self._module.params.get('interface'), str(entity.interface)) and
equal(self._module.params.get('linked'), entity.linked) and
equal(self._module.params.get('name'), str(entity.name)) 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)
)
elif self._module.params.get('template'):
return (
equal(self._module.params.get('interface'), str(entity.interface)) and
equal(self._module.params.get('linked'), entity.linked) and
equal(self._module.params.get('name'), str(entity.name)) and
equal(self._module.params.get('profile'), get_link_name(self._connection, entity.vnic_profile))
)
def get_vnics(networks_service, network, connection):
resp = []
vnic_services = connection.system_service().vnic_profiles_service()
for vnic in vnic_services.list():
if vnic.network.id == network.id:
resp.append(vnic)
return resp
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(type='str', default='present', choices=['absent', 'plugged', 'present', 'unplugged']),
vm=dict(type='str'),
id=dict(default=None),
template=dict(type='str'),
name=dict(type='str', required=True),
interface=dict(type='str'),
profile=dict(type='str'),
network=dict(type='str'),
mac_address=dict(type='str'),
linked=dict(type='bool'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_one_of=[['vm', 'template']],
)
check_sdk(module)
try:
# Locate the service that manages the virtual machines and use it to
# search for the NIC:
auth = module.params.pop('auth')
connection = create_connection(auth)
entity_name = None
if module.params.get('vm'):
# Locate the VM, where we will manage NICs:
entity_name = module.params.get('vm')
collection_service = connection.system_service().vms_service()
elif module.params.get('template'):
entity_name = module.params.get('template')
collection_service = connection.system_service().templates_service()
# TODO: We have to modify the search_by_name function to accept raise_error=True/False,
entity = search_by_name(collection_service, entity_name)
if entity is None:
raise Exception("Vm/Template '%s' was not found." % entity_name)
service = collection_service.service(entity.id)
cluster_id = entity.cluster
nics_service = service.nics_service()
entitynics_module = EntityNicsModule(
connection=connection,
module=module,
service=nics_service,
)
# Find vNIC id of the network interface (if any):
if module.params['network']:
profile = module.params.get('profile')
cluster_name = get_link_name(connection, cluster_id)
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 = next(
(n for n in networks_service.list()
if n.name == module.params['network']),
None
)
if network is None:
raise Exception(
"Network '%s' was not found in datacenter '%s'." % (
module.params['network'],
dc.name
)
)
if profile:
for vnic in connection.system_service().vnic_profiles_service().list():
if vnic.name == profile and vnic.network.id == network.id:
entitynics_module.vnic_id = vnic.id
else:
# When not specified which vnic use ovirtmgmt/ovirtmgmt
vnics = get_vnics(networks_service, network, connection)
if len(vnics) == 1:
entitynics_module.vnic_id = vnics[0].id
else:
raise Exception(
"You didn't specify any vnic profile. "
"Following vnic profiles are in system: '%s', please specify one of them" % ([vnic.name for vnic in vnics])
)
# Handle appropriate action:
state = module.params['state']
if state == 'present':
ret = entitynics_module.create()
elif state == 'absent':
ret = entitynics_module.remove()
elif state == 'plugged':
entitynics_module.create()
ret = entitynics_module.action(
action='activate',
action_condition=lambda nic: not nic.plugged,
wait_condition=lambda nic: nic.plugged,
)
elif state == 'unplugged':
entitynics_module.create()
ret = entitynics_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=auth.get('token') is None)
if __name__ == "__main__":
main()

@ -1,138 +0,0 @@
#!/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/>.
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_nic_info
short_description: Retrieve information about one or more oVirt/RHV virtual machine network interfaces
author: "Ondra Machacek (@machacekondra)"
version_added: "2.3"
description:
- "Retrieve information about one or more oVirt/RHV virtual machine network interfaces."
- This module was called C(ovirt_nic_facts) before Ansible 2.9, returning C(ansible_facts).
Note that the M(ovirt_nic_info) module no longer returns C(ansible_facts)!
notes:
- "This module returns a variable C(ovirt_nics), which
contains a list of NICs. You need to register the result with
the I(register) keyword to use it."
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_info
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather information about all NICs which names start with C(eth) for VM named C(centos7):
- ovirt_nic_info:
vm: centos7
name: eth*
register: result
- debug:
msg: "{{ result.ovirt_nics }}"
'''
RETURN = '''
ovirt_nics:
description: "List of dictionaries describing the network interfaces. NIC attributes are mapped to dictionary keys,
all NICs attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/nic."
returned: On success.
type: list
'''
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_info_full_argument_spec,
search_by_name,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
vm=dict(required=True),
name=dict(default=None),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name == 'ovirt_nic_facts'
if is_old_facts:
module.deprecate("The 'ovirt_nic_facts' module has been renamed to 'ovirt_nic_info', "
"and the renamed one no longer returns ansible_facts", version='2.13')
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(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()
result = dict(
ovirt_nics=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in nics
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

@ -1,320 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2017, Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_permission
short_description: Module to manage permissions of users/groups in oVirt/RHV
version_added: "2.3"
author:
- Ondra Machacek (@machacekondra)
description:
- Module to manage permissions of users/groups in oVirt/RHV.
options:
role:
description:
- Name of the role to be assigned to user/group on specific object.
default: UserRole
state:
description:
- Should the permission be present/absent.
choices: [ absent, present ]
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.
choices:
- cluster
- cpu_profile
- data_center
- disk
- disk_profile
- host
- network
- storage_domain
- system
- template
- vm
- vm_pool
- vnic_profile
default: vm
user_name:
description:
- Username of 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.
- Note that if user does not exist in the system this module will fail,
you should ensure the user exists by using M(ovirt_users) module.
group_name:
description:
- Name of the group to manage.
- Note that if group does not exist in the system this module will fail,
you should ensure the group exists by using M(ovirt_groups) module.
authz_name:
description:
- Authorization provider of the user/group.
required: true
aliases: [ domain ]
namespace:
description:
- Namespace of the authorization provider, where user/group resides.
quota_name:
description:
- Name of the quota to assign permission. Works only with C(object_type) I(data_center).
version_added: "2.7"
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
- name: Add user user1 from authorization provider example.com-authz
ovirt_permission:
user_name: user1
authz_name: example.com-authz
object_type: vm
object_name: myvm
role: UserVmManager
- name: Remove permission from user
ovirt_permission:
state: absent
user_name: user1
authz_name: example.com-authz
object_type: cluster
object_name: mycluster
role: ClusterAdmin
- name: Assign QuotaConsumer role to user
ovirt_permissions:
state: present
user_name: user1
authz_name: example.com-authz
object_type: data_center
object_name: mydatacenter
quota_name: myquota
role: QuotaConsumer
- name: Assign QuotaConsumer role to group
ovirt_permissions:
state: present
group_name: group1
authz_name: example.com-authz
object_type: data_center
object_name: mydatacenter
quota_name: myquota
role: QuotaConsumer
'''
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/RHV instance
at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/permission."
returned: On success if permission is found.
type: dict
'''
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,
get_id_by_name
)
def _objects_service(connection, object_type):
if object_type == 'system':
return connection.system_service()
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)
if object_type == 'system':
return objects_service
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
object_service = objects_service.service(object_id)
if module.params['quota_name'] and object_type == 'data_center':
quotas_service = object_service.quotas_service()
return quotas_service.quota_service(get_id_by_name(quotas_service, module.params['quota_name']))
return object_service
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/RHV 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(type='str', default='present', choices=['absent', 'present']),
role=dict(type='str', default='UserRole'),
object_type=dict(type='str', default='vm',
choices=[
'cluster',
'cpu_profile',
'data_center',
'disk',
'disk_profile',
'host',
'network',
'storage_domain',
'system',
'template',
'vm',
'vm_pool',
'vnic_profile',
]),
authz_name=dict(type='str', required=True, aliases=['domain']),
object_id=dict(type='str'),
object_name=dict(type='str'),
user_name=dict(type='str'),
group_name=dict(type='str'),
namespace=dict(type='str'),
quota_name=dict(type='str'),
)
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) and module.params['object_type'] != 'system':
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:
auth = module.params.pop('auth')
connection = create_connection(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=auth.get('token') is None)
if __name__ == "__main__":
main()

@ -1,161 +0,0 @@
#!/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/>.
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_permission_info
short_description: Retrieve information about one or more oVirt/RHV permissions
author: "Ondra Machacek (@machacekondra)"
version_added: "2.3"
description:
- "Retrieve information about one or more oVirt/RHV permissions."
- This module was called C(ovirt_permission_facts) before Ansible 2.9, returning C(ansible_facts).
Note that the M(ovirt_permission_info) module no longer returns C(ansible_facts)!
notes:
- "This module returns a variable C(ovirt_permissions), which
contains a list of permissions. You need to register the result with
the I(register) keyword to use it."
options:
user_name:
description:
- "Username of 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 group to manage."
authz_name:
description:
- "Authorization provider of the user/group. In previous versions of oVirt/RHV known as domain."
required: true
aliases: ['domain']
namespace:
description:
- "Namespace of the authorization provider, where user/group resides."
required: false
extends_documentation_fragment: ovirt_info
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather information about all permissions of user with username C(john):
- ovirt_permission_info:
user_name: john
authz_name: example.com-authz
register: result
- debug:
msg: "{{ result.ovirt_permissions }}"
'''
RETURN = '''
ovirt_permissions:
description: "List of dictionaries describing the permissions. Permission attributes are mapped to dictionary keys,
all permissions attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/permission."
returned: On success.
type: list
'''
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_info_full_argument_spec,
search_by_name,
)
def _permissions_service(connection, module):
if module.params['user_name']:
service = connection.system_service().users_service()
entity = next(
iter(
service.list(
search='usrname={0}'.format(
'{0}@{1}'.format(module.params['user_name'], module.params['authz_name'])
)
)
),
None
)
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_info_full_argument_spec(
authz_name=dict(required=True, aliases=['domain']),
user_name=dict(default=None),
group_name=dict(default=None),
namespace=dict(default=None),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name == 'ovirt_permission_facts'
if is_old_facts:
module.deprecate("The 'ovirt_permission_facts' module has been renamed to 'ovirt_permission_info', "
"and the renamed one no longer returns ansible_facts", version='2.13')
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(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)
newperm['%s_id' % key[1:]] = value.id
permissions.append(newperm)
result = dict(ovirt_permissions=permissions)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

@ -1,319 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_quota
short_description: Module to manage datacenter quotas in oVirt/RHV
version_added: "2.3"
author: "Ondra Machacek (@machacekondra)"
description:
- "Module to manage datacenter quotas in oVirt/RHV"
options:
id:
description:
- "ID of the quota to manage."
version_added: "2.8"
name:
description:
- "Name of the quota to manage."
required: true
state:
description:
- "Should the quota be present/absent."
choices: ['present', 'absent']
default: present
data_center:
description:
- "Name of the datacenter where quota should be managed."
required: true
description:
description:
- "Description of the quota to manage."
cluster_threshold:
description:
- "Cluster threshold(soft limit) defined in percentage (0-100)."
aliases:
- "cluster_soft_limit"
cluster_grace:
description:
- "Cluster grace(hard limit) defined in percentage (1-100)."
aliases:
- "cluster_hard_limit"
storage_threshold:
description:
- "Storage threshold(soft limit) defined in percentage (0-100)."
aliases:
- "storage_soft_limit"
storage_grace:
description:
- "Storage grace(hard limit) defined in percentage (1-100)."
aliases:
- "storage_hard_limit"
clusters:
description:
- "List of dictionary of cluster limits, which is valid to specific cluster."
- "If cluster isn't specified it's valid to all clusters in system:"
suboptions:
cluster:
description:
- Name of the cluster.
memory:
description:
- Memory limit (in GiB).
cpu:
description:
- CPU limit.
storages:
description:
- "List of dictionary of storage limits, which is valid to specific storage."
- "If storage isn't specified it's valid to all storages in system:"
suboptions:
storage:
description:
- Name of the storage.
size:
description:
- 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_quota:
name: quota1
data_center: dcX
clusters:
- name: cluster1
memory: 20
cpu: 10
# Add cluster quota to all clusters with memory limit 30GiB and CPU limit to 15:
- ovirt_quota:
name: quota2
data_center: dcX
clusters:
- memory: 30
cpu: 15
# Add storage quota to storage data1 with size limit to 100GiB
- ovirt_quota:
name: quota3
data_center: 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_quota:
state: absent
data_center: dcX
name: quota1
# Change Quota Name
- ovirt_quota:
id: 00000000-0000-0000-0000-000000000000
name: "new_quota_name"
data_center: dcX
'''
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/RHV instance
at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/quota."
returned: On success if quota is found.
type: dict
'''
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,
)
class QuotasModule(BaseModule):
def build_entity(self):
return otypes.Quota(
description=self._module.params['description'],
name=self._module.params['name'],
id=self._module.params['id'],
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
# appropriately, 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('name'), entity.name) 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',
),
id=dict(default=None),
name=dict(required=True),
data_center=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:
auth = module.params.pop('auth')
connection = create_connection(auth)
datacenters_service = connection.system_service().data_centers_service()
dc_name = module.params['data_center']
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=auth.get('token') is None)
if __name__ == "__main__":
main()

@ -1,138 +0,0 @@
#!/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/>.
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_quota_info
short_description: Retrieve information about one or more oVirt/RHV quotas
version_added: "2.3"
author: "Maor Lipchuk (@machacekondra)"
description:
- "Retrieve information about one or more oVirt/RHV quotas."
- This module was called C(ovirt_quota_facts) before Ansible 2.9, returning C(ansible_facts).
Note that the M(ovirt_quota_info) module no longer returns C(ansible_facts)!
notes:
- "This module returns a variable C(ovirt_quotas), which
contains a list of quotas. You need to register the result with
the I(register) keyword to use it."
options:
data_center:
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_info
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather information about quota named C<myquota> in Default datacenter:
- ovirt_quota_info:
data_center: Default
name: myquota
register: result
- debug:
msg: "{{ result.ovirt_quotas }}"
'''
RETURN = '''
ovirt_quotas:
description: "List of dictionaries describing the quotas. Quota attributes are mapped to dictionary keys,
all quotas attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/quota."
returned: On success.
type: list
'''
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_info_full_argument_spec,
search_by_name,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
data_center=dict(required=True),
name=dict(default=None),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name == 'ovirt_quota_facts'
if is_old_facts:
module.deprecate("The 'ovirt_quota_facts' module has been renamed to 'ovirt_quota_info', "
"and the renamed one no longer returns ansible_facts", version='2.13')
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
datacenters_service = connection.system_service().data_centers_service()
dc_name = module.params['data_center']
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()
result = dict(
ovirt_quotas=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in quotas
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

@ -1,190 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_role
short_description: Module to manage roles in oVirt/RHV
version_added: "2.8"
author: "Martin Necas (@mnecas)"
description:
- "Module to manage roles in oVirt/RHV."
options:
name:
description:
- "Name of the role to manage."
id:
description:
- "ID of the role to manage."
description:
description:
- "Description of the role."
state:
description:
- "Should the role be present/absent."
choices: ['present', 'absent']
default: present
administrative:
description:
- "Defines the role as administrative-only or not."
type: bool
permits:
description:
- "List of permits which role will have"
- "Permit 'login' is default and all roles will have it."
- "List can contain name of permit."
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 administrative role with two permits
- ovirt_role:
name: role
administrative: true
permits:
- manipulate_permissions
- create_instance
# Remove role
- ovirt_role:
name: role
state: absent
# Remove all permit
- ovirt_role:
name: role
administrative: ture
permits:
- login
'''
RETURN = '''
ovirt_role:
description: "List of dictionaries describing the Roles. Role attributes are mapped to dictionary keys,
all Roles attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/role."
returned: On success.
type: list
'''
from ansible.module_utils.ovirt import (
BaseModule,
check_sdk,
convert_to_bytes,
create_connection,
equal,
get_dict_of_struct,
get_link_name,
get_id_by_name,
ovirt_full_argument_spec,
search_by_attributes,
search_by_name,
)
from ansible.module_utils.basic import AnsibleModule
import traceback
try:
import ovirtsdk4.types as otypes
except ImportError:
pass
class RoleModule(BaseModule):
def build_entity(self):
if 'login' not in self.param('permits'):
self.param('permits').append('login')
all_permits = self.get_all_permits()
return otypes.Role(
id=self.param('id'),
name=self.param('name'),
administrative=self.param('administrative') if self.param(
'administrative') else None,
permits=[
otypes.Permit(id=all_permits.get(new_permit)) for new_permit in self.param('permits')
] if self.param('permits') else None,
description=self.param('description') if self.param('administrative') else None,
)
def get_all_permits(self):
return dict((permit.name, permit.id) for permit in self._connection.system_service().cluster_levels_service().level_service('4.3').get().permits)
def update_check(self, entity):
def check_permits():
if self.param('permits'):
if 'login' not in self.param('permits'):
self.param('permits').append('login')
permits_service = self._service.service(entity.id).permits_service()
current = [er.name for er in permits_service.list()]
passed = [pr for pr in self.param('permits')]
if not sorted(current) == sorted(passed):
if self._module.check_mode:
return False
# remove all
for permit in permits_service.list():
permits_service.permit_service(permit.id).remove()
# add passed permits
all_permits = self.get_all_permits()
for new_permit in passed:
permits_service.add(otypes.Permit(id=all_permits.get(new_permit)))
return False
return True
return (
check_permits() and
equal(self.param('administrative'), entity.administrative) and
equal(self.param('description'), entity.description)
)
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(
choices=['present', 'absent'],
default='present',
),
id=dict(default=None),
name=dict(default=None),
description=dict(default=None),
administrative=dict(type='bool', default=False),
permits=dict(type='list', default=[]),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_one_of=[['id', 'name']],
)
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
roles_service = connection.system_service().roles_service()
roles_module = RoleModule(
connection=connection,
module=module,
service=roles_service,
)
state = module.params['state']
if state == 'present':
ret = roles_module.create()
elif state == 'absent':
ret = roles_module.remove()
module.exit_json(**ret)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == "__main__":
main()

@ -1,137 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2017 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/>.
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_scheduling_policy_info
short_description: Retrieve information about one or more oVirt scheduling policies
author: "Ondra Machacek (@machacekondra)"
version_added: "2.4"
description:
- "Retrieve information about one or more oVirt scheduling policies."
- This module was called C(ovirt_scheduling_policy_facts) before Ansible 2.9, returning C(ansible_facts).
Note that the M(ovirt_scheduling_policy_info) module no longer returns C(ansible_facts)!
notes:
- "This module returns a variable C(ovirt_scheduling_policies),
which contains a list of scheduling policies. You need to register the result with
the I(register) keyword to use it."
options:
id:
description:
- "ID of the scheduling policy."
required: true
name:
description:
- "Name of the scheduling policy, can be used as glob expression."
extends_documentation_fragment: ovirt_info
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather information about all scheduling policies with name InClusterUpgrade:
- ovirt_scheduling_policy_info:
name: InClusterUpgrade
register: result
- debug:
msg: "{{ result.ovirt_scheduling_policies }}"
'''
RETURN = '''
ovirt_scheduling_policies:
description: "List of dictionaries describing the scheduling policies.
Scheduling policies attributes are mapped to dictionary keys,
all scheduling policies attributes can be found at following
url: https://ovirt.example.com/ovirt-engine/api/model#types/scheduling_policy."
returned: On success.
type: list
'''
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_info_full_argument_spec,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
id=dict(default=None),
name=dict(default=None),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name == 'ovirt_scheduling_policy_facts'
if is_old_facts:
module.deprecate("The 'ovirt_scheduling_policy_facts' module has been renamed to 'ovirt_scheduling_policy_info', "
"and the renamed one no longer returns ansible_facts", version='2.13')
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
system_service = connection.system_service()
sched_policies_service = system_service.scheduling_policies_service()
if module.params['name']:
sched_policies = [
e for e in sched_policies_service.list()
if fnmatch.fnmatch(e.name, module.params['name'])
]
elif module.params['id']:
sched_policies = [
sched_policies_service.service(module.params['id']).get()
]
else:
sched_policies = sched_policies_service.list()
result = dict(
ovirt_scheduling_policies=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in sched_policies
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

@ -1,551 +0,0 @@
#!/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/>.
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_snapshot
short_description: "Module to manage Virtual Machine Snapshots in oVirt/RHV"
version_added: "2.3"
author: "Ondra Machacek (@machacekondra)"
description:
- "Module to manage Virtual Machine Snapshots in oVirt/RHV"
options:
snapshot_id:
description:
- "ID of the snapshot to manage."
vm_name:
description:
- "Name of the Virtual Machine to manage."
required: true
state:
description:
- "Should the Virtual Machine snapshot be restore/present/absent."
choices: ['restore', 'present', 'absent']
default: present
description:
description:
- "Description of the snapshot."
disk_id:
description:
- "Disk id which you want to upload or download"
- "To get disk, you need to define disk_id or disk_name"
version_added: "2.8"
disk_name:
description:
- "Disk name which you want to upload or download"
version_added: "2.8"
download_image_path:
description:
- "Path on a file system where snapshot should be downloaded."
- "Note that you must have an valid oVirt/RHV engine CA in your system trust store
or you must provide it in C(ca_file) parameter."
- "Note that the snapshot is not downloaded when the file already exists,
but you can forcibly download the snapshot when using C(force) I (true)."
version_added: "2.8"
upload_image_path:
description:
- "Path to disk image, which should be uploaded."
version_added: "2.8"
use_memory:
description:
- "If I(true) and C(state) is I(present) save memory of the Virtual
Machine if it's running."
- "If I(true) and C(state) is I(restore) restore memory of the
Virtual Machine."
- "Note that Virtual Machine will be paused while saving the memory."
aliases:
- "restore_memory"
- "save_memory"
type: bool
keep_days_old:
description:
- "Number of days after which should snapshot be deleted."
- "It will check all snapshots of virtual machine and delete them, if they are older."
version_added: "2.8"
disks:
description:
- "List of disks which should be created with snapshot."
suboptions:
id:
description:
- "Id of the disk which should will be created."
type: str
name:
description:
- "Name of the disk which should will be created."
type: str
type: list
version_added: "2.10"
notes:
- "Note that without a guest agent the data on the created snapshot may be
inconsistent."
- "Deleting a snapshot does not remove any information from the virtual
machine - it simply removes a return-point. However, restoring a virtual
machine from a snapshot deletes any content that was written to the
virtual machine after the time the snapshot was taken."
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 snapshot:
- ovirt_snapshot:
vm_name: rhel7
description: MySnapshot
register: snapshot
# Create snapshot and save memory:
- ovirt_snapshot:
vm_name: rhel7
description: SnapWithMem
use_memory: true
register: snapshot
# Restore snapshot:
- ovirt_snapshot:
state: restore
vm_name: rhel7
snapshot_id: "{{ snapshot.id }}"
# Remove snapshot:
- ovirt_snapshot:
state: absent
vm_name: rhel7
snapshot_id: "{{ snapshot.id }}"
# Upload local image to disk and attach it to vm:
# Since Ansible 2.8
- ovirt_snapshot:
name: mydisk
vm_name: myvm
upload_image_path: /path/to/mydisk.qcow2
# Download snapshot to local file system:
# Since Ansible 2.8
- ovirt_snapshot:
snapshot_id: 7de90f31-222c-436c-a1ca-7e655bd5b60c
disk_name: DiskName
vm_name: myvm
download_image_path: /home/user/mysnaphost.qcow2
# Delete all snapshots older than 2 days
- ovirt_snapshot:
vm_name: test
keep_days_old: 2
- name: Select which disks should be add to snapshot
ovirt_snapshot:
vm_name: test
disks:
- id: 7de90f31-222c-436c-a1ca-7e655bd5b60c
- name: my_disk_name
'''
RETURN = '''
id:
description: ID of the snapshot which is managed
returned: On success if snapshot is found.
type: str
sample: 7de90f31-222c-436c-a1ca-7e655bd5b60c
snapshot:
description: "Dictionary of all the snapshot attributes. Snapshot attributes can be found on your oVirt/RHV instance
at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/snapshot."
returned: On success if snapshot is found.
type: dict
snapshots:
description: List of deleted snapshots when keep_days_old is defined and snapshot is older than the input days
returned: On success returns deleted snapshots
type: list
'''
import traceback
try:
import ovirtsdk4.types as otypes
except ImportError:
pass
import os
import ssl
import time
from ansible.module_utils.six.moves.http_client import HTTPSConnection, IncompleteRead
from ansible.module_utils.six.moves.urllib.parse import urlparse
from datetime import datetime
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
get_entity,
ovirt_full_argument_spec,
search_by_name,
wait,
get_id_by_name,
get_link_name
)
def transfer(connection, module, direction, transfer_func):
transfers_service = connection.system_service().image_transfers_service()
transfer = transfers_service.add(
otypes.ImageTransfer(
image=otypes.Image(
id=module.params['disk_id'],
),
direction=direction,
)
)
transfer_service = transfers_service.image_transfer_service(transfer.id)
try:
# After adding a new transfer for the disk, the transfer's status will be INITIALIZING.
# Wait until the init phase is over. The actual transfer can start when its status is "Transferring".
while transfer.phase == otypes.ImageTransferPhase.INITIALIZING:
time.sleep(module.params['poll_interval'])
transfer = transfer_service.get()
proxy_url = urlparse(transfer.proxy_url)
context = ssl.create_default_context()
auth = module.params['auth']
if auth.get('insecure'):
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
elif auth.get('ca_file'):
context.load_verify_locations(cafile=auth.get('ca_file'))
proxy_connection = HTTPSConnection(
proxy_url.hostname,
proxy_url.port,
context=context,
)
transfer_func(
transfer_service,
proxy_connection,
proxy_url,
transfer.signed_ticket
)
return True
finally:
transfer_service.finalize()
while transfer.phase in [
otypes.ImageTransferPhase.TRANSFERRING,
otypes.ImageTransferPhase.FINALIZING_SUCCESS,
]:
time.sleep(module.params['poll_interval'])
transfer = transfer_service.get()
if transfer.phase in [
otypes.ImageTransferPhase.UNKNOWN,
otypes.ImageTransferPhase.FINISHED_FAILURE,
otypes.ImageTransferPhase.FINALIZING_FAILURE,
otypes.ImageTransferPhase.CANCELLED,
]:
raise Exception(
"Error occurred while uploading image. The transfer is in %s" % transfer.phase
)
if module.params.get('logical_unit'):
disks_service = connection.system_service().disks_service()
wait(
service=disks_service.service(module.params['id']),
condition=lambda d: d.status == otypes.DiskStatus.OK,
wait=module.params['wait'],
timeout=module.params['timeout'],
)
def upload_disk_image(connection, module):
def _transfer(transfer_service, proxy_connection, proxy_url, transfer_ticket):
BUF_SIZE = 128 * 1024
path = module.params['upload_image_path']
image_size = os.path.getsize(path)
proxy_connection.putrequest("PUT", proxy_url.path)
proxy_connection.putheader('Content-Length', "%d" % (image_size,))
proxy_connection.endheaders()
with open(path, "rb") as disk:
pos = 0
while pos < image_size:
to_read = min(image_size - pos, BUF_SIZE)
chunk = disk.read(to_read)
if not chunk:
transfer_service.pause()
raise RuntimeError("Unexpected end of file at pos=%d" % pos)
proxy_connection.send(chunk)
pos += len(chunk)
return transfer(
connection,
module,
otypes.ImageTransferDirection.UPLOAD,
transfer_func=_transfer,
)
def download_disk_image(connection, module):
def _transfer(transfer_service, proxy_connection, proxy_url, transfer_ticket):
BUF_SIZE = 128 * 1024
transfer_headers = {
'Authorization': transfer_ticket,
}
proxy_connection.request(
'GET',
proxy_url.path,
headers=transfer_headers,
)
r = proxy_connection.getresponse()
path = module.params["download_image_path"]
image_size = int(r.getheader('Content-Length'))
with open(path, "wb") as mydisk:
pos = 0
while pos < image_size:
to_read = min(image_size - pos, BUF_SIZE)
chunk = r.read(to_read)
if not chunk:
raise RuntimeError("Socket disconnected")
mydisk.write(chunk)
pos += len(chunk)
return transfer(
connection,
module,
otypes.ImageTransferDirection.DOWNLOAD,
transfer_func=_transfer,
)
def get_disk_attachment(disk, disk_attachments, connection):
for disk_attachment in disk_attachments:
if get_link_name(connection, disk_attachment.disk) == disk.get('name') or\
disk_attachment.disk.id == disk.get('id'):
return disk_attachment
def create_snapshot(module, vm_service, snapshots_service, connection):
changed = False
snapshot = get_entity(
snapshots_service.snapshot_service(module.params['snapshot_id'])
)
if snapshot is None:
if not module.check_mode:
disk_attachments_id = set(
get_disk_attachment(disk, vm_service.disk_attachments_service().list(), connection).id
for disk in module.params.get('disks')
) if module.params.get('disks') else None
snapshot = snapshots_service.add(
otypes.Snapshot(
description=module.params.get('description'),
persist_memorystate=module.params.get('use_memory'),
disk_attachments=[otypes.DiskAttachment(disk=otypes.Disk(id=da_id)) for da_id in disk_attachments_id] if disk_attachments_id else None
)
)
changed = True
wait(
service=snapshots_service.snapshot_service(snapshot.id),
condition=lambda snap: snap.snapshot_status == otypes.SnapshotStatus.OK,
wait=module.params['wait'],
timeout=module.params['timeout'],
)
return {
'changed': changed,
'id': snapshot.id,
'snapshot': get_dict_of_struct(snapshot),
}
def remove_snapshot(module, vm_service, snapshots_service, snapshot_id=None):
changed = False
if not snapshot_id:
snapshot_id = module.params['snapshot_id']
snapshot = get_entity(
snapshots_service.snapshot_service(snapshot_id)
)
if snapshot:
snapshot_service = snapshots_service.snapshot_service(snapshot.id)
if not module.check_mode:
snapshot_service.remove()
changed = True
wait(
service=snapshot_service,
condition=lambda snapshot: snapshot is None,
wait=module.params['wait'],
timeout=module.params['timeout'],
)
return {
'changed': changed,
'id': snapshot.id if snapshot else None,
'snapshot': get_dict_of_struct(snapshot),
}
def restore_snapshot(module, vm_service, snapshots_service):
changed = False
snapshot_service = snapshots_service.snapshot_service(
module.params['snapshot_id']
)
snapshot = get_entity(snapshot_service)
if snapshot is None:
raise Exception(
"Snapshot with id '%s' doesn't exist" % module.params['snapshot_id']
)
if snapshot.snapshot_status != otypes.SnapshotStatus.IN_PREVIEW:
if not module.check_mode:
snapshot_service.restore(
restore_memory=module.params.get('use_memory'),
)
changed = True
else:
if not module.check_mode:
vm_service.commit_snapshot()
changed = True
if changed:
wait(
service=snapshot_service,
condition=lambda snap: snap.snapshot_status == otypes.SnapshotStatus.OK,
wait=module.params['wait'],
timeout=module.params['timeout'],
)
return {
'changed': changed,
'id': snapshot.id if snapshot else None,
'snapshot': get_dict_of_struct(snapshot),
}
def get_snapshot_disk_id(module, snapshots_service):
snapshot_service = snapshots_service.snapshot_service(module.params.get('snapshot_id'))
snapshot_disks_service = snapshot_service.disks_service()
disk_id = ''
if module.params.get('disk_id'):
disk_id = module.params.get('disk_id')
elif module.params.get('disk_name'):
disk_id = get_id_by_name(snapshot_disks_service, module.params.get('disk_name'))
return disk_id
def remove_old_snapshosts(module, vm_service, snapshots_service):
deleted_snapshots = []
changed = False
date_now = datetime.now()
for snapshot in snapshots_service.list():
if snapshot.vm is not None and snapshot.vm.name == module.params.get('vm_name'):
diff = date_now - snapshot.date.replace(tzinfo=None)
if diff.days >= module.params.get('keep_days_old'):
snapshot = remove_snapshot(module, vm_service, snapshots_service, snapshot.id).get('snapshot')
deleted_snapshots.append(snapshot)
changed = True
return dict(snapshots=deleted_snapshots, changed=changed)
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(
choices=['restore', 'present', 'absent'],
default='present',
),
vm_name=dict(required=True),
snapshot_id=dict(default=None),
disks=dict(
type='list',
options=dict(
name=dict(default=None, type='str'),
id=dict(default=None, type='str'),
)
),
disk_id=dict(default=None),
disk_name=dict(default=None),
description=dict(default=None),
download_image_path=dict(default=None),
upload_image_path=dict(default=None),
keep_days_old=dict(default=None, type='int'),
use_memory=dict(
default=None,
type='bool',
aliases=['restore_memory', 'save_memory'],
),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
('state', 'absent', ['snapshot_id']),
('state', 'restore', ['snapshot_id']),
]
)
check_sdk(module)
ret = {}
vm_name = module.params.get('vm_name')
auth = module.params['auth']
connection = create_connection(auth)
vms_service = connection.system_service().vms_service()
vm = search_by_name(vms_service, vm_name)
if not vm:
module.fail_json(
msg="Vm '{name}' doesn't exist.".format(name=vm_name),
)
vm_service = vms_service.vm_service(vm.id)
snapshots_service = vms_service.vm_service(vm.id).snapshots_service()
try:
state = module.params['state']
if state == 'present':
if module.params.get('disk_id') or module.params.get('disk_name'):
module.params['disk_id'] = get_snapshot_disk_id(module, snapshots_service)
if module.params['upload_image_path']:
ret['changed'] = upload_disk_image(connection, module)
if module.params['download_image_path']:
ret['changed'] = download_disk_image(connection, module)
if module.params.get('keep_days_old') is not None:
ret = remove_old_snapshosts(module, vm_service, snapshots_service)
else:
ret = create_snapshot(module, vm_service, snapshots_service, connection)
elif state == 'restore':
ret = restore_snapshot(module, vm_service, snapshots_service)
elif state == 'absent':
ret = remove_snapshot(module, vm_service, snapshots_service)
module.exit_json(**ret)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == "__main__":
main()

@ -1,133 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_snapshot_info
short_description: Retrieve information about one or more oVirt/RHV virtual machine snapshots
author: "Ondra Machacek (@machacekondra)"
version_added: "2.3"
description:
- "Retrieve information about one or more oVirt/RHV virtual machine snapshots."
- This module was called C(ovirt_snapshot_facts) before Ansible 2.9, returning C(ansible_facts).
Note that the M(ovirt_snapshot_info) module no longer returns C(ansible_facts)!
notes:
- "This module returns a variable C(ovirt_snapshots), which
contains a list of snapshots. You need to register the result with
the I(register) keyword to use it."
options:
vm:
description:
- "Name of the VM with snapshot."
required: true
description:
description:
- "Description of the snapshot, can be used as glob expression."
snapshot_id:
description:
- "Id of the snapshot we want to retrieve information about."
extends_documentation_fragment: ovirt_info
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather information about all snapshots which description start with C(update) for VM named C(centos7):
- ovirt_snapshot_info:
vm: centos7
description: update*
register: result
- debug:
msg: "{{ result.ovirt_snapshots }}"
'''
RETURN = '''
ovirt_snapshots:
description: "List of dictionaries describing the snapshot. Snapshot attributes are mapped to dictionary keys,
all snapshot attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/snapshot."
returned: On success.
type: list
'''
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_info_full_argument_spec,
search_by_name,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
vm=dict(required=True),
description=dict(default=None),
snapshot_id=dict(default=None),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name == 'ovirt_snapshot_facts'
if is_old_facts:
module.deprecate("The 'ovirt_snapshot_facts' module has been renamed to 'ovirt_snapshot_info', "
"and the renamed one no longer returns ansible_facts", version='2.13')
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(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)
snapshots_service = vms_service.service(vm.id).snapshots_service()
if module.params['description']:
snapshots = [
e for e in snapshots_service.list()
if fnmatch.fnmatch(e.description, module.params['description'])
]
elif module.params['snapshot_id']:
snapshots = [
snapshots_service.snapshot_service(module.params['snapshot_id']).get()
]
else:
snapshots = snapshots_service.list()
result = dict(
ovirt_snapshots=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in snapshots
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

@ -1,285 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2017 Red Hat, Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_storage_connection
short_description: Module to manage storage connections in oVirt
version_added: "2.4"
author: "Ondra Machacek (@machacekondra)"
description:
- "Module to manage storage connections in oVirt"
options:
id:
description:
- "Id of the storage connection to manage."
state:
description:
- "Should the storage connection be present or absent."
choices: ['present', 'absent']
default: present
storage:
description:
- "Name of the storage domain to be used with storage connection."
address:
description:
- "Address of the storage server. E.g.: myserver.mydomain.com"
path:
description:
- "Path of the mount point of the storage. E.g.: /path/to/my/data"
nfs_version:
description:
- "NFS version. One of: I(auto), I(v3), I(v4) or I(v4_1)."
nfs_timeout:
description:
- "The time in tenths of a second to wait for a response before retrying NFS requests. Range 0 to 65535."
nfs_retrans:
description:
- "The number of times to retry a request before attempting further recovery actions. Range 0 to 65535."
mount_options:
description:
- "Option which will be passed when mounting storage."
password:
description:
- "A CHAP password for logging into a target."
username:
description:
- "A CHAP username for logging into a target."
port:
description:
- "Port of the iSCSI storage server."
target:
description:
- "The target IQN for the storage device."
type:
description:
- "Storage type. For example: I(nfs), I(iscsi), etc."
vfs_type:
description:
- "Virtual File System type."
force:
description:
- "This parameter is relevant only when updating a connection."
- "If I(true) the storage domain don't have to be in I(MAINTENANCE)
state, so the storage connection is updated."
type: bool
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 new storage connection:
- ovirt_storage_connection:
storage: myiscsi
address: 10.34.63.199
target: iqn.2016-08-09.domain-01:nickname
port: 3260
type: iscsi
# Update the existing storage connection address:
- ovirt_storage_connection:
id: 26915c96-92ff-47e5-9e77-b581db2f2d36
address: 10.34.63.204
force: true
# Remove storage connection:
- ovirt_storage_connection:
id: 26915c96-92ff-47e5-9e77-b581db2f2d36
'''
RETURN = '''
id:
description: ID of the storage connection which is managed
returned: On success if storage connection is found.
type: str
sample: 7de90f31-222c-436c-a1ca-7e655bd5b60c
storage_connection:
description: "Dictionary of all the storage connection attributes. Storage connection attributes can be found on your oVirt instance
at following url: https://ovirt.example.com/ovirt-engine/api/model#types/storage_connection."
returned: On success if storage connection is found.
type: dict
'''
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,
ovirt_full_argument_spec,
search_by_name,
)
class StorageConnectionModule(BaseModule):
def build_entity(self):
return otypes.StorageConnection(
address=self.param('address'),
path=self.param('path'),
nfs_version=otypes.NfsVersion(
self.param('nfs_version')
) if self.param('nfs_version') is not None else None,
nfs_timeo=self.param('nfs_timeout'),
nfs_retrans=self.param('nfs_retrans'),
mount_options=self.param('mount_options'),
password=self.param('password'),
username=self.param('username'),
port=self.param('port'),
target=self.param('target'),
type=otypes.StorageType(
self.param('type')
) if self.param('type') is not None else None,
vfs_type=self.param('vfs_type'),
)
def _get_storage_domain_service(self):
sds_service = self._connection.system_service().storage_domains_service()
sd = search_by_name(sds_service, self.param('storage'))
if sd is None:
raise Exception(
"Storage '%s' was not found." % self.param('storage')
)
return sd, sds_service.storage_domain_service(sd.id)
def post_present(self, entity_id):
if self.param('storage'):
sd, sd_service = self._get_storage_domain_service()
if entity_id not in [
sd_conn.id for sd_conn in self._connection.follow_link(sd.storage_connections)
]:
scs_service = sd_service.storage_connections_service()
if not self._module.check_mode:
scs_service.add(
connection=otypes.StorageConnection(
id=entity_id,
),
)
self.changed = True
def pre_remove(self, entity_id):
if self.param('storage'):
sd, sd_service = self._get_storage_domain_service()
if entity_id in [
sd_conn.id for sd_conn in self._connection.follow_link(sd.storage_connections)
]:
scs_service = sd_service.storage_connections_service()
sc_service = scs_service.connection_service(entity_id)
if not self._module.check_mode:
sc_service.remove()
self.changed = True
def update_check(self, entity):
return (
equal(self.param('address'), entity.address) and
equal(self.param('path'), entity.path) and
equal(self.param('nfs_version'), str(entity.nfs_version)) and
equal(self.param('nfs_timeout'), entity.nfs_timeo) and
equal(self.param('nfs_retrans'), entity.nfs_retrans) and
equal(self.param('mount_options'), entity.mount_options) and
equal(self.param('username'), entity.username) and
equal(self.param('port'), entity.port) and
equal(self.param('target'), entity.target) and
equal(self.param('type'), str(entity.type)) and
equal(self.param('vfs_type'), entity.vfs_type)
)
def find_sc_by_attributes(module, storage_connections_service):
for sd_conn in [
sc for sc in storage_connections_service.list()
if str(sc.type) == module.params['type']
]:
sd_conn_type = str(sd_conn.type)
if sd_conn_type in ['nfs', 'posixfs', 'glusterfs', 'localfs']:
if (
module.params['address'] == sd_conn.address and
module.params['path'] == sd_conn.path
):
return sd_conn
elif sd_conn_type in ['iscsi', 'fcp']:
if (
module.params['address'] == sd_conn.address and
module.params['target'] == sd_conn.target
):
return sd_conn
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(
choices=['present', 'absent'],
default='present',
),
id=dict(default=None),
address=dict(default=None),
path=dict(default=None),
nfs_version=dict(default=None),
nfs_timeout=dict(default=None, type='int'),
nfs_retrans=dict(default=None, type='int'),
mount_options=dict(default=None),
password=dict(default=None, no_log=True),
username=dict(default=None),
port=dict(default=None, type='int'),
target=dict(default=None),
type=dict(default=None),
vfs_type=dict(default=None),
force=dict(type='bool', default=False),
storage=dict(default=None),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
)
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
storage_connections_service = connection.system_service().storage_connections_service()
storage_connection_module = StorageConnectionModule(
connection=connection,
module=module,
service=storage_connections_service,
)
entity = None
if module.params['id'] is None:
entity = find_sc_by_attributes(module, storage_connections_service)
state = module.params['state']
if state == 'present':
ret = storage_connection_module.create(
entity=entity,
update_params={'force': True},
)
storage_connection_module.post_present(ret['id'])
elif state == 'absent':
storage_connection_module.pre_remove(module.params['id'])
ret = storage_connection_module.remove(entity=entity)
module.exit_json(**ret)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == "__main__":
main()

@ -1,809 +0,0 @@
#!/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/>.
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_storage_domain
short_description: Module to manage storage domains in oVirt/RHV
version_added: "2.3"
author: "Ondra Machacek (@machacekondra)"
description:
- "Module to manage storage domains in oVirt/RHV"
options:
id:
description:
- "Id of the storage domain to be imported."
version_added: "2.4"
name:
description:
- "Name of the storage domain to manage. (Not required when state is I(imported))"
state:
description:
- "Should the storage domain be present/absent/maintenance/unattached/imported/update_ovf_store"
- "I(imported) is supported since version 2.4."
- "I(update_ovf_store) is supported since version 2.5, currently if C(wait) is (true), we don't wait for update."
choices: ['present', 'absent', 'maintenance', 'unattached', 'imported', 'update_ovf_store']
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."
- "This parameter isn't idempotent, it's not possible to change data center of storage domain."
domain_function:
description:
- "Function of the storage domain."
- "This parameter isn't idempotent, it's not possible to change domain function of storage domain."
choices: ['data', 'iso', 'export']
default: 'data'
aliases: ['type']
host:
description:
- "Host to be used to mount storage."
localfs:
description:
- "Dictionary with values for localfs storage type:"
- "Note that these parameters are not idempotent."
suboptions:
path:
description:
- "Path of the mount point. E.g.: /path/to/my/data"
version_added: "2.4"
nfs:
description:
- "Dictionary with values for NFS storage type:"
- "Note that these parameters are not idempotent."
suboptions:
address:
description:
- "Address of the NFS server. E.g.: myserver.mydomain.com"
path:
description:
- "Path of the mount point. E.g.: /path/to/my/data"
version:
description:
- "NFS version. One of: I(auto), I(v3), I(v4) or I(v4_1)."
timeout:
description:
- "The time in tenths of a second to wait for a response before retrying NFS requests. Range 0 to 65535."
retrans:
description:
- "The number of times to retry a request before attempting further recovery actions. Range 0 to 65535."
mount_options:
description:
- "Option which will be passed when mounting storage."
iscsi:
description:
- "Dictionary with values for iSCSI storage type:"
- "Note that these parameters are not idempotent."
suboptions:
address:
description:
- Address of the iSCSI storage server.
port:
description:
- Port of the iSCSI storage server.
target:
description:
- The target IQN for the storage device.
lun_id:
description:
- LUN id(s).
username:
description:
- A CHAP user name for logging into a target.
password:
description:
- A CHAP password for logging into a target.
override_luns:
description:
- If I(True) ISCSI storage domain luns will be overridden before adding.
type: bool
target_lun_map:
description:
- List of dictionary containing targets and LUNs.
version_added: 2.5
posixfs:
description:
- "Dictionary with values for PosixFS storage type:"
- "Note that these parameters are not idempotent."
suboptions:
path:
description:
- "Path of the mount point. E.g.: /path/to/my/data"
vfs_type:
description:
- Virtual File System type.
mount_options:
description:
- Option which will be passed when mounting storage.
glusterfs:
description:
- "Dictionary with values for GlusterFS storage type:"
- "Note that these parameters are not idempotent."
suboptions:
address:
description:
- "Address of the Gluster server. E.g.: myserver.mydomain.com"
path:
description:
- "Path of the mount point. E.g.: /path/to/my/data"
mount_options:
description:
- Option which will be passed when mounting storage.
managed_block_storage:
description:
- "Dictionary with values for managed block storage type"
- "Note: available from ovirt 4.3"
suboptions:
driver_options:
description:
- "The options to be passed when creating a storage domain using a cinder driver."
- "List of dictionary containing C(name) and C(value) of driver option"
driver_sensitive_options:
description:
- "Parameters containing sensitive information, to be passed when creating a storage domain using a cinder driver."
- "List of dictionary containing C(name) and C(value) of driver sensitive option"
version_added: "2.9"
fcp:
description:
- "Dictionary with values for fibre channel storage type:"
- "Note that these parameters are not idempotent."
suboptions:
lun_id:
description:
- LUN id.
override_luns:
description:
- If I(True) FCP storage domain LUNs will be overridden before adding.
type: bool
wipe_after_delete:
description:
- "Boolean flag which indicates whether the storage domain should wipe the data after delete."
type: bool
version_added: "2.5"
backup:
description:
- "Boolean flag which indicates whether the storage domain is configured as backup or not."
type: bool
version_added: "2.5"
critical_space_action_blocker:
description:
- "Indicates the minimal free space the storage domain should contain in percentages."
version_added: "2.5"
warning_low_space:
description:
- "Indicates the minimum percentage of a free space in a storage domain to present a warning."
version_added: "2.5"
destroy:
description:
- "Logical remove of the storage domain. If I(true) retains the storage domain's data for import."
- "This parameter is relevant only when C(state) is I(absent)."
type: bool
format:
description:
- "If I(True) storage domain will be formatted after removing it from oVirt/RHV."
- "This parameter is relevant only when C(state) is I(absent)."
type: bool
discard_after_delete:
description:
- "If I(True) storage domain blocks will be discarded upon deletion. Enabled by default."
- "This parameter is relevant only for block based storage domains."
type: bool
version_added: 2.5
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_domain:
name: data_nfs
host: myhost
data_center: mydatacenter
nfs:
address: 10.34.63.199
path: /path/data
# Add data NFS storage domain with id for data center
- ovirt_storage_domain:
name: data_nfs
host: myhost
data_center: 11111
nfs:
address: 10.34.63.199
path: /path/data
mount_options: noexec,nosuid
# Add data localfs storage domain
- ovirt_storage_domain:
name: data_localfs
host: myhost
data_center: mydatacenter
localfs:
path: /path/to/data
# Add data iSCSI storage domain:
- ovirt_storage_domain:
name: data_iscsi
host: myhost
data_center: mydatacenter
iscsi:
target: iqn.2016-08-09.domain-01:nickname
lun_id:
- 1IET_000d0001
- 1IET_000d0002
address: 10.34.63.204
discard_after_delete: True
backup: False
critical_space_action_blocker: 5
warning_low_space: 10
# Since Ansible 2.5 you can specify multiple targets for storage domain,
# Add data iSCSI storage domain with multiple targets:
- ovirt_storage_domain:
name: data_iscsi
host: myhost
data_center: mydatacenter
iscsi:
target_lun_map:
- target: iqn.2016-08-09.domain-01:nickname
lun_id: 1IET_000d0001
- target: iqn.2016-08-09.domain-02:nickname
lun_id: 1IET_000d0002
address: 10.34.63.204
discard_after_delete: True
# Add data glusterfs storage domain
- ovirt_storage_domain:
name: glusterfs_1
host: myhost
data_center: mydatacenter
glusterfs:
address: 10.10.10.10
path: /path/data
# Create export NFS storage domain:
- ovirt_storage_domain:
name: myexportdomain
domain_function: export
host: myhost
data_center: mydatacenter
nfs:
address: 10.34.63.199
path: /path/export
wipe_after_delete: False
backup: True
critical_space_action_blocker: 2
warning_low_space: 5
# Import export NFS storage domain:
- ovirt_storage_domain:
state: imported
domain_function: export
host: myhost
data_center: mydatacenter
nfs:
address: 10.34.63.199
path: /path/export
# Import FCP storage domain:
- ovirt_storage_domain:
state: imported
name: data_fcp
host: myhost
data_center: mydatacenter
fcp: {}
# Update OVF_STORE:
- ovirt_storage_domain:
state: update_ovf_store
name: domain
# Create ISO NFS storage domain
- ovirt_storage_domain:
name: myiso
domain_function: iso
host: myhost
data_center: mydatacenter
nfs:
address: 10.34.63.199
path: /path/iso
# Create managed storage domain
# Available from ovirt 4.3 and ansible 2.9
- ovirt_storage_domain:
name: my_managed_domain
host: myhost
data_center: mydatacenter
managed_block_storage:
driver_options:
- name: rbd_pool
value: pool1
- name: rbd_user
value: admin
- name: volume_driver
value: cinder.volume.drivers.rbd.RBDDriver
- name: rbd_keyring_conf
value: /etc/ceph/keyring
driver_sensitive_options:
- name: secret_password
value: password
# Remove storage domain
- ovirt_storage_domain:
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/RHV instance
at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/storage_domain."
returned: On success if storage domain is found.
type: dict
'''
try:
import ovirtsdk4.types as otypes
from ovirtsdk4.types import StorageDomainStatus as sdstate
from ovirtsdk4.types import HostStatus as hoststate
from ovirtsdk4.types import DataCenterStatus as dcstatus
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_entity,
get_id_by_name,
OvirtRetry,
ovirt_full_argument_spec,
search_by_name,
search_by_attributes,
wait,
)
class StorageDomainModule(BaseModule):
def _get_storage_type(self):
for sd_type in ['nfs', 'iscsi', 'posixfs', 'glusterfs', 'fcp', 'localfs', 'managed_block_storage']:
if self.param(sd_type) is not None:
return sd_type
def _get_storage(self):
for sd_type in ['nfs', 'iscsi', 'posixfs', 'glusterfs', 'fcp', 'localfs', 'managed_block_storage']:
if self.param(sd_type) is not None:
return self.param(sd_type)
def _login(self, storage_type, storage):
if storage_type == 'iscsi':
hosts_service = self._connection.system_service().hosts_service()
host_id = get_id_by_name(hosts_service, self.param('host'))
if storage.get('target'):
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'),
),
)
elif storage.get('target_lun_map'):
for target in [m['target'] for m in storage.get('target_lun_map')]:
hosts_service.host_service(host_id).iscsi_login(
iscsi=otypes.IscsiDetails(
username=storage.get('username'),
password=storage.get('password'),
address=storage.get('address'),
target=target,
),
)
def __target_lun_map(self, storage):
if storage.get('target'):
lun_ids = storage.get('lun_id') if isinstance(storage.get('lun_id'), list) else [(storage.get('lun_id'))]
return [(lun_id, storage.get('target')) for lun_id in lun_ids]
elif storage.get('target_lun_map'):
return [(target_map.get('lun_id'), target_map.get('target')) for target_map in storage.get('target_lun_map')]
else:
lun_ids = storage.get('lun_id') if isinstance(storage.get('lun_id'), list) else [(storage.get('lun_id'))]
return [(lun_id, None) for lun_id in lun_ids]
def build_entity(self):
storage_type = self._get_storage_type()
storage = self._get_storage()
self._login(storage_type, storage)
return otypes.StorageDomain(
name=self.param('name'),
description=self.param('description'),
comment=self.param('comment'),
wipe_after_delete=self.param('wipe_after_delete'),
backup=self.param('backup'),
critical_space_action_blocker=self.param('critical_space_action_blocker'),
warning_low_space_indicator=self.param('warning_low_space'),
import_=True if self.param('state') == 'imported' else None,
id=self.param('id') if self.param('state') == 'imported' else None,
type=otypes.StorageDomainType(storage_type if storage_type == 'managed_block_storage' else self.param('domain_function')),
host=otypes.Host(name=self.param('host')),
discard_after_delete=self.param('discard_after_delete'),
storage=otypes.HostStorage(
driver_options=[
otypes.Property(
name=do.get('name'),
value=do.get('value')
) for do in storage.get('driver_options')
] if storage.get('driver_options') else None,
driver_sensitive_options=[
otypes.Property(
name=dso.get('name'),
value=dso.get('value')
) for dso in storage.get('driver_sensitive_options')
] if storage.get('driver_sensitive_options') else None,
type=otypes.StorageType(storage_type),
logical_units=[
otypes.LogicalUnit(
id=lun_id,
address=storage.get('address'),
port=int(storage.get('port', 3260)),
target=target,
username=storage.get('username'),
password=storage.get('password'),
) for lun_id, target in self.__target_lun_map(storage)
] if storage_type in ['iscsi', 'fcp'] else None,
override_luns=storage.get('override_luns'),
mount_options=storage.get('mount_options'),
vfs_type=(
'glusterfs'
if storage_type in ['glusterfs'] else storage.get('vfs_type')
),
address=storage.get('address'),
path=storage.get('path'),
nfs_retrans=storage.get('retrans'),
nfs_timeo=storage.get('timeout'),
nfs_version=otypes.NfsVersion(
storage.get('version')
) if storage.get('version') else None,
) if storage_type is not None else None
)
def _find_attached_datacenter_name(self, sd_name):
"""
Finds the name of the datacenter that a given
storage domain is attached to.
Args:
sd_name (str): Storage Domain name
Returns:
str: Data Center name
Raises:
Exception: In case storage domain in not attached to
an active Datacenter
"""
dcs_service = self._connection.system_service().data_centers_service()
dc = search_by_attributes(dcs_service, storage=sd_name)
if dc is None:
raise Exception(
"Can't bring storage to state `%s`, because it seems that"
"it is not attached to any datacenter"
% self.param('state')
)
else:
if dc.status == dcstatus.UP:
return dc.name
else:
raise Exception(
"Can't bring storage to state `%s`, because Datacenter "
"%s is not UP" % (self.param('state'), dc.name)
)
def _attached_sds_service(self, dc_name):
# Get data center object of the storage domain:
dcs_service = self._connection.system_service().data_centers_service()
# Search the data_center name, if it does not exist, try to search by guid.
dc = search_by_name(dcs_service, dc_name)
if dc is None:
dc = get_entity(dcs_service.service(dc_name))
if dc is None:
return None
dc_service = dcs_service.data_center_service(dc.id)
return dc_service.storage_domains_service()
def _attached_sd_service(self, storage_domain):
dc_name = self.param('data_center')
if not dc_name:
# Find the DC, where the storage resides:
dc_name = self._find_attached_datacenter_name(storage_domain.name)
attached_sds_service = self._attached_sds_service(dc_name)
attached_sd_service = attached_sds_service.storage_domain_service(storage_domain.id)
return attached_sd_service
def _maintenance(self, storage_domain):
attached_sd_service = self._attached_sd_service(storage_domain)
attached_sd = get_entity(attached_sd_service)
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.param('wait'),
timeout=self.param('timeout'),
)
def _unattach(self, storage_domain):
attached_sd_service = self._attached_sd_service(storage_domain)
attached_sd = get_entity(attached_sd_service)
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.param('wait'),
timeout=self.param('timeout'),
)
def pre_remove(self, storage_domain):
# In case the user chose to destroy the storage domain there is no need to
# move it to maintenance or detach it, it should simply be removed from the DB.
# Also if storage domain in already unattached skip this step.
if storage_domain.status == sdstate.UNATTACHED or self.param('destroy'):
return
# 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()
dc_name = self.param('data_center')
if not dc_name:
# Find the DC, where the storage resides:
dc_name = self._find_attached_datacenter_name(storage_domain.name)
self._service = self._attached_sds_service(dc_name)
# If storage domain isn't attached, attach it:
attached_sd_service = self._service.service(storage_domain.id)
if get_entity(attached_sd_service) 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.param('wait'),
timeout=self.param('timeout'),
)
def unattached_pre_action(self, storage_domain):
dc_name = self.param('data_center')
if not dc_name:
# Find the DC, where the storage resides:
dc_name = self._find_attached_datacenter_name(storage_domain.name)
self._service = self._attached_sds_service(dc_name)
self._maintenance(storage_domain)
def update_check(self, entity):
return (
equal(self.param('comment'), entity.comment) and
equal(self.param('description'), entity.description) and
equal(self.param('backup'), entity.backup) and
equal(self.param('critical_space_action_blocker'), entity.critical_space_action_blocker) and
equal(self.param('discard_after_delete'), entity.discard_after_delete) and
equal(self.param('wipe_after_delete'), entity.wipe_after_delete) and
equal(self.param('warning_low_space_indicator'), entity.warning_low_space_indicator)
)
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)
# In the case of no status returned, it's an attached storage domain.
# Redetermine the corresponding service and entity:
if sd.status is None:
sd_service = sd_module._attached_sd_service(sd)
sd = get_entity(sd_service)
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', 'imported', 'update_ovf_store'],
default='present',
),
id=dict(default=None),
name=dict(default=None),
description=dict(default=None),
comment=dict(default=None),
data_center=dict(default=None),
domain_function=dict(choices=['data', 'iso', 'export'], default='data', aliases=['type']),
host=dict(default=None),
localfs=dict(default=None, type='dict'),
nfs=dict(default=None, type='dict'),
iscsi=dict(default=None, type='dict'),
managed_block_storage=dict(default=None, type='dict', options=dict(
driver_options=dict(type='list'),
driver_sensitive_options=dict(type='list', no_log=True))),
posixfs=dict(default=None, type='dict'),
glusterfs=dict(default=None, type='dict'),
fcp=dict(default=None, type='dict'),
wipe_after_delete=dict(type='bool', default=None),
backup=dict(type='bool', default=None),
critical_space_action_blocker=dict(type='int', default=None),
warning_low_space=dict(type='int', default=None),
destroy=dict(type='bool', default=None),
format=dict(type='bool', default=None),
discard_after_delete=dict(type='bool', default=None)
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
)
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(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':
# Pick random available host when host parameter is missing
host_param = module.params['host']
if not host_param:
host = search_by_attributes(connection.system_service().hosts_service(), status='up')
if host is None:
raise Exception(
"Not possible to remove storage domain '%s' "
"because no host found with status `up`." % module.params['name']
)
host_param = host.name
ret = storage_domains_module.remove(
destroy=module.params['destroy'],
format=module.params['format'],
host=host_param,
)
elif state == 'present' or state == 'imported':
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,
search_params={'id': sd_id} if state == 'imported' else None
)
elif state == 'maintenance':
sd_id = storage_domains_module.create()['id']
storage_domains_module.post_create_check(sd_id)
ret = OvirtRetry.backoff(tries=5, delay=1, backoff=2)(
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
elif state == 'update_ovf_store':
ret = storage_domains_module.action(
action='update_ovf_store'
)
module.exit_json(**ret)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == "__main__":
main()

@ -1,120 +0,0 @@
#!/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/>.
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_storage_domain_info
short_description: Retrieve information about one or more oVirt/RHV storage domains
author: "Ondra Machacek (@machacekondra)"
version_added: "2.3"
description:
- "Retrieve information about one or more oVirt/RHV storage domains."
- This module was called C(ovirt_storage_domain_facts) before Ansible 2.9, returning C(ansible_facts).
Note that the M(ovirt_storage_domain_info) module no longer returns C(ansible_facts)!
notes:
- "This module returns a variable C(ovirt_storage_domains), which
contains a list of storage domains. You need to register the result with
the I(register) keyword to use it."
options:
pattern:
description:
- "Search term which is accepted by oVirt/RHV search backend."
- "For example to search storage domain X from datacenter Y use following pattern:
name=X and datacenter=Y"
extends_documentation_fragment: ovirt_info
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather information about all storage domains which names start with C(data) and
# belong to data center C(west):
- ovirt_storage_domain_info:
pattern: name=data* and datacenter=west
register: result
- debug:
msg: "{{ result.ovirt_storage_domains }}"
'''
RETURN = '''
ovirt_storage_domains:
description: "List of dictionaries describing the storage domains. Storage_domain attributes are mapped to dictionary keys,
all storage domains attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/storage_domain."
returned: On success.
type: list
'''
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
pattern=dict(default='', required=False),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name == 'ovirt_storage_domain_facts'
if is_old_facts:
module.deprecate("The 'ovirt_storage_domain_facts' module has been renamed to 'ovirt_storage_domain_info', "
"and the renamed one no longer returns ansible_facts", version='2.13')
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
storage_domains_service = connection.system_service().storage_domains_service()
storage_domains = storage_domains_service.list(search=module.params['pattern'])
result = dict(
ovirt_storage_domains=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in storage_domains
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

@ -1,138 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2017 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/>.
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_storage_template_info
short_description: Retrieve information about one or more oVirt/RHV templates relate to a storage domain.
author: "Maor Lipchuk (@machacekondra)"
version_added: "2.4"
description:
- "Retrieve information about one or more oVirt/RHV templates relate to a storage domain."
- This module was called C(ovirt_storage_template_facts) before Ansible 2.9, returning C(ansible_facts).
Note that the M(ovirt_storage_template_info) module no longer returns C(ansible_facts)!
notes:
- "This module returns a variable C(ovirt_storage_templates), which
contains a list of templates. You need to register the result with
the I(register) keyword to use it."
options:
unregistered:
description:
- "Flag which indicates whether to get unregistered templates which contain one or more
disks which reside on a storage domain or diskless templates."
type: bool
default: false
max:
description:
- "Sets the maximum number of templates to return. If not specified all the templates are returned."
storage_domain:
description:
- "The storage domain name where the templates should be listed."
extends_documentation_fragment: ovirt_info
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather information about all Templates which relate to a storage domain and
# are unregistered:
- ovirt_storage_template_info:
unregistered=True
register: result
- debug:
msg: "{{ result.ovirt_storage_templates }}"
'''
RETURN = '''
ovirt_storage_templates:
description: "List of dictionaries describing the Templates. Template attributes are mapped to dictionary keys,
all Templates attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/template."
returned: On success.
type: list
'''
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
get_id_by_name
)
def main():
argument_spec = ovirt_info_full_argument_spec(
storage_domain=dict(default=None),
max=dict(default=None, type='int'),
unregistered=dict(default=False, type='bool'),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name == 'ovirt_storage_template_facts'
if is_old_facts:
module.deprecate("The 'ovirt_storage_template_facts' module has been renamed to 'ovirt_storage_template_info', "
"and the renamed one no longer returns ansible_facts", version='2.13')
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
storage_domains_service = connection.system_service().storage_domains_service()
sd_id = get_id_by_name(storage_domains_service, module.params['storage_domain'])
storage_domain_service = storage_domains_service.storage_domain_service(sd_id)
templates_service = storage_domain_service.templates_service()
# Find the unregistered Template we want to register:
if module.params.get('unregistered'):
templates = templates_service.list(unregistered=True)
else:
templates = templates_service.list(max=module.params['max'])
result = dict(
ovirt_storage_templates=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in templates
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

@ -1,138 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2017 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/>.
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_storage_vm_info
short_description: Retrieve information about one or more oVirt/RHV virtual machines relate to a storage domain.
author: "Maor Lipchuk (@machacekondra)"
version_added: "2.4"
description:
- "Retrieve information about one or more oVirt/RHV virtual machines relate to a storage domain."
- This module was called C(ovirt_storage_vm_facts) before Ansible 2.9, returning C(ansible_facts).
Note that the M(ovirt_storage_vm_info) module no longer returns C(ansible_facts)!
notes:
- "This module returns a variable C(ovirt_storage_vms), which
contains a list of virtual machines. You need to register the result with
the I(register) keyword to use it."
options:
unregistered:
description:
- "Flag which indicates whether to get unregistered virtual machines which contain one or more
disks which reside on a storage domain or diskless virtual machines."
type: bool
default: false
max:
description:
- "Sets the maximum number of virtual machines to return. If not specified all the virtual machines are returned."
storage_domain:
description:
- "The storage domain name where the virtual machines should be listed."
extends_documentation_fragment: ovirt_info
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather information about all VMs which relate to a storage domain and
# are unregistered:
- ovirt_vms_info:
unregistered=True
register: result
- debug:
msg: "{{ result.ovirt_storage_vms }}"
'''
RETURN = '''
ovirt_storage_vms:
description: "List of dictionaries describing the VMs. VM attributes are mapped to dictionary keys,
all VMs attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/vm."
returned: On success.
type: list
'''
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
get_id_by_name
)
def main():
argument_spec = ovirt_info_full_argument_spec(
storage_domain=dict(default=None),
max=dict(default=None, type='int'),
unregistered=dict(default=False, type='bool'),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name == 'ovirt_storage_vm_facts'
if is_old_facts:
module.deprecate("The 'ovirt_storage_vm_facts' module has been renamed to 'ovirt_storage_vm_info', "
"and the renamed one no longer returns ansible_facts", version='2.13')
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
storage_domains_service = connection.system_service().storage_domains_service()
sd_id = get_id_by_name(storage_domains_service, module.params['storage_domain'])
storage_domain_service = storage_domains_service.storage_domain_service(sd_id)
vms_service = storage_domain_service.vms_service()
# Find the unregistered VM we want to register:
if module.params.get('unregistered'):
vms = vms_service.list(unregistered=True)
else:
vms = vms_service.list()
result = dict(
ovirt_storage_vms=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in vms
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

@ -1,257 +0,0 @@
#!/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/>.
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_tag
short_description: Module to manage tags in oVirt/RHV
version_added: "2.3"
author: "Ondra Machacek (@machacekondra)"
description:
- "This module manage tags in oVirt/RHV. It can also manage assignments
of those tags to entities."
options:
id:
description:
- "ID of the tag to manage."
version_added: "2.8"
name:
description:
- "Name of the tag to manage."
required: true
state:
description:
- "Should the tag be present/absent/attached/detached."
- "C(Note): I(attached) and I(detached) states are supported since version 2.4."
choices: ['present', 'absent', 'attached', 'detached']
default: present
description:
description:
- "Description of the tag to manage."
parent:
description:
- "Name of the parent tag."
vms:
description:
- "List of the VMs names, which should have assigned this tag."
hosts:
description:
- "List of the hosts names, which should have assigned this tag."
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 tag to vms vm1 and vm2:
- ovirt_tag:
name: mytag
vms:
- vm1
- vm2
# Attach a tag to VM 'vm3', keeping the rest already attached tags on VM:
- ovirt_tag:
name: mytag
state: attached
vms:
- vm3
# Detach a tag from VM 'vm3', keeping the rest already attached tags on VM:
- ovirt_tag:
name: mytag
state: detached
vms:
- vm3
# To detach all VMs from tag:
- ovirt_tag:
name: mytag
vms: []
# Remove tag
- ovirt_tag:
state: absent
name: mytag
# Change Tag Name
- ovirt_tag:
id: 00000000-0000-0000-0000-000000000000
name: "new_tag_name"
'''
RETURN = '''
id:
description: ID of the tag which is managed
returned: On success if tag is found.
type: str
sample: 7de90f31-222c-436c-a1ca-7e655bd5b60c
tag:
description: "Dictionary of all the tag attributes. Tag attributes can be found on your oVirt/RHV instance
at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/tag."
returned: On success if tag is found.
type: dict
'''
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_id_by_name,
ovirt_full_argument_spec,
)
class TagsModule(BaseModule):
def build_entity(self):
return otypes.Tag(
id=self._module.params['id'],
name=self._module.params['name'],
description=self._module.params['description'],
parent=otypes.Tag(
name=self._module.params['parent'],
) if self._module.params['parent'] else None,
)
def post_create(self, entity):
self.update_check(entity)
def _update_tag_assignments(self, entity, name):
if self._module.params[name] is None:
return
state = self.param('state')
entities_service = getattr(self._connection.system_service(), '%s_service' % name)()
current_vms = [
vm.name
for vm in entities_service.list(search='tag=%s' % self._module.params['name'])
]
# Assign tags:
if state in ['present', 'attached', 'detached']:
for entity_name in self._module.params[name]:
entity_id = get_id_by_name(entities_service, entity_name)
tags_service = entities_service.service(entity_id).tags_service()
current_tags = [tag.name for tag in tags_service.list()]
# Assign the tag:
if state in ['attached', 'present']:
if self._module.params['name'] not in current_tags:
if not self._module.check_mode:
tags_service.add(
tag=otypes.Tag(
name=self._module.params['name'],
),
)
self.changed = True
# Detach the tag:
elif state == 'detached':
if self._module.params['name'] in current_tags:
tag_id = get_id_by_name(tags_service, self.param('name'))
if not self._module.check_mode:
tags_service.tag_service(tag_id).remove()
self.changed = True
# Unassign tags:
if state == 'present':
for entity_name in [e for e in current_vms if e not in self._module.params[name]]:
if not self._module.check_mode:
entity_id = get_id_by_name(entities_service, entity_name)
tags_service = entities_service.service(entity_id).tags_service()
tag_id = get_id_by_name(tags_service, self.param('name'))
tags_service.tag_service(tag_id).remove()
self.changed = True
def _get_parent(self, entity):
parent = None
if entity.parent:
parent = self._connection.follow_link(entity.parent).name
return parent
def update_check(self, entity):
self._update_tag_assignments(entity, 'vms')
self._update_tag_assignments(entity, 'hosts')
return (
equal(self._module.params.get('description'), entity.description) and
equal(self._module.params.get('name'), entity.name) and
equal(self._module.params.get('parent'), self._get_parent(entity))
)
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(
choices=['present', 'absent', 'attached', 'detached'],
default='present',
),
id=dict(default=None),
name=dict(required=True),
description=dict(default=None),
parent=dict(default=None),
vms=dict(default=None, type='list'),
hosts=dict(default=None, type='list'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
)
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
tags_service = connection.system_service().tags_service()
tags_module = TagsModule(
connection=connection,
module=module,
service=tags_service,
)
state = module.params['state']
if state in ['present', 'attached', 'detached']:
ret = tags_module.create()
elif state == 'absent':
ret = tags_module.remove()
module.exit_json(**ret)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == "__main__":
main()

@ -1,167 +0,0 @@
#!/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/>.
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_tag_info
short_description: Retrieve information about one or more oVirt/RHV tags
author: "Ondra Machacek (@machacekondra)"
version_added: "2.3"
description:
- "Retrieve information about one or more oVirt/RHV tags."
- This module was called C(ovirt_tag_facts) before Ansible 2.9, returning C(ansible_facts).
Note that the M(ovirt_tag_info) module no longer returns C(ansible_facts)!
notes:
- "This module returns a variable C(ovirt_tags), which
contains a list of tags. You need to register the result with
the I(register) keyword to use it."
options:
name:
description:
- "Name of the tag which should be listed."
vm:
description:
- "Name of the VM, which tags should be listed."
host:
description:
- "Name of the host, which tags should be listed."
extends_documentation_fragment: ovirt_info
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather information about all tags, which names start with C(tag):
- ovirt_tag_info:
name: tag*
register: result
- debug:
msg: "{{ result.ovirt_tags }}"
# Gather information about all tags, which are assigned to VM C(postgres):
- ovirt_tag_info:
vm: postgres
register: result
- debug:
msg: "{{ result.ovirt_tags }}"
# Gather information about all tags, which are assigned to host C(west):
- ovirt_tag_info:
host: west
register: result
- debug:
msg: "{{ result.ovirt_tags }}"
'''
RETURN = '''
ovirt_tags:
description: "List of dictionaries describing the tags. Tags attributes are mapped to dictionary keys,
all tags attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/tag."
returned: On success.
type: list
'''
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_info_full_argument_spec,
search_by_name,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
name=dict(default=None),
host=dict(default=None),
vm=dict(default=None),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name == 'ovirt_tag_facts'
if is_old_facts:
module.deprecate("The 'ovirt_tag_facts' module has been renamed to 'ovirt_tag_info', "
"and the renamed one no longer returns ansible_facts", version='2.13')
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
tags_service = connection.system_service().tags_service()
tags = []
all_tags = tags_service.list()
if module.params['name']:
tags.extend([
t for t in all_tags
if fnmatch.fnmatch(t.name, module.params['name'])
])
if module.params['host']:
hosts_service = connection.system_service().hosts_service()
host = search_by_name(hosts_service, module.params['host'])
if host is None:
raise Exception("Host '%s' was not found." % module.params['host'])
tags.extend([
tag for tag in hosts_service.host_service(host.id).tags_service().list()
])
if module.params['vm']:
vms_service = connection.system_service().vms_service()
vm = search_by_name(vms_service, module.params['vm'])
if vm is None:
raise Exception("Vm '%s' was not found." % module.params['vm'])
tags.extend([
tag for tag in vms_service.vm_service(vm.id).tags_service().list()
])
if not (module.params['vm'] or module.params['host'] or module.params['name']):
tags = all_tags
result = dict(
ovirt_tags=[
get_dict_of_struct(
struct=t,
connection=connection,
fetch_nested=module.params['fetch_nested'],
attributes=module.params['nested_attributes'],
) for t in tags
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

File diff suppressed because it is too large Load Diff

@ -1,120 +0,0 @@
#!/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/>.
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_template_info
short_description: Retrieve information about one or more oVirt/RHV templates
author: "Ondra Machacek (@machacekondra)"
version_added: "2.3"
description:
- "Retrieve information about one or more oVirt/RHV templates."
- This module was called C(ovirt_template_facts) before Ansible 2.9, returning C(ansible_facts).
Note that the M(ovirt_template_info) module no longer returns C(ansible_facts)!
notes:
- "This module returns a variable C(ovirt_templates), which
contains a list of templates. You need to register the result with
the I(register) keyword to use it."
options:
pattern:
description:
- "Search term which is accepted by oVirt/RHV search backend."
- "For example to search template X from datacenter Y use following pattern:
name=X and datacenter=Y"
extends_documentation_fragment: ovirt_info
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather information about all templates which names start with C(centos) and
# belongs to data center C(west):
- ovirt_template_info:
pattern: name=centos* and datacenter=west
register: result
- debug:
msg: "{{ result.ovirt_templates }}"
'''
RETURN = '''
ovirt_templates:
description: "List of dictionaries describing the templates. Template attributes are mapped to dictionary keys,
all templates attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/template."
returned: On success.
type: list
'''
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
pattern=dict(default='', required=False),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name == 'ovirt_template_facts'
if is_old_facts:
module.deprecate("The 'ovirt_template_facts' module has been renamed to 'ovirt_template_info', "
"and the renamed one no longer returns ansible_facts", version='2.13')
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
templates_service = connection.system_service().templates_service()
templates = templates_service.list(search=module.params['pattern'])
result = dict(
ovirt_templates=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in templates
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

@ -1,176 +0,0 @@
#!/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/>.
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_user
short_description: Module to manage users in oVirt/RHV
version_added: "2.3"
author: "Ondra Machacek (@machacekondra)"
description:
- "Module to manage users in oVirt/RHV."
options:
name:
description:
- "Name of 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/RHV known as domain."
required: true
aliases: ['domain']
namespace:
description:
- "Namespace where the user resides. When using the authorization provider that stores users in the LDAP server,
this attribute equals the naming context of the LDAP server."
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_user:
name: user1
domain: example.com-authz
# Add user user1 from authorization provider example.com-authz
# In case of Active Directory specify UPN:
- ovirt_user:
name: user1@ad2.example.com
domain: example.com-authz
# Remove user user1 with authorization provider example.com-authz
- ovirt_user:
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/RHV instance
at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/user."
returned: On success if user is found.
type: dict
'''
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,
)
def username(module):
return '{0}@{1}'.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:
auth = module.params.pop('auth')
connection = create_connection(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=auth.get('token') is None)
if __name__ == "__main__":
main()

@ -1,118 +0,0 @@
#!/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/>.
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_user_info
short_description: Retrieve information about one or more oVirt/RHV users
author: "Ondra Machacek (@machacekondra)"
version_added: "2.3"
description:
- "Retrieve information about one or more oVirt/RHV users."
- This module was called C(ovirt_user_facts) before Ansible 2.9, returning C(ansible_facts).
Note that the M(ovirt_user_info) module no longer returns C(ansible_facts)!
notes:
- "This module returns a variable C(ovirt_users), which
contains a list of users. You need to register the result with
the I(register) keyword to use it."
options:
pattern:
description:
- "Search term which is accepted by oVirt/RHV search backend."
- "For example to search user X use following pattern: name=X"
extends_documentation_fragment: ovirt_info
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather information about all users which first names start with C(john):
- ovirt_user_info:
pattern: name=john*
register: result
- debug:
msg: "{{ result.ovirt_users }}"
'''
RETURN = '''
ovirt_users:
description: "List of dictionaries describing the users. User attributes are mapped to dictionary keys,
all users attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/user."
returned: On success.
type: list
'''
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
pattern=dict(default='', required=False),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name == 'ovirt_user_facts'
if is_old_facts:
module.deprecate("The 'ovirt_user_facts' module has been renamed to 'ovirt_user_info', "
"and the renamed one no longer returns ansible_facts", version='2.13')
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
users_service = connection.system_service().users_service()
users = users_service.list(search=module.params['pattern'])
result = dict(
ovirt_users=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in users
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

File diff suppressed because it is too large Load Diff

@ -1,160 +0,0 @@
#!/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/>.
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_vm_info
short_description: Retrieve information about one or more oVirt/RHV virtual machines
author: "Ondra Machacek (@machacekondra)"
version_added: "2.3"
description:
- "Retrieve information about one or more oVirt/RHV virtual machines."
- This module was called C(ovirt_vm_facts) before Ansible 2.9, returning C(ansible_facts).
Note that the M(ovirt_vm_info) module no longer returns C(ansible_facts)!
notes:
- "This module returns a variable C(ovirt_vms), which
contains a list of virtual machines. You need to register the result with
the I(register) keyword to use it."
options:
pattern:
description:
- "Search term which is accepted by oVirt/RHV search backend."
- "For example to search VM X from cluster Y use following pattern:
name=X and cluster=Y"
all_content:
description:
- "If I(true) all the attributes of the virtual machines should be
included in the response."
type: bool
case_sensitive:
description:
- "If I(true) performed search will take case into account."
type: bool
default: true
max:
description:
- "The maximum number of results to return."
next_run:
description:
- "Indicates if the returned result describes the virtual machine as it is currently running or if describes
the virtual machine with the modifications that have already been performed but that will only come into
effect when the virtual machine is restarted. By default the value is set by engine."
type: bool
version_added: "2.8"
extends_documentation_fragment: ovirt_info
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather information about all VMs which names start with C(centos) and
# belong to cluster C(west):
- ovirt_vm_info:
pattern: name=centos* and cluster=west
register: result
- debug:
msg: "{{ result.ovirt_vms }}"
# Gather info about next run configuration of virtual machine named myvm
- ovirt_vm_info:
pattern: name=myvm
next_run: true
register: result
- debug:
msg: "{{ result.ovirt_vms[0] }}"
'''
RETURN = '''
ovirt_vms:
description: "List of dictionaries describing the VMs. VM attributes are mapped to dictionary keys,
all VMs attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/vm."
returned: On success.
type: list
'''
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
pattern=dict(default='', required=False),
all_content=dict(default=False, type='bool'),
next_run=dict(default=None, type='bool'),
case_sensitive=dict(default=True, type='bool'),
max=dict(default=None, type='int'),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name == 'ovirt_vm_facts'
if is_old_facts:
module.deprecate("The 'ovirt_vm_facts' module has been renamed to 'ovirt_vm_info', "
"and the renamed one no longer returns ansible_facts", version='2.13')
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
vms_service = connection.system_service().vms_service()
vms = vms_service.list(
search=module.params['pattern'],
all_content=module.params['all_content'],
case_sensitive=module.params['case_sensitive'],
max=module.params['max'],
)
if module.params['next_run']:
vms = [vms_service.vm_service(vm.id).get(next_run=True) for vm in vms]
result = dict(
ovirt_vms=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in vms
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

@ -1,485 +0,0 @@
#!/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/>.
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_vmpool
short_description: Module to manage VM pools in oVirt/RHV
version_added: "2.3"
author: "Ondra Machacek (@machacekondra)"
description:
- "Module to manage VM pools in oVirt/RHV."
options:
id:
description:
- "ID of the vmpool to manage."
version_added: "2.8"
name:
description:
- "Name of the VM pool to manage."
required: true
comment:
description:
- Comment of the Virtual Machine pool.
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."
vm:
description:
- "For creating vm pool without editing template."
- "Note: You can use C(vm) only for creating vm pool."
type: dict
suboptions:
comment:
description:
- Comment of the Virtual Machine.
timezone:
description:
- Sets time zone offset of the guest hardware clock.
- For example C(Etc/GMT)
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.
memory_max:
description:
- Upper bound of virtual machine memory up to which memory hot-plug can be performed.
Prefix uses IEC 60027-2 standard (for example 1GiB, 1024MiB).
- Default value is set by engine.
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. This is appended to the end of the
cloud-init script generated by any other options.
- 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 C(none), C(dhcp) or C(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.
sso:
description:
- "I(True) enable Single Sign On by Guest Agent, I(False) to disable it. By default is chosen by oVirt/RHV engine."
type: bool
smartcard_enabled:
description:
- "If I(true), use smart card authentication."
type: bool
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.
- 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.
version_added: "2.9"
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
- name: Create VM pool from template
ovirt_vmpool:
cluster: mycluster
name: myvmpool
template: rhel7
vm_count: 2
prestarted: 2
vm_per_user: 1
- name: Remove vmpool, note that all VMs in pool will be stopped and removed
ovirt_vmpool:
state: absent
name: myvmpool
- name: Change Pool Name
ovirt_vmpool:
id: 00000000-0000-0000-0000-000000000000
name: "new_pool_name"
- name: Create vm pool and override the pool values
ovirt_vmpool:
cluster: mycluster
name: vmpool
template: blank
vm_count: 2
prestarted: 1
vm_per_user: 1
vm:
memory: 4GiB
memory_guaranteed: 4GiB
memory_max: 10GiB
comment: vncomment
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
nics:
- name: nicname
interface: virtio
profile_name: network
'''
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/RHV instance
at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/vm_pool."
returned: On success if VM pool is found.
type: dict
'''
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,
convert_to_bytes,
search_by_name,
)
class VmPoolsModule(BaseModule):
def __init__(self, *args, **kwargs):
super(VmPoolsModule, self).__init__(*args, **kwargs)
self._initialization = None
def build_entity(self):
vm = self.param('vm')
return otypes.VmPool(
id=self._module.params['id'],
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,
vm=self.build_vm(vm) if self._module.params['vm'] else None,
)
def build_vm(self, vm):
return otypes.Vm(
comment=vm.get('comment'),
memory=convert_to_bytes(
vm.get('memory')
) if vm.get('memory') else None,
memory_policy=otypes.MemoryPolicy(
guaranteed=convert_to_bytes(vm.get('memory_guaranteed')),
max=convert_to_bytes(vm.get('memory_max')),
) if any((
vm.get('memory_guaranteed'),
vm.get('memory_max')
)) else None,
initialization=self.get_initialization(vm),
display=otypes.Display(
smartcard_enabled=vm.get('smartcard_enabled')
) if vm.get('smartcard_enabled') is not None else None,
sso=(
otypes.Sso(
methods=[otypes.Method(id=otypes.SsoMethod.GUEST_AGENT)] if vm.get('sso') else []
)
) if vm.get('sso') is not None else None,
time_zone=otypes.TimeZone(
name=vm.get('timezone'),
) if vm.get('timezone') else None,
)
def get_initialization(self, vm):
if self._initialization is not None:
return self._initialization
sysprep = vm.get('sysprep')
cloud_init = vm.get('cloud_init')
cloud_init_nics = vm.get('cloud_init_nics') or []
if cloud_init is not None:
cloud_init_nics.append(cloud_init)
if cloud_init or cloud_init_nics:
self._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:
self._initialization = otypes.Initialization(
**sysprep
)
return self._initialization
def get_vms(self, entity):
vms = self._connection.system_service().vms_service().list()
resp = []
for vm in vms:
if vm.vm_pool is not None and vm.vm_pool.id == entity.id:
resp.append(vm)
return resp
def post_create(self, entity):
vm_param = self.param('vm')
if vm_param is not None and vm_param.get('nics') is not None:
vms = self.get_vms(entity)
for vm in vms:
self.__attach_nics(vm, vm_param)
def __attach_nics(self, entity, vm_param):
# Attach NICs to VM, if specified:
vms_service = self._connection.system_service().vms_service()
nics_service = vms_service.service(entity.id).nics_service()
for nic in vm_param.get('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=self.__get_vnic_profile_id(nic),
) 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_vnic_profile_id(self, nic):
"""
Return VNIC profile ID looked up by it's name, because there can be
more VNIC profiles with same name, other criteria of filter is cluster.
"""
vnics_service = self._connection.system_service().vnic_profiles_service()
clusters_service = self._connection.system_service().clusters_service()
cluster = search_by_name(clusters_service, self.param('cluster'))
profiles = [
profile for profile in vnics_service.list()
if profile.name == nic.get('profile_name')
]
cluster_networks = [
net.id for net in self._connection.follow_link(cluster.networks)
]
try:
return next(
profile.id for profile in profiles
if profile.network.id in cluster_networks
)
except StopIteration:
raise Exception(
"Profile '%s' was not found in cluster '%s'" % (
nic.get('profile_name'),
self.param('cluster')
)
)
def update_check(self, entity):
return (
equal(self._module.params.get('name'), entity.name) and
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(
id=dict(default=None),
state=dict(
choices=['present', 'absent'],
default='present',
),
name=dict(required=True),
template=dict(default=None),
cluster=dict(default=None),
description=dict(default=None),
vm=dict(default=None, type='dict'),
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:
auth = module.params.pop('auth')
connection = create_connection(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=auth.get('token') is None)
if __name__ == "__main__":
main()

@ -1,118 +0,0 @@
#!/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/>.
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_vmpool_info
short_description: Retrieve information about one or more oVirt/RHV vmpools
author: "Ondra Machacek (@machacekondra)"
version_added: "2.3"
description:
- "Retrieve information about one or more oVirt/RHV vmpools."
- This module was called C(ovirt_vmpool_facts) before Ansible 2.9, returning C(ansible_facts).
Note that the M(ovirt_vmpool_info) module no longer returns C(ansible_facts)!
notes:
- "This module returns a variable C(ovirt_vmpools), which
contains a list of vmpools. You need to register the result with
the I(register) keyword to use it."
options:
pattern:
description:
- "Search term which is accepted by oVirt/RHV search backend."
- "For example to search vmpool X: name=X"
extends_documentation_fragment: ovirt_info
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather information about all vm pools which names start with C(centos):
- ovirt_vmpool_info:
pattern: name=centos*
register: result
- debug:
msg: "{{ result.ovirt_vm_pools }}"
'''
RETURN = '''
ovirt_vm_pools:
description: "List of dictionaries describing the vmpools. Vm pool attributes are mapped to dictionary keys,
all vmpools attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/vm_pool."
returned: On success.
type: list
'''
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
pattern=dict(default='', required=False),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name == 'ovirt_vmpool_facts'
if is_old_facts:
module.deprecate("The 'ovirt_vmpool_facts' module has been renamed to 'ovirt_vmpool_info', "
"and the renamed one no longer returns ansible_facts", version='2.13')
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
vmpools_service = connection.system_service().vm_pools_service()
vmpools = vmpools_service.list(search=module.params['pattern'])
result = dict(
ovirt_vm_pools=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in vmpools
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

@ -1,321 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2017, Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_vnic_profile
short_description: Module to manage vNIC profile of network in oVirt/RHV
version_added: "2.8"
author:
- "Ondra Machacek (@machacekondra)"
- "Martin Necas (@mnecas)"
description:
- "Module to manage vNIC profile of network in oVirt/RHV"
options:
name:
description:
- "A human-readable name in plain text."
required: true
state:
description:
- "Should the vNIC be absent/present."
choices: ['absent', 'present']
default: present
description:
description:
- "A human-readable description in plain text."
data_center:
description:
- "Datacenter name where network reside."
required: true
network:
description:
- "Name of network to which is vNIC attached."
required: true
network_filter:
description:
- "The network filter enables to filter packets send to/from the VM's nic according to defined rules."
custom_properties:
description:
- "Custom properties applied to the vNIC profile."
- "Custom properties is a list of dictionary which can have following values:"
suboptions:
name:
description:
- "Name of the custom property. For example: I(hugepages), I(vhost), I(sap_agent), etc."
regexp:
description:
- Regular expression to set for custom property.
value:
description:
- Value to set for custom property.
qos:
description:
- "Quality of Service attributes regulate inbound and outbound network traffic of the NIC."
port_mirroring:
description:
- "Enables port mirroring."
type: bool
pass_through:
description:
- "Enables passthrough to an SR-IOV-enabled host NIC."
- "When enabled C(qos) and C(network_filter) are automatically set to None and C(port_mirroring) to False."
- "When enabled and C(migratable) not specified then C(migratable) is enabled."
- "Port mirroring, QoS and network filters are not supported on passthrough profiles."
choices: ['disabled', 'enabled']
migratable:
description:
- "Marks whether pass_through NIC is migratable or not."
type: bool
extends_documentation_fragment: ovirt
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
- name: Add vNIC
ovirt_vnic_profile:
name: myvnic
network: mynetwork
state: present
data_center: datacenter
- name: Editing vNICs network_filter, custom_properties, qos
ovirt_vnic_profile:
name: myvnic
network: mynetwork
data_center: datacenter
qos: myqos
custom_properties:
- name: SecurityGroups
value: 9bd9bde9-39da-44a8-9541-aa39e1a81c9d
network_filter: allow-dhcp
- name: Remove vNICs network_filter, custom_properties, qos
ovirt_vnic_profile:
name: myvnic
network: mynetwork
data_center: datacenter
qos: ""
custom_properties: ""
network_filter: ""
- name: Dont use migratable
ovirt_vnic_profile:
name: myvnic
network: mynetwork
data_center: datacenter
migratable: False
pass_through: enabled
- name: Remove vNIC
ovirt_vnic_profile:
name: myvnic
network: mynetwork
state: absent
data_center: datacenter
'''
RETURN = '''
id:
description: ID of the vNIC profile which is managed
returned: On success if vNIC profile is found.
type: str
sample: 7de90f31-222c-436c-a1ca-7e655bd5b60c
vnic:
description: "Dictionary of all the vNIC profile attributes. Network interface attributes can be found on your oVirt/RHV instance
at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/nic."
returned: On success if vNIC profile is found.
type: dict
'''
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,
get_id_by_name
)
class EntityVnicPorfileModule(BaseModule):
def __init__(self, *args, **kwargs):
super(EntityVnicPorfileModule, self).__init__(*args, **kwargs)
def _get_dcs_service(self):
return self._connection.system_service().data_centers_service()
def _get_dcs_id(self):
return get_id_by_name(self._get_dcs_service(), self.param('data_center'))
def _get_network_id(self):
networks_service = self._get_dcs_service().service(self._get_dcs_id()).networks_service()
return get_id_by_name(networks_service, self.param('network'))
def _get_qos_id(self):
if self.param('qos'):
qoss_service = self._get_dcs_service().service(self._get_dcs_id()).qoss_service()
return get_id_by_name(qoss_service, self.param('qos')) if self.param('qos') else None
return None
def _get_network_filter_id(self):
nf_service = self._connection.system_service().network_filters_service()
return get_id_by_name(nf_service, self.param('network_filter')) if self.param('network_filter') else None
def _get_network_filter(self):
network_filter = None
# The order of these condition is necessary.
# When would network_filter and pass_through specified it would try to create and network_filter and fail on engine.
if self.param('network_filter') == '' or self.param('pass_through') == 'enabled':
network_filter = otypes.NetworkFilter()
elif self.param('network_filter'):
network_filter = otypes.NetworkFilter(id=self._get_network_filter_id())
return network_filter
def _get_qos(self):
qos = None
# The order of these condition is necessary. When would qos and pass_through specified it would try to create and qos and fail on engine.
if self.param('qos') == '' or self.param('pass_through') == 'enabled':
qos = otypes.Qos()
elif self.param('qos'):
qos = otypes.Qos(id=self._get_qos_id())
return qos
def _get_port_mirroring(self):
if self.param('pass_through') == 'enabled':
return False
return self.param('port_mirroring')
def _get_migratable(self):
if self.param('migratable') is not None:
return self.param('migratable')
if self.param('pass_through') == 'enabled':
return True
def build_entity(self):
return otypes.VnicProfile(
name=self.param('name'),
network=otypes.Network(id=self._get_network_id()),
description=self.param('description') if self.param('description') is not None else None,
pass_through=otypes.VnicPassThrough(mode=otypes.VnicPassThroughMode(self.param('pass_through'))) if self.param('pass_through') else None,
custom_properties=[
otypes.CustomProperty(
name=cp.get('name'),
regexp=cp.get('regexp'),
value=str(cp.get('value')),
) for cp in self.param('custom_properties') if cp
] if self.param('custom_properties') else None,
migratable=self._get_migratable(),
qos=self._get_qos(),
port_mirroring=self._get_port_mirroring(),
network_filter=self._get_network_filter()
)
def update_check(self, entity):
def check_custom_properties():
if self.param('custom_properties'):
current = []
if entity.custom_properties:
current = [(cp.name, cp.regexp, str(cp.value)) for cp in entity.custom_properties]
passed = [(cp.get('name'), cp.get('regexp'), str(cp.get('value'))) for cp in self.param('custom_properties') if cp]
return sorted(current) == sorted(passed)
return True
pass_through = getattr(entity.pass_through.mode, 'name', None)
return (
check_custom_properties() and
# The reason why we can't use equal method, is we get None from _get_network_filter_id or _get_qos_id method, when passing empty string.
# And when first param of equal method is None it returns true.
self._get_network_filter_id() == getattr(entity.network_filter, 'id', None) and
self._get_qos_id() == getattr(entity.qos, 'id', None) and
equal(self.param('migratable'), getattr(entity, 'migratable', None)) and
equal(self.param('pass_through'), pass_through.lower() if pass_through else None) and
equal(self.param('description'), entity.description) and
equal(self.param('port_mirroring'), getattr(entity, 'port_mirroring', None))
)
def get_entity(vnic_services, entitynics_module):
vnic_profiles = vnic_services.list()
network_id = entitynics_module._get_network_id()
for vnic in vnic_profiles:
# When vNIC already exist update it, when not create it
if vnic.name == entitynics_module.param('name') and network_id == vnic.network.id:
return vnic
def check_params(module):
if (module.params.get('port_mirroring') or module.params.get('network_filter') or module.params.get('qos'))\
and module.params.get('pass_through') == 'enabled':
module.fail_json(msg="Cannot edit VM network interface profile. 'Port Mirroring,'Qos' and 'Network Filter' are not supported on passthrough profiles.")
def main():
argument_spec = ovirt_full_argument_spec(
state=dict(type='str', default='present', choices=['absent', 'present']),
network=dict(type='str', required=True),
data_center=dict(type='str', required=True),
description=dict(type='str'),
name=dict(type='str', required=True),
network_filter=dict(type='str'),
custom_properties=dict(type='list'),
qos=dict(type='str'),
pass_through=dict(type='str', choices=['disabled', 'enabled']),
port_mirroring=dict(type='bool'),
migratable=dict(type='bool'),
)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
)
check_sdk(module)
check_params(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
vnic_services = connection.system_service().vnic_profiles_service()
entitynics_module = EntityVnicPorfileModule(
connection=connection,
module=module,
service=vnic_services,
)
state = module.params['state']
entity = get_entity(vnic_services, entitynics_module)
if state == 'present':
ret = entitynics_module.create(entity=entity, force_create=entity is None)
elif state == 'absent':
if entity is not None:
ret = entitynics_module.remove(entity=entity)
else:
raise Exception("Vnic profile '%s' in network '%s' was not found." % (module.params['name'], module.params['network']))
module.exit_json(**ret)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == "__main__":
main()

@ -1,119 +0,0 @@
#!/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/>.
#
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: ovirt_vnic_profile_info
short_description: Retrieve information about one or more oVirt/RHV vnic profiles
author: "Martin Necas (@mnecas)"
version_added: "2.10"
description:
- "Retrieve information about one or more oVirt/RHV vnic profiles."
notes:
- "This module returns a variable C(ovirt_vnic_profiles), which
contains a list of vnic profiles. You need to register the result with
the I(register) keyword to use it."
options:
max:
description:
- "The maximum number of results to return."
type: int
name:
description:
- "Name of vnic profile."
type: str
extends_documentation_fragment: ovirt_info
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
# Gather information 10 vnic profiles
- ovirt_vnic_profile_info:
max: 10
register: result
- debug:
msg: "{{ result.ovirt_vnic_profiles }}"
'''
RETURN = '''
ovirt_vnic_profiles:
description: "List of dictionaries describing the vnic profiles. Vnic_profile attributes are mapped to dictionary keys,
all vnic profiles attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/vnic_profile."
returned: On success.
type: list
'''
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
max=dict(default=None, type='int'),
name=dict(default=None),
)
module = AnsibleModule(argument_spec)
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
vnic_profiles_service = connection.system_service().vnic_profiles_service()
vnic_profiles = vnic_profiles_service.list(max=module.params.get('max'))
if module.params.get('name') and vnic_profiles:
vnic_profiles = [vnic_profile for vnic_profile in vnic_profiles if vnic_profile.name == module.params.get("name")]
result = dict(
ovirt_vnic_profiles=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in vnic_profiles
],
)
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

@ -1,102 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2016, Red Hat, Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
class ModuleDocFragment(object):
# Standard oVirt documentation fragment
DOCUMENTATION = r'''
options:
wait:
description:
- "C(yes) if the module should wait for the entity to get into desired state."
type: bool
default: yes
fetch_nested:
description:
- "If I(True) the module will fetch additional data from the API."
- "It will fetch IDs of the VMs disks, snapshots, etc. User can configure to fetch other
attributes of the nested entities by specifying C(nested_attributes)."
type: bool
version_added: "2.3"
nested_attributes:
description:
- "Specifies list of the attributes which should be fetched from the API."
- "This parameter apply only when C(fetch_nested) is I(true)."
type: list
version_added: "2.3"
auth:
description:
- "Dictionary with values needed to create HTTP/HTTPS connection to oVirt:"
suboptions:
username:
description:
- The name of the user, something like I(admin@internal).
- Default value is set by C(OVIRT_USERNAME) environment variable.
type: str
required: true
password:
description:
- The password of the user.
- Default value is set by C(OVIRT_PASSWORD) environment variable.
type: str
required: true
url:
description:
- A string containing the API URL of the server, usually something like `I(https://server.example.com/ovirt-engine/api)`.
- Default value is set by C(OVIRT_URL) environment variable.
- Either C(url) or C(hostname) is required.
type: str
hostname:
description:
- A string containing the hostname of the server, usually something like `I(server.example.com)`.
- Default value is set by C(OVIRT_HOSTNAME) environment variable.
- Either C(url) or C(hostname) is required.
type: str
token:
description:
- Token to be used instead of login with username/password.
- Default value is set by C(OVIRT_TOKEN) environment variable.
type: str
insecure:
description:
- A boolean flag that indicates if the server TLS certificate and host name should be checked.
type: bool
ca_file:
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.
- Default value is set by C(OVIRT_CAFILE) environment variable.
type: str
kerberos:
description:
- A boolean flag indicating if Kerberos authentication should be used instead of the default basic authentication.
type: bool
headers:
description:
- Dictionary of HTTP headers to be added to each API call.
type: dict
type: dict
required: true
timeout:
description:
- "The amount of time in seconds the module should wait for the instance to
get into desired state."
type: int
default: 180
poll_interval:
description:
- "Number of the seconds the module waits until another poll request on entity status is sent."
type: int
default: 3
requirements:
- python >= 2.7
- ovirt-engine-sdk-python >= 4.3.0
notes:
- "In order to use this module you have to install oVirt Python SDK.
To ensure it's installed with correct version you can create the following task:
I(pip: name=ovirt-engine-sdk-python version=4.3.0)"
'''

@ -1,57 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2016, Red Hat, Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
class ModuleDocFragment(object):
# info standard oVirt documentation fragment
DOCUMENTATION = r'''
options:
fetch_nested:
description:
- If I(yes) the module will fetch additional data from the API.
- It will fetch only IDs of nested entity. It doesn't fetch multiple levels of nested attributes.
Only the attributes of the current entity. User can configure to fetch other
attributes of the nested entities by specifying C(nested_attributes).
type: bool
version_added: "2.3"
nested_attributes:
description:
- Specifies list of the attributes which should be fetched from the API.
- This parameter apply only when C(fetch_nested) is I(true).
type: list
version_added: "2.3"
auth:
description:
- "Dictionary with values needed to create HTTP/HTTPS connection to oVirt:"
- C(username)[I(required)] - The name of the user, something like I(admin@internal).
Default value is set by I(OVIRT_USERNAME) environment variable.
- "C(password)[I(required)] - The password of the user. Default value is set by I(OVIRT_PASSWORD) environment variable."
- "C(url)- A string containing the API URL of the server, usually
something like `I(https://server.example.com/ovirt-engine/api)`. Default value is set by I(OVIRT_URL) environment variable.
Either C(url) or C(hostname) is required."
- "C(hostname) - A string containing the hostname of the server, usually
something like `I(server.example.com)`. Default value is set by I(OVIRT_HOSTNAME) environment variable.
Either C(url) or C(hostname) is required."
- "C(token) - Token to be used instead of login with username/password. Default value is set by I(OVIRT_TOKEN) environment variable."
- "C(insecure) - A boolean flag that indicates if the server TLS
certificate and host name should be checked."
- "C(ca_file) - 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. Default value is set by I(OVIRT_CAFILE) environment variable."
- "C(kerberos) - A boolean flag indicating if Kerberos authentication
should be used instead of the default basic authentication."
- "C(headers) - Dictionary of HTTP headers to be added to each API call."
type: dict
required: true
requirements:
- python >= 2.7
- ovirt-engine-sdk-python >= 4.3.0
notes:
- "In order to use this module you have to install oVirt Python SDK.
To ensure it's installed with correct version you can create the following task:
pip: name=ovirt-engine-sdk-python version=4.3.0"
'''

@ -94,8 +94,6 @@ lib/ansible/module_utils/network/skydive/api.py future-import-boilerplate
lib/ansible/module_utils/network/skydive/api.py metaclass-boilerplate
lib/ansible/module_utils/network/vyos/vyos.py future-import-boilerplate
lib/ansible/module_utils/network/vyos/vyos.py metaclass-boilerplate
lib/ansible/module_utils/ovirt.py future-import-boilerplate
lib/ansible/module_utils/ovirt.py metaclass-boilerplate
lib/ansible/module_utils/parsing/convert_bool.py future-import-boilerplate
lib/ansible/module_utils/parsing/convert_bool.py metaclass-boilerplate
lib/ansible/module_utils/powershell/Ansible.ModuleUtils.ArgvParser.psm1 pslint:PSUseApprovedVerbs
@ -1016,256 +1014,6 @@ lib/ansible/modules/cloud/google/gcp_tpu_node_info.py validate-modules:parameter
lib/ansible/modules/cloud/hcloud/hcloud_network_info.py validate-modules:return-syntax-error
lib/ansible/modules/cloud/hcloud/hcloud_server.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/hcloud/hcloud_server_network.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_affinity_group.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_affinity_group.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_affinity_group.py validate-modules:doc-required-mismatch
lib/ansible/modules/cloud/ovirt/ovirt_affinity_group.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_affinity_group.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/cloud/ovirt/ovirt_affinity_label.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_affinity_label.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_affinity_label.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_affinity_label.py validate-modules:no-default-for-required-parameter
lib/ansible/modules/cloud/ovirt/ovirt_affinity_label.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_affinity_label.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/cloud/ovirt/ovirt_affinity_label_info.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_affinity_label_info.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_affinity_label_info.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_affinity_label_info.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_api_info.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_auth.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_auth.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_auth.py validate-modules:doc-default-does-not-match-spec
lib/ansible/modules/cloud/ovirt/ovirt_auth.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_auth.py validate-modules:invalid-ansiblemodule-schema
lib/ansible/modules/cloud/ovirt/ovirt_auth.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/cloud/ovirt/ovirt_auth.py validate-modules:undocumented-parameter
lib/ansible/modules/cloud/ovirt/ovirt_cluster.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_cluster.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_cluster.py validate-modules:doc-choices-do-not-match-spec
lib/ansible/modules/cloud/ovirt/ovirt_cluster.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_cluster.py validate-modules:no-default-for-required-parameter
lib/ansible/modules/cloud/ovirt/ovirt_cluster.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_cluster.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/cloud/ovirt/ovirt_cluster.py validate-modules:undocumented-parameter
lib/ansible/modules/cloud/ovirt/ovirt_cluster_info.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_cluster_info.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_cluster_info.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_cluster_info.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_datacenter.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_datacenter.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_datacenter.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_datacenter.py validate-modules:no-default-for-required-parameter
lib/ansible/modules/cloud/ovirt/ovirt_datacenter.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_datacenter_info.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_datacenter_info.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_datacenter_info.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_datacenter_info.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_disk.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_disk.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_disk.py validate-modules:doc-choices-do-not-match-spec
lib/ansible/modules/cloud/ovirt/ovirt_disk.py validate-modules:doc-default-does-not-match-spec
lib/ansible/modules/cloud/ovirt/ovirt_disk.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_disk.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_disk.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/cloud/ovirt/ovirt_disk.py validate-modules:undocumented-parameter
lib/ansible/modules/cloud/ovirt/ovirt_disk_info.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_disk_info.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_disk_info.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_disk_info.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_event.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_event_info.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_external_provider.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_external_provider.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_external_provider.py validate-modules:doc-default-does-not-match-spec
lib/ansible/modules/cloud/ovirt/ovirt_external_provider.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_external_provider.py validate-modules:doc-required-mismatch
lib/ansible/modules/cloud/ovirt/ovirt_external_provider.py validate-modules:no-default-for-required-parameter
lib/ansible/modules/cloud/ovirt/ovirt_external_provider.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_external_provider.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/cloud/ovirt/ovirt_external_provider.py validate-modules:undocumented-parameter
lib/ansible/modules/cloud/ovirt/ovirt_external_provider_info.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_external_provider_info.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_external_provider_info.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_external_provider_info.py validate-modules:no-default-for-required-parameter
lib/ansible/modules/cloud/ovirt/ovirt_external_provider_info.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_external_provider_info.py validate-modules:undocumented-parameter
lib/ansible/modules/cloud/ovirt/ovirt_group.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_group.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_group.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_group.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_group_info.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_group_info.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_group_info.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_group_info.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_host.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_host.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_host.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_host.py validate-modules:implied-parameter-type-mismatch
lib/ansible/modules/cloud/ovirt/ovirt_host.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_host.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/cloud/ovirt/ovirt_host_info.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_host_info.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_host_info.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_host_info.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_host_network.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_host_network.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_host_network.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_host_network.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_host_network.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/cloud/ovirt/ovirt_host_pm.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_host_pm.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_host_pm.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_host_pm.py validate-modules:no-default-for-required-parameter
lib/ansible/modules/cloud/ovirt/ovirt_host_pm.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_host_pm.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/cloud/ovirt/ovirt_host_storage_info.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_host_storage_info.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_host_storage_info.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_host_storage_info.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_host_storage_info.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/cloud/ovirt/ovirt_instance_type.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_instance_type.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_instance_type.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_instance_type.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/cloud/ovirt/ovirt_job.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_job.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_job.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_job.py validate-modules:doc-required-mismatch
lib/ansible/modules/cloud/ovirt/ovirt_job.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_mac_pool.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_mac_pool.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_mac_pool.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_mac_pool.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_mac_pool.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/cloud/ovirt/ovirt_network.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_network.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_network.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_network.py validate-modules:doc-required-mismatch
lib/ansible/modules/cloud/ovirt/ovirt_network.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_network.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/cloud/ovirt/ovirt_network_info.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_network_info.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_network_info.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_network_info.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_nic.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_nic.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_nic.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_nic.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_nic.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/cloud/ovirt/ovirt_nic_info.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_nic_info.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_nic_info.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_nic_info.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_permission.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_permission.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_permission.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_permission.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/cloud/ovirt/ovirt_permission_info.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_permission_info.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_permission_info.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_permission_info.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_quota.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_quota.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_quota.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_quota.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_quota.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/cloud/ovirt/ovirt_quota_info.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_quota_info.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_quota_info.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_quota_info.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_role.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_role.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_role.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_role.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_role.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/cloud/ovirt/ovirt_scheduling_policy_info.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_scheduling_policy_info.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_scheduling_policy_info.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_scheduling_policy_info.py validate-modules:doc-required-mismatch
lib/ansible/modules/cloud/ovirt/ovirt_scheduling_policy_info.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_snapshot.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_snapshot.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_snapshot.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_snapshot.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_snapshot.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/cloud/ovirt/ovirt_snapshot_info.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_snapshot_info.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_snapshot_info.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_snapshot_info.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_storage_connection.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_storage_connection.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_storage_connection.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_storage_connection.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_storage_connection.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/cloud/ovirt/ovirt_storage_domain.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_storage_domain.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_storage_domain.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_storage_domain.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_storage_domain.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/cloud/ovirt/ovirt_storage_domain_info.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_storage_domain_info.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_storage_domain_info.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_storage_domain_info.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_storage_template_info.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_storage_template_info.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_storage_template_info.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_storage_template_info.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_storage_template_info.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/cloud/ovirt/ovirt_storage_vm_info.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_storage_vm_info.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_storage_vm_info.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_storage_vm_info.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_storage_vm_info.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/cloud/ovirt/ovirt_tag.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_tag.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_tag.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_tag.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_tag.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/cloud/ovirt/ovirt_tag_info.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_tag_info.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_tag_info.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_tag_info.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_template.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_template.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_template.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_template.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_template.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/cloud/ovirt/ovirt_template_info.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_template_info.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_template_info.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_template_info.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_user.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_user.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_user.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_user.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_user_info.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_user_info.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_user_info.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_user_info.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_vm.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_vm.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_vm.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_vm.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_vm.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/cloud/ovirt/ovirt_vm_info.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_vm_info.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_vm_info.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_vm_info.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_vm_info.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/cloud/ovirt/ovirt_vmpool.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_vmpool.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_vmpool.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_vmpool.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_vmpool.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/cloud/ovirt/ovirt_vmpool_info.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_vmpool_info.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_vmpool_info.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/ovirt/ovirt_vmpool_info.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_vnic_profile.py future-import-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_vnic_profile.py metaclass-boilerplate
lib/ansible/modules/cloud/ovirt/ovirt_vnic_profile.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/ovirt/ovirt_vnic_profile.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/cloud/ovirt/ovirt_vnic_profile_info.py validate-modules:parameter-list-no-elements
lib/ansible/modules/commands/command.py validate-modules:doc-missing-type
lib/ansible/modules/commands/command.py validate-modules:nonexistent-parameter-documented
lib/ansible/modules/commands/command.py validate-modules:parameter-list-no-elements
@ -1667,10 +1415,6 @@ lib/ansible/plugins/doc_fragments/hcloud.py future-import-boilerplate
lib/ansible/plugins/doc_fragments/hcloud.py metaclass-boilerplate
lib/ansible/plugins/doc_fragments/inventory_cache.py future-import-boilerplate
lib/ansible/plugins/doc_fragments/inventory_cache.py metaclass-boilerplate
lib/ansible/plugins/doc_fragments/ovirt.py future-import-boilerplate
lib/ansible/plugins/doc_fragments/ovirt.py metaclass-boilerplate
lib/ansible/plugins/doc_fragments/ovirt_info.py future-import-boilerplate
lib/ansible/plugins/doc_fragments/ovirt_info.py metaclass-boilerplate
lib/ansible/plugins/doc_fragments/return_common.py future-import-boilerplate
lib/ansible/plugins/doc_fragments/return_common.py metaclass-boilerplate
lib/ansible/plugins/doc_fragments/shell_common.py future-import-boilerplate

Loading…
Cancel
Save