vmware_dvs_portgroup: Add configuration of vlan trunk, security settings and port policies and integration tests (#32298)

* Add configuration of vlan trunk, security settings and port policies, and tests

This commit adds the following capabilities to the
vmware_dvs_portgroup module:
- Support for VLAN trunk portgroup
- Support for all security settings (promiscuous, forged transmits & mac
address changes)
- Support for all the port specific policies
- port specific policies match the vCenter UI behaviour (for instance:
block override is enabled by default)
- Cleanup and use of proper API entities not root entities
- Integration testing

* Cleanup of docs and adding more examples
pull/32600/head
Philippe Dellaert 7 years ago committed by jctanner
parent 03a06fdc0f
commit 930fde5f70

@ -17,20 +17,23 @@ ANSIBLE_METADATA = {'metadata_version': '1.1',
DOCUMENTATION = ''' DOCUMENTATION = '''
--- ---
module: vmware_dvs_portgroup module: vmware_dvs_portgroup
short_description: Create or remove a Distributed vSwitch portgroup short_description: Create or remove a Distributed vSwitch portgroup.
description: description:
- Create or remove a Distributed vSwitch portgroup - Create or remove a Distributed vSwitch portgroup.
version_added: 2.0 version_added: 2.0
author: "Joseph Callen (@jcpowermac)" author:
- Joseph Callen (@jcpowermac)
- Philippe Dellaert (@pdellaert) <philippe@dellaert.org>
notes: notes:
- Tested on vSphere 5.5 - Tested on vSphere 5.5
- Tested on vSphere 6.5
requirements: requirements:
- "python >= 2.6" - "python >= 2.6"
- PyVmomi - PyVmomi
options: options:
portgroup_name: portgroup_name:
description: description:
- The name of the portgroup that is to be created or deleted - The name of the portgroup that is to be created or deleted.
required: True required: True
switch_name: switch_name:
description: description:
@ -38,36 +41,133 @@ options:
required: True required: True
vlan_id: vlan_id:
description: description:
- The VLAN ID that should be configured with the portgroup - The VLAN ID that should be configured with the portgroup, use 0 for no VLAN.
- 'If C(vlan_trunk) is configured to be I(true), this can be a range, example: 1-4094.'
required: True required: True
num_ports: num_ports:
description: description:
- The number of ports the portgroup should contain - The number of ports the portgroup should contain.
required: True required: True
portgroup_type: portgroup_type:
description: description:
- See VMware KB 1022312 regarding portgroup types - See VMware KB 1022312 regarding portgroup types.
required: True required: True
choices: choices:
- 'earlyBinding' - 'earlyBinding'
- 'lateBinding' - 'lateBinding'
- 'ephemeral' - 'ephemeral'
state:
description:
- Determines if the portgroup should be present or not.
required: True
choices:
- 'present'
- 'absent'
version_added: '2.5'
vlan_trunk:
description:
- Indicates whether this is a VLAN trunk or not.
required: False
default: False
version_added: '2.5'
security:
description:
- Dict which configures the different security values for portgroup.
- 'Valid attributes are:'
- '- C(promiscuous) (bool): indicates whether promiscuous mode is allowed. (default: false)'
- '- C(forged_transmits) (bool): indicates whether forged transmits are allowed. (default: false)'
- '- C(mac_changes) (bool): indicates whether mac changes are allowed. (default: false)'
required: False
version_added: '2.5'
port_policy:
description:
- Dict which configures the advanced policy settings for the portgroup.
- 'Valid attributes are:'
- '- C(block_override) (bool): indicates if the block policy can be changed per port. (default: true)'
- '- C(ipfix_override) (bool): indicates if the ipfix policy can be changed per port. (default: false)'
- '- C(live_port_move) (bool): indicates if a live port can be moved in or out of the portgroup. (default: false)'
- '- C(network_rp_override) (bool): indicates if the network resource pool can be changed per port. (default: false)'
- '- C(port_config_reset_at_disconnect) (bool): indicates if the configuration of a port is reset automatically after disconnect. (default: true)'
- '- C(security_override) (bool): indicates if the security policy can be changed per port. (default: false)'
- '- C(shaping_override) (bool): indicates if the shaping policy can be changed per port. (default: false)'
- '- C(traffic_filter_override) (bool): indicates if the traffic filter can be changed per port. (default: false)'
- '- C(uplink_teaming_override) (bool): indicates if the uplink teaming policy can be changed per port. (default: false)'
- '- C(vendor_config_override) (bool): indicates if the vendor config can be changed per port. (default: false)'
- '- C(vlan_override) (bool): indicates if the vlan can be changed per port. (default: false)'
required: False
version_added: '2.5'
extends_documentation_fragment: vmware.documentation extends_documentation_fragment: vmware.documentation
''' '''
EXAMPLES = ''' EXAMPLES = '''
- name: Create Management portgroup - name: Create vlan portgroup
local_action: connection: local
module: vmware_dvs_portgroup vmware_dvs_portgroup:
hostname: vcenter_ip_or_hostname
username: vcenter_username
password: vcenter_password
portgroup_name: vlan-123-portrgoup
switch_name: dvSwitch
vlan_id: 123
num_ports: 120
portgroup_type: earlyBinding
state: present
- name: Create vlan trunk portgroup
connection: local
vmware_dvs_portgroup:
hostname: vcenter_ip_or_hostname
username: vcenter_username
password: vcenter_password
portgroup_name: vlan-trunk-portrgoup
switch_name: dvSwitch
vlan_id: 1-1000
vlan_trunk: True
num_ports: 120
portgroup_type: earlyBinding
state: present
- name: Create no-vlan portgroup
connection: local
vmware_dvs_portgroup:
hostname: vcenter_ip_or_hostname hostname: vcenter_ip_or_hostname
username: vcenter_username username: vcenter_username
password: vcenter_password password: vcenter_password
portgroup_name: Management portgroup_name: no-vlan-portrgoup
switch_name: dvSwitch
vlan_id: 0
num_ports: 120
portgroup_type: earlyBinding
state: present
- name: Create vlan portgroup with all security and port policies
connection: local
vmware_dvs_portgroup:
hostname: vcenter_ip_or_hostname
username: vcenter_username
password: vcenter_password
portgroup_name: vlan-123-portrgoup
switch_name: dvSwitch switch_name: dvSwitch
vlan_id: 123 vlan_id: 123
num_ports: 120 num_ports: 120
portgroup_type: earlyBinding portgroup_type: earlyBinding
state: present state: present
security:
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
''' '''
try: try:
@ -92,6 +192,21 @@ class VMwareDvsPortgroup(object):
self.portgroup_type = self.module.params['portgroup_type'] self.portgroup_type = self.module.params['portgroup_type']
self.dv_switch = None self.dv_switch = None
self.state = self.module.params['state'] self.state = self.module.params['state']
self.vlan_trunk = self.module.params['vlan_trunk']
self.security_promiscuous = self.module.params['security']['promiscuous']
self.security_forged_transmits = self.module.params['security']['forged_transmits']
self.security_mac_changes = self.module.params['security']['mac_changes']
self.policy_block_override = self.module.params['port_policy']['block_override']
self.policy_ipfix_override = self.module.params['port_policy']['ipfix_override']
self.policy_live_port_move = self.module.params['port_policy']['live_port_move']
self.policy_network_rp_override = self.module.params['port_policy']['network_rp_override']
self.policy_port_config_reset_at_disconnect = self.module.params['port_policy']['port_config_reset_at_disconnect']
self.policy_security_override = self.module.params['port_policy']['security_override']
self.policy_shaping_override = self.module.params['port_policy']['shaping_override']
self.policy_traffic_filter_override = self.module.params['port_policy']['traffic_filter_override']
self.policy_uplink_teaming_override = self.module.params['port_policy']['uplink_teaming_override']
self.policy_vendor_config_override = self.module.params['port_policy']['vendor_config_override']
self.policy_vlan_override = self.module.params['port_policy']['vlan_override']
self.content = connect_to_api(module) self.content = connect_to_api(module)
def process_state(self): def process_state(self):
@ -118,19 +233,40 @@ class VMwareDvsPortgroup(object):
def create_port_group(self): def create_port_group(self):
config = vim.dvs.DistributedVirtualPortgroup.ConfigSpec() config = vim.dvs.DistributedVirtualPortgroup.ConfigSpec()
# Basic config
config.name = self.portgroup_name config.name = self.portgroup_name
config.numPorts = self.num_ports config.numPorts = self.num_ports
# vim.VMwareDVSPortSetting() does not exist in the pyvmomi documentation # Default port config
# but this is the correct managed object type. config.defaultPortConfig = vim.dvs.VmwareDistributedVirtualSwitch.VmwarePortConfigPolicy()
if self.vlan_trunk:
config.defaultPortConfig = vim.VMwareDVSPortSetting() config.defaultPortConfig.vlan = vim.dvs.VmwareDistributedVirtualSwitch.TrunkVlanSpec()
vlan_id_start, vlan_id_end = self.vlan_id.split('-')
# vim.VmwareDistributedVirtualSwitchVlanIdSpec() does not exist in the config.defaultPortConfig.vlan.vlanId = [vim.NumericRange(start=int(vlan_id_start.strip()), end=int(vlan_id_end.strip()))]
# pyvmomi documentation but this is the correct managed object type else:
config.defaultPortConfig.vlan = vim.VmwareDistributedVirtualSwitchVlanIdSpec() config.defaultPortConfig.vlan = vim.dvs.VmwareDistributedVirtualSwitch.VlanIdSpec()
config.defaultPortConfig.vlan.vlanId = int(self.vlan_id)
config.defaultPortConfig.vlan.inherited = False config.defaultPortConfig.vlan.inherited = False
config.defaultPortConfig.vlan.vlanId = self.vlan_id config.defaultPortConfig.securityPolicy = vim.dvs.VmwareDistributedVirtualSwitch.SecurityPolicy()
config.defaultPortConfig.securityPolicy.allowPromiscuous = vim.BoolPolicy(value=self.security_promiscuous)
config.defaultPortConfig.securityPolicy.forgedTransmits = vim.BoolPolicy(value=self.security_forged_transmits)
config.defaultPortConfig.securityPolicy.macChanges = vim.BoolPolicy(value=self.security_mac_changes)
# PG policy (advanced_policy)
config.policy = vim.dvs.VmwareDistributedVirtualSwitch.VMwarePortgroupPolicy()
config.policy.blockOverrideAllowed = self.policy_block_override
config.policy.ipfixOverrideAllowed = self.policy_ipfix_override
config.policy.livePortMovingAllowed = self.policy_live_port_move
config.policy.networkResourcePoolOverrideAllowed = self.policy_network_rp_override
config.policy.portConfigResetAtDisconnect = self.policy_port_config_reset_at_disconnect
config.policy.securityPolicyOverrideAllowed = self.policy_security_override
config.policy.shapingOverrideAllowed = self.policy_shaping_override
config.policy.trafficFilterOverrideAllowed = self.policy_traffic_filter_override
config.policy.uplinkTeamingOverrideAllowed = self.policy_uplink_teaming_override
config.policy.vendorConfigOverrideAllowed = self.policy_vendor_config_override
config.policy.vlanOverrideAllowed = self.policy_vlan_override
# PG Type
config.type = self.portgroup_type config.type = self.portgroup_type
spec = [config] spec = [config]
@ -176,12 +312,59 @@ class VMwareDvsPortgroup(object):
def main(): def main():
argument_spec = vmware_argument_spec() argument_spec = vmware_argument_spec()
argument_spec.update(dict(portgroup_name=dict(required=True, type='str'), argument_spec.update(
dict(
portgroup_name=dict(required=True, type='str'),
switch_name=dict(required=True, type='str'), switch_name=dict(required=True, type='str'),
vlan_id=dict(required=True, type='int'), vlan_id=dict(required=True, type='str'),
num_ports=dict(required=True, type='int'), num_ports=dict(required=True, type='int'),
portgroup_type=dict(required=True, choices=['earlyBinding', 'lateBinding', 'ephemeral'], type='str'), portgroup_type=dict(required=True, choices=['earlyBinding', 'lateBinding', 'ephemeral'], type='str'),
state=dict(default='present', choices=['present', 'absent'], type='str'))) state=dict(required=True, choices=['present', 'absent'], type='str'),
vlan_trunk=dict(type='bool', default=False),
security=dict(
type='dict',
options=dict(
promiscuous=dict(type='bool', default=False),
forged_transmits=dict(type='bool', default=False),
mac_changes=dict(type='bool', default=False)
),
default=dict(
promiscuous=False,
forged_transmits=False,
mac_changes=False
)
),
port_policy=dict(
type='dict',
options=dict(
block_override=dict(type='bool', default=True),
ipfix_override=dict(type='bool', default=False),
live_port_move=dict(type='bool', default=False),
network_rp_override=dict(type='bool', default=False),
port_config_reset_at_disconnect=dict(type='bool', default=True),
security_override=dict(type='bool', default=False),
shaping_override=dict(type='bool', default=False),
traffic_filter_override=dict(type='bool', default=False),
uplink_teaming_override=dict(type='bool', default=False),
vendor_config_override=dict(type='bool', default=False),
vlan_override=dict(type='bool', default=False)
),
default=dict(
block_override=True,
ipfix_override=False,
live_port_move=False,
network_rp_override=False,
port_config_reset_at_disconnect=True,
security_override=False,
shaping_override=False,
traffic_filter_override=False,
uplink_teaming_override=False,
vendor_config_override=False,
vlan_override=False
)
)
)
)
module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)

@ -0,0 +1,3 @@
posix/ci/cloud/group1/vcenter
cloud/vcenter
destructive

@ -0,0 +1,244 @@
# Test code for the vmware_dvs_portgroup module.
# (c) 2017, Philippe Dellaert <philippe@dellaert.org>
# 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/>.
#
- name: make sure pyvmomi is installed
pip:
name: pyvmomi
state: latest
when: "{{ ansible_user_id == 'root' }}"
- 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
- debug: var=vcsim_instance
- 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'] }}"
# Testcase 0001: Add basic portgroup
- name: create basic portgroup
vmware_dvs_portgroup:
validate_certs: False
hostname: "{{ vcsim }}"
username: "{{ vcsim_instance['json']['username'] }}"
password: "{{ vcsim_instance['json']['password'] }}"
switch_name: "{{ new_dvs_0001['json'][0] | basename }}"
portgroup_name: "basic"
vlan_id: 0
num_ports: 32
portgroup_type: earlyBinding
state: present
register: dvs_pg_result_0001
- name: ensure dvs portgroup is present
assert:
that:
- "{{ dvs_pg_result_0001.changed == true }}"
# Testcase 0002: Add basic VLAN portgroup
- name: create basic VLAN portgroup
vmware_dvs_portgroup:
validate_certs: False
hostname: "{{ vcsim }}"
username: "{{ vcsim_instance['json']['username'] }}"
password: "{{ vcsim_instance['json']['password'] }}"
switch_name: "{{ new_dvs_0001['json'][0] | basename }}"
portgroup_name: "basic-vlan10"
vlan_id: 10
num_ports: 32
portgroup_type: earlyBinding
state: present
register: dvs_pg_result_0002
- name: ensure dvs portgroup is present
assert:
that:
- "{{ dvs_pg_result_0002.changed == true }}"
# Testcase 0003: Add basic trunk portgroup
- name: create basic trunk portgroup
vmware_dvs_portgroup:
validate_certs: False
hostname: "{{ vcsim }}"
username: "{{ vcsim_instance['json']['username'] }}"
password: "{{ vcsim_instance['json']['password'] }}"
switch_name: "{{ new_dvs_0001['json'][0] | basename }}"
portgroup_name: "basic-trunk"
vlan_id: 1-4096
vlan_trunk: True
num_ports: 32
portgroup_type: earlyBinding
state: present
register: dvs_pg_result_0003
- name: ensure dvs portgroup is present
assert:
that:
- "{{ dvs_pg_result_0003.changed == true }}"
# Testcase 0004: Add basic portgroup again
- name: create basic portgroup again
vmware_dvs_portgroup:
validate_certs: False
hostname: "{{ vcsim }}"
username: "{{ vcsim_instance['json']['username'] }}"
password: "{{ vcsim_instance['json']['password'] }}"
switch_name: "{{ new_dvs_0001['json'][0] | basename }}"
portgroup_name: "basic"
vlan_id: 0
num_ports: 32
portgroup_type: earlyBinding
state: present
register: dvs_pg_result_0004
- name: ensure dvs portgroup is present
assert:
that:
- "{{ dvs_pg_result_0004.changed == false }}"
# Testcase 0005: Add basic portgroup with all security and policy settings enabled
- name: create basic portgroup with all security and policy settings enabled
vmware_dvs_portgroup:
validate_certs: False
hostname: "{{ vcsim }}"
username: "{{ vcsim_instance['json']['username'] }}"
password: "{{ vcsim_instance['json']['password'] }}"
switch_name: "{{ new_dvs_0001['json'][0] | basename }}"
portgroup_name: "basic-all-enabled"
vlan_id: 0
num_ports: 32
portgroup_type: earlyBinding
state: present
security:
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
register: dvs_pg_result_0005
- name: ensure dvs portgroup is present
assert:
that:
- "{{ dvs_pg_result_0005.changed == true }}"
# Testcase 0006: Add basic portgroup with some settings enabled
- name: create basic portgroup with all security and policy settings enabled
vmware_dvs_portgroup:
validate_certs: False
hostname: "{{ vcsim }}"
username: "{{ vcsim_instance['json']['username'] }}"
password: "{{ vcsim_instance['json']['password'] }}"
switch_name: "{{ new_dvs_0001['json'][0] | basename }}"
portgroup_name: "basic-some-enabled"
vlan_id: 0
num_ports: 32
portgroup_type: earlyBinding
state: present
security:
promiscuous: yes
forged_transmits: yes
mac_changes: no
port_policy:
vlan_override: yes
register: dvs_pg_result_0006
- name: ensure dvs portgroup is present
assert:
that:
- "{{ dvs_pg_result_0006.changed == true }}"
# Testcase 0007: Delete basic portgroup
- name: delete basic portgroup
vmware_dvs_portgroup:
validate_certs: False
hostname: "{{ vcsim }}"
username: "{{ vcsim_instance['json']['username'] }}"
password: "{{ vcsim_instance['json']['password'] }}"
switch_name: "{{ new_dvs_0001['json'][0] | basename }}"
portgroup_name: "basic"
vlan_id: 0
num_ports: 32
portgroup_type: earlyBinding
state: absent
register: dvs_pg_result_0007
- name: ensure dvs portgroup is removed
assert:
that:
- "{{ dvs_pg_result_0007.changed == true }}"
# Testcase 0008: Delete basic portgroup again
- name: delete basic portgroup again
vmware_dvs_portgroup:
validate_certs: False
hostname: "{{ vcsim }}"
username: "{{ vcsim_instance['json']['username'] }}"
password: "{{ vcsim_instance['json']['password'] }}"
switch_name: "{{ new_dvs_0001['json'][0] | basename }}"
portgroup_name: "basic"
vlan_id: 0
num_ports: 32
portgroup_type: earlyBinding
state: absent
register: dvs_pg_result_0008
- name: ensure dvs portgroup is removed
assert:
that:
- "{{ dvs_pg_result_0008.changed == false }}"
Loading…
Cancel
Save