Dre4m Shell
Server IP : 85.214.239.14  /  Your IP : 52.14.7.103
Web Server : Apache/2.4.62 (Debian)
System : Linux h2886529.stratoserver.net 4.9.0 #1 SMP Tue Jan 9 19:45:01 MSK 2024 x86_64
User : www-data ( 33)
PHP Version : 7.4.18
Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
MySQL : OFF  |  cURL : OFF  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : ON  |  Pkexec : OFF
Directory :  /lib/python3/dist-packages/ansible_collections/dellemc/powerflex/plugins/modules/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ HOME SHELL ]     

Current File : /lib/python3/dist-packages/ansible_collections/dellemc/powerflex/plugins/modules/device.py
#!/usr/bin/python

# 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) <ansible.team@dell.com>
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()

Anon7 - 2022
AnonSec Team