From 7fa569497524e33b92169e6ae85858f43580ccbb Mon Sep 17 00:00:00 2001 From: gyorgypeter <32464524+gyorgypeter@users.noreply.github.com> Date: Fri, 8 Feb 2019 05:46:57 +0100 Subject: [PATCH] VMware: Module for managing mirroring sessions. (#50338) This module manages the mirroring sessions, and the necessary port settings. * Correct Documentation and CS * PEP8, YAML, Documentation Error Fix * Added empty return statement Co-Authored-By: gyorgypeter <32464524+gyorgypeter@users.noreply.github.com> --- .../cloud/vmware/vmware_vspan_session.py | 618 ++++++++++++++++++ .../targets/vmware_vspan_session/aliases | 2 + .../vmware_vspan_session/tasks/main.yml | 151 +++++ 3 files changed, 771 insertions(+) create mode 100644 lib/ansible/modules/cloud/vmware/vmware_vspan_session.py create mode 100644 test/integration/targets/vmware_vspan_session/aliases create mode 100644 test/integration/targets/vmware_vspan_session/tasks/main.yml diff --git a/lib/ansible/modules/cloud/vmware/vmware_vspan_session.py b/lib/ansible/modules/cloud/vmware/vmware_vspan_session.py new file mode 100644 index 00000000000..2b6d41b3b48 --- /dev/null +++ b/lib/ansible/modules/cloud/vmware/vmware_vspan_session.py @@ -0,0 +1,618 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2018, Ansible Project +# Copyright: (c) 2018, CrySyS Lab +# Copyright: (c) 2018, Peter Gyorgy +# 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: vmware_vspan_session +short_description: Create or remove a Port Mirroring session. +description: + - This module can be used to create, delete or edit different kind of port mirroring sessions. +version_added: '2.8' +author: +- Peter Gyorgy (@gyorgypeter) +notes: + - Tested on vSphere 6.7 +requirements: + - "python > = 2.6" + - PyVmomi +options: + switch: + description: + - The name of the distributed vSwitch on which to add or remove the mirroring session. + required: True + aliases: [ 'switch_name' ] + name: + description: + - Name of the session. + required: True + state: + choices: + - 'present' + - 'absent' + description: + - Create or remove the session. + required: True + session_type: + default: 'dvPortMirror' + choices: + - 'encapsulatedRemoteMirrorSource' + - 'remoteMirrorDest' + - 'remoteMirrorSource' + - 'dvPortMirror' + description: + - Select the mirroring type. + - '- C(encapsulatedRemoteMirrorSource) (str): In encapsulatedRemoteMirrorSource session, Distributed Ports + can be used as source entities, and Ip address can be used as destination entities.' + - '- C(remoteMirrorDest) (str): In remoteMirrorDest session, vlan Ids can be used as source entities, and + Distributed Ports can be used as destination entities.' + - '- C(remoteMirrorSource) (str): In remoteMirrorSource session, Distributed Ports can be used as source + entities, and uplink ports name can be used as destination entities.' + - '- C(dvPortMirror) (str): In dvPortMirror session, Distributed Ports can be used as both source and + destination entities.' + required: False + enabled: + type: bool + default: True + description: + - Whether the session is enabled. + description: + description: + - The description for the session. + required: False + source_port_transmitted: + description: + - Source port for which transmitted packets are mirrored. + required: False + source_port_received: + description: + - Source port for which received packets are mirrored. + required: False + destination_port: + description: + - Destination port that received the mirrored packets. Also any port designated in the value of this + property can not match the source port in any of the Distributed Port Mirroring session. + required: False + encapsulation_vlan_id: + description: + - VLAN ID used to encapsulate the mirrored traffic. + required: False + strip_original_vlan: + description: + - Whether to strip the original VLAN tag. if false, the original VLAN tag will be preserved on the mirrored + traffic. If encapsulationVlanId has been set and this property is false, the frames will be double tagged + with the original VLAN ID as the inner tag. + type: bool + required: False + mirrored_packet_length: + description: + - An integer that describes how much of each frame to mirror. If unset, all of the frame would be mirrored. + Setting this property to a smaller value is useful when the consumer will look only at the headers. + The value cannot be less than 60. + required: False + normal_traffic_allowed: + description: + - Whether or not destination ports can send and receive "normal" traffic. Setting this to false will make + mirror ports be used solely for mirroring and not double as normal access ports. + type: bool + required: False + sampling_rate: + description: + - Sampling rate of the session. If its value is n, one of every n packets is mirrored. + Valid values are between 1 to 65535, and default value is 1. + type: int + required: False + source_vm_transmitted: + description: + - With this parameter it is possible, to add a NIC of a VM to a port mirroring session. + - 'Valid attributes are:' + - '- C(name) (str): Name of the VM' + - '- C(nic_label) (bool): Label of the Network Interface Card to use.' + source_vm_received: + description: + - With this parameter it is possible, to add a NIC of a VM to a port mirroring session. + - 'Valid attributes are:' + - '- C(name) (str): Name of the VM' + - '- C(nic_label) (bool): Label of the Network Interface Card to use.' + destination_vm: + description: + - With this parameter it is possible, to add a NIC of a VM to a port mirroring session. + - 'Valid attributes are:' + - '- C(name) (str): Name of the VM' + - '- C(nic_label) (bool): Label of the Network Interface Card to use.' + required: False +extends_documentation_fragment: vmware.documentation +''' + +EXAMPLES = ''' +- name: Create distributed mirroring session. + vmware_vspan_session: + hostname: '{{ vcenter_hostname }}' + username: '{{ vcenter_username }}' + password: '{{ vcenter_password }}' + switch_name: dvSwitch + state: present + name: Basic Session + enabled: True + description: "Example description" + source_port_transmitted: 817 + source_port_received: 817 + destination_port: 815 + delegate_to: localhost + +- name: Create remote destination mirroring session. + vmware_vspan_session: + hostname: '{{ vcenter_hostname }}' + username: '{{ vcenter_username }}' + password: '{{ vcenter_password }}' + switch_name: dvSwitch + state: present + name: Remote Session + enabled: True + description: "Example description" + source_port_received: 105 + destination_port: 815 + session_type: "remoteMirrorDest" + delegate_to: localhost + +- name: Create remote destination mirroring session. + vmware_vspan_session: + hostname: '{{ vcenter_hostname }}' + username: '{{ vcenter_username }}' + password: '{{ vcenter_password }}' + switch_name: dvSwitch + state: absent + name: Remote Session + delegate_to: localhost +''' + +RETURN = """# +""" + +try: + from pyVmomi import vim, vmodl +except ImportError as e: + pass + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.vmware import (vmware_argument_spec, PyVmomi, find_dvs_by_name, + find_vm_by_name, wait_for_task) + + +class VMwareVspanSession(PyVmomi): + def __init__(self, module): + super(VMwareVspanSession, self).__init__(module) + self.switch = module.params['switch'] + self.name = module.params['name'] + self.session_type = module.params['session_type'] + self.enabled = module.params['enabled'] + self.state = module.params['state'] + self.description = module.params['description'] + self.source_port_transmitted = module.params['source_port_transmitted'] + self.source_port_received = module.params['source_port_received'] + self.destination_port = module.params['destination_port'] + self.encapsulation_vlan_id = module.params['encapsulation_vlan_id'] + self.strip_original_vlan = module.params['strip_original_vlan'] + self.mirrored_packet_length = module.params['mirrored_packet_length'] + self.normal_traffic_allowed = module.params['normal_traffic_allowed'] + self.sampling_rate = module.params['sampling_rate'] + self.dv_switch = find_dvs_by_name(self.content, self.switch) + if self.dv_switch is None: + self.module.fail_json(msg="There is no dvSwitch with the name: {0:s}.".format(self.switch)) + self.operation = None + self.modified_ports = dict() + self.deleted_session = None + if module.params['source_vm_transmitted'] is not None: + if (module.params['source_vm_transmitted']['name'] is None or + module.params['source_vm_transmitted']['nic_label'] is None): + self.module.fail_json(msg="Please provide both VM name and NIC Label") + self.source_vm_transmitted_name = module.params['source_vm_transmitted']['name'] + self.source_vm_transmitted_nic_label = module.params['source_vm_transmitted']['nic_label'] + if module.params['source_vm_received'] is not None: + if (module.params['source_vm_received']['name'] is None or + module.params['source_vm_received']['nic_label'] is None): + self.module.fail_json(msg="Please provide both VM name and NIC Label") + self.source_vm_received_name = module.params['source_vm_received']['name'] + self.source_vm_received_nic_label = module.params['source_vm_received']['nic_label'] + if module.params['destination_vm'] is not None: + if (module.params['destination_vm']['name'] is None or + module.params['destination_vm']['nic_label'] is None): + self.module.fail_json(msg="Please provide both VM name and NIC Label") + self.destination_vm_name = module.params['destination_vm']['name'] + self.destination_vm_nic_label = module.params['destination_vm']['nic_label'] + + def set_operation(self): + """Sets the operation according to state""" + if self.state == 'absent': + self.operation = 'remove' + elif self.state == 'present' and self.find_session_by_name() is None: + self.operation = 'add' + else: + self.operation = 'edit' + + def find_session_by_name(self): + """Finds a session by name + Returns + ------- + vim.dvs.VmwareDistributedVirtualSwitch.VspanSession + The session if there was a session by the given name, else returns None + """ + for vspan_session in self.dv_switch.config.vspanSession: + if vspan_session.name == self.name: + return vspan_session + return None + + def get_vm_port(self, vm_name, nic_label): + """Finds the port of the VM + Returns + ------- + str + the port number as a string, or None if the NIC couldnt be found + """ + vm = find_vm_by_name(self.content, vm_name) + if vm is None: + self.module.fail_json(msg="There is no VM with the name: {0:s}.".format(vm_name)) + for hardware in vm.config.hardware.device: + if isinstance(hardware, vim.vm.device.VirtualVmxnet3): + if hardware.deviceInfo.label == nic_label: + return hardware.backing.port.portKey + return None + + def set_port_for_vm(self): + """Sets the ports, to the VM's specified port.""" + if hasattr(self, 'source_vm_transmitted_name') and hasattr(self, 'source_vm_transmitted_nic_label'): + port = self.get_vm_port(self.source_vm_transmitted_name, self.source_vm_transmitted_nic_label) + if port is not None: + self.source_port_transmitted = port + else: + self.module.fail_json( + msg="No port could be found for VM: {0:s} NIC: {1:s}".format(self.source_vm_transmitted_name, + self.source_vm_transmitted_nic_label)) + if hasattr(self, 'source_vm_received_name') and hasattr(self, 'source_vm_received_nic_label'): + port = self.get_vm_port(self.source_vm_received_name, self.source_vm_received_nic_label) + if port is not None: + self.source_port_received = port + else: + self.module.fail_json( + msg="No port could be found for VM: {0:s} NIC: {1:s}".format(self.source_vm_received_name, + self.source_vm_received_nic_label)) + if hasattr(self, 'destination_vm_name') and hasattr(self, 'destination_vm_nic_label'): + port = self.get_vm_port(self.destination_vm_name, self.destination_vm_nic_label) + if port is not None: + self.destination_port = port + else: + self.module.fail_json( + msg="No port could be found for VM: {0:s} NIC: {1:s}".format(self.destination_vm_name, + self.destination_vm_nic_label)) + + def process_operation(self): + """Calls the create or delete function based on the operation""" + self.set_operation() + if self.operation == 'remove': + results = self.remove_vspan_session() + self.module.exit_json(**results) + if self.operation == 'add': + self.set_port_for_vm() + results = self.add_vspan_session() + self.module.exit_json(**results) + if self.operation == 'edit': + self.remove_vspan_session() + self.set_port_for_vm() + results = self.add_vspan_session() + self.module.exit_json(**results) + + def set_port_security_promiscuous(self, ports, state): + """Set the given port to the given promiscuous state. + Parameters + ---------- + port : str[] + PortKey + state: bool + State of the promiscuous mode, if true its allowed, else not. + """ + # Creating the new port policy + port_spec = [] + vim_bool = vim.BoolPolicy(value=state) + port_policy = vim.dvs.VmwareDistributedVirtualSwitch.SecurityPolicy(allowPromiscuous=vim_bool) + port_settings = vim.dvs.VmwareDistributedVirtualSwitch.VmwarePortConfigPolicy(securityPolicy=port_policy) + for port in ports: + temp_port_spec = vim.dvs.DistributedVirtualPort.ConfigSpec( + operation="edit", + key=port, + setting=port_settings + ) + port_spec.append(temp_port_spec) + + task = self.dv_switch.ReconfigureDVPort_Task(port_spec) + try: + wait_for_task(task) + except Exception: + self.restore_original_state() + self.module.fail_json(msg=task.info.error.msg) + + def turn_off_promiscuous(self): + """Disable all promiscuous mode ports, and give them back in a list. + Returns + ------- + list + Contains every port, where promiscuous mode has been turned off + """ + # Ports that are in mirror sessions + ports = [] + ports_of_selected_session = [] + for vspan_session in self.dv_switch.config.vspanSession: + if vspan_session.sourcePortReceived is not None: + session_ports = vspan_session.sourcePortReceived.portKey + for port in session_ports: + if vspan_session.name == self.name: + ports_of_selected_session.append(port) + elif not(port in ports): + ports.append(port) + if vspan_session.sourcePortTransmitted is not None: + session_ports = vspan_session.sourcePortTransmitted.portKey + for port in session_ports: + if vspan_session.name == self.name: + ports_of_selected_session.append(port) + elif not(port in ports): + ports.append(port) + if vspan_session.destinationPort is not None: + session_ports = vspan_session.destinationPort.portKey + for port in session_ports: + if vspan_session.name == self.name: + ports_of_selected_session.append(port) + elif not(port in ports): + ports.append(port) + promiscuous_ports = [] + if ports: + dv_ports = self.dv_switch.FetchDVPorts(vim.dvs.PortCriteria(portKey=ports)) + # If a port is promiscuous set disable it, and add it to the array to enable it after the changes are made. + for dv_port in dv_ports: + if dv_port.config.setting.securityPolicy.allowPromiscuous.value: + self.set_port_security_promiscuous([dv_port.key], False) + self.modified_ports.update({dv_port.key: True}) + promiscuous_ports.append(dv_port.key) + if ports_of_selected_session: + current_dv_ports = self.dv_switch.FetchDVPorts(vim.dvs.PortCriteria(portKey=ports_of_selected_session)) + for dv_port in current_dv_ports: + if dv_port.config.setting.securityPolicy.allowPromiscuous.value: + self.set_port_security_promiscuous([dv_port.key], False) + self.modified_ports.update({dv_port.key: True}) + # Return the promiscuous ports array, to set them back after the config is finished. + return promiscuous_ports + + def delete_mirroring_session(self, key): + """Deletes the mirroring session. + Parameters + ---------- + key : str + Key of the Session + """ + session = vim.dvs.VmwareDistributedVirtualSwitch.VspanSession( + key=key + ) + config_version = self.dv_switch.config.configVersion + s_spec = vim.dvs.VmwareDistributedVirtualSwitch.VspanConfigSpec(vspanSession=session, operation="remove") + c_spec = vim.dvs.VmwareDistributedVirtualSwitch.ConfigSpec(vspanConfigSpec=[s_spec], configVersion=config_version) + task = self.dv_switch.ReconfigureDvs_Task(c_spec) + try: + wait_for_task(task) + except Exception: + self.restore_original_state() + self.module.fail_json(msg=task.info.error.msg) + + def restore_original_state(self): + """In case of failure restore, the changes we made.""" + for port, state in self.modified_ports.items(): + self.set_port_security_promiscuous([port], state) + if self.deleted_session is not None: + session = self.deleted_session + config_version = self.dv_switch.config.configVersion + s_spec = vim.dvs.VmwareDistributedVirtualSwitch.VspanConfigSpec(vspanSession=session, operation="add") + c_spec = vim.dvs.VmwareDistributedVirtualSwitch.ConfigSpec(vspanConfigSpec=[s_spec], configVersion=config_version) + # Revert the delete + task = self.dv_switch.ReconfigureDvs_Task(c_spec) + try: + wait_for_task(task) + except Exception: + self.restore_original_state() + self.module.fail_json(msg=task.info.error.msg) + + def remove_vspan_session(self): + """Calls the necessary functions to delete a VSpanSession.""" + results = dict(changed=False, result="") + mirror_session = self.find_session_by_name() + if mirror_session is None: + results['result'] = "There is no VSpanSession with the name: {0:s}.".format(self.name) + return results + promiscuous_ports = self.turn_off_promiscuous() + session_key = mirror_session.key + # Delete Mirroring Session + self.delete_mirroring_session(session_key) + # Session + self.deleted_session = mirror_session + # Set back the promiscuous ports + if promiscuous_ports: + self.set_port_security_promiscuous(promiscuous_ports, True) + results['changed'] = True + results['result'] = 'VSpan Session has been deleted' + return results + + def check_if_session_name_is_free(self): + """Checks whether the name is used or not + Returns + ------- + bool + True if the name is free and False if it is used. + """ + for vspan_session in self.dv_switch.config.vspanSession: + if vspan_session.name == self.name: + return False + return True + + def create_vspan_session(self): + """Builds up the session, adds the parameters that we specified, then creates it on the vSwitch""" + + session = vim.dvs.VmwareDistributedVirtualSwitch.VspanSession( + name=self.name, + enabled=True + ) + if self.session_type is not None: + session.sessionType = self.session_type + if self.session_type == 'encapsulatedRemoteMirrorSource': + if self.source_port_received is not None: + port = vim.dvs.VmwareDistributedVirtualSwitch.VspanPorts(portKey=str(self.source_port_received)) + if not self.dv_switch.FetchDVPorts(vim.dvs.PortCriteria(portKey=port.portKey)): + self.module.fail_json(msg="Couldn't find port: {0:s}".format(self.source_port_received)) + session.sourcePortReceived = port + if self.source_port_transmitted is not None: + port = vim.dvs.VmwareDistributedVirtualSwitch.VspanPorts(portKey=str(self.source_port_transmitted)) + if not self.dv_switch.FetchDVPorts(vim.dvs.PortCriteria(portKey=port.portKey)): + self.module.fail_json(msg="Couldn't find port: {0:s}".format(self.source_port_transmitted)) + session.sourcePortTransmitted = port + if self.destination_port is not None: + port = vim.dvs.VmwareDistributedVirtualSwitch.VspanPorts(ipAddress=str(self.destination_port)) + session.destinationPort = port + if self.session_type == 'remoteMirrorSource': + if self.source_port_received is not None: + port = vim.dvs.VmwareDistributedVirtualSwitch.VspanPorts(portKey=str(self.source_port_received)) + if not self.dv_switch.FetchDVPorts(vim.dvs.PortCriteria(portKey=port.portKey)): + self.module.fail_json(msg="Couldn't find port: {0:s}".format(self.source_port_received)) + session.sourcePortReceived = port + if self.source_port_transmitted is not None: + port = vim.dvs.VmwareDistributedVirtualSwitch.VspanPorts(portKey=str(self.source_port_transmitted)) + if not self.dv_switch.FetchDVPorts(vim.dvs.PortCriteria(portKey=port.portKey)): + self.module.fail_json(msg="Couldn't find port: {0:s}".format(self.source_port_transmitted)) + session.sourcePortTransmitted = port + if self.destination_port is not None: + port = vim.dvs.VmwareDistributedVirtualSwitch.VspanPorts(uplinkPortName=str(self.destination_port)) + session.destinationPort = port + if self.session_type == 'remoteMirrorDest': + if self.source_port_received is not None: + port = vim.dvs.VmwareDistributedVirtualSwitch.VspanPorts(vlans=[int(self.source_port_received)]) + if int(self.source_port_received) not in self.dv_switch.QueryUsedVlanIdInDvs(): + self.module.fail_json(msg="Couldn't find vlan: {0:s}".format(self.source_port_received)) + session.sourcePortReceived = port + if self.destination_port is not None: + port = vim.dvs.VmwareDistributedVirtualSwitch.VspanPorts(portKey=str(self.destination_port)) + if not self.dv_switch.FetchDVPorts(vim.dvs.PortCriteria(portKey=port.portKey)): + self.module.fail_json(msg="Couldn't find port: {0:s}".format(self.destination_port)) + session.destinationPort = port + if self.session_type == 'dvPortMirror': + if self.source_port_received is not None: + port = vim.dvs.VmwareDistributedVirtualSwitch.VspanPorts(portKey=str(self.source_port_received)) + if not self.dv_switch.FetchDVPorts(vim.dvs.PortCriteria(portKey=port.portKey)): + self.module.fail_json(msg="Couldn't find port: {0:s}".format(self.source_port_received)) + session.sourcePortReceived = port + if self.source_port_transmitted is not None: + port = vim.dvs.VmwareDistributedVirtualSwitch.VspanPorts(portKey=str(self.source_port_transmitted)) + if not self.dv_switch.FetchDVPorts(vim.dvs.PortCriteria(portKey=port.portKey)): + self.module.fail_json(msg="Couldn't find port: {0:s}".format(self.source_port_transmitted)) + session.sourcePortTransmitted = port + if self.destination_port is not None: + port = vim.dvs.VmwareDistributedVirtualSwitch.VspanPorts(portKey=str(self.destination_port)) + if not self.dv_switch.FetchDVPorts(vim.dvs.PortCriteria(portKey=port.portKey)): + self.module.fail_json(msg="Couldn't find port: {0:s}".format(self.destination_port)) + session.destinationPort = port + if self.description is not None: + session.description = self.description + if self.encapsulation_vlan_id is not None: + session.encapsulationVlanId = self.encapsulation_vlan_id + if self.strip_original_vlan is not None: + session.stripOriginalVlan = self.strip_original_vlan + if self.mirrored_packet_length is not None: + session.mirroredPacketLength = self.mirrored_packet_length + if self.normal_traffic_allowed is not None: + session.normalTrafficAllowed = self.normal_traffic_allowed + if self.sampling_rate is not None: + session.samplingRate = self.sampling_rate + config_version = self.dv_switch.config.configVersion + s_spec = vim.dvs.VmwareDistributedVirtualSwitch.VspanConfigSpec(vspanSession=session, operation="add") + c_spec = vim.dvs.VmwareDistributedVirtualSwitch.ConfigSpec(vspanConfigSpec=[s_spec], configVersion=config_version) + task = self.dv_switch.ReconfigureDvs_Task(c_spec) + try: + wait_for_task(task) + except Exception: + self.restore_original_state() + self.module.fail_json(msg=task.info.error.msg) + + def add_vspan_session(self): + """Calls the necessary functions to create a VSpanSession""" + results = dict(changed=False, result="") + promiscous_ports = self.turn_off_promiscuous() + if not self.check_if_session_name_is_free(): + self.module.fail_json(msg="There is another VSpan Session with the name: {0:s}.".format(self.name)) + # Locate the ports, we want to use + dv_ports = None + ports = [str(self.source_port_received), str(self.source_port_transmitted), str(self.destination_port)] + if ports: + dv_ports = self.dv_switch.FetchDVPorts(vim.dvs.PortCriteria(portKey=ports)) + for dv_port in dv_ports: + if dv_port.config.setting.securityPolicy.allowPromiscuous.value: + self.set_port_security_promiscuous([dv_port.key], False) + self.modified_ports.update({dv_port.key: True}) + # Now we can create the VspanSession + self.create_vspan_session() + # Finally we can set the destination port to promiscuous mode + if self.session_type == 'dvPortMirror' or self.session_type == 'remoteMirrorDest': + self.set_port_security_promiscuous([str(self.destination_port)], True) + # Set Back the Promiscuous ports + if promiscous_ports: + self.set_port_security_promiscuous(promiscous_ports, True) + results['changed'] = True + results['result'] = 'Mirroring session has been created.' + return results + + +def main(): + argument_spec = vmware_argument_spec() + argument_spec.update(dict( + switch=dict(type='str', required=True, aliases=['switch_name']), + name=dict(type='str', required=True), + state=dict(type='str', required=True, choices=['present', 'absent']), + session_type=dict(type='str', default='dvPortMirror', choices=['dvPortMirror', + 'encapsulatedRemoteMirrorSource', + 'remoteMirrorDest', + 'remoteMirrorSource']), + enabled=dict(type='bool', default=True), + description=dict(type='str'), + source_port_transmitted=dict(type='str'), + source_port_received=dict(type='str'), + destination_port=dict(type='str'), + encapsulation_vlan_id=dict(type='int'), + strip_original_vlan=dict(type='bool'), + mirrored_packet_length=dict(type='int'), + normal_traffic_allowed=dict(type='bool'), + sampling_rate=dict(type='int'), + source_vm_transmitted=dict(type='dict', + options=dict( + name=dict(type='str'), + nic_label=dict(type='str'))), + source_vm_received=dict(type='dict', + options=dict( + name=dict(type='str'), + nic_label=dict(type='str'))), + destination_vm=dict(type='dict', + options=dict( + name=dict(type='str'), + nic_label=dict(type='str'))), + )) + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False) + session = VMwareVspanSession(module) + session.process_operation() + + +if __name__ == '__main__': + main() diff --git a/test/integration/targets/vmware_vspan_session/aliases b/test/integration/targets/vmware_vspan_session/aliases new file mode 100644 index 00000000000..845e8a6dad5 --- /dev/null +++ b/test/integration/targets/vmware_vspan_session/aliases @@ -0,0 +1,2 @@ +cloud/vcenter +unsupported diff --git a/test/integration/targets/vmware_vspan_session/tasks/main.yml b/test/integration/targets/vmware_vspan_session/tasks/main.yml new file mode 100644 index 00000000000..27607e20064 --- /dev/null +++ b/test/integration/targets/vmware_vspan_session/tasks/main.yml @@ -0,0 +1,151 @@ +# Test code for the vmware_vspan_session module. +# Copyright: (c) 2018, Peter Gyorgy +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: store the vcenter container ip + set_fact: + vcsim: "{{ lookup('env', 'vcenter_host') }}" + +- debug: var=vcsim + +- name: Wait for Flask controller to come up online + wait_for: + host: "{{ vcsim }}" + port: 5000 + state: started + +- name: kill vcsim + uri: + url: http://{{ vcsim }}:5000/killall + +- name: start vcsim + uri: + url: http://{{ vcsim }}:5000/spawn?cluster=2 + register: vcsim_instance + +- name: Wait for vcsim server to come up online + wait_for: + host: "{{ vcsim }}" + port: 443 + state: started + +- name: get a list of Datacenter from vcsim + uri: + url: http://{{ vcsim }}:5000/govc_find?filter=DC + register: datacenters + +- debug: var=vcsim_instance +- debug: var=datacenters + +- name: add distributed vSwitch + vmware_dvswitch: + validate_certs: False + hostname: "{{ vcsim }}" + username: "{{ vcsim_instance['json']['username'] }}" + password: "{{ vcsim_instance['json']['password'] }}" + datacenter_name: "{{ item | basename }}" + state: present + switch_name: dvswitch_0001 + mtu: 9000 + uplink_quantity: 2 + discovery_proto: lldp + discovery_operation: both + register: dvs_result_0001 + with_items: + - "{{ datacenters['json'] }}" + +- name: ensure distributed vswitch is present + assert: + that: + - "{{ dvs_result_0001.changed == true }}" + +- name: get a list of distributed vswitch from vcsim after adding + uri: + url: http://{{ vcsim }}:5000/govc_find?filter=DVS + register: new_dvs_0001 + +- debug: + msg: "{{ item | basename }}" + with_items: "{{ new_dvs_0001['json'] }}" + +- set_fact: new_dvs_name="{% for dvs in new_dvs_0001['json'] %} {{ True if (dvs | basename) == 'dvswitch_0001' else False }}{% endfor %}" + +- debug: var=new_dvs_name +- assert: + that: + - "{{ 'True' in new_dvs_name }}" + +- name: Create vlan portgroup with all security and port policies + vmware_dvs_portgroup: + hostname: "{{ vcsim }}" + username: "{{ vcsim_instance['json']['username'] }}" + password: "{{ vcsim_instance['json']['password'] }}" + validate_certs: False + portgroup_name: vlan-123-portrgoup + switch_name: dvswitch_0001 + vlan_id: 123 + num_ports: 120 + portgroup_type: earlyBinding + state: present + network_policy: + promiscuous: yes + forged_transmits: yes + mac_changes: yes + port_policy: + block_override: yes + ipfix_override: yes + live_port_move: yes + network_rp_override: yes + port_config_reset_at_disconnect: yes + security_override: yes + shaping_override: yes + traffic_filter_override: yes + uplink_teaming_override: yes + vendor_config_override: yes + vlan_override: yes + delegate_to: localhost + register: portgroup_create_result + +- name: ensure portgroup was created + assert: + that: + - portgroup_create_result.changed + +- name: create a session. + vmware_vspan_session: + hostname: "{{ vcsim }}" + username: "{{ vcsim_instance['json']['username'] }}" + password: "{{ vcsim_instance['json']['password'] }}" + validate_certs: False + switch: dvswitch_0001 + name: "session_0001" + state: "present" + enabled: True + description: "basic_description" + source_port_transmitted: 13 + source_port_received: 13 + destination_port: 12 + delegate_to: localhost + register: vspan_session_create_result + +- name: ensure session was created + assert: + that: + - vspan_session_create_result.changed + +- name: delete a session. + vmware_vspan_session: + hostname: "{{ vcsim }}" + username: "{{ vcsim_instance['json']['username'] }}" + password: "{{ vcsim_instance['json']['password'] }}" + validate_certs: False + switch: dvswitch_0001 + name: "session_0001" + state: "absent" + delegate_to: localhost + register: vspan_session_delete_result + +- name: ensure session was deleted + assert: + that: + - vspan_session_delete_result.changed