# Copyright (c) 2013 EMC Corporation
# All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#        http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.
 
import os
import platform
import random
import string
import sys
import time
import traceback
 
from oslo.config import cfg
 
from cinder import context
from cinder import exception
from cinder.openstack.common import log as logging
from cinder.volume import volume_types
 
# for the delegator
LOG = logging.getLogger(__name__)
 
volume_opts = [
    cfg.StrOpt('vipr_hostname',
               default=None,
               help='Hostname for the EMC ViPR Instance'),
    cfg.IntOpt('vipr_port',
               default=4443,
               help='Port for the EMC ViPR Instance'),
    cfg.StrOpt('vipr_username',
               default=None,
               help='Username for accessing the EMC ViPR Instance'),
    cfg.StrOpt('vipr_password',
               default=None,
               help='Password for accessing the EMC ViPR Instance'),
    cfg.StrOpt('vipr_tenant',
               default=None,
               help='Tenant to utilize within the EMC ViPR Instance'),
    cfg.StrOpt('vipr_project',
               default=None,
               help='Project to utilize within the EMC ViPR Instance'),
    cfg.StrOpt('vipr_varray',
               default=None,
               help='Virtual Array to utilize within the EMC ViPR Instance'),
    cfg.StrOpt('vipr_cli_path',
               default="/opt/storageos/cli/bin",
               help='The system path where ViPR CLI is installed'),
    cfg.StrOpt('vipr_cookiedir',
               default='/tmp',
               help='directory to store temporary cookies, defaults to /tmp')
]
 
CONF = cfg.CONF
CONF.register_opts(volume_opts)
 
URI_VPOOL_VARRAY_CAPACITY = '/block/vpools/{0}/varrays/{1}/capacity'
 
 
def retry_wrapper(func):
    def try_and_retry(*args, **kwargs):
        global AUTHENTICATED
        retry = False
 
        from common import SOSError
 
        try:
            return func(*args, **kwargs)
        except SOSError as e:
            # if we got an http error and
            # the string contains 401 or if the string contains the word cookie
            if (e.err_code == SOSError.HTTP_ERR and
                (e.err_text.find('401') != -1 or
                 e.err_text.lower().find('cookie') != -1)):
                retry = True
                AUTHENTICATED = False
            else:
                exception_message = "\nViPR Exception: %s\nStack Trace:\n%s" \
                    % (e.err_text, traceback.format_exc())
                raise exception.VolumeBackendAPIException(
                    data=exception_message)
        except Exception as o:
            exception_message = "\nGeneral Exception: %s\nStack Trace:\n%s" \
                % (sys.exc_info()[0], traceback.format_exc())
            raise exception.VolumeBackendAPIException(
                data=exception_message)
 
        if (retry):
            return func(*args, **kwargs)
 
    return try_and_retry
 
 
AUTHENTICATED = False
 
 
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}
 
    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,
                                         # no longer specified in volume
                                         # creation
                                         protection=None,
                                         protection_varrays=None,
                                         consistent_volume_label=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']
        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,
                None,
                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