def host_list_initiators(args):
    hostObj = Host(args.ip, args.port)
    from common import TableGenerator

    try:
        initiatorList = hostObj.list_initiators(args.hostlabel)

        if len(initiatorList) > 0:
            initiatorListDetails = []
            from hostinitiators import HostInitiator

            hostInitiatorObj = HostInitiator(args.ip, args.port)
            initiatorListDetails = hostInitiatorObj.show(initiatorList)

            if args.verbose == True:
                return common.format_json_object(initiatorListDetails)
            else:
                if args.largetable == True:
                    TableGenerator(
                        initiatorListDetails, ["name", "protocol", "initiator_node", "initiator_port", "host_name"]
                    ).printTable()
                else:
                    TableGenerator(initiatorListDetails, ["name", "protocol", "host_name"]).printTable()

    except SOSError as e:
        common.format_err_msg_and_raise("list-initiators", "host", e.err_text, e.err_code)
    def exportgroup_add_initiator(self, exportgroupname, tenantname, projectname, initators, hostlabel, sync):
        exportgroup_uri = self.exportgroup_query(exportgroupname, projectname, tenantname)
        initiator_uris = []
        hiObject = HostInitiator(self.__ipAddr, self.__port)
        for initator in initators:
            initiator_uris.append(hiObject.query_by_portwwn(initator, hostlabel))
        parms = {}
        # initiator_changes
        parms["initiator_changes"] = self._add_list(initiator_uris)

        o = self.send_json_request(exportgroup_uri, parms)
        return self.check_for_sync(o, sync)
 def __init__(self, ipAddr, port, verbose):
     '''
     Constructor: takes IP address and port of the ViPR instance. These are
     needed to make http requests for REST API   
     '''
     self.__ipAddr = ipAddr
     self.__port = port
     self._host = Host(self.__ipAddr, self.__port)
     self._hostinitiator = HostInitiator(self.__ipAddr, self.__port)
     self._network = Network(self.__ipAddr, self.__port)
     self._execute = utils.execute
     self._vipr_info = ViPRInfo(self.VIPR_CONFIG_FILE)
     self.set_logging(verbose)
    def init_vipr_cli_components(self):
        import common as vipr_utils
        vipr_utils.COOKIE = None

        from exportgroup import ExportGroup
        from host import Host
        from hostinitiators import HostInitiator
        from snapshot import Snapshot
        from virtualarray import VirtualArray
        from volume import Volume

        # instantiate a few vipr cli objects for later use
        self.volume_obj = Volume(self.configuration.vipr_hostname,
                                 self.configuration.vipr_port)
        self.exportgroup_obj = ExportGroup(self.configuration.vipr_hostname,
                                           self.configuration.vipr_port)
        self.host_obj = Host(self.configuration.vipr_hostname,
                             self.configuration.vipr_port)
        self.hostinitiator_obj = HostInitiator(
            self.configuration.vipr_hostname, self.configuration.vipr_port)
        self.varray_obj = VirtualArray(self.configuration.vipr_hostname,
                                       self.configuration.vipr_port)
        self.snapshot_obj = Snapshot(self.configuration.vipr_hostname,
                                     self.configuration.vipr_port)
class EMCViPRDriverCommon(object):

    OPENSTACK_TAG = 'OpenStack'

    def __init__(self, protocol, default_backend_name, configuration=None):
        self.protocol = protocol
        self.configuration = configuration
        self.configuration.append_config_values(volume_opts)

        self.check_for_vipr_cli_path()
        self.init_vipr_cli_components()

        self.stats = {
            'driver_version':
            '1.0',
            'free_capacity_gb':
            'unknown',
            'reserved_percentage':
            '0',
            'storage_protocol':
            protocol,
            'total_capacity_gb':
            'unknown',
            'vendor_name':
            'EMC',
            'volume_backend_name':
            self.configuration.volume_backend_name or default_backend_name
        }

        self.volume_api = cinder_volume.API()

    def check_for_vipr_cli_path(self):
        if (self.configuration.vipr_cli_path is None):
            message = "vipr_cli_path is not set in cinder configuration"
            raise exception.VolumeBackendAPIException(data=message)

        if (os.path.exists(self.configuration.vipr_cli_path)):
            sys.path.append(self.configuration.vipr_cli_path)
        else:
            message = self.configuration.vipr_cli_path + " path does not" + \
                " exist in the system. Please check/add/change" + \
                " vipr_cli_path" + \
                " in cinder configuration with valid ViPR" + \
                " CLI installation path"
            raise exception.VolumeBackendAPIException(data=message)

    def init_vipr_cli_components(self):
        import common as vipr_utils
        vipr_utils.COOKIE = None

        from exportgroup import ExportGroup
        from host import Host
        from hostinitiators import HostInitiator
        from snapshot import Snapshot
        from virtualarray import VirtualArray
        from volume import Volume

        # instantiate a few vipr cli objects for later use
        self.volume_obj = Volume(self.configuration.vipr_hostname,
                                 self.configuration.vipr_port)
        self.exportgroup_obj = ExportGroup(self.configuration.vipr_hostname,
                                           self.configuration.vipr_port)
        self.host_obj = Host(self.configuration.vipr_hostname,
                             self.configuration.vipr_port)
        self.hostinitiator_obj = HostInitiator(
            self.configuration.vipr_hostname, self.configuration.vipr_port)
        self.varray_obj = VirtualArray(self.configuration.vipr_hostname,
                                       self.configuration.vipr_port)
        self.snapshot_obj = Snapshot(self.configuration.vipr_hostname,
                                     self.configuration.vipr_port)

    def check_for_setup_error(self):
        # validate all of the vipr_* configuration values
        if (self.configuration.vipr_hostname is None):
            message = "vipr_hostname is not set in cinder configuration"
            raise exception.VolumeBackendAPIException(data=message)

        if (self.configuration.vipr_port is None):
            message = "vipr_port is not set in cinder configuration"
            raise exception.VolumeBackendAPIException(data=message)

        if (self.configuration.vipr_username is None):
            message = "vipr_username is not set in cinder configuration"
            raise exception.VolumeBackendAPIException(data=message)

        if (self.configuration.vipr_password is None):
            message = "vipr_password is not set in cinder configuration"
            raise exception.VolumeBackendAPIException(data=message)

        if (self.configuration.vipr_tenant is None):
            message = "vipr_tenant is not set in cinder configuration"
            raise exception.VolumeBackendAPIException(data=message)

        if (self.configuration.vipr_project is None):
            message = "vipr_project is not set in cinder configuration"
            raise exception.VolumeBackendAPIException(data=message)

        if (self.configuration.vipr_varray is None):
            message = "vipr_varray is not set in cinder configuration"
            raise exception.VolumeBackendAPIException(data=message)

    def authenticate_user(self):
        global AUTHENTICATED
        from authentication import Authentication
        # we should check to see if we are already authenticated before blindly
        # doing it again
        if (AUTHENTICATED is False):
            obj = Authentication(self.configuration.vipr_hostname,
                                 self.configuration.vipr_port)
            # cookiedir = os.getcwd()
            cookiedir = self.configuration.vipr_cookiedir
            obj.authenticate_user(self.configuration.vipr_username,
                                  self.configuration.vipr_password, cookiedir,
                                  None)
            AUTHENTICATED = True

    @retry_wrapper
    def create_volume(self, vol):
        self.authenticate_user()
        name = self._get_volume_name(vol)
        size = int(vol['size']) * 1073741824

        from common import SOSError
        vpool = self._get_vpool(vol)
        self.vpool = vpool['ViPR:VPOOL']

        try:
            res = self.volume_obj.create(
                self.configuration.vipr_tenant + "/" +
                self.configuration.vipr_project,
                name,
                size,
                self.configuration.vipr_varray,
                self.vpool,
                protocol=None,
                # no longer specified in volume
                # creation
                sync=True,
                number_of_volumes=1,
                thin_provisioned=None,
                consistencygroup=None)
        except SOSError as e:
            if (e.err_code == SOSError.SOS_FAILURE_ERR):
                raise SOSError(
                    SOSError.SOS_FAILURE_ERR,
                    "Volume " + name + ": Tag failed\n" + e.err_text)
            else:
                raise e

    @retry_wrapper
    def setTags(self, vol):

        self.authenticate_user()
        name = self._get_volume_name(vol)
        from common import SOSError

        # first, get the current tags that start with the OPENSTACK_TAG
        # eyecatcher
        removeTags = []
        currentTags = self.volume_obj.getTags(self.configuration.vipr_tenant +
                                              "/" +
                                              self.configuration.vipr_project +
                                              "/" + name)
        for cTag in currentTags:
            if (cTag.startswith(self.OPENSTACK_TAG)):
                removeTags.append(cTag)

        try:
            if (len(removeTags) > 0):
                self.volume_obj.tag(
                    self.configuration.vipr_tenant + "/" +
                    self.configuration.vipr_project + "/" + name, None,
                    removeTags)
        except SOSError as e:
            if (e.err_code == SOSError.SOS_FAILURE_ERR):
                LOG.debug("SOSError adding the tag: " + e.err_text)

        # now add the tags for the volume
        addTags = []
        # put all the openstack volume properties into the ViPR volume
        try:
            for prop, value in vars(vol).iteritems():
                try:
                    # don't put the status in, it's always the status before
                    # the current transaction
                    if (not prop.startswith("status")):
                        addTags.append(self.OPENSTACK_TAG + ":" + prop + ":" +
                                       value)
                except Exception:
                    pass
        except Exception:
            pass

        try:
            self.volume_obj.tag(
                self.configuration.vipr_tenant + "/" +
                self.configuration.vipr_project + "/" + name, addTags, None)
        except SOSError as e:
            if (e.err_code == SOSError.SOS_FAILURE_ERR):
                LOG.debug("SOSError adding the tag: " + e.err_text)

        return (self.volume_obj.getTags(self.configuration.vipr_tenant + "/" +
                                        self.configuration.vipr_project + "/" +
                                        name))

    @retry_wrapper
    def create_cloned_volume(self, vol, src_vref):
        """Creates a clone of the specified volume."""
        self.authenticate_user()
        name = self._get_volume_name(vol)
        srcname = self._get_volume_name(src_vref)
        number_of_volumes = 1
        from common import SOSError

        try:
            res = self.volume_obj.clone(self.configuration.vipr_tenant + "/" +
                                        self.configuration.vipr_project,
                                        name,
                                        number_of_volumes,
                                        srcname,
                                        None,
                                        sync=True)
        except SOSError as e:
            if (e.err_code == SOSError.SOS_FAILURE_ERR):
                raise SOSError(
                    SOSError.SOS_FAILURE_ERR,
                    "Volume " + name + ": clone failed\n" + e.err_text)
            else:
                raise e

    @retry_wrapper
    def expand_volume(self, vol, new_size):
        """expands the volume to new_size specified."""
        self.authenticate_user()
        volume_name = self._get_volume_name(vol)
        import common as vipr_utils
        size_in_bytes = vipr_utils.to_bytes(str(new_size) + "G")
        from common import SOSError

        try:
            self.volume_obj.expand(
                self.configuration.vipr_tenant + "/" +
                self.configuration.vipr_project + "/" + volume_name,
                size_in_bytes, True)
        except SOSError as e:
            if (e.err_code == SOSError.SOS_FAILURE_ERR):
                raise SOSError(
                    SOSError.SOS_FAILURE_ERR,
                    "Volume " + volume_name + ": expand failed\n" + e.err_text)
            else:
                raise e

    @retry_wrapper
    def create_volume_from_snapshot(self, snapshot, volume):
        """Creates volume from given snapshot ( snapshot clone to volume )."""
        self.authenticate_user()
        src_snapshot_name = snapshot['name']
        src_vol_ref = self.volume_api.get(context.get_admin_context(),
                                          snapshot['volume_id'])
        src_vol_name = self._get_volume_name(src_vol_ref)
        new_volume_name = self._get_volume_name(volume)
        number_of_volumes = 1
        from common import SOSError

        try:
            self.volume_obj.clone(self.configuration.vipr_tenant + "/" +
                                  self.configuration.vipr_project,
                                  new_volume_name,
                                  number_of_volumes,
                                  src_vol_name,
                                  src_snapshot_name,
                                  sync=True)
        except SOSError as e:
            if (e.err_code == SOSError.SOS_FAILURE_ERR):
                raise SOSError(
                    SOSError.SOS_FAILURE_ERR, "Snapshot " + src_snapshot_name +
                    ": clone failed\n" + e.err_text)
            else:
                raise e

    @retry_wrapper
    def delete_volume(self, vol):
        self.authenticate_user()
        name = self._get_volume_name(vol)
        from common import SOSError
        try:
            self.volume_obj.delete(self.configuration.vipr_tenant + "/" +
                                   self.configuration.vipr_project + "/" +
                                   name,
                                   volume_name_list=None,
                                   sync=True)
        except SOSError as e:
            if e.err_code == SOSError.NOT_FOUND_ERR:
                LOG.info("Volume " + name +
                         " no longer exists; volume deletion is" +
                         " considered success.")
            elif e.err_code == SOSError.SOS_FAILURE_ERR:
                raise SOSError(
                    SOSError.SOS_FAILURE_ERR,
                    "Volume " + name + ": Delete failed\n" + e.err_text)
            else:
                raise e

    @retry_wrapper
    def list_volume(self):
        import common as vipr_utils
        from common import SOSError
        try:
            uris = self.volume_obj.list_volumes(
                self.configuration.vipr_tenant + "/" +
                self.configuration.vipr_project)
            if (len(uris) > 0):
                output = []
                for uri in uris:
                    output.append(self.volume_obj.show_by_uri(uri))

                return vipr_utils.format_json_object(output)
            else:
                return
        except SOSError as e:
            raise e

    @retry_wrapper
    def create_snapshot(self, snapshot):
        self.authenticate_user()
        from common import SOSError
        try:
            snapshotname = snapshot['name']
            vol = snapshot['volume']
            volumename = self._get_volume_name(vol)
            projectname = self.configuration.vipr_project
            tenantname = self.configuration.vipr_tenant
            storageresType = 'block'
            storageresTypename = 'volumes'
            resourceUri = self.snapshot_obj.storageResource_query(
                storageresType,
                fileshareName=None,
                volumeName=volumename,
                cgName=None,
                project=projectname,
                tenant=tenantname)
            inactive = False
            rptype = None
            sync = True
            self.snapshot_obj.snapshot_create(storageresType,
                                              storageresTypename, resourceUri,
                                              snapshotname, inactive, rptype,
                                              sync)
            return

        except SOSError as e:
            if (e.err_code == SOSError.SOS_FAILURE_ERR):
                raise SOSError(
                    SOSError.SOS_FAILURE_ERR, "Snapshot: " + snapshotname +
                    ", Create Failed\n" + e.err_text)
            else:
                raise e

    @retry_wrapper
    def delete_snapshot(self, snapshot):
        self.authenticate_user()
        snapshotname = snapshot['name']
        from common import SOSError
        try:
            vol = snapshot['volume']
            volumename = self._get_volume_name(vol)
            projectname = self.configuration.vipr_project
            tenantname = self.configuration.vipr_tenant
            storageresType = 'block'
            storageresTypename = 'volumes'
            resourceUri = self.snapshot_obj.storageResource_query(
                storageresType,
                fileshareName=None,
                volumeName=volumename,
                cgName=None,
                project=projectname,
                tenant=tenantname)
            if resourceUri is None:
                LOG.info("Snapshot " + snapshotname +
                         " is not found; snapshot deletion" +
                         " is considered successful.")
            else:
                self.snapshot_obj.snapshot_delete(storageresType,
                                                  storageresTypename,
                                                  resourceUri,
                                                  snapshotname,
                                                  sync=True)
            return
        except SOSError as e:
            if (e.err_code == SOSError.SOS_FAILURE_ERR):
                raise SOSError(
                    SOSError.SOS_FAILURE_ERR,
                    "Snapshot " + snapshotname + ": Delete Failed\n")
            else:
                raise e

    @retry_wrapper
    def initialize_connection(self, volume, protocol, initiatorNodes,
                              initiatorPorts, hostname):

        from common import SOSError

        try:
            self.authenticate_user()
            volumename = self._get_volume_name(volume)
            foundgroupname = self._find_exportgroup(initiatorPorts)
            if (foundgroupname is None):
                for i in xrange(len(initiatorPorts)):
                    # check if this initiator is contained in any ViPR Host
                    # object
                    LOG.debug("checking for initiator port:" +
                              initiatorPorts[i])
                    foundhostname = self._find_host(initiatorPorts[i])
                    if (foundhostname is None):
                        hostfound = self._host_exists(hostname)
                        if (hostfound is None):
                            # create a host so it can be added to the export
                            # group
                            hostfound = hostname
                            self.host_obj.create(
                                hostname,
                                platform.system(),
                                hostname,
                                self.configuration.vipr_tenant,
                                port=None,
                                username=None,
                                passwd=None,
                                usessl=None,
                                osversion=None,
                                cluster=None,
                                datacenter=None,
                                vcenter=None,
                                autodiscovery=True)
                            LOG.info("Created host " + hostname)
                        # add the initiator to the host
                        self.hostinitiator_obj.create(hostfound, protocol,
                                                      initiatorNodes[i],
                                                      initiatorPorts[i])
                        LOG.info("Initiator " + initiatorPorts[i] +
                                 " added to host " + hostfound)
                        foundhostname = hostfound
                    else:
                        LOG.info("Found host " + foundhostname)
                    # create an export group for this host
                    foundgroupname = foundhostname + 'SG'
                    # create a unique name
                    foundgroupname = foundgroupname + '-' + \
                        ''.join(random.choice(string.ascii_uppercase
                                              + string.digits)
                                for x in range(6))
                    res = self.exportgroup_obj.exportgroup_create(
                        foundgroupname, self.configuration.vipr_project,
                        self.configuration.vipr_tenant,
                        self.configuration.vipr_varray, 'Host', foundhostname)
            LOG.debug("adding the volume to the exportgroup : " + volumename)
            res = self.exportgroup_obj.exportgroup_add_volumes(
                True, foundgroupname, self.configuration.vipr_tenant,
                self.configuration.vipr_project, [volumename], None, None)
            return self._find_device_info(volume, initiatorPorts)

        except SOSError as e:
            raise SOSError(
                SOSError.SOS_FAILURE_ERR,
                "Attach volume (" + self._get_volume_name(volume) +
                ") to host (" + hostname + ") initiator (" +
                initiatorPorts[0] + ") failed: " + e.err_text)

    @retry_wrapper
    def terminate_connection(self, volume, protocol, initiatorNodes,
                             initiatorPorts, hostname):
        from common import SOSError
        try:
            self.authenticate_user()
            volumename = self._get_volume_name(volume)
            tenantproject = self.configuration.vipr_tenant + \
                '/' + self.configuration.vipr_project
            voldetails = self.volume_obj.show(tenantproject + '/' + volumename)
            volid = voldetails['id']

            # find the exportgroups
            exports = self.volume_obj.get_exports_by_uri(volid)
            exportgroups = set()
            itls = exports['itl']
            for itl in itls:
                itl_port = itl['initiator']['port']
                if (itl_port in initiatorPorts):
                    exportgroups.add(itl['export']['id'])

            for exportgroup in exportgroups:
                res = self.exportgroup_obj.exportgroup_remove_volumes_by_uri(
                    exportgroup, volid, True, None, None, None, None)
            else:
                LOG.info("No export group found for the host: " + hostname +
                         "; this is considered already detached.")

            return itls

        except SOSError as e:
            raise SOSError(
                SOSError.SOS_FAILURE_ERR, "Detaching volume " + volumename +
                " from host " + hostname + " failed: " + e.err_text)

    @retry_wrapper
    def _find_device_info(self, volume, initiator_ports):
        '''Returns the device_info in a list of itls that have
        the matched initiator
        (there could be multiple targets, hence a list):
                [
                 {
                  "hlu":9,
                  "initiator":{...,"port":"20:00:00:25:B5:49:00:22"},
                  "export":{...},
                  "device":{...,"wwn":"600601602B802D00B62236585D0BE311"},
                  "target":{...,"port":"50:06:01:6A:46:E0:72:EF"},
                  "san_zone_name":"..."
                 },
                 {
                  "hlu":9,
                  "initiator":{...,"port":"20:00:00:25:B5:49:00:22"},
                  "export":{...},
                  "device":{...,"wwn":"600601602B802D00B62236585D0BE311"},
                  "target":{...,"port":"50:06:01:62:46:E0:72:EF"},
                  "san_zone_name":"..."
                 }
                ]
        '''
        volumename = self._get_volume_name(volume)
        fullname = self.configuration.vipr_project + '/' + volumename
        vol_uri = self.volume_obj.volume_query(fullname)
        '''
        The itl info shall be available at the first try since now export is a
        synchronous call.  We are trying a few more times to accommodate any
        delay on filling in the itl info after the export task is completed.
        '''
        itls = []
        for x in xrange(10):
            exports = self.volume_obj.get_exports_by_uri(vol_uri)
            LOG.debug(_("Volume exports: %s") % exports)
            for itl in exports['itl']:
                itl_port = itl['initiator']['port']
                if (itl_port in initiator_ports):
                    found_device_number = itl['hlu']
                    if (found_device_number is not None
                            and found_device_number != '-1'):
                        # 0 is a valid number for found_device_number.
                        # Only loop if it is None or -1
                        LOG.debug("Found Device Number: " +
                                  str(found_device_number))
                        itls.append(itl)

            if itls:
                break
            else:
                LOG.debug("Device Number not found yet." +
                          " Retrying after 10 seconds...")
                time.sleep(10)

        if itls is None:
            # No device number found after 10 tries; return an empty itl
            LOG.info("No device number has been found after 10 tries;" +
                     "this likely indicates an unsuccessful attach of" +
                     "volume " + volumename + " to" + " initiator " +
                     str(initiator_ports))

        return itls

    def _get_volume_name(self, vol):
        try:
            name = vol['display_name']
        except Exception as exp:
            name = None

        if (name is None or len(name) == 0):
            name = vol['name']

        return name

    def _get_vpool(self, volume):
        vpool = {}
        ctxt = context.get_admin_context()
        type_id = volume['volume_type_id']
        if type_id is not None:
            volume_type = volume_types.get_volume_type(ctxt, type_id)
            specs = volume_type.get('extra_specs')
            for key, value in specs.iteritems():
                vpool[key] = value

        return vpool

    @retry_wrapper
    def _find_exportgroup(self, initiator_ports):
        '''Find the export group to which the given initiator ports are the
        same as the initiators in the group
        '''
        foundgroupname = None
        grouplist = self.exportgroup_obj.exportgroup_list(
            self.configuration.vipr_project, self.configuration.vipr_tenant)
        for groupid in grouplist:
            groupdetails = self.exportgroup_obj.exportgroup_show(
                groupid, self.configuration.vipr_project,
                self.configuration.vipr_tenant)
            if groupdetails is not None:
                if (groupdetails['inactive']):
                    continue
                initiators = groupdetails['initiators']
                if initiators is not None:
                    inits_eg = set()
                    for initiator in initiators:
                        inits_eg.add(initiator['initiator_port'])

                    if (inits_eg == set(initiator_ports)):
                        foundgroupname = groupdetails['name']
                    if foundgroupname is not None:
                        # Check the associated varray
                        if groupdetails['varray']:
                            varray_uri = groupdetails['varray']['id']
                            varray_details = self.varray_obj.varray_show(
                                varray_uri)
                            if (varray_details['name'] ==
                                    self.configuration.vipr_varray):
                                LOG.debug("Found exportgroup " +
                                          foundgroupname)
                                break

                        # Not the right varray
                        foundgroupname = None

        return foundgroupname

    @retry_wrapper
    def _find_host(self, initiator_port):
        '''Find the host, if exists, to which the given initiator belong.'''
        foundhostname = None
        hosts = self.host_obj.list_by_tenant(self.configuration.vipr_tenant)
        for host in hosts:
            initiators = self.host_obj.list_initiators(host['id'])
            for initiator in initiators:
                if (initiator_port == initiator['name']):
                    foundhostname = host['name']
                    break

            if foundhostname is not None:
                break

        return foundhostname

    @retry_wrapper
    def _host_exists(self, host_name):
        '''Check if a Host object with the given
        hostname already exists in ViPR
        '''
        hosts = self.host_obj.search_by_name(host_name)

        if (len(hosts) > 0):
            for host in hosts:
                hostname = host['match']
                if (host_name == hostname):
                    return hostname
            return hostname
        LOG.debug("no host found for:" + host_name)
        return None

    @retry_wrapper
    def update_volume_stats(self):
        """Retrieve stats info."""
        LOG.debug(_("Updating volume stats"))
        self.authenticate_user()
        import common as vipr_utils
        from common import SOSError

        try:
            vols = self.volume_obj.list_volumes(
                self.configuration.vipr_tenant + "/" +
                self.configuration.vipr_project)
            vpairs = set()
            if (len(vols) > 0):
                for vol in vols:
                    if (vol):
                        vpair = (vol["vpool"]["id"], vol["varray"]["id"])
                        if (vpair not in vpairs):
                            vpairs.add(vpair)

            if (len(vpairs) > 0):
                free_gb = 0.0
                used_gb = 0.0
                provisioned_gb = 0.0
                precent_used = 0.0
                percent_provisioned = 0.0
                for vpair in vpairs:
                    if (vpair):
                        (s, h) = vipr_utils.service_json_request(
                            self.configuration.vipr_hostname,
                            self.configuration.vipr_port,
                            "GET",
                            URI_VPOOL_VARRAY_CAPACITY.format(
                                vpair[0], vpair[1]),
                            body=None)
                        capacity = vipr_utils.json_decode(s)

                        free_gb += float(capacity["free_gb"])
                        used_gb += float(capacity["used_gb"])
                        provisioned_gb += float(capacity["provisioned_gb"])

                self.stats['free_capacity_gb'] = free_gb
                self.stats['total_capacity_gb'] = free_gb + used_gb
                self.stats['reserved_percentage'] = 100 * \
                    provisioned_gb / (free_gb + used_gb)

            return self.stats

        except SOSError as e:
            raise e
class Openstack(object):
    '''
    The class definition for operations related to 'Openstack'. 
    '''

    #Commonly used URIs for the 'Openstack' module
    URI_HOST_SEARCH = '/compute/hosts/search?name={0}'
    URI_HOST_BULK = '/compute/hosts/bulk'
    URI_NETWORK_BULK = '/vdc/networks/bulk'
    URI_NETWORK_PORTS = '/vdc/networks/{0}/storage-ports'    
    URI_STORAGEPORT_ALL = '/vdc/storage-ports'
    URI_STORAGEPORT_BULK = '/vdc/storage-ports/bulk'

    VIPR_CONFIG_FILE = '/etc/cinder/cinder.conf'

        
    def __init__(self, ipAddr, port, verbose):
        '''
        Constructor: takes IP address and port of the ViPR instance. These are
        needed to make http requests for REST API   
        '''
        self.__ipAddr = ipAddr
        self.__port = port
        self._host = Host(self.__ipAddr, self.__port)
        self._hostinitiator = HostInitiator(self.__ipAddr, self.__port)
        self._network = Network(self.__ipAddr, self.__port)
        self._execute = utils.execute
        self._vipr_info = ViPRInfo(self.VIPR_CONFIG_FILE)
        self.set_logging(verbose)
            
    def set_logging(self, verbose):
        self._logger = logging.getLogger(__name__)
        if (verbose):
            self._logger.setLevel(logging.DEBUG)
        else:
            self._logger.setLevel(logging.INFO)
        logging.basicConfig(format='%(asctime)s:%(levelname)s: %(message)s')
    def get_logger(self):
        return self._logger    
                
    def get_hostname(self, hostname = None):
        if (not hostname):
            return socket.getfqdn()
        else:
            return hostname
    
    def get_vipr_info(self):
        return self._vipr_info
    
    #@retry_wrapper
    def add_host(self, host_param, connector, vipr_param):
        self._vipr_info.authenticate_user()
        varray = vipr_param['varray']
        
        # Find or create host.
        host = self.create_host(host_param['hostname'], vipr_param['tenant'], vipr_param['project'])
        self._logger.info('Created/found host %s', host['name'])
        self._logger.debug('Details of host %s: %s', host_param['hostname'], host)     
                
        # Find or create initiator.
        initiator = self.create_initiator(host, connector)    
        self._logger.info('Added initiator %s to host %s', initiator['initiator_port'], host['name'])
        self._logger.debug('Details of initiator %s', initiator)
         
        # Find network
        network = self.find_iscsi_network(vipr_param['varray'], vipr_param['network']) 
        if (network):
            self._logger.info('Found network %s in virtual array %s', network['name'], varray)
        else:
            self._logger('Cannot find a network in virtual array %s to place the initiator', varray)
            exit(1)
            
        # add initiator to network
        if (initiator['initiator_port'] not in network['endpoints']):
            self.add_initiator_to_network(host, initiator, network, vipr_param['varray'])
        self._logger.info('Added initiator %s to network %s', initiator['initiator_port'], network['name'])
        self._logger.debug('Network details %s: ', network)
    
    @vipr_retry_wrapper         
    def create_host(self, hostname, tenant, project, ostype='Linux'):
        # find host
        host = self.find_host(hostname)
        if (not host):
            if (not ostype) :
                ostype = "Linux"
            
                # host not found, create a new one.
            task_rep = self._host.create(hostname, ostype, hostname, tenant, None, None, None, None, None, None, None, None, None)
            host = common.show_by_href(self.__ipAddr, self.__port, task_rep['resource']) 
        return host                
    
    '''
        Find host by name of host object in ViPR, normally the hostname of the host.
        Parameters:
            name: name of the host
        Returns:
            host details in JSON
    '''
    def find_host(self, hostname):
        shortname = hostname[:hostname.find(".")]
        (s, h) = common.service_json_request(self.__ipAddr, self.__port,
                                             "GET",
                                             self.URI_HOST_SEARCH.format(shortname), 
                                             None)
        o = common.json_decode(s);
        ids = []
        for host in o['resource'] :
            ids.append(host['id'])
    
        body = json.dumps({'id' : ids})    
        (s, h) = common.service_json_request(self.__ipAddr, self.__port,
                                             "POST",
                                             self.URI_HOST_BULK, 
                                             body)
        o = common.json_decode(s)
        for host in o['host']:
            if (host['inactive']):
                continue
            if (hostname in host['host_name'] or host['host_name'] in hostname ):
                return host
               
    def get_localhost_initiator(self, protocol='iSCSI'):
        if (protocol == 'iSCSI'):
            wwpn = libvirt_utils.get_iscsi_initiator()
            initiator = {'wwpn' : wwpn}
            return initiator
    
    def find_initiator(self, host, wwpn):
        initiators = self._host.list_initiators(host)
        for initiator in initiators:
            if (initiator['name'] == wwpn):
                return initiator
        return None    
    
    def create_initiator(self, host, connector):
        initiator = self.find_initiator(host['name'], connector['wwpn'])
        if (not initiator): 
            initiator = self._hostinitiator.create(host['name'], 'iSCSI', None, connector['wwpn'])
        return common.show_by_href(self.__ipAddr, self.__port, initiator)
    
    '''
        Find network for a given network name. If network name is not specified 
    '''
    def find_iscsi_network(self, varray, network_name):
        if (network_name):
            try:
                return self._network.network_query(network_name, varray)
            except SOSError:
                # TODO: re-raise the exception with correct name. To be removed
                raise SOSError(SOSError.NOT_FOUND_ERR, "Network {0} not found".format(network_name))
            
        storage_ports = self.get_varray_iscsi_storageports(varray)
        for port in storage_ports:
            port_info = dict()
            port_info['native_guid'] = port['native_guid']
            port_info['port_name'] = port['port_name']
            try:
                ip_address = port['ip_address'] 
                port_info['ip_address'] = ip_address             
                if (self.is_ip_pingable(ip_address)):
                    network = port['network']
                    network_detail = common.show_by_href(self.__ipAddr, self.__port, network)
                    port_info['network'] = network_detail['name']
                    self._logger.debug('Select storage port %s: ', port_info)
                    return network_detail
                else:    
                    self._logger.debug('Skip storage port %s: ', port_info)
 
            except KeyError:
                self._logger.debug('Skip storage port %s: ', port_info)
                continue
 
    def is_ip_pingable(self, ip_address):
        self._logger.debug('ping ip address %s ', ip_address)
        try:
            (out, err) = self._execute('ping', '-c', '2', ip_address)
            self._logger.debug(out)
            return True
        except Exception as ex:
            return False
    
    def get_ip_networks(self, varray):
        networks = self._network.list_networks(varray)
        ip_networks = []
        resources = self.get_bulk_details(networks, self.URI_NETWORK_BULK)                         
        for x in resources['network']:
            if (x['transport_type'] == 'IP'):
                ip_networks.append(x)
                    
        return ip_networks
        
    def get_bulk_details(self, resources, bulkuri):
        ids = []
        for each in resources :
            ids.append(each['id'])
    
        body = json.dumps({'id' : ids})    
        (s, h) = common.service_json_request(self.__ipAddr, self.__port,
                                             "POST",
                                             bulkuri, 
                                             body)
        return common.json_decode(s)          

    '''
        Attach host initiators to a network
        Parameters:
            name: name of the host
            network: name of the network to be attached
        Return:
            network details in JSON
    '''
    def add_initiator_to_network(self, host, initiator, network, varray):
        if (network['transport_type'] == 'IP' and initiator['protocol'] == 'iSCSI'):
            return self._network.add_endpoint(varray, network['name'], initiator['initiator_port'])
    
    def get_varray_iscsi_storageports(self, varray):
        iscsi_ports = []
        for port in self.get_varray_storageports(varray):
            if (port['transport_type'] != 'IP'):
                continue
            if ('iqn' not in port['port_network_id']):
                continue
            if ('Not Available' in port['ip_address'] ):
                continue
            iscsi_ports.append(port)
        return iscsi_ports
         
    """
        Get all storage ports
        Returns:
            Storage ports in JSON
    """
    def get_varray_storageports(self, varray):
        networks = self._network.list_networks(varray)
        ids = []
        for net in networks:
            net_id = net['id']
            (s, h) = common.service_json_request(self.__ipAddr, self.__port,
                                                 "GET",
                                                 self.URI_NETWORK_PORTS.format(net_id) , None)
            o = common.json_decode(s)
            for port in o['storage_port']:
                ids.append(port['id'])
                
        body = json.dumps({'id' : ids})
                
        (s, h) = common.service_json_request(self.__ipAddr, self.__port,
                                             "POST",
                                             self.URI_STORAGEPORT_BULK,
                                             body)
        o = common.json_decode(s)
        return o['storage_port']
    
    def log_info(self, message):
        import datetime
        timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        sys.stdout.write(timestamp + ': ' + message + '\n')