File: //lib/python3.9/site-packages/ansible_collections/dellemc/powerflex/plugins/modules/device.py
# Copyright: (c) 2021, Dell Technologies
# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt)
""" Ansible module for managing device on Dell Technologies (Dell) PowerFlex"""
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
DOCUMENTATION = r'''
module: device
version_added: '1.1.0'
short_description: Manage device on Dell PowerFlex
description:
- Managing device on PowerFlex storage system includes
adding new device, getting details of device, and removing a device.
author:
- Rajshree Khare (@khareRajshree) <[email protected]>
extends_documentation_fragment:
- dellemc.powerflex.powerflex
options:
current_pathname:
description:
- Full path of the device to be added.
- Required while adding a device.
type: str
device_name:
description:
- Device name.
- Mutually exclusive with I(device_id).
type: str
device_id:
description:
- Device ID.
- Mutually exclusive with I(device_name).
type: str
sds_name:
description:
- The name of the SDS.
- Required while adding a device.
- Mutually exclusive with I(sds_id).
type: str
sds_id:
description:
- The ID of the SDS.
- Required while adding a device.
- Mutually exclusive with I(sds_name).
type: str
storage_pool_name:
description:
- Storage Pool name.
- Used while adding a storage device.
- Mutually exclusive with I(storage_pool_id), I(acceleration_pool_id) and
I(acceleration_pool_name).
type: str
storage_pool_id:
description:
- Storage Pool ID.
- Used while adding a storage device.
- Media type supported are C(SSD) and C(HDD).
- Mutually exclusive with I(storage_pool_name), I(acceleration_pool_id) and
I(acceleration_pool_name).
type: str
acceleration_pool_name:
description:
- Acceleration Pool Name.
- Used while adding an acceleration device.
- Media type supported are C(SSD) and C(NVDIMM).
- Mutually exclusive with I(storage_pool_id), I(storage_pool_name) and
I(acceleration_pool_name).
type: str
acceleration_pool_id:
description:
- Acceleration Pool ID.
- Used while adding an acceleration device.
- Media type supported are C(SSD) and C(NVDIMM).
- Mutually exclusive with I(acceleration_pool_name), I(storage_pool_name) and
I(storage_pool_id).
type: str
protection_domain_name:
description:
- Protection domain name.
- Used while identifying a storage pool along with I(storage_pool_name).
- Mutually exclusive with I(protection_domain_id).
type: str
protection_domain_id:
description:
- Protection domain ID.
- Used while identifying a storage pool along with I(storage_pool_name).
- Mutually exclusive with I(protection_domain_name).
type: str
external_acceleration_type:
description:
- Device external acceleration types.
- Used while adding a device.
type: str
choices: ['Invalid', 'None', 'Read', 'Write', 'ReadAndWrite']
media_type:
description:
- Device media types.
- Required while adding a device.
type: str
choices: ['HDD', 'SSD', 'NVDIMM']
state:
description:
- State of the device.
choices: ['present', 'absent']
required: true
type: str
notes:
- The value for device_id is generated only after successful addition of the
device.
- To uniquely identify a device, either I(device_id) can be passed or one of
I(current_pathname) or I(device_name) must be passed with I(sds_id) or I(sds_name).
- It is recommended to install Rfcache driver for SSD device on SDS in
order to add it to an acceleration pool.
- The I(check_mode) is not supported.
'''
EXAMPLES = r'''
- name: Add a device
dellemc.powerflex.device:
hostname: "{{hostname}}"
username: "{{username}}"
password: "{{password}}"
validate_certs: "{{validate_certs}}"
port: "{{port}}"
current_pathname: "/dev/sdb"
sds_name: "node1"
media_type: "HDD"
device_name: "device2"
storage_pool_name: "pool1"
protection_domain_name: "domain1"
external_acceleration_type: "ReadAndWrite"
state: "present"
- name: Get device details using device_id
dellemc.powerflex.device:
hostname: "{{hostname}}"
username: "{{username}}"
password: "{{password}}"
validate_certs: "{{validate_certs}}"
port: "{{port}}"
device_id: "d7fe088900000000"
state: "present"
- name: Get device details using (current_pathname, sds_name)
dellemc.powerflex.device:
hostname: "{{hostname}}"
username: "{{username}}"
password: "{{password}}"
validate_certs: "{{validate_certs}}"
port: "{{port}}"
current_pathname: "/dev/sdb"
sds_name: "node0"
state: "present"
- name: Get device details using (current_pathname, sds_id)
dellemc.powerflex.device:
hostname: "{{hostname}}"
username: "{{username}}"
password: "{{password}}"
validate_certs: "{{validate_certs}}"
port: "{{port}}"
current_pathname: "/dev/sdb"
sds_id: "5717d71800000000"
state: "present"
- name: Remove a device using device_id
dellemc.powerflex.device:
hostname: "{{hostname}}"
username: "{{username}}"
password: "{{password}}"
validate_certs: "{{validate_certs}}"
port: "{{port}}"
device_id: "76eb7e2f00010000"
state: "absent"
- name: Remove a device using (current_pathname, sds_id)
dellemc.powerflex.device:
hostname: "{{hostname}}"
username: "{{username}}"
password: "{{password}}"
validate_certs: "{{validate_certs}}"
port: "{{port}}"
current_pathname: "/dev/sdb"
sds_name: "node1"
state: "absent"
'''
RETURN = r'''
changed:
description: Whether or not the resource has changed.
returned: always
type: bool
sample: 'false'
device_details:
description: Details of the device.
returned: When device exists
type: dict
contains:
accelerationPoolId:
description: Acceleration pool ID.
type: str
accelerationPoolName:
description: Acceleration pool name.
type: str
accelerationProps:
description: Indicates acceleration props.
type: str
aggregatedState:
description: Indicates aggregated state.
type: str
ataSecurityActive:
description: Indicates ATA security active state.
type: bool
autoDetectMediaType:
description: Indicates auto detection of media type.
type: str
cacheLookAheadActive:
description: Indicates cache look ahead active state.
type: bool
capacity:
description: Device capacity.
type: int
capacityLimitInKb:
description: Device capacity limit in KB.
type: int
deviceCurrentPathName:
description: Device current path name.
type: str
deviceOriginalPathName:
description: Device original path name.
type: str
deviceState:
description: Indicates device state.
type: str
deviceType:
description: Indicates device type.
type: str
errorState:
description: Indicates error state.
type: str
externalAccelerationType:
description: Indicates external acceleration type.
type: str
fglNvdimmMetadataAmortizationX100:
description: Indicates FGL NVDIMM meta data amortization value.
type: int
fglNvdimmWriteCacheSize:
description: Indicates FGL NVDIMM write cache size.
type: int
firmwareVersion:
description: Indicates firmware version.
type: str
id:
description: Device ID.
type: str
ledSetting:
description: Indicates LED setting.
type: str
links:
description: Device links.
type: list
contains:
href:
description: Device instance URL.
type: str
rel:
description: Relationship of device with different
entities.
type: str
logicalSectorSizeInBytes:
description: Logical sector size in bytes.
type: int
longSuccessfulIos:
description: Indicates long successful IOs.
type: list
maxCapacityInKb:
description: Maximum device capacity limit in KB.
type: int
mediaFailing:
description: Indicates media failing.
type: bool
mediaType:
description: Indicates media type.
type: str
modelName:
description: Indicates model name.
type: str
name:
description: Device name.
type: str
persistentChecksumState:
description: Indicates persistent checksum state.
type: str
physicalSectorSizeInBytes:
description: Physical sector size in bytes.
type: int
protectionDomainId:
description: Protection domain ID.
type: str
protectionDomainName:
description: Protection domain name.
type: str
raidControllerSerialNumber:
description: RAID controller serial number.
type: str
rfcacheErrorDeviceDoesNotExist:
description: Indicates RF cache error device does not exist.
type: bool
rfcacheProps:
description: RF cache props.
type: str
sdsId:
description: SDS ID.
type: str
sdsName:
description: SDS name.
type: str
serialNumber:
description: Indicates Serial number.
type: str
spSdsId:
description: Indicates SPs SDS ID.
type: str
ssdEndOfLifeState:
description: Indicates SSD end of life state.
type: str
storagePoolId:
description: Storage Pool ID.
type: str
storagePoolName:
description: Storage Pool name.
type: str
storageProps:
description: Storage props.
type: list
temperatureState:
description: Indicates temperature state.
type: str
vendorName:
description: Indicates vendor name.
type: str
writeCacheActive:
description: Indicates write cache active.
type: bool
sample: {
"accelerationPoolId": null,
"accelerationProps": null,
"aggregatedState": "NeverFailed",
"ataSecurityActive": false,
"autoDetectMediaType": "SSD",
"cacheLookAheadActive": false,
"capacity": 0,
"capacityLimitInKb": 365772800,
"deviceCurrentPathName": "/dev/sdb",
"deviceOriginalPathName": "/dev/sdb",
"deviceState": "Normal",
"deviceType": "Unknown",
"errorState": "None",
"externalAccelerationType": "None",
"fglNvdimmMetadataAmortizationX100": 150,
"fglNvdimmWriteCacheSize": 16,
"firmwareVersion": null,
"id": "b6efa59900000000",
"ledSetting": "Off",
"links": [
{
"href": "/api/instances/Device::b6efa59900000000",
"rel": "self"
},
{
"href": "/api/instances/Device::b6efa59900000000/relationships
/Statistics",
"rel": "/api/Device/relationship/Statistics"
},
{
"href": "/api/instances/Sds::8f3bb0ce00000000",
"rel": "/api/parent/relationship/sdsId"
},
{
"href": "/api/instances/StoragePool::e0d8f6c900000000",
"rel": "/api/parent/relationship/storagePoolId"
},
{
"href": "/api/instances/SpSds::fedf6f2000000000",
"rel": "/api/parent/relationship/spSdsId"
}
],
"logicalSectorSizeInBytes": 0,
"longSuccessfulIos": {
"longWindow": null,
"mediumWindow": null,
"shortWindow": null
},
"maxCapacityInKb": 365772800,
"mediaFailing": false,
"mediaType": "HDD",
"modelName": null,
"name": "device230",
"persistentChecksumState": "Protected",
"physicalSectorSizeInBytes": 0,
"protectionDomainId": "9300c1f900000000",
"protectionDomainName": "domain1",
"raidControllerSerialNumber": null,
"rfcacheErrorDeviceDoesNotExist": false,
"rfcacheProps": null,
"sdsId": "8f3bb0ce00000000",
"sdsName": "node1",
"serialNumber": null,
"slotNumber": null,
"spSdsId": "fedf6f2000000000",
"ssdEndOfLifeState": "NeverFailed",
"storagePoolId": "e0d8f6c900000000",
"storagePoolName": "pool1",
"storageProps": {
"destFglAccDeviceId": null,
"destFglNvdimmSizeMb": 0,
"fglAccDeviceId": null,
"fglNvdimmSizeMb": 0
},
"temperatureState": "NeverFailed",
"vendorName": null,
"writeCacheActive": false
}
'''
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.dellemc.powerflex.plugins.module_utils.storage.dell\
import utils
LOG = utils.get_logger('device')
class PowerFlexDevice(object):
"""Class with device operations"""
def __init__(self):
""" Define all parameters required by this module"""
self.module_params = utils.get_powerflex_gateway_host_parameters()
self.module_params.update(get_powerflex_device_parameters())
mut_ex_args = [['sds_name', 'sds_id'],
['device_name', 'device_id'],
['protection_domain_name',
'protection_domain_id'],
['storage_pool_name', 'storage_pool_id'],
['acceleration_pool_name', 'acceleration_pool_id'],
['acceleration_pool_id', 'storage_pool_id'],
['acceleration_pool_name', 'storage_pool_name'],
['device_id', 'sds_name'],
['device_id', 'sds_id'],
['device_id', 'current_pathname']]
# initialize the Ansible module
self.module = AnsibleModule(
argument_spec=self.module_params,
supports_check_mode=False,
mutually_exclusive=mut_ex_args)
utils.ensure_required_libs(self.module)
try:
self.powerflex_conn = utils.get_powerflex_gateway_host_connection(
self.module.params)
LOG.info("Got the PowerFlex system connection object instance")
except Exception as e:
LOG.error(str(e))
self.module.fail_json(msg=str(e))
def get_device_details(self, current_pathname=None, sds_id=None,
device_name=None, device_id=None):
"""Get device details
:param current_pathname: Device path name
:type current_pathname: str
:param sds_id: ID of the SDS
:type sds_id: str
:param device_name: Name of the device
:type device_name: str
:param device_id: ID of the device
:type device_id: str
:return: Details of device if it exist
:rtype: dict
"""
try:
if current_pathname and sds_id:
device_details = self.powerflex_conn.device.get(
filter_fields={'deviceCurrentPathName': current_pathname,
'sdsId': sds_id})
elif device_name and sds_id:
device_details = self.powerflex_conn.device.get(
filter_fields={'name': device_name,
'sdsId': sds_id})
else:
device_details = self.powerflex_conn.device.get(
filter_fields={'id': device_id})
if len(device_details) == 0:
msg = "Device not found"
LOG.info(msg)
return None
return device_details[0]
except Exception as e:
error_msg = "Failed to get the device with error '%s'" % str(e)
LOG.error(error_msg)
self.module.fail_json(msg=error_msg)
def get_sds(self, sds_name=None, sds_id=None):
"""Get SDS details
:param sds_name: Name of the SDS
:param sds_id: ID of the SDS
:return: SDS details
:rtype: dict
"""
name_or_id = sds_id if sds_id else sds_name
try:
sds_details = None
if sds_id:
sds_details = self.powerflex_conn.sds.get(
filter_fields={'id': sds_id})
if sds_name:
sds_details = self.powerflex_conn.sds.get(
filter_fields={'name': sds_name})
if not sds_details:
error_msg = "Unable to find the SDS with '%s'. Please " \
"enter a valid SDS name/id." % name_or_id
LOG.error(error_msg)
self.module.fail_json(msg=error_msg)
return sds_details[0]
except Exception as e:
error_msg = "Failed to get the SDS '%s' with error '%s'" \
% (name_or_id, str(e))
LOG.error(error_msg)
self.module.fail_json(msg=error_msg)
def get_protection_domain(self, protection_domain_name=None,
protection_domain_id=None):
"""Get protection domain details
:param protection_domain_name: Name of the protection domain
:param protection_domain_id: ID of the protection domain
:return: Protection domain details
:rtype: dict
"""
name_or_id = protection_domain_id if protection_domain_id \
else protection_domain_name
try:
pd_details = None
if protection_domain_id:
pd_details = self.powerflex_conn.protection_domain.get(
filter_fields={'id': protection_domain_id})
if protection_domain_name:
pd_details = self.powerflex_conn.protection_domain.get(
filter_fields={'name': protection_domain_name})
if not pd_details:
error_msg = "Unable to find the protection domain with " \
"'%s'. Please enter a valid protection domain " \
"name/id." % name_or_id
LOG.error(error_msg)
self.module.fail_json(msg=error_msg)
return pd_details[0]
except Exception as e:
error_msg = "Failed to get the protection domain '%s' with " \
"error '%s'" % (name_or_id, str(e))
LOG.error(error_msg)
self.module.fail_json(msg=error_msg)
def get_storage_pool(self, storage_pool_name=None,
storage_pool_id=None,
protection_domain_id=None):
"""Get storage pool details
:param storage_pool_name: Name of the storage pool
:param storage_pool_id: ID of the storage pool
:param protection_domain_id: ID of the protection domain
:return: Storage pool details
:rtype: dict
"""
name_or_id = storage_pool_id if storage_pool_id else storage_pool_name
try:
storage_pool_details = None
if storage_pool_id:
storage_pool_details = self.powerflex_conn.storage_pool.get(
filter_fields={'id': storage_pool_id})
if storage_pool_name:
storage_pool_details = self.powerflex_conn.storage_pool.get(
filter_fields={'name': storage_pool_name,
'protectionDomainId': protection_domain_id}
)
if not storage_pool_details:
error_msg = "Unable to find the storage pool with " \
"'%s'. Please enter a valid storage pool " \
"name/id." % name_or_id
LOG.error(error_msg)
self.module.fail_json(msg=error_msg)
return storage_pool_details[0]
except Exception as e:
error_msg = "Failed to get the storage_pool '%s' with " \
"error '%s'" % (name_or_id, str(e))
LOG.error(error_msg)
self.module.fail_json(msg=error_msg)
def get_acceleration_pool(self, acceleration_pool_name=None,
acceleration_pool_id=None,
protection_domain_id=None):
"""Get acceleration pool details
:param acceleration_pool_name: Name of the acceleration pool
:param acceleration_pool_id: ID of the acceleration pool
:param protection_domain_id: ID of the protection domain
:return: Acceleration pool details
:rtype: dict
"""
name_or_id = acceleration_pool_id \
if acceleration_pool_id else acceleration_pool_name
try:
acceleration_pool_details = None
if acceleration_pool_id:
acceleration_pool_details = self.powerflex_conn.\
acceleration_pool.get(filter_fields={
'id': acceleration_pool_id})
if acceleration_pool_name:
acceleration_pool_details = self.powerflex_conn.\
acceleration_pool.get(filter_fields={
'name': acceleration_pool_name,
'protectionDomainId': protection_domain_id})
if not acceleration_pool_details:
error_msg = "Unable to find the acceleration pool with " \
"'%s'. Please enter a valid acceleration pool " \
"name/id." % name_or_id
LOG.error(error_msg)
self.module.fail_json(msg=error_msg)
return acceleration_pool_details[0]
except Exception as e:
error_msg = "Failed to get the acceleration pool '%s' with " \
"error '%s'" % (name_or_id, str(e))
LOG.error(error_msg)
self.module.fail_json(msg=error_msg)
def add_device(self, device_name, current_pathname, sds_id,
storage_pool_id, media_type, acceleration_pool_id,
external_acceleration_type):
"""Add device
:param device_name: Device name
:type device_name: str
:param current_pathname: Current pathname of device
:type current_pathname: str
:param sds_id: SDS ID
:type sds_id: str
:param storage_pool_id: Storage Pool ID
:type storage_pool_id: str
:param media_type: Media type of device
:type media_type: str
:param acceleration_pool_id: Acceleration pool ID
:type acceleration_pool_id: str
:param external_acceleration_type: External acceleration type
:type external_acceleration_type: str
return: Boolean indicating if add device operation is successful
"""
try:
if device_name is None or len(device_name.strip()) == 0:
error_msg = "Please provide valid device_name value for " \
"adding a device."
LOG.error(error_msg)
self.module.fail_json(msg=error_msg)
if current_pathname is None or len(current_pathname.strip()) == 0:
error_msg = "Current pathname of device is a mandatory " \
"parameter for adding a device. Please enter a " \
"valid value."
LOG.error(error_msg)
self.module.fail_json(msg=error_msg)
if sds_id is None or len(sds_id.strip()) == 0:
error_msg = "Please provide valid sds_id value " \
"for adding a device."
LOG.error(error_msg)
self.module.fail_json(msg=error_msg)
if storage_pool_id is None and acceleration_pool_id is None:
error_msg = "Please provide either storage pool name/ID " \
"or acceleration pool name/ID for adding a " \
"device."
LOG.error(error_msg)
self.module.fail_json(msg=error_msg)
add_params = ("current_pathname: %s, "
"sds_id: %s, "
"acceleration_pool_id: %s,"
"external_acceleration_type: %s,"
"media_type: %s,"
"device_name: %s,"
"storage_pool_id: %s,"
% (current_pathname, sds_id,
acceleration_pool_id,
external_acceleration_type,
media_type,
device_name,
storage_pool_id))
LOG.info("Adding device with params: %s", add_params)
self.powerflex_conn.device.create(
current_pathname=current_pathname,
sds_id=sds_id,
acceleration_pool_id=acceleration_pool_id,
external_acceleration_type=external_acceleration_type,
media_type=media_type,
name=device_name,
storage_pool_id=storage_pool_id)
return True
except Exception as e:
error_msg = "Adding device %s operation failed with " \
"error '%s'" % (device_name, str(e))
LOG.error(error_msg)
self.module.fail_json(msg=error_msg)
def remove_device(self, device_id):
"""Remove device
:param device_id: Device ID
:type device_id: str
return: Boolean indicating if remove device operation is
successful
"""
try:
LOG.info("Device to be removed: %s", device_id)
self.powerflex_conn.device.delete(device_id=device_id)
return True
except Exception as e:
error_msg = "Remove device '%s' operation failed with " \
"error '%s'" % (device_id, str(e))
LOG.error(error_msg)
self.module.fail_json(msg=error_msg)
def validate_input_parameters(self, device_name=None, device_id=None,
current_pathname=None, sds_name=None,
sds_id=None):
"""Validate the input parameters"""
# Unique ways to identify a device:
# (current_pathname , sds_id)
# (current_pathname , sds_name)
# (device_name , sds_name)
# (device_name , sds_id)
# device_id.
if current_pathname:
if (sds_name is None or len(sds_name.strip()) == 0) \
and (sds_id is None or len(sds_id.strip()) == 0):
error_msg = "sds_name or sds_id is mandatory along with " \
"current_pathname. Please enter a valid value."
LOG.error(error_msg)
self.module.fail_json(msg=error_msg)
elif current_pathname is not None \
and len(current_pathname.strip()) == 0:
error_msg = "Please enter a valid value for current_pathname."
LOG.error(error_msg)
self.module.fail_json(msg=error_msg)
if device_name:
if (sds_name is None or len(sds_name.strip()) == 0) \
and (sds_id is None or len(sds_id.strip()) == 0):
error_msg = "sds_name or sds_id is mandatory along with " \
"device_name. Please enter a valid value."
LOG.error(error_msg)
self.module.fail_json(msg=error_msg)
elif device_name is not None and len(device_name.strip()) == 0:
error_msg = "Please enter a valid value for device_name."
LOG.error(error_msg)
self.module.fail_json(msg=error_msg)
if sds_name:
if (current_pathname is None
or len(current_pathname.strip()) == 0) \
and (device_name is None
or len(device_name.strip()) == 0):
error_msg = "current_pathname or device_name is mandatory " \
"along with sds_name. Please enter a valid value."
LOG.error(error_msg)
self.module.fail_json(msg=error_msg)
elif sds_name is not None and len(sds_name.strip()) == 0:
error_msg = "Please enter a valid value for sds_name."
LOG.error(error_msg)
self.module.fail_json(msg=error_msg)
if sds_id:
if (current_pathname is None
or len(current_pathname.strip()) == 0) \
and (device_name is None
or len(device_name.strip()) == 0):
error_msg = "current_pathname or device_name is mandatory " \
"along with sds_id. Please enter a valid value."
LOG.error(error_msg)
self.module.fail_json(msg=error_msg)
elif sds_id is not None and len(sds_id.strip()) == 0:
error_msg = "Please enter a valid value for sds_id."
LOG.error(error_msg)
self.module.fail_json(msg=error_msg)
if device_id is not None and len(device_id.strip()) == 0:
error_msg = "Please provide valid device_id value to identify " \
"a device."
LOG.error(error_msg)
self.module.fail_json(msg=error_msg)
if current_pathname is None and device_name is None \
and device_id is None:
error_msg = "Please specify a valid parameter combination to " \
"identify a device."
LOG.error(error_msg)
self.module.fail_json(msg=error_msg)
def validate_add_parameters(self, device_id=None,
external_acceleration_type=None,
storage_pool_id=None,
storage_pool_name=None,
acceleration_pool_id=None,
acceleration_pool_name=None):
"""Validate the add device parameters"""
if device_id:
error_msg = "Addition of device is allowed using " \
"device_name only, device_id given."
LOG.info(error_msg)
self.module.fail_json(msg=error_msg)
if external_acceleration_type and storage_pool_id is None \
and storage_pool_name is None \
and acceleration_pool_id is None \
and acceleration_pool_name is None:
error_msg = "Storage Pool ID/name or Acceleration Pool " \
"ID/name is mandatory along with " \
"external_acceleration_type."
LOG.error(error_msg)
self.module.fail_json(msg=error_msg)
def perform_module_operation(self):
"""
Perform different actions on device based on parameters passed in
the playbook
"""
current_pathname = self.module.params['current_pathname']
device_name = self.module.params['device_name']
device_id = self.module.params['device_id']
sds_name = self.module.params['sds_name']
sds_id = self.module.params['sds_id']
storage_pool_name = self.module.params['storage_pool_name']
storage_pool_id = self.module.params['storage_pool_id']
acceleration_pool_id = self.module.params['acceleration_pool_id']
acceleration_pool_name = self.module.params['acceleration_pool_name']
protection_domain_name = self.module.params['protection_domain_name']
protection_domain_id = self.module.params['protection_domain_id']
external_acceleration_type = self.module.params[
'external_acceleration_type']
media_type = self.module.params['media_type']
state = self.module.params['state']
# result is a dictionary to contain end state and device details
changed = False
result = dict(
changed=False,
device_details={}
)
# validate input parameters
self.validate_input_parameters(device_name, device_id,
current_pathname, sds_name, sds_id)
# get SDS ID from name
if sds_name:
sds_details = self.get_sds(sds_name)
if sds_details:
sds_id = sds_details['id']
msg = "Fetched the SDS details with id '%s', name '%s'" \
% (sds_id, sds_name)
LOG.info(msg)
# get device details
device_details = self.get_device_details(current_pathname,
sds_id, device_name,
device_id)
if device_details:
device_id = device_details['id']
msg = "Fetched the device details %s" % (str(device_details))
LOG.info(msg)
# add operation
add_changed = False
if state == 'present' and not device_details:
# get Protection Domain ID from name
# it is needed to uniquely identify a storage pool or acceleration
# pool using name
if protection_domain_name \
and (storage_pool_name or acceleration_pool_name):
pd_details = self.get_protection_domain(
protection_domain_name)
if pd_details:
protection_domain_id = pd_details['id']
msg = "Fetched the protection domain details with id " \
"'%s', name '%s'" % (protection_domain_id,
protection_domain_name)
LOG.info(msg)
# get storage pool ID from name
if storage_pool_name:
if protection_domain_id:
storage_pool_details = self.get_storage_pool(
storage_pool_name=storage_pool_name,
protection_domain_id=protection_domain_id)
if storage_pool_details:
storage_pool_id = storage_pool_details['id']
msg = "Fetched the storage pool details with id '%s', " \
"name '%s'" % (storage_pool_id, storage_pool_name)
LOG.info(msg)
else:
error_msg = "Protection domain name/id is required to " \
"uniquely identify a storage pool, only " \
"storage_pool_name is given."
LOG.info(error_msg)
self.module.fail_json(msg=error_msg)
# get acceleration pool ID from name
if acceleration_pool_name:
if protection_domain_id:
acceleration_pool_details = self.get_acceleration_pool(
acceleration_pool_name=acceleration_pool_name,
protection_domain_id=protection_domain_id)
if acceleration_pool_details:
acceleration_pool_id = acceleration_pool_details['id']
msg = "Fetched the acceleration pool details with id " \
"'%s', name '%s'" % (acceleration_pool_id,
acceleration_pool_name)
LOG.info(msg)
else:
error_msg = "Protection domain name/id is required to " \
"uniquely identify a acceleration pool, " \
"only acceleration_pool_name is given."
LOG.info(error_msg)
self.module.fail_json(msg=error_msg)
# validate input parameters
self.validate_add_parameters(device_id,
external_acceleration_type,
storage_pool_id,
storage_pool_name,
acceleration_pool_id,
acceleration_pool_name)
add_changed = self.add_device(device_name, current_pathname,
sds_id, storage_pool_id, media_type,
acceleration_pool_id,
external_acceleration_type)
if add_changed:
device_details = self.get_device_details(
device_name=device_name, sds_id=sds_id)
device_id = device_details['id']
msg = "Device created successfully, fetched device details " \
"%s" % (str(device_details))
LOG.info(msg)
# remove operation
remove_changed = False
if state == 'absent' and device_details:
remove_changed = self.remove_device(device_id)
if add_changed or remove_changed:
changed = True
# modify operation
if device_details and state == 'present':
modify_dict = to_modify(device_details, media_type,
external_acceleration_type)
if modify_dict:
error_msg = "Modification of device attributes is " \
"currently not supported by Ansible modules."
LOG.info(error_msg)
self.module.fail_json(msg=error_msg)
# Returning the updated device details
if state == 'present':
device_details = self.show_output(device_id)
result['device_details'] = device_details
result['changed'] = changed
self.module.exit_json(**result)
def show_output(self, device_id):
"""Show device details
:param device_id: ID of the device
:type device_id: str
:return: Details of device
:rtype: dict
"""
try:
device_details = self.powerflex_conn.device.get(
filter_fields={'id': device_id})
if len(device_details) == 0:
msg = "Device with identifier '%s' not found" % device_id
LOG.error(msg)
return None
# Append SDS name
if 'sdsId' in device_details[0] and device_details[0]['sdsId']:
sds_details = self.get_sds(sds_id=device_details[0]['sdsId'])
device_details[0]['sdsName'] = sds_details['name']
# Append storage pool name and its protection domain name and ID
if 'storagePoolId' in device_details[0] \
and device_details[0]['storagePoolId']:
sp_details = self.get_storage_pool(
storage_pool_id=device_details[0]['storagePoolId'])
device_details[0]['storagePoolName'] = sp_details['name']
pd_id = sp_details['protectionDomainId']
device_details[0]['protectionDomainId'] = pd_id
pd_details = self.get_protection_domain(
protection_domain_id=pd_id)
device_details[0]['protectionDomainName'] = pd_details['name']
# Append acceleration pool name and its protection domain name
# and ID
if 'accelerationPoolId' in device_details[0] \
and device_details[0]['accelerationPoolId']:
ap_details = self.get_acceleration_pool(
acceleration_pool_id=device_details[0][
'accelerationPoolId'])
device_details[0]['accelerationPoolName'] = ap_details['name']
pd_id = ap_details['protectionDomainId']
device_details[0]['protectionDomainId'] = pd_id
pd_details = self.get_protection_domain(
protection_domain_id=pd_id)
device_details[0]['protectionDomainName'] = pd_details['name']
return device_details[0]
except Exception as e:
error_msg = "Failed to get the device '%s' with error '%s'"\
% (device_id, str(e))
LOG.error(error_msg)
self.module.fail_json(msg=error_msg)
def to_modify(device_details, media_type, external_acceleration_type):
"""Identify device attributes to be modified"""
modify_dict = {}
if media_type is not None and \
device_details['mediaType'] != media_type:
modify_dict['mediaType'] = media_type
if external_acceleration_type is not None and \
device_details['externalAccelerationType'] \
!= external_acceleration_type:
modify_dict['externalAccelerationType'] \
= external_acceleration_type
if len(modify_dict) != 0:
LOG.info("Attributes to be modified: %s", modify_dict)
return modify_dict
def get_powerflex_device_parameters():
"""This method provide parameter required for the device module on
PowerFlex"""
return dict(
current_pathname=dict(),
device_name=dict(),
device_id=dict(),
sds_name=dict(),
sds_id=dict(),
storage_pool_name=dict(),
storage_pool_id=dict(),
acceleration_pool_id=dict(),
acceleration_pool_name=dict(),
protection_domain_name=dict(),
protection_domain_id=dict(),
external_acceleration_type=dict(choices=['Invalid', 'None', 'Read',
'Write', 'ReadAndWrite']),
media_type=dict(choices=['HDD', 'SSD', 'NVDIMM']),
state=dict(required=True, type='str', choices=['present', 'absent'])
)
def main():
""" Create PowerFlex device object and perform actions on it
based on user input from playbook"""
obj = PowerFlexDevice()
obj.perform_module_operation()
if __name__ == '__main__':
main()