Define NetApp E-Series ASUP module (#41153)

* Define NetApp E-Series ASUP module

ASUP, or Auto-Support, is a mechanism that allows NetApp support
to receive information on the status of E-Series storage-systems
in order to proactively resolve issues for customers. This module
gives customers the ability to tune ASUP settings to their liking,
including disabling the feature entirely.

* Improved testing for netapp_e_asup module

Added coverage and validation to asup integration and unit testing
This commit is contained in:
Michael Price
2018-08-28 11:05:25 -05:00
committed by John R Barker
parent 56ea56f2b5
commit f781f341a2
5 changed files with 734 additions and 0 deletions

View File

@@ -0,0 +1,10 @@
# This test is not enabled by default, but can be utilized by defining required variables in integration_config.yml
# Example integration_config.yml:
# ---
#netapp_e_api_host: 10.113.1.111:8443
#netapp_e_api_username: admin
#netapp_e_api_password: myPass
#netapp_e_ssid: 1
unsupported
netapp/eseries

View File

@@ -0,0 +1 @@
- include_tasks: run.yml

View File

@@ -0,0 +1,233 @@
# Test code for the netapp_e_iscsi_interface module
# (c) 2018, NetApp, Inc
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
- name: NetApp Test ASUP module
fail:
msg: 'Please define netapp_e_api_username, netapp_e_api_password, netapp_e_api_host, and netapp_e_ssid.'
when: netapp_e_api_username is undefined or netapp_e_api_password is undefined
or netapp_e_api_host is undefined or netapp_e_ssid is undefined
vars: &vars
credentials: &creds
api_url: "https://{{ netapp_e_api_host }}/devmgr/v2"
api_username: "{{ netapp_e_api_username }}"
api_password: "{{ netapp_e_api_password }}"
ssid: "{{ netapp_e_ssid }}"
validate_certs: no
- name: set credentials
set_fact:
credentials: *creds
- name: Show some debug information
debug:
msg: "Using user={{ credentials.api_username }} on server={{ credentials.api_url }}."
# ****************************************************
# *** Enable auto-support using all default values ***
# ****************************************************
- name: Enable auto-support using default values
netapp_e_asup:
<<: *creds
verbose: true
- name: Collect auto-support state information from the array
uri:
url: "{{ credentials.api_url }}/device-asup"
user: "{{ credentials.api_username }}"
password: "{{ credentials.api_password }}"
body_format: json
validate_certs: no
register: current
- name: Validate auto-support expected default state
assert:
that: "{{ current.json.asupEnabled and
current.json.onDemandEnabled and
current.json.remoteDiagsEnabled and
current.json.schedule.dailyMinTime == 0 and
current.json.schedule.dailyMaxTime == 1439 }}"
msg: "Unexpected auto-support state"
- name: Validate auto-support schedule
assert:
that: "{{ item in current.json.schedule.daysOfWeek }}"
msg: "{{ item }} is missing from the schedule"
loop: "{{ lookup('list', ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']) }}"
# ****************************
# *** Disable auto-support ***
# ****************************
- name: Disable auto-support
netapp_e_asup:
<<: *creds
state: disabled
- name: Collect auto-support state information from the array
uri:
url: "{{ credentials.api_url }}/device-asup"
user: "{{ credentials.api_username }}"
password: "{{ credentials.api_password }}"
body_format: json
validate_certs: no
register: current
- name: Validate auto-support is disabled
assert:
that: "{{ not current.json.asupEnabled }}"
msg: "Auto-support failed to be disabled"
# ****************************************************
# *** Enable auto-support using specific values ***
# ****************************************************
- name: Enable auto-support using specific values
netapp_e_asup:
<<: *creds
state: enabled
active: true
start: 22
end: 24
days:
- friday
- saturday
verbose: true
- name: Collect auto-support state information from the array
uri:
url: "{{ credentials.api_url }}/device-asup"
user: "{{ credentials.api_username }}"
password: "{{ credentials.api_password }}"
body_format: json
validate_certs: no
register: current
- name: Validate auto-support expected state
assert:
that: "{{ current.json.asupEnabled and
current.json.onDemandEnabled and
current.json.remoteDiagsEnabled and
current.json.schedule.dailyMinTime == (22 * 60) and
current.json.schedule.dailyMaxTime == (24 * 60 - 1) }}"
msg: "Unexpected auto-support state"
- name: Validate auto-support schedule
assert:
that: "{{ item in current.json.schedule.daysOfWeek }}"
msg: "{{ item }} is missing from the schedule"
loop: "{{ lookup('list', ['friday', 'saturday']) }}"
# ***********************************
# *** Alter auto-support schedule ***
# ***********************************
- name: Auto auto-support schedule
netapp_e_asup:
<<: *creds
state: enabled
active: true
start: 0
end: 5
days:
- monday
- thursday
- sunday
verbose: true
- name: Collect auto-support state information from the array
uri:
url: "{{ credentials.api_url }}/device-asup"
user: "{{ credentials.api_username }}"
password: "{{ credentials.api_password }}"
body_format: json
validate_certs: no
register: current
- name: Validate auto-support expected state
assert:
that: "{{ current.json.asupEnabled and
current.json.onDemandEnabled and
current.json.remoteDiagsEnabled and
current.json.schedule.dailyMinTime == (0 * 60) and
current.json.schedule.dailyMaxTime == (5 * 60) }}"
msg: "Unexpected auto-support state"
- name: Validate auto-support schedule
assert:
that: "{{ item in current.json.schedule.daysOfWeek }}"
msg: "{{ item }} is missing from the schedule"
loop: "{{ lookup('list', ['monday', 'thursday', 'sunday']) }}"
# *************************************************************
# *** Repeat previous test to verify state remains the same ***
# *************************************************************
- name: Repeat auto-support schedule change to verify idempotency
netapp_e_asup:
<<: *creds
state: enabled
active: true
start: 0
end: 5
days:
- monday
- thursday
- sunday
verbose: true
register: result
- name: Collect auto-support state information from the array
uri:
url: "{{ credentials.api_url }}/device-asup"
user: "{{ credentials.api_username }}"
password: "{{ credentials.api_password }}"
body_format: json
validate_certs: no
register: current
- name: Validate auto-support expected state
assert:
that: "{{ current.json.asupEnabled and
current.json.onDemandEnabled and
current.json.remoteDiagsEnabled and
current.json.schedule.dailyMinTime == (0 * 60) and
current.json.schedule.dailyMaxTime == (5 * 60) }}"
msg: "Unexpected auto-support state"
- name: Validate auto-support schedule
assert:
that: "{{ item in current.json.schedule.daysOfWeek }}"
msg: "{{ item }} is missing from the schedule"
loop: "{{ lookup('list', ['monday', 'thursday', 'sunday']) }}"
- name: Validate change was not detected
assert:
that: "{{ not result.changed }}"
msg: "Invalid change was detected"
# ***********************************
# *** Disable auto-support active ***
# ***********************************
- name: Auto auto-support schedule
netapp_e_asup:
<<: *creds
state: enabled
active: false
start: 0
end: 5
days:
- monday
- thursday
- sunday
verbose: true
- name: Collect auto-support state information from the array
uri:
url: "{{ credentials.api_url }}/device-asup"
user: "{{ credentials.api_username }}"
password: "{{ credentials.api_password }}"
body_format: json
validate_certs: no
register: current
- name: Validate auto-support expected state
assert:
that: "{{ current.json.asupEnabled and not current.json.onDemandEnabled and not current.json.remoteDiagsEnabled }}"
msg: "Unexpected auto-support state"

View File

@@ -0,0 +1,181 @@
# (c) 2018, NetApp Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
import json
from ansible.modules.storage.netapp.netapp_e_asup import Asup
from units.modules.utils import AnsibleExitJson, AnsibleFailJson, ModuleTestCase, set_module_args
__metaclass__ = type
from ansible.compat.tests import mock
class AsupTest(ModuleTestCase):
REQUIRED_PARAMS = {
'api_username': 'rw',
'api_password': 'password',
'api_url': 'http://localhost',
'ssid': '1',
}
REQ_FUNC = 'ansible.modules.storage.netapp.netapp_e_asup.request'
def _set_args(self, args=None):
module_args = self.REQUIRED_PARAMS.copy()
if args is not None:
module_args.update(args)
set_module_args(module_args)
def test_get_config_asup_capable_false(self):
"""Ensure we fail correctly if ASUP is not available on this platform"""
self._set_args()
expected = dict(asupCapable=False, onDemandCapable=True)
asup = Asup()
# Expecting an update
with self.assertRaisesRegexp(AnsibleFailJson, r"not supported"):
with mock.patch(self.REQ_FUNC, return_value=(200, expected)):
asup.get_configuration()
def test_get_config_on_demand_capable_false(self):
"""Ensure we fail correctly if ASUP is not available on this platform"""
self._set_args()
expected = dict(asupCapable=True, onDemandCapable=False)
asup = Asup()
# Expecting an update
with self.assertRaisesRegexp(AnsibleFailJson, r"not supported"):
with mock.patch(self.REQ_FUNC, return_value=(200, expected)):
asup.get_configuration()
def test_get_config(self):
"""Validate retrieving the ASUP configuration"""
self._set_args()
expected = dict(asupCapable=True, onDemandCapable=True)
asup = Asup()
with mock.patch(self.REQ_FUNC, return_value=(200, expected)):
config = asup.get_configuration()
self.assertEquals(config, expected)
def test_update_configuration(self):
"""Validate retrieving the ASUP configuration"""
self._set_args(dict(asup='enabled'))
expected = dict()
initial = dict(asupCapable=True,
asupEnabled=True,
onDemandEnabled=False,
remoteDiagsEnabled=False,
schedule=dict(daysOfWeek=[], dailyMinTime=0, weeklyMinTime=0, dailyMaxTime=24, weeklyMaxTime=24))
asup = Asup()
with mock.patch(self.REQ_FUNC, return_value=(200, expected)) as req:
with mock.patch.object(asup, 'get_configuration', return_value=initial):
updated = asup.update_configuration()
self.assertTrue(req.called)
self.assertTrue(updated)
def test_update_configuration_asup_disable(self):
"""Validate retrieving the ASUP configuration"""
self._set_args(dict(asup='disabled'))
expected = dict()
initial = dict(asupCapable=True,
asupEnabled=True,
onDemandEnabled=False,
remoteDiagsEnabled=False,
schedule=dict(daysOfWeek=[], dailyMinTime=0, weeklyMinTime=0, dailyMaxTime=24, weeklyMaxTime=24))
asup = Asup()
with mock.patch(self.REQ_FUNC, return_value=(200, expected)) as req:
with mock.patch.object(asup, 'get_configuration', return_value=initial):
updated = asup.update_configuration()
self.assertTrue(updated)
self.assertTrue(req.called)
# Ensure it was called with the right arguments
called_with = req.call_args
body = json.loads(called_with[1]['data'])
self.assertFalse(body['asupEnabled'])
def test_update_configuration_enable(self):
"""Validate retrieving the ASUP configuration"""
self._set_args(dict(asup='enabled'))
expected = dict()
initial = dict(asupCapable=False,
asupEnabled=False,
onDemandEnabled=False,
remoteDiagsEnabled=False,
schedule=dict(daysOfWeek=[], dailyMinTime=0, weeklyMinTime=0, dailyMaxTime=24, weeklyMaxTime=24))
asup = Asup()
with mock.patch(self.REQ_FUNC, return_value=(200, expected)) as req:
with mock.patch.object(asup, 'get_configuration', return_value=initial):
updated = asup.update_configuration()
self.assertTrue(updated)
self.assertTrue(req.called)
# Ensure it was called with the right arguments
called_with = req.call_args
body = json.loads(called_with[1]['data'])
self.assertTrue(body['asupEnabled'])
self.assertTrue(body['onDemandEnabled'])
self.assertTrue(body['remoteDiagsEnabled'])
def test_update_configuration_request_exception(self):
"""Validate exception handling when request throws an exception."""
config_response = dict(asupEnabled=True,
onDemandEnabled=True,
remoteDiagsEnabled=True,
schedule=dict(daysOfWeek=[],
dailyMinTime=0,
weeklyMinTime=0,
dailyMaxTime=24,
weeklyMaxTime=24))
self._set_args(dict(state="enabled"))
asup = Asup()
with self.assertRaises(Exception):
with mock.patch.object(asup, 'get_configuration', return_value=config_response):
with mock.patch(self.REQ_FUNC, side_effect=Exception):
asup.update_configuration()
def test_init_schedule(self):
"""Validate schedule correct schedule initialization"""
self._set_args(dict(state="enabled", active=True, days=["sunday", "monday", "tuesday"], start=20, end=24))
asup = Asup()
self.assertTrue(asup.asup)
self.assertEquals(asup.days, ["sunday", "monday", "tuesday"]),
self.assertEquals(asup.start, 1200)
self.assertEquals(asup.end, 1439)
def test_init_schedule_invalid(self):
"""Validate updating ASUP with invalid schedule fails test."""
self._set_args(dict(state="enabled", active=True, start=22, end=20))
with self.assertRaisesRegexp(AnsibleFailJson, r"start time is invalid"):
Asup()
def test_init_schedule_days_invalid(self):
"""Validate updating ASUP with invalid schedule fails test."""
self._set_args(dict(state="enabled", active=True, days=["someday", "thataday", "nonday"]))
with self.assertRaises(AnsibleFailJson):
Asup()
def test_update(self):
"""Validate updating ASUP with valid schedule passes"""
initial = dict(asupCapable=True,
onDemandCapable=True,
asupEnabled=True,
onDemandEnabled=False,
remoteDiagsEnabled=False,
schedule=dict(daysOfWeek=[], dailyMinTime=0, weeklyMinTime=0, dailyMaxTime=24, weeklyMaxTime=24))
self._set_args(dict(state="enabled", active=True, days=["sunday", "monday", "tuesday"], start=10, end=20))
asup = Asup()
with self.assertRaisesRegexp(AnsibleExitJson, r"ASUP settings have been updated"):
with mock.patch(self.REQ_FUNC, return_value=(200, dict(asupCapable=True))):
with mock.patch.object(asup, "get_configuration", return_value=initial):
asup.update()