File: //lib/python3.9/site-packages/ansible_collections/hpe/nimble/plugins/modules/hpe_nimble_info.py
# Copyright 2020 Hewlett Packard Enterprise Development LP
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
# file except in compliance with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
# OF ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
# author Alok Ranjan ([email protected])
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = r'''
---
author:
- HPE Nimble Storage Ansible Team (@ar-india) <[email protected]>
description:
- Collect information from a HPE Nimble Storage array. By default, the module will collect basic information
including array, groups config, protection templates, protection schedules, snapshots, snapshot collections, volume
collections and volume counts. Additional information can be collected based on the configured set of arguments.
module: hpe_nimble_info
options:
gather_subset:
required: False
default: minimum
type: list
elements: raw
description:
- When supplied, this argument will define the information to be collected. Possible values for this include "all" "minimum" "config"
"access_control_records", "alarms", "application_servers", "application_categories", "arrays", "chap_users", "controllers", "disks",
"fibre_channel_interfaces", "fibre_channel_configs", "fibre_channel_initiator_aliases", "fibre_channel_ports", "folders", "groups",
"initiator_groups", "initiators", "master_key", "network_configs", "performance_policies", "pools", "protection_schedules",
"protection_templates", "protocol_endpoints", "replication_partners", "shelves", "snapshots", "snapshot_collections", "software_versions",
"user_groups", "user_policies", "users", "volumes", "volume_collections".
- Each subset except "all", "minimum" and "config" supports four types of subset options. Subset "all" supports limit and detail as subset options.
Subset "config" and "minimum" does not support any subset options.
- See the example section for usage of the following subset options.
- fields - A string representing which attributes to display for a given subset.
- limit - An integer value which represents how many latest items to show for a given subset.
- detail - A bool flag when set to true fetches everything for a given subset. Default is "True".
- query - A key-value pair to query.
extends_documentation_fragment: hpe.nimble.hpe_nimble
short_description: Collect information from HPE Nimble Storage array
version_added: "1.0.0"
notes:
- This module supports C(check_mode).
'''
EXAMPLES = r'''
- name: Collect default set of information
hpe.nimble.hpe_nimble_info:
host: "{{ host }}"
username: "{{ username }}"
password: "{{ password }}"
gather_subset:
- minimum:
register: array_info
- name: Show default information
ansible.builtin.debug:
msg: "{{ array_info['nimble_info']['default'] }}"
- name: Collect config
hpe.nimble.hpe_nimble_info:
host: "{{ host }}"
username: "{{ username }}"
password: "{{ password }}"
gather_subset:
- config:
register: array_info
- name: Show config information
ansible.builtin.debug:
msg: "{{ array_info['nimble_info']['config'] }}"
- name: Collect all
hpe.nimble.hpe_nimble_info:
host: "{{ host }}"
username: "{{ username }}"
password: "{{ password }}"
gather_subset:
- all:
limit: 1
register: array_info
- name: Show all information
ansible.builtin.debug:
msg: "{{ array_info['nimble_info'] }}"
- name: Collect volume, snapshot and volume collection. Below query will show just one
snapshot detail with attributes 'name and id' for a volume called 'vol1'
hpe.nimble.hpe_nimble_info:
host: "{{ host }}"
username: "{{ username }}"
password: "{{ password }}"
gather_subset:
- volumes:
fields: "name,id"
limit: 2
- volume_collections:
limit: 1
detail: false
- snapshots:
fields: "name,id"
query:
vol_name: "vol1"
limit: 1
detail: True
register: array_info
- name: Show information
ansible.builtin.debug:
msg: "{{ array_info['nimble_info'] }}"
'''
RETURN = r'''
nimble_info:
description: Returns the information collected from the HPE Nimble Storage array
returned: always
type: complex
contains: {}
sample: {
"config": {
"arrays": [
{
"all_flash": false,
"extended_model": "vmware-4G-5T-160F",
"full_name": "ansibler1-va",
"role": "leader",
"serial": "ansibler1-va"
}
],
"groups": [
{
"alarms_enabled": true,
"auto_switchover_enabled": true,
"auto_switchover_messages": [],
"autosupport_enabled": true,
"default_iscsi_target_scope": "group",
"dns_servers": [
{
"ip_addr": "10.235.0.185"
},
{
"ip_addr": "10.1.255.254"
}
],
"domain_name": "vlab.nimblestorage.com",
"encryption_config": {
"cipher": "aes_256_xts",
"encryption_active": true,
"encryption_key_manager": "local",
"master_key_set": true,
"mode": "available",
"scope": "group"
},
"failover_mode": "Manual",
"fc_enabled": false,
"iscsi_enabled": true,
"isns_enabled": true,
"leader_array_name": "ansibler1-va",
"member_list": [
"ansibler1-va"
],
"name": "group-ansibler1-va",
"ntp_server": "time.nimblestorage.com",
"send_alert_to_support": true,
"smtp_auth_enabled": false,
"smtp_auth_username": "",
"smtp_port": 25,
"smtp_server": "",
"snmp_community": "public",
"snmp_trap_enabled": false,
"snmp_trap_host": "",
"snmp_trap_port": 162,
"syslogd_enabled": false,
"syslogd_server": "",
"vvol_enabled": true
}
],
"network_configs": [
{
"active_since": 1592210265,
"array_list": [
{
"ctrlr_a_support_ip": "10.18.1.1",
"ctrlr_b_support_ip": "10.18.2.2",
"member_gid": 1,
"name": "ansibler1-va",
"nic_list": [
{
"data_ip": "172.16.41.139",
"name": "eth3",
"subnet_label": "data1",
"tagged": false
},
{
"data_ip": "172.16.234.76",
"name": "eth4",
"subnet_label": "data2",
"tagged": false
},
{
"data_ip": "",
"name": "eth2",
"subnet_label": "mgmt-data",
"tagged": false
},
{
"data_ip": "",
"name": "eth1",
"subnet_label": "mgmt-data",
"tagged": false
}
]
}
],
"creation_time": 1586411318,
"group_leader_array": "ansibler1-va",
"id": "177321e77f009f2013000000000000000000000001",
"iscsi_automatic_connection_method": true,
"iscsi_connection_rebalancing": true,
"last_active": 1592210256,
"last_modified": 1586411356,
"mgmt_ip": "10.18.171.96",
"name": "active",
"role": "active",
"route_list": [
{
"gateway": "10.18.160.1",
"tgt_netmask": "0.0.0.0",
"tgt_network": "0.0.0.0"
}
],
"secondary_mgmt_ip": "",
"subnet_list": [
{
"allow_group": true,
"allow_iscsi": true,
"discovery_ip": "172.16.41.140",
"failover": true,
"failover_enable_time": 0,
"label": "data1",
"mtu": 1500,
"netmask": "255.255.224.0",
"network": "172.16.32.0",
"netzone_type": "single",
"type": "data",
"vlan_id": 0
},
{
"allow_group": true,
"allow_iscsi": true,
"discovery_ip": "172.16.234.101",
"failover": true,
"failover_enable_time": 0,
"label": "data2",
"mtu": 1500,
"netmask": "255.255.224.0",
"network": "172.16.224.0",
"netzone_type": "single",
"type": "data",
"vlan_id": 0
},
{
"allow_group": false,
"allow_iscsi": false,
"discovery_ip": "",
"failover": true,
"failover_enable_time": 0,
"label": "mgmt-data",
"mtu": 1500,
"netmask": "255.255.224.0",
"network": "10.18.160.0",
"netzone_type": "none",
"type": "mgmt",
"vlan_id": 0
}
]
},
{
"active_since": 0,
"array_list": [
{
"ctrlr_a_support_ip": "10.18.1.1",
"ctrlr_b_support_ip": "10.18.2.2",
"member_gid": 1,
"name": "ansibler1-va",
"nic_list": [
{
"data_ip": "",
"name": "eth2",
"subnet_label": "mgmt-data",
"tagged": false
},
{
"data_ip": "",
"name": "eth1",
"subnet_label": "mgmt-data",
"tagged": false
},
{
"data_ip": "172.16.41.139",
"name": "eth3",
"subnet_label": "data1",
"tagged": false
},
{
"data_ip": "172.16.234.76",
"name": "eth4",
"subnet_label": "data2",
"tagged": false
}
]
}
],
"creation_time": 1586411356,
"group_leader_array": "ansibler1-va",
"id": "177321e77f009f2013000000000000000000000002",
"iscsi_automatic_connection_method": true,
"iscsi_connection_rebalancing": true,
"last_active": 1592210265,
"last_modified": 1586411318,
"mgmt_ip": "10.18.171.96",
"name": "backup",
"role": "backup",
"route_list": [
{
"gateway": "10.18.160.1",
"tgt_netmask": "0.0.0.0",
"tgt_network": "0.0.0.0"
}
],
"secondary_mgmt_ip": "",
"subnet_list": [
{
"allow_group": false,
"allow_iscsi": false,
"discovery_ip": "",
"failover": true,
"failover_enable_time": 0,
"label": "mgmt-data",
"mtu": 1500,
"netmask": "255.255.224.0",
"network": "10.18.160.0",
"netzone_type": "none",
"type": "mgmt",
"vlan_id": 0
},
{
"allow_group": true,
"allow_iscsi": true,
"discovery_ip": "172.16.41.140",
"failover": true,
"failover_enable_time": 0,
"label": "data1",
"mtu": 1500,
"netmask": "255.255.224.0",
"network": "172.16.32.0",
"netzone_type": "single",
"type": "data",
"vlan_id": 0
},
{
"allow_group": true,
"allow_iscsi": true,
"discovery_ip": "172.16.234.101",
"failover": true,
"failover_enable_time": 0,
"label": "data2",
"mtu": 1500,
"netmask": "255.255.224.0",
"network": "172.16.224.0",
"netzone_type": "single",
"type": "data",
"vlan_id": 0
}
]
}
],
"pools": [
{
"array_count": 1,
"dedupe_all_volumes": false,
"dedupe_capable": false,
"is_default": true,
"name": "default",
"vol_list": [
{
"id": "0675a5e21cc205c609000000000000000000000001",
"name": "vol1",
"vol_id": "0675a5e21cc205c609000000000000000000000001",
"vol_name": "vol1"
},
{
"id": "067321e77f009f2013000000000000000000000271",
"name": "volumetc-vol1-0-24-07-2020-71470d6d-cd6e-11ea-9165-00505696c568",
"vol_id": "067321e77f009f2013000000000000000000000271",
"vol_name": "volumetc-vol1-0-24-07-2020-71470d6d-cd6e-11ea-9165-00505696c568"
},
{
"id": "067321e77f009f201300000000000000000000024d",
"name": "ansible-vol1",
"vol_id": "067321e77f009f201300000000000000000000024d",
"vol_name": "ansible-vol1"
}
]
}
]
},
"default": {
"arrays": [
{
"all_flash": false,
"extended_model": "vmware-4G-5T-160F",
"full_name": "ansibler1-va"
}
],
"disks": 16,
"folders": 0,
"groups": [
{
"auto_switchover_messages": [],
"default_iscsi_target_scope": "group",
"encryption_config": {
"cipher": "aes_256_xts",
"encryption_active": true,
"encryption_key_manager": "local",
"master_key_set": true,
"mode": "available",
"scope": "group"
},
"fc_enabled": false,
"iscsi_enabled": true,
"leader_array_name": "ansibler1-va",
"name": "group-ansibler1-va",
"num_snaps": 49
}
],
"initiator_groups": 1,
"protection_schedules": 6,
"protection_templates": 3,
"protocol_endpoints": 0,
"snapshot_collections": 49,
"snapshots": 49,
"software_versions": "5.2.2.0-730069-opt",
"users": 2,
"volume_collections": 1,
"volumes": 3
},
"snapshots":
[
{
"access_control_records": null,
"agent_type": "none",
"app_uuid": "",
"creation_time": 1586429663,
"description": "Replicated by protection policy volcoll2 schedule Schedule-new",
"expiry_after": 1,
"expiry_time": 0,
"id": "0475a5e21cc205c609000000000000000200000004",
"is_manually_managed": true,
"is_replica": true,
"is_unmanaged": false,
"last_modified": 1586429956,
"metadata": null,
"name": "adfsasfasfasf",
"new_data_compressed_bytes": 0,
"new_data_uncompressed_bytes": 0,
"new_data_valid": true,
"offline_reason": "user",
"online": false,
"origin_name": "",
"pool_name": "default",
"replication_status": null,
"schedule_id": "0c7321e77f009f2013000000000000000000000008",
"schedule_name": "Schedule-new",
"serial_number": "022e0240e677ef2f6c9ce9006cc7be73",
"size": 1073741824,
"snap_collection_id": "0575a5e21cc205c609000000000000000000000004",
"snap_collection_name": "adfsasfasfasf",
"target_name": "iqn.2007-11.com.nimblestorage:group-ansibler1-va-g7321e77f009f2013",
"vol_id": "0675a5e21cc205c609000000000000000000000001",
"vol_name": "vol1",
"vpd_ieee0": "022e0240e677ef2f",
"vpd_ieee1": "6c9ce9006cc7be73",
"vpd_t10": "Nimble 022e0240e677ef2f6c9ce9006cc7be73",
"writable": false
}
],
"volume_collections":
[
"volcoll2": {
"id": "077321e77f009f2013000000000000000000000005",
"name": "volcoll2"
}
],
"volumes":
[
"10.18.180.239-ansible-vol1": {
"id": "067321e77f009f2013000000000000000000000230",
"name": "10.18.180.239-ansible-vol1"
},
"changed-volname": {
"id": "067321e77f009f201300000000000000000000022f",
"name": "changed-volname"
}
]
}
'''
from ansible.module_utils.basic import AnsibleModule
try:
from nimbleclient.v1 import client
except ImportError:
client = None
from ansible_collections.hpe.nimble.plugins.module_utils.hpe_nimble import __version__ as NIMBLE_ANSIBLE_VERSION
import ansible_collections.hpe.nimble.plugins.module_utils.hpe_nimble as utils
import re
limit_not_supported = [
"controllers",
"disks",
"shelves",
"software_versions"
]
def add_to_valid_subset_list(valid_subset_list,
subset_name,
subset_options,
fetch_all=False):
if valid_subset_list is None:
return []
valid_subset = {}
fields = query = limit = None
detail = True # default
count = -1
if subset_options is not None:
if 'fields' in subset_options and subset_options['fields'] is not None:
temp = ""
for item in subset_options['fields']:
temp += item + ','
fields = temp.strip(',')
# fields = subset_options['fields'].strip()
if 'detail' in subset_options and subset_options['detail'] is not None:
detail = subset_options['detail']
if 'limit' in subset_options:
count = limit = subset_options['limit']
if fetch_all is True:
# few subset do not support limit option. hence in case of subset 'all' ,set it to none
if subset_name in limit_not_supported:
limit = None
if subset_options is not None and 'query' in subset_options:
query = subset_options['query']
valid_subset['name'] = subset_name.lower()
valid_subset['fields'] = fields
valid_subset['query'] = query
valid_subset['limit'] = limit
valid_subset['detail'] = detail
valid_subset['count'] = count
valid_subset_list.append(dict(valid_subset))
return valid_subset_list
def is_subset_option_valid(subset_options):
if subset_options is None:
return (True, "", "")
if isinstance(subset_options, dict) is False:
raise Exception("Subset options should be provided as dictionary.")
for key, value in subset_options.items():
if key != "fields" and key != "query" and key != "limit" and key != "detail":
return (False, key, "Valid subset option names are:'fields', 'query', 'limit', and 'detail'")
if key == 'limit' and type(value) is not int:
return (False, key, "Subset options 'limit' should be provided as integer.")
if key == 'detail' and type(value) is not bool:
return (False, key, "Subset options 'detail' should be provided as bool.")
if key == 'fields' and type(value) is not list:
return (False, key, "Subset options 'fields' should be provided as list.")
if key == 'query' and type(value) is not dict:
return (False, key, "Subset options 'query' should be provided as dict.")
return (True, "", "")
def is_subset_already_added(key, valid_subset_list):
if valid_subset_list is None:
return False
for item in valid_subset_list:
if key == item['name']:
return True
return False
def handle_all_subset(info_subset, valid_subset_list, subset_options):
if valid_subset_list is None or info_subset is None:
return []
msg = "Subset options 'fields and query' cannot be used with 'all' subset. Only 'limit and detail' option can be used."
if subset_options is not None:
if 'fields' in subset_options or 'query' in subset_options:
raise Exception(msg)
for key, value in info_subset.items():
if (is_subset_already_added(key, valid_subset_list) is False
and (key != 'minimum' and key != 'config' and key != 'snapshots')):
add_to_valid_subset_list(valid_subset_list, key, subset_options, True)
return valid_subset_list
def raise_invalid_subset_ex(key):
msg = f"Subset name '{key}' is not valid. Please provide a correct subset name."
raise Exception(msg)
def raise_repeat_subset_ex(key):
msg = f"Subset '{key}' is already provided as input. Please remove one entry."
raise Exception(msg)
def raise_subset_mutually_exclusive_ex():
msg = "Subset 'all' and 'minimum' are mutually exclusive. Please provide only one of them"
raise Exception(msg)
def parse_subset_list(info_subset, gather_subset):
valid_subset_list = []
try:
if gather_subset is None or isinstance(gather_subset, list) is False:
add_to_valid_subset_list(valid_subset_list, 'minimum', None)
return valid_subset_list
# each entry in gather subset represents a dictonary or list for each object set
for object_set in gather_subset:
object_set_type = type(object_set)
if object_set_type is dict:
for key, subset_options in object_set.items():
key = key.strip()
if info_subset.get(key, None) is None:
raise_invalid_subset_ex(key)
flag, param_key, err_msg = is_subset_option_valid(subset_options)
if flag is False:
msg = f"Invalid subset option '{param_key}' provided for subset '{key}'."
raise Exception(msg + ' ' + err_msg)
else:
if key == 'all':
if is_subset_already_added('minimum', valid_subset_list) is True:
raise_subset_mutually_exclusive_ex()
handle_all_subset(info_subset, valid_subset_list, subset_options)
continue
if key == 'minimum' or key == 'config':
if subset_options is not None:
raise Exception("Subset options cannot be used with 'minimum' and 'config' subset.")
if key == 'minimum':
if is_subset_already_added('all', valid_subset_list) is True:
raise_subset_mutually_exclusive_ex()
elif is_subset_already_added(key, valid_subset_list) is True:
raise_repeat_subset_ex(key)
add_to_valid_subset_list(valid_subset_list, key, subset_options)
elif object_set_type is str:
key = object_set.strip()
if info_subset.get(key, None) is None:
raise_invalid_subset_ex(key)
if is_subset_already_added(key, valid_subset_list) is True:
raise_repeat_subset_ex(key)
if key == 'all':
if is_subset_already_added('minimum', valid_subset_list) is True:
raise_subset_mutually_exclusive_ex()
handle_all_subset(info_subset, valid_subset_list, None)
continue
add_to_valid_subset_list(valid_subset_list, key, None)
return (valid_subset_list)
except Exception as ex:
raise(ex)
def generate_dict(name, resp):
temp_dict = {}
if utils.is_null_or_empty(resp) or name is None:
return {}
for item in resp:
key = item.attrs.get(name)
if key in temp_dict:
# we need to convert the dict into a list of items as we have more than one item for the same key
temp_list = [temp_dict[key]]
if isinstance(temp_dict[key], dict) is True:
temp_dict.pop(key)
temp_dict.setdefault(key, temp_list).append(item.attrs)
elif key is None or key == "N/A":
temp_dict.setdefault(name, []).append(item.attrs)
else:
temp_dict[key] = item.attrs
return temp_dict
def fetch_config_subset(info_subset):
if info_subset is None:
return ({}, True)
toreturn = {'config': {}}
result = {}
temp_dict = {}
grp_fields = """
smtp_server,
smtp_port,
smtp_auth_enabled,
smtp_auth_username,
autosupport_enabled,
send_alert_to_support,
isns_enabled,
snmp_trap_enabled,
snmp_trap_host,
snmp_trap_port,
snmp_community,
domain_name,
dns_servers,
ntp_server,
syslogd_enabled,
syslogd_server,
vvol_enabled,
alarms_enabled,
member_list,
encryption_config,
name,
fc_enabled,
iscsi_enabled
"""
try:
for key, cl_obj in info_subset.items():
if key == 'arrays':
resp = cl_obj.list(detail=True, fields="extended_model,full_name,all_flash,serial,role")
elif key == 'groups':
resp = cl_obj.list(detail=True, fields=re.sub('\\s+', '', grp_fields))
elif key == 'pools':
resp = cl_obj.list(detail=True, fields="array_count,dedupe_all_volumes,dedupe_capable,is_default,name,vol_list")
elif key == 'network_configs':
resp = cl_obj.list(detail=True)
else:
continue
temp_dict[key] = resp
# prepare
result['arrays'] = generate_dict('arrays', temp_dict['arrays'])['arrays']
result['groups'] = generate_dict('groups', temp_dict['groups'])['groups']
result['pools'] = generate_dict('pools', temp_dict['pools'])['pools']
result['network_configs'] = generate_dict('network_configs', temp_dict['network_configs'])['network_configs']
toreturn['config'] = result
return (toreturn, True)
except Exception:
raise
def fetch_minimum_subset(info_subset):
if info_subset is None:
return ({}, True)
minimum_subset = [
"arrays",
"disks",
"folders",
"groups",
"initiator_groups",
"performance_policies",
"pools",
"protection_schedules",
"protection_templates",
"protocol_endpoints",
"snapshot_collections",
"software_versions",
"users",
"volumes",
"volume_collections"
]
toreturn = {'default': {}}
result = {}
temp_dict = {}
try:
for key in minimum_subset:
cl_obj = info_subset[key]
if key == 'arrays':
resp = cl_obj.list(detail=True, fields="extended_model,full_name,all_flash")
elif key == 'groups':
# certain fields were only added in NimOS 5.1 and above
if utils.is_array_version_above_or_equal(info_subset['arrays'], "5.1"):
resp = cl_obj.list(detail=True,
fields="encryption_config,name,fc_enabled,iscsi_enabled,leader_array_name,default_iscsi_target_scope,num_snaps")
else:
resp = cl_obj.list(detail=True, fields="name")
else:
resp = cl_obj.list(detail=False)
temp_dict[key] = resp
# prepare
result['volumes'] = len(temp_dict['volumes'])
result['volume_collections'] = len(temp_dict['volume_collections'])
result['users'] = len(temp_dict['users'])
result['software_versions'] = temp_dict['software_versions'][-1].attrs.get('version') # get the latest
result['snapshot_collections'] = len(temp_dict['snapshot_collections'])
result['snapshots'] = temp_dict['groups'][-1].attrs.get('num_snaps')
result['protocol_endpoints'] = len(temp_dict['protocol_endpoints'])
result['protection_templates'] = len(temp_dict['protection_templates'])
result['protection_schedules'] = len(temp_dict['protection_schedules'])
result['initiator_groups'] = len(temp_dict['initiator_groups'])
result['folders'] = len(temp_dict['folders'])
result['disks'] = len(temp_dict['disks'])
result['folders'] = len(temp_dict['folders'])
result['arrays'] = generate_dict('arrays', temp_dict['arrays'])['arrays']
result['groups'] = generate_dict('groups', temp_dict['groups'])['groups']
toreturn['default'] = result
return (toreturn, True)
except Exception as ex:
result['failed'] = str(ex)
toreturn['default'] = result
return (toreturn, False)
# snapshots actually needs a vol_name/vol_id as mandatory params. Hence ,in case of 'all' subset
# where user cannot provide a query option. we need to fetch the snapshots by iterating
# over the list of volumes and see if those volumes have snapshots.
def fetch_snapshots_for_all_subset(subset, client_obj):
if subset is None or client_obj is None:
return {}
result = {}
total_snap = []
# get the volume list
vol_list_resp = client_obj.volumes.list(detail=False)
if vol_list_resp is not None and vol_list_resp.__len__() > 0:
for vol_item in vol_list_resp:
vol_name = vol_item.attrs.get('name')
snap_list = client_obj.snapshots.list(detail=subset['detail'], vol_name=vol_name, limit=subset['limit'])
if snap_list is not None and snap_list.__len__() > 0:
total_snap.extend(snap_list)
if subset['limit'] is not None and total_snap.__len__() >= subset['limit']:
total_snap = total_snap[0:subset['limit']]
break
if total_snap.__len__() > 0:
result['snapshots'] = generate_dict('snapshots', total_snap)['snapshots']
return result
def fetch_subset(valid_subset_list, info_subset):
if valid_subset_list is None or isinstance(valid_subset_list, list) is False:
return {}
try:
result_dict = {}
resp = None
for subset in valid_subset_list:
result = {}
try:
if subset['name'] == "minimum":
result, flag = fetch_minimum_subset(info_subset)
if flag is False:
raise Exception(result)
elif subset['name'] == "config":
result, flag = fetch_config_subset(info_subset)
if flag is False:
raise Exception(result)
elif subset['name'] == "all":
result = fetch_snapshots_for_all_subset(subset, info_subset['all'])
for key, value in result.items():
result_dict[key] = value
continue
else:
# if subset is user_policies then make sure nimos aversion is fiji and above
if subset['name'] == 'user_policies' and utils.is_array_version_above_or_equal(info_subset['arrays'], "5.1.0") is False:
continue
cl_obj_set = info_subset[subset['name']]
query = subset['query']
if query is not None:
resp = cl_obj_set.list(detail=subset['detail'], **query, fields=subset['fields'], limit=subset['limit'])
else:
resp = cl_obj_set.list(detail=subset['detail'], fields=subset['fields'], limit=subset['limit'])
if resp is not None and resp.__len__() != 0:
# limit is not supported for few subset, hence for those slice the result and keep the number as asked by user.
if subset['count'] != -1 and resp.__len__() > subset['count']:
resp = resp[: subset['count']]
result[subset['name']] = generate_dict('data', resp)['data']
else:
result[subset['name']] = resp
for key, value in result.items():
result_dict[key] = value
except Exception as ex:
msg = f"Failed to fetch {subset['name']} details. Error:'{str(ex)}'"
raise Exception(msg) from ex
return result_dict
except Exception:
raise
def intialize_info_subset(client_obj):
info_subset = {
"all": client_obj,
"minimum": client_obj,
"config": client_obj,
"access_control_records": client_obj.access_control_records,
"alarms": client_obj.alarms,
"application_servers": client_obj.application_servers,
"application_categories": client_obj.application_categories,
"arrays": client_obj.arrays,
"chap_users": client_obj.chap_users,
"controllers": client_obj.controllers,
"disks": client_obj.disks,
"fibre_channel_interfaces": client_obj.fibre_channel_interfaces,
"fibre_channel_configs": client_obj.fibre_channel_configs,
"fibre_channel_initiator_aliases": client_obj.fibre_channel_initiator_aliases,
"fibre_channel_ports": client_obj.fibre_channel_ports,
"folders": client_obj.folders,
"groups": client_obj.groups,
"initiator_groups": client_obj.initiator_groups,
"initiators": client_obj.initiators,
"master_key": client_obj.master_key,
"network_configs": client_obj.network_configs,
"network_interfaces": client_obj.network_interfaces,
"performance_policies": client_obj.performance_policies,
"pools": client_obj.pools,
"protection_schedules": client_obj.protection_schedules,
"protection_templates": client_obj.protection_templates,
"protocol_endpoints": client_obj.protocol_endpoints,
"replication_partners": client_obj.replication_partners,
"shelves": client_obj.shelves,
"snapshots": client_obj.snapshots,
"snapshot_collections": client_obj.snapshot_collections,
"software_versions": client_obj.software_versions,
"user_groups": client_obj.user_groups,
"user_policies": client_obj.user_policies,
"users": client_obj.users,
"volumes": client_obj.volumes,
"volume_collections": client_obj.volume_collections
}
return info_subset
def get_subset_info(
client_obj,
gather_subset):
if utils.is_null_or_empty(gather_subset):
return (False, False, "Please provide atleast one subset.", {})
result_dict = []
try:
info_subset = intialize_info_subset(client_obj)
valid_subset_list = parse_subset_list(info_subset, gather_subset)
if valid_subset_list is not None and valid_subset_list.__len__() > 0:
# we got subset list to work on. get the details of these subset
result_dict = fetch_subset(valid_subset_list, info_subset)
return (True, False, "Fetched the subset details.", result_dict)
else:
return (True, False, "No vaild subset provided.", result_dict)
except Exception as ex:
return (False, False, f"{ex}", {})
def main():
fields = {
"gather_subset": {
"required": False,
"type": "list",
"elements": 'raw',
'default': "minimum"
}
}
default_fields = utils.basic_auth_arg_fields()
fields.update(default_fields)
module = AnsibleModule(argument_spec=fields, supports_check_mode=True)
if client is None:
module.fail_json(msg='Python nimble-sdk could not be found.')
hostname = module.params["host"]
username = module.params["username"]
password = module.params["password"]
gather_subset = module.params["gather_subset"]
if (username is None or password is None or hostname is None):
module.fail_json(
msg="Missing variables: hostname, username and password is mandatory.")
# defaults
return_status = changed = False
msg = "No task to run."
try:
client_obj = client.NimOSClient(
hostname,
username,
password,
f"HPE Nimble Ansible Modules v{NIMBLE_ANSIBLE_VERSION}"
)
return_status, changed, msg, result_dict = get_subset_info(client_obj, gather_subset)
except Exception as ex:
# failed for some reason.
msg = str(ex)
if return_status:
if utils.is_null_or_empty(result_dict) is False and result_dict.__len__() > 0:
module.exit_json(return_status=return_status,
changed=changed,
message=msg,
nimble_info=result_dict)
else:
module.exit_json(return_status=return_status, changed=changed, msg=msg)
else:
module.fail_json(return_status=return_status, changed=changed, msg=msg)
if __name__ == '__main__':
main()