1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

VMware: Refactor vmware_portgroup module (#33442)

This fix adds following:

* hosts as argument spec
* cluster_name as argument spec
* refactor to use Pyvmomi class
* API refactor and documentation

Fixes: #18980

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
This commit is contained in:
Abhijeet Kasurde 2017-12-07 16:47:38 +05:30 committed by GitHub
parent f4cc3fb56d
commit 2caae251ff
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 208 additions and 96 deletions

View file

@ -223,14 +223,6 @@ def find_vm_by_name(content, vm_name, folder=None, recurse=True):
return None return None
def find_host_portgroup_by_name(host, portgroup_name):
for portgroup in host.config.network.portgroup:
if portgroup.spec.name == portgroup_name:
return portgroup
return None
def compile_folder_path_for_object(vobj): def compile_folder_path_for_object(vobj):
""" make a /vm/foo/bar/baz like folder path for an object """ """ make a /vm/foo/bar/baz like folder path for an object """
@ -813,6 +805,7 @@ class PyVmomi(object):
self.current_vm_obj = None self.current_vm_obj = None
self.content = connect_to_api(self.module) self.content = connect_to_api(self.module)
# Virtual Machine related functions
def get_vm(self): def get_vm(self):
vm = None vm = None
match_first = (self.params['name_match'] == 'first') match_first = (self.params['name_match'] == 'first')
@ -830,3 +823,60 @@ class PyVmomi(object):
def gather_facts(self, vm): def gather_facts(self, vm):
return gather_vm_facts(self.content, vm) return gather_vm_facts(self.content, vm)
# Cluster related functions
def find_cluster_by_name(self, cluster_name, datacenter_name=None):
"""
Find Cluster by name in given datacenter
Args:
cluster_name: Name of cluster name to find
datacenter_name: (optional) Name of datacenter
Returns: True if found
"""
return find_cluster_by_name(self.content, cluster_name, datacenter=datacenter_name)
def get_all_hosts_by_cluster(self, cluster_name):
"""
Get all hosts from cluster by cluster name
Args:
cluster_name: Name of cluster
Returns: List of hosts
"""
cluster_obj = self.find_cluster_by_name(cluster_name=cluster_name)
if cluster_obj:
return [host for host in cluster_obj.host]
else:
return []
# Hosts related functions
def find_hostsystem_by_name(self, host_name):
"""
Find Host by name
Args:
host_name: Name of ESXi host
Returns: True if found
"""
return find_hostsystem_by_name(self.content, hostname=host_name)
# Network related functions
@staticmethod
def find_host_portgroup_by_name(host, portgroup_name):
"""
Find Portgroup on given host
Args:
host: Host config object
portgroup_name: Name of portgroup
Returns: True if found else False
"""
for portgroup in host.config.network.portgroup:
if portgroup.spec.name == portgroup_name:
return portgroup
return False

View file

@ -1,16 +1,20 @@
#!/usr/bin/python #!/usr/bin/python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# (c) 2015, Joseph Callen <jcallen () csc.com> # Copyright: (c) 2015, Joseph Callen <jcallen () csc.com>
# Copyright: (c) 2017, Ansible Project
# Copyright: (c) 2017, Abhijeet Kasurde <akasurde@redhat.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) # 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 from __future__ import absolute_import, division, print_function
__metaclass__ = type __metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1', ANSIBLE_METADATA = {
'status': ['preview'], 'metadata_version': '1.1',
'supported_by': 'community'} 'status': ['preview'],
'supported_by': 'community'
}
DOCUMENTATION = ''' DOCUMENTATION = '''
@ -18,138 +22,196 @@ DOCUMENTATION = '''
module: vmware_portgroup module: vmware_portgroup
short_description: Create a VMware portgroup short_description: Create a VMware portgroup
description: description:
- Create a VMware portgroup - Create a VMware portgroup on given host/s or hosts of given cluster
version_added: 2.0 version_added: 2.0
author: "Joseph Callen (@jcpowermac), Russell Teague (@mtnbikenc)" author:
- Joseph Callen (@jcpowermac)
- Russell Teague (@mtnbikenc)
- Abhijeet Kasurde (@akasurde) <akasurde@redhat.com>
notes: notes:
- Tested on vSphere 5.5 - Tested on vSphere 5.5, 6.5
requirements: requirements:
- "python >= 2.6" - "python >= 2.6"
- PyVmomi - PyVmomi
options: options:
switch_name: switch_name:
description: description:
- vSwitch to modify - vSwitch to modify.
required: True required: True
portgroup_name: portgroup_name:
description: description:
- Portgroup name to add - Portgroup name to add.
required: True required: True
vlan_id: vlan_id:
description: description:
- VLAN ID to assign to portgroup - VLAN ID to assign to portgroup.
required: True required: True
network_policy: network_policy:
description: description:
- Network policy specifies layer 2 security settings for a - Network policy specifies layer 2 security settings for a
portgroup such as promiscuous mode, where guest adapter listens portgroup such as promiscuous mode, where guest adapter listens
to all the packets, MAC address changes and forged transmits. to all the packets, MAC address changes and forged transmits.
Settings are promiscuous_mode, forged_transmits, mac_changes - Dict which configures the different security values for portgroup.
- 'Valid attributes are:'
- '- C(promiscuous_mode) (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 required: False
version_added: "2.2" version_added: "2.2"
cluster_name:
description:
- Name of cluster name for host membership.
- Portgroup will be created on all hosts of the given cluster.
- This option is required if hosts is not specified.
version_added: "2.5"
hosts:
description:
- List of name of host or hosts on which portgroup needs to be added.
- This option is required if cluster_name is not specified.
version_added: "2.5"
extends_documentation_fragment: vmware.documentation extends_documentation_fragment: vmware.documentation
''' '''
EXAMPLES = ''' EXAMPLES = r'''
# Example from Ansible playbook - name: Add Management Network VM Portgroup
vmware_portgroup:
hostname: esxi_hostname
username: esxi_username
password: esxi_password
switch_name: vswitch_name
portgroup_name: portgroup_name
vlan_id: vlan_id
- name: Add Management Network VM Portgroup - name: Add Portgroup with Promiscuous Mode Enabled
local_action: vmware_portgroup:
module: vmware_portgroup hostname: esxi_hostname
hostname: esxi_hostname username: esxi_username
username: esxi_username password: esxi_password
password: esxi_password switch_name: vswitch_name
switch_name: vswitch_name portgroup_name: portgroup_name
portgroup_name: portgroup_name network_policy:
vlan_id: vlan_id promiscuous_mode: True
- name: Add Management Network VM Portgroup to specific hosts
vmware_portgroup:
hostname: vCenter_hostname
username: esxi_username
password: esxi_password
hosts: [esxi_hostname_one]
switch_name: vswitch_name
portgroup_name: portgroup_name
vlan_id: vlan_id
- name: Add Management Network VM Portgroup to all hosts in a cluster
vmware_portgroup:
hostname: vCenter_hostname
username: esxi_username
password: esxi_password
cluster_name: rh_engineering
switch_name: vswitch_name
portgroup_name: portgroup_name
vlan_id: vlan_id
- name: Add Portgroup with Promiscuous Mode Enabled
local_action:
module: vmware_portgroup
hostname: esxi_hostname
username: esxi_username
password: esxi_password
switch_name: vswitch_name
portgroup_name: portgroup_name
network_policy:
promiscuous_mode: True
''' '''
try: try:
from pyVmomi import vim, vmodl from pyVmomi import vim, vmodl
HAS_PYVMOMI = True
except ImportError: except ImportError:
HAS_PYVMOMI = False pass
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.vmware import (HAS_PYVMOMI, from ansible.module_utils.vmware import PyVmomi, vmware_argument_spec
connect_to_api,
find_host_portgroup_by_name,
get_all_objs,
vmware_argument_spec,
)
def create_network_policy(promiscuous_mode, forged_transmits, mac_changes): class PyVmomiHelper(PyVmomi):
def __init__(self, module):
super(PyVmomiHelper, self).__init__(module)
security_policy = vim.host.NetworkPolicy.SecurityPolicy() self.hosts = self.params['hosts']
if promiscuous_mode: self.cluster = self.params['cluster_name']
security_policy.allowPromiscuous = promiscuous_mode self.portgroup_name = self.params['portgroup_name']
if forged_transmits: self.switch_name = self.params['switch_name']
security_policy.forgedTransmits = forged_transmits self.vlan_id = self.params['vlan_id']
if mac_changes: self.promiscuous_mode = self.params['network_policy'].get('promiscuous_mode')
security_policy.macChanges = mac_changes self.forged_transmits = self.params['network_policy'].get('forged_transmits')
network_policy = vim.host.NetworkPolicy(security=security_policy) self.mac_changes = self.params['network_policy'].get('mac_changes')
return network_policy self.network_policy = self.create_network_policy()
self.changed = False
def add_hosts_port_group(self, hosts):
for host in hosts:
self.changed = self.create_port_group(host, self.portgroup_name, self.vlan_id,
self.switch_name, self.network_policy)
def create_port_group(host_system, portgroup_name, vlan_id, vswitch_name, network_policy): def create_port_group(self, host_system, portgroup_name, vlan_id, vswitch_name, network_policy):
config = vim.host.NetworkConfig()
config.portgroup = [vim.host.PortGroup.Config()]
config.portgroup[0].changeOperation = "add"
config.portgroup[0].spec = vim.host.PortGroup.Specification()
config.portgroup[0].spec.name = portgroup_name
config.portgroup[0].spec.vlanId = vlan_id
config.portgroup[0].spec.vswitchName = vswitch_name
config.portgroup[0].spec.policy = network_policy
config = vim.host.NetworkConfig() host_system.configManager.networkSystem.UpdateNetworkConfig(config, "modify")
config.portgroup = [vim.host.PortGroup.Config()] return True
config.portgroup[0].changeOperation = "add"
config.portgroup[0].spec = vim.host.PortGroup.Specification()
config.portgroup[0].spec.name = portgroup_name
config.portgroup[0].spec.vlanId = vlan_id
config.portgroup[0].spec.vswitchName = vswitch_name
config.portgroup[0].spec.policy = network_policy
host_system.configManager.networkSystem.UpdateNetworkConfig(config, "modify") def create_network_policy(self):
return True security_policy = vim.host.NetworkPolicy.SecurityPolicy()
if self.promiscuous_mode:
security_policy.allowPromiscuous = self.promiscuous_mode
if self.forged_transmits:
security_policy.forgedTransmits = self.forged_transmits
if self.mac_changes:
security_policy.macChanges = self.mac_changes
network_policy = vim.host.NetworkPolicy(security=security_policy)
return network_policy
def add_portgroup(self):
if self.cluster and self.find_cluster_by_name(cluster_name=self.cluster):
hosts = self.get_all_hosts_by_cluster(cluster_name=self.cluster)
self.add_hosts_port_group(hosts=hosts)
elif self.hosts:
for host in self.hosts:
host_system = self.find_hostsystem_by_name(host_name=host)
if host_system:
self.add_hosts_port_group([host_system])
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(
switch_name=dict(required=True, type='str'), portgroup_name=dict(required=True, type='str'),
vlan_id=dict(required=True, type='int'), switch_name=dict(required=True, type='str'),
network_policy=dict(required=False, type='dict', default={}))) vlan_id=dict(required=True, type='int'),
hosts=dict(type='list'),
cluster_name=dict(type='str'),
network_policy=dict(type='dict',
options=dict(
promiscuous_mode=dict(type='bool'),
forged_transmits=dict(type='bool'),
mac_changes=dict(type='bool'),
),
default=dict(
promiscuous_mode=False,
forged_transmits=False,
mac_changes=False,
)
)
)
)
module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False) module = AnsibleModule(argument_spec=argument_spec,
supports_check_mode=False,
if not HAS_PYVMOMI: required_one_of=[
module.fail_json(msg='pyvmomi is required for this module') ['cluster_name', 'hosts'],
]
portgroup_name = module.params['portgroup_name'] )
switch_name = module.params['switch_name']
vlan_id = module.params['vlan_id']
promiscuous_mode = module.params['network_policy'].get('promiscuous_mode', None)
forged_transmits = module.params['network_policy'].get('forged_transmits', None)
mac_changes = module.params['network_policy'].get('mac_changes', None)
try: try:
content = connect_to_api(module) pyv = PyVmomiHelper(module)
host = get_all_objs(content, [vim.HostSystem]) pyv.add_portgroup()
if not host: changed = pyv.changed
raise SystemExit("Unable to locate Physical Host.")
host_system = host.keys()[0]
if find_host_portgroup_by_name(host_system, portgroup_name):
module.exit_json(changed=False)
network_policy = create_network_policy(promiscuous_mode, forged_transmits, mac_changes)
changed = create_port_group(host_system, portgroup_name, vlan_id, switch_name, network_policy)
module.exit_json(changed=changed) module.exit_json(changed=changed)
except vmodl.RuntimeFault as runtime_fault: except vmodl.RuntimeFault as runtime_fault: