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>
This commit is contained in:
parent
851d248096
commit
7fa5694975
3 changed files with 771 additions and 0 deletions
618
lib/ansible/modules/cloud/vmware/vmware_vspan_session.py
Normal file
618
lib/ansible/modules/cloud/vmware/vmware_vspan_session.py
Normal file
|
@ -0,0 +1,618 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright: (c) 2018, Ansible Project
|
||||
# Copyright: (c) 2018, CrySyS Lab <www.crysys.hu>
|
||||
# Copyright: (c) 2018, Peter Gyorgy <gyorgy.peter@edu.bme.hu>
|
||||
# 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) <gyorgy.peter1996@gmail.com>
|
||||
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()
|
2
test/integration/targets/vmware_vspan_session/aliases
Normal file
2
test/integration/targets/vmware_vspan_session/aliases
Normal file
|
@ -0,0 +1,2 @@
|
|||
cloud/vcenter
|
||||
unsupported
|
151
test/integration/targets/vmware_vspan_session/tasks/main.yml
Normal file
151
test/integration/targets/vmware_vspan_session/tasks/main.yml
Normal file
|
@ -0,0 +1,151 @@
|
|||
# Test code for the vmware_vspan_session module.
|
||||
# Copyright: (c) 2018, Peter Gyorgy <gyorgy.peter@edu.bme.hu>
|
||||
# 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
|
Loading…
Reference in a new issue