Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modify na_ontap_net_port NetAppModule module format, allow for multiple ports, unit tests #52286

Merged
merged 5 commits into from
Mar 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
201 changes: 97 additions & 104 deletions lib/ansible/modules/storage/netapp/na_ontap_net_port.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/python

# (c) 2018, NetApp, Inc
# (c) 2018-2019, NetApp, Inc
# 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
Expand Down Expand Up @@ -30,9 +30,11 @@
description:
- Specifies the name of node.
required: true
port:
ports:
aliases:
- port
description:
- Specifies the name of port.
- Specifies the name of port(s).
required: true
mtu:
description:
Expand Down Expand Up @@ -60,21 +62,24 @@
EXAMPLES = """
- name: Modify Net Port
na_ontap_net_port:
state=present
username={{ netapp_username }}
password={{ netapp_password }}
hostname={{ netapp_hostname }}
node={{ Vsim server name }}
port=e0d
autonegotiate_admin=true
state: present
username: "{{ netapp_username }}"
password: "{{ netapp_password }}"
hostname: "{{ netapp_hostname }}"
node: "{{ node_name }}"
ports: e0d,e0c
autonegotiate_admin: true
"""

RETURN = """

"""
import traceback

from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
import ansible.module_utils.netapp as netapp_utils
from ansible.module_utils.netapp_module import NetAppModule

HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()

Expand All @@ -92,7 +97,7 @@ def __init__(self):
self.argument_spec.update(dict(
state=dict(required=False, choices=['present'], default='present'),
node=dict(required=True, type="str"),
port=dict(required=True, type="str"),
ports=dict(required=True, type="list", aliases=['port']),
mtu=dict(required=False, type="str", default=None),
autonegotiate_admin=dict(required=False, type="str", default=None),
duplex_admin=dict(required=False, type="str", default=None),
Expand All @@ -106,119 +111,107 @@ def __init__(self):
supports_check_mode=True
)

p = self.module.params

# set up state variables
self.state = p['state']
self.node = p['node']
self.port = p['port']
# the following option are optional, but at least one need to be set
self.mtu = p['mtu']
self.autonegotiate_admin = p["autonegotiate_admin"]
self.duplex_admin = p["duplex_admin"]
self.speed_admin = p["speed_admin"]
self.flowcontrol_admin = p["flowcontrol_admin"]
self.na_helper = NetAppModule()
self.parameters = self.na_helper.set_parameters(self.module.params)
self.set_playbook_zapi_key_map()

if HAS_NETAPP_LIB is False:
self.module.fail_json(
msg="the python NetApp-Lib module is required")
self.module.fail_json(msg="the python NetApp-Lib module is required")
else:
self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
return

def get_net_port(self):
def set_playbook_zapi_key_map(self):
self.na_helper.zapi_string_keys = {
'mtu': 'mtu',
'autonegotiate_admin': 'is-administrative-auto-negotiate',
'duplex_admin': 'administrative-duplex',
'speed_admin': 'administrative-speed',
'flowcontrol_admin': 'administrative-flowcontrol',
'ipspace': 'ipspace'
}

def get_net_port(self, port):
"""
Return details about the net port

:return: Details about the net port. None if not found.
:param: port: Name of the port
:return: Dictionary with current state of the port. None if not found.
:rtype: dict
"""
net_port_info = netapp_utils.zapi.NaElement('net-port-get-iter')
net_port_attributes = netapp_utils.zapi.NaElement('net-port-info')
net_port_attributes.add_new_child('node', self.node)
net_port_attributes.add_new_child('port', self.port)
query = netapp_utils.zapi.NaElement('query')
query.add_child_elem(net_port_attributes)
net_port_info.add_child_elem(query)
result = self.server.invoke_successfully(net_port_info, True)
return_value = None

if result.get_child_by_name('num-records') and \
int(result.get_child_content('num-records')) >= 1:

net_port_attributes = result.get_child_by_name('attributes-list').\
get_child_by_name('net-port-info')
return_value = {
'node': net_port_attributes.get_child_content('node'),
'port': net_port_attributes.get_child_content('port'),
'mtu': net_port_attributes.get_child_content('mtu'),
'autonegotiate_admin': net_port_attributes.get_child_content(
'is-administrative-auto-negotiate'),
'duplex_admin': net_port_attributes.get_child_content(
'administrative-duplex'),
'speed_admin': net_port_attributes.get_child_content(
'administrative-speed'),
'flowcontrol_admin': net_port_attributes.get_child_content(
'administrative-flowcontrol'),
net_port_get = netapp_utils.zapi.NaElement('net-port-get-iter')
attributes = {
'query': {
'net-port-info': {
'node': self.parameters['node'],
'port': port
}
}
return return_value
}
net_port_get.translate_struct(attributes)

try:
result = self.server.invoke_successfully(net_port_get, True)
if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) >= 1:
port_info = result['attributes-list']['net-port-info']
port_details = dict()
else:
return None
except netapp_utils.zapi.NaApiError as error:
self.module.fail_json(msg='Error getting net ports for %s: %s' % (self.parameters['node'], to_native(error)),
exception=traceback.format_exc())

for item_key, zapi_key in self.na_helper.zapi_string_keys.items():
port_details[item_key] = port_info.get_child_content(zapi_key)
return port_details

def modify_net_port(self):
def modify_net_port(self, port, modify):
"""
Modify a port

:param port: Name of the port
:param modify: dict with attributes to be modified
:return: None
"""
port_modify = netapp_utils.zapi.NaElement('net-port-modify')
port_attributes = {'node': self.parameters['node'],
'port': port}
for key in modify:
if key in self.na_helper.zapi_string_keys:
zapi_key = self.na_helper.zapi_string_keys.get(key)
port_attributes[zapi_key] = modify[key]
port_modify.translate_struct(port_attributes)
try:
self.server.invoke_successfully(port_modify, enable_tunneling=True)
except netapp_utils.zapi.NaApiError as error:
self.module.fail_json(msg='Error modifying net ports for %s: %s' % (self.parameters['node'], to_native(error)),
exception=traceback.format_exc())

def autosupport_log(self):
"""
AutoSupport log for na_ontap_net_port
:return: None
"""
port_obj = netapp_utils.zapi.NaElement('net-port-modify')
port_obj.add_new_child("node", self.node)
port_obj.add_new_child("port", self.port)
# The following options are optional.
# We will only call them if they are not set to None
if self.mtu:
port_obj.add_new_child("mtu", self.mtu)
if self.autonegotiate_admin:
port_obj.add_new_child(
"is-administrative-auto-negotiate", self.autonegotiate_admin)
if self.duplex_admin:
port_obj.add_new_child("administrative-duplex", self.duplex_admin)
if self.speed_admin:
port_obj.add_new_child("administrative-speed", self.speed_admin)
if self.flowcontrol_admin:
port_obj.add_new_child(
"administrative-flowcontrol", self.flowcontrol_admin)
self.server.invoke_successfully(port_obj, True)
results = netapp_utils.get_cserver(self.server)
cserver = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=results)
netapp_utils.ems_log_event("na_ontap_net_port", cserver)

def apply(self):
"""
Run Module based on play book
"""
changed = False
net_port_exists = False
results = netapp_utils.get_cserver(self.server)
cserver = netapp_utils.setup_na_ontap_zapi(
module=self.module, vserver=results)
netapp_utils.ems_log_event("na_ontap_net_port", cserver)
net_port_details = self.get_net_port()
if net_port_details:
net_port_exists = True
if self.state == 'present':
if (self.mtu and self.mtu != net_port_details['mtu']) or \
(self.autonegotiate_admin and
self.autonegotiate_admin != net_port_details['autonegotiate_admin']) or \
(self.duplex_admin and
self.duplex_admin != net_port_details['duplex_admin']) or \
(self.speed_admin and
self.speed_admin != net_port_details['speed_admin']) or \
(self.flowcontrol_admin and
self.flowcontrol_admin != net_port_details['flowcontrol_admin']):
changed = True

if changed:
if self.module.check_mode:
pass
else:
if self.state == 'present':
if net_port_exists:
self.modify_net_port()
self.module.exit_json(changed=changed)

self.autosupport_log()
# Run the task for all ports in the list of 'ports'
for port in self.parameters['ports']:
current = self.get_net_port(port)
modify = self.na_helper.get_modified_attributes(current, self.parameters)
if self.na_helper.changed:
if self.module.check_mode:
pass
else:
if modify:
self.modify_net_port(port, modify)
self.module.exit_json(changed=self.na_helper.changed)


def main():
Expand Down