From c9a37dd0f860caa247f8492be80e323c31637bbd Mon Sep 17 00:00:00 2001 From: Ondra Machacek Date: Mon, 5 Dec 2016 18:42:41 +0100 Subject: Add oVirt ovirt_nics and ovirt_nics_facts modules (#3205) --- cloud/ovirt/ovirt_nics.py | 243 ++++++++++++++++++++++++++++++++++++++++ cloud/ovirt/ovirt_nics_facts.py | 118 +++++++++++++++++++ 2 files changed, 361 insertions(+) create mode 100644 cloud/ovirt/ovirt_nics.py create mode 100644 cloud/ovirt/ovirt_nics_facts.py diff --git a/cloud/ovirt/ovirt_nics.py b/cloud/ovirt/ovirt_nics.py new file mode 100644 index 0000000000..912e03c988 --- /dev/null +++ b/cloud/ovirt/ovirt_nics.py @@ -0,0 +1,243 @@ +#!/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 . +# + +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, +) + + +DOCUMENTATION = ''' +--- +module: ovirt_nics +short_description: Module to manage network interfaces of Virtual Machines in oVirt +version_added: "2.3" +author: "Ondra Machacek (@machacekondra)" +description: + - "Module to manage network interfaces of Virtual Machines in oVirt." +options: + name: + description: + - "Name of the network interface to manage." + required: true + vm: + description: + - "Name of the Virtual Machine to manage." + required: true + state: + description: + - "Should the Virtual Machine NIC be present/absent/plugged/unplugged." + choices: ['present', 'absent', 'plugged', 'unplugged'] + default: present + network: + description: + - "Logical network to which the VM network interface should use, + by default Empty network is used if network is not specified." + profile: + description: + - "Virtual network interface profile to be attached to VM network interface." + interface: + description: + - "Type of the network interface." + choices: ['virtio', 'e1000', 'rtl8139', 'pci_passthrough', 'rtl8139_virtio', 'spapr_vlan'] + default: 'virtio' + mac_address: + description: + - "Custom MAC address of the network interface, by default it's obtained from MAC pool." +extends_documentation_fragment: ovirt +''' + +EXAMPLES = ''' +# Examples don't contain auth parameter for simplicity, +# look at ovirt_auth module to see how to reuse authentication: + +# Add NIC to VM +- ovirt_nics: + state: present + vm: myvm + name: mynic + interface: e1000 + mac_address: 00:1a:4a:16:01:56 + profile: ovirtmgmt + network: ovirtmgmt + +# Plug NIC to VM +- ovirt_nics: + state: plugged + vm: myvm + name: mynic + +# Unplug NIC from VM +- ovirt_nics: + state: unplugged + vm: myvm + name: mynic + +# Remove NIC from VM +- ovirt_nics: + state: absent + vm: myvm + name: mynic +''' + +RETURN = ''' +id: + description: ID of the network interface which is managed + returned: On success if network interface is found. + type: str + sample: 7de90f31-222c-436c-a1ca-7e655bd5b60c +nic: + description: "Dictionary of all the network interface attributes. Network interface attributes can be found on your oVirt instance + at following url: https://ovirt.example.com/ovirt-engine/api/model#types/nic." + returned: On success if network interface is found. +''' + + +class VmNicsModule(BaseModule): + + def __init__(self, *args, **kwargs): + super(VmNicsModule, self).__init__(*args, **kwargs) + self.vnic_id = None + + @property + def vnic_id(self): + return self._vnic_id + + @vnic_id.setter + def vnic_id(self, vnic_id): + self._vnic_id = vnic_id + + def build_entity(self): + return otypes.Nic( + name=self._module.params.get('name'), + interface=otypes.NicInterface( + self._module.params.get('interface') + ) if self._module.params.get('interface') else None, + vnic_profile=otypes.VnicProfile( + id=self.vnic_id, + ) if self.vnic_id else None, + mac=otypes.Mac( + address=self._module.params.get('mac_address') + ) if self._module.params.get('mac_address') else None, + ) + + def update_check(self, entity): + return ( + equal(self._module.params.get('interface'), str(entity.interface)) and + equal(self._module.params.get('profile'), get_link_name(self._connection, entity.vnic_profile)) and + equal(self._module.params.get('mac_address'), entity.mac.address) + ) + + +def main(): + argument_spec = ovirt_full_argument_spec( + state=dict( + choices=['present', 'absent', 'plugged', 'unplugged'], + default='present' + ), + vm=dict(required=True), + name=dict(required=True), + interface=dict(default=None), + profile=dict(default=None), + network=dict(default=None), + mac_address=dict(default=None), + ) + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + ) + check_sdk(module) + + try: + # Locate the service that manages the virtual machines and use it to + # search for the NIC: + connection = create_connection(module.params.pop('auth')) + vms_service = connection.system_service().vms_service() + + # Locate the VM, where we will manage NICs: + vm_name = module.params.get('vm') + vm = search_by_name(vms_service, vm_name) + if vm is None: + raise Exception("VM '%s' was not found." % vm_name) + + # Locate the service that manages the virtual machines NICs: + vm_service = vms_service.vm_service(vm.id) + nics_service = vm_service.nics_service() + vmnics_module = VmNicsModule( + connection=connection, + module=module, + service=nics_service, + ) + + # Find vNIC id of the network interface (if any): + profile = module.params.get('profile') + if profile and module.params['network']: + cluster_name = get_link_name(connection, vm.cluster) + dcs_service = connection.system_service().data_centers_service() + dc = dcs_service.list(search='Clusters.name=%s' % cluster_name)[0] + networks_service = dcs_service.service(dc.id).networks_service() + network = search_by_name(networks_service, module.params['network']) + for vnic in connection.system_service().vnic_profiles_service().list(): + if vnic.name == profile and vnic.network.id == network.id: + vmnics_module.vnic_id = vnic.id + + # Handle appropriate action: + state = module.params['state'] + if state == 'present': + ret = vmnics_module.create() + elif state == 'absent': + ret = vmnics_module.remove() + elif state == 'plugged': + vmnics_module.create() + ret = vmnics_module.action( + action='activate', + action_condition=lambda nic: not nic.plugged, + wait_condition=lambda nic: nic.plugged, + ) + elif state == 'unplugged': + vmnics_module.create() + ret = vmnics_module.action( + action='deactivate', + action_condition=lambda nic: nic.plugged, + wait_condition=lambda nic: not nic.plugged, + ) + + module.exit_json(**ret) + except Exception as e: + module.fail_json(msg=str(e), exception=traceback.format_exc()) + finally: + connection.close(logout=False) + +if __name__ == "__main__": + main() diff --git a/cloud/ovirt/ovirt_nics_facts.py b/cloud/ovirt/ovirt_nics_facts.py new file mode 100644 index 0000000000..0e91391264 --- /dev/null +++ b/cloud/ovirt/ovirt_nics_facts.py @@ -0,0 +1,118 @@ +#!/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 . +# + +import fnmatch +import traceback + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ovirt import ( + check_sdk, + create_connection, + get_dict_of_struct, + ovirt_full_argument_spec, + search_by_name, +) + + +DOCUMENTATION = ''' +--- +module: ovirt_nics_facts +short_description: Retrieve facts about one or more oVirt virtual machine network interfaces +author: "Ondra Machacek (@machacekondra)" +version_added: "2.3" +description: + - "Retrieve facts about one or more oVirt virtual machine network interfaces." +notes: + - "This module creates a new top-level C(ovirt_nics) fact, which + contains a list of NICs." +options: + vm: + description: + - "Name of the VM where NIC is attached." + required: true + name: + description: + - "Name of the NIC, can be used as glob expression." +extends_documentation_fragment: ovirt +''' + +EXAMPLES = ''' +# Examples don't contain auth parameter for simplicity, +# look at ovirt_auth module to see how to reuse authentication: + +# Gather facts about all NICs which names start with C(eth) for VM named C(centos7): +- ovirt_nics_facts: + vm: centos7 + name: eth* +- debug: + var: ovirt_nics +''' + +RETURN = ''' +ovirt_nics: + description: "List of dictionaries describing the network interfaces. NIC attribues are mapped to dictionary keys, + all NICs attributes can be found at following url: https://ovirt.example.com/ovirt-engine/api/model#types/nic." + returned: On success. + type: list +''' + + +def main(): + argument_spec = ovirt_full_argument_spec( + vm=dict(required=True), + name=dict(default=None), + ) + module = AnsibleModule(argument_spec) + check_sdk(module) + + try: + connection = create_connection(module.params.pop('auth')) + vms_service = connection.system_service().vms_service() + vm_name = module.params['vm'] + vm = search_by_name(vms_service, vm_name) + if vm is None: + raise Exception("VM '%s' was not found." % vm_name) + + nics_service = vms_service.service(vm.id).nics_service() + if module.params['name']: + nics = [ + e for e in nics_service.list() + if fnmatch.fnmatch(e.name, module.params['name']) + ] + else: + nics = nics_service.list() + + module.exit_json( + changed=False, + ansible_facts=dict( + ovirt_nics=[ + get_dict_of_struct(c) for c in nics + ], + ), + ) + except Exception as e: + module.fail_json(msg=str(e), exception=traceback.format_exc()) + finally: + connection.close(logout=False) + + +if __name__ == '__main__': + main() -- cgit v1.2.1