"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "cinder/volume/drivers/dell_emc/powerstore/adapter.py" between
cinder-17.0.1.tar.gz and cinder-17.1.0.tar.gz

About: OpenStack Cinder (Core Service: Block Storage) provides persistent block storage to running instances. Its pluggable driver architecture facilitates the creation and management of block storage devices.
The "Victoria" series (latest release).

adapter.py  (cinder-17.0.1):adapter.py  (cinder-17.1.0)
skipping to change at line 19 skipping to change at line 19
# #
# Unless required by applicable law or agreed to in writing, software # Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
"""Adapter for Dell EMC PowerStore Cinder driver.""" """Adapter for Dell EMC PowerStore Cinder driver."""
from oslo_log import log as logging from oslo_log import log as logging
from oslo_utils import strutils
from cinder import coordination from cinder import coordination
from cinder import exception from cinder import exception
from cinder.i18n import _ from cinder.i18n import _
from cinder.objects.snapshot import Snapshot from cinder.objects.snapshot import Snapshot
from cinder.volume.drivers.dell_emc.powerstore import client from cinder.volume.drivers.dell_emc.powerstore import client
from cinder.volume.drivers.dell_emc.powerstore import options from cinder.volume.drivers.dell_emc.powerstore import options
from cinder.volume.drivers.dell_emc.powerstore import utils from cinder.volume.drivers.dell_emc.powerstore import utils
from cinder.volume import volume_utils from cinder.volume import volume_utils
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
PROTOCOL_FC = "FC" PROTOCOL_FC = "FC"
PROTOCOL_ISCSI = "iSCSI" PROTOCOL_ISCSI = "iSCSI"
CHAP_MODE_SINGLE = "Single"
class CommonAdapter(object): class CommonAdapter(object):
def __init__(self, active_backend_id, configuration): def __init__(self, active_backend_id, configuration):
self.active_backend_id = active_backend_id self.active_backend_id = active_backend_id
self.appliances = None self.appliances = None
self.appliances_to_ids_map = {} self.appliances_to_ids_map = {}
self.client = None self.client = None
self.configuration = configuration self.configuration = configuration
self.storage_protocol = None self.storage_protocol = None
self.allowed_ports = None self.allowed_ports = None
self.use_chap_auth = None
@staticmethod @staticmethod
def initiators(connector): def initiators(connector):
raise NotImplementedError raise NotImplementedError
def _port_is_allowed(self, port): def _port_is_allowed(self, port):
"""Check if port is in allowed ports list. """Check if port is in allowed ports list.
If allowed ports are empty then all ports are allowed. If allowed ports are empty then all ports are allowed.
skipping to change at line 84 skipping to change at line 87
def check_for_setup_error(self): def check_for_setup_error(self):
self.client.check_for_setup_error() self.client.check_for_setup_error()
if not self.appliances: if not self.appliances:
msg = _("PowerStore appliances must be set.") msg = _("PowerStore appliances must be set.")
raise exception.VolumeBackendAPIException(data=msg) raise exception.VolumeBackendAPIException(data=msg)
self.appliances_to_ids_map = {} self.appliances_to_ids_map = {}
for appliance_name in self.appliances: for appliance_name in self.appliances:
self.appliances_to_ids_map[appliance_name] = ( self.appliances_to_ids_map[appliance_name] = (
self.client.get_appliance_id_by_name(appliance_name) self.client.get_appliance_id_by_name(appliance_name)
) )
self.use_chap_auth = False
if self.storage_protocol == PROTOCOL_ISCSI:
chap_config = self.client.get_chap_config()
if chap_config.get("mode") == CHAP_MODE_SINGLE:
self.use_chap_auth = True
LOG.debug("Successfully initialized PowerStore %(protocol)s adapter. " LOG.debug("Successfully initialized PowerStore %(protocol)s adapter. "
"PowerStore appliances: %(appliances)s. " "PowerStore appliances: %(appliances)s. "
"Allowed ports: %(allowed_ports)s.", "Allowed ports: %(allowed_ports)s. "
"Use CHAP authentication: %(use_chap_auth)s.",
{ {
"protocol": self.storage_protocol, "protocol": self.storage_protocol,
"appliances": self.appliances, "appliances": self.appliances,
"allowed_ports": self.allowed_ports, "allowed_ports": self.allowed_ports,
"use_chap_auth": self.use_chap_auth,
}) })
def create_volume(self, volume): def create_volume(self, volume):
appliance_name = volume_utils.extract_host(volume.host, "pool") appliance_name = volume_utils.extract_host(volume.host, "pool")
appliance_id = self.appliances_to_ids_map[appliance_name] appliance_id = self.appliances_to_ids_map[appliance_name]
LOG.debug("Create PowerStore volume %(volume_name)s of size " LOG.debug("Create PowerStore volume %(volume_name)s of size "
"%(volume_size)s GiB with id %(volume_id)s on appliance " "%(volume_size)s GiB with id %(volume_id)s on appliance "
"%(appliance_name)s.", "%(appliance_name)s.",
{ {
"volume_name": volume.name, "volume_name": volume.name,
skipping to change at line 315 skipping to change at line 325
"provider_id": volume_provider_id, "provider_id": volume_provider_id,
} }
def initialize_connection(self, volume, connector, **kwargs): def initialize_connection(self, volume, connector, **kwargs):
connection_properties = self._connect_volume(volume, connector) connection_properties = self._connect_volume(volume, connector)
LOG.debug("Connection properties for volume %(volume_name)s with id " LOG.debug("Connection properties for volume %(volume_name)s with id "
"%(volume_id)s: %(connection_properties)s.", "%(volume_id)s: %(connection_properties)s.",
{ {
"volume_name": volume.name, "volume_name": volume.name,
"volume_id": volume.id, "volume_id": volume.id,
"connection_properties": connection_properties, "connection_properties": strutils.mask_password(
connection_properties
),
}) })
return connection_properties return connection_properties
def terminate_connection(self, volume, connector, **kwargs): def terminate_connection(self, volume, connector, **kwargs):
self._disconnect_volume(volume, connector) self._disconnect_volume(volume, connector)
return {} return {}
def update_volume_stats(self): def update_volume_stats(self):
stats = { stats = {
"volume_backend_name": ( "volume_backend_name": (
skipping to change at line 430 skipping to change at line 442
LOG.error(msg) LOG.error(msg)
raise exception.VolumeBackendAPIException(data=msg) raise exception.VolumeBackendAPIException(data=msg)
else: else:
return hosts_found[0] return hosts_found[0]
@coordination.synchronized("powerstore-create-host") @coordination.synchronized("powerstore-create-host")
def _create_host_if_not_exist(self, connector): def _create_host_if_not_exist(self, connector):
"""Create PowerStore host if it does not exist. """Create PowerStore host if it does not exist.
:param connector: connection properties :param connector: connection properties
:return: PowerStore host object :return: PowerStore host object, iSCSI CHAP credentials
""" """
initiators = self.initiators(connector) initiators = self.initiators(connector)
host = self._filter_hosts_by_initiators(initiators) host = self._filter_hosts_by_initiators(initiators)
if self.use_chap_auth:
chap_credentials = utils.get_chap_credentials()
else:
chap_credentials = {}
if host: if host:
self._modify_host_initiators(host, initiators) self._modify_host_initiators(host, chap_credentials, initiators)
else: else:
host_name = utils.powerstore_host_name( host_name = utils.powerstore_host_name(
connector, connector,
self.storage_protocol self.storage_protocol
) )
LOG.debug("Create PowerStore host %(host_name)s. " LOG.debug("Create PowerStore host %(host_name)s. "
"Initiators: %(initiators)s.", "Initiators: %(initiators)s.",
{ {
"host_name": host_name, "host_name": host_name,
"initiators": initiators, "initiators": initiators,
}) })
ports = [ ports = [
{ {
"port_name": initiator, "port_name": initiator,
"port_type": self.storage_protocol, "port_type": self.storage_protocol,
**chap_credentials,
} for initiator in initiators } for initiator in initiators
] ]
host = self.client.create_host(host_name, ports) host = self.client.create_host(host_name, ports)
host["name"] = host_name host["name"] = host_name
LOG.debug("Successfully created PowerStore host %(host_name)s. " LOG.debug("Successfully created PowerStore host %(host_name)s. "
"Initiators: %(initiators)s. PowerStore host id: " "Initiators: %(initiators)s. PowerStore host id: "
"%(host_provider_id)s.", "%(host_provider_id)s.",
{ {
"host_name": host["name"], "host_name": host["name"],
"initiators": initiators, "initiators": initiators,
"host_provider_id": host["id"], "host_provider_id": host["id"],
}) })
return host return host, chap_credentials
def _modify_host_initiators(self, host, initiators): def _modify_host_initiators(self, host, chap_credentials, initiators):
"""Update PowerStore host initiators if needed. """Update PowerStore host initiators if needed.
:param host: PowerStore host object :param host: PowerStore host object
:param chap_credentials: iSCSI CHAP credentials
:param initiators: list of initiators :param initiators: list of initiators
:return: None :return: None
""" """
initiators_added = [ initiators_added = [
initiator["port_name"] for initiator in host["host_initiators"] initiator["port_name"] for initiator in host["host_initiators"]
] ]
initiators_to_add = []
initiators_to_modify = []
initiators_to_remove = [ initiators_to_remove = [
initiator for initiator in initiators_added initiator for initiator in initiators_added
if initiator not in initiators if initiator not in initiators
] ]
initiators_to_add = [ for initiator in initiators:
{ initiator_add_modify = {
"port_name": initiator, "port_name": initiator,
"port_type": self.storage_protocol, **chap_credentials,
} for initiator in initiators }
if initiator not in initiators_added if initiator not in initiators_added:
] initiator_add_modify["port_type"] = self.storage_protocol
initiators_to_add.append(initiator_add_modify)
elif self.use_chap_auth:
initiators_to_modify.append(initiator_add_modify)
if initiators_to_remove: if initiators_to_remove:
LOG.debug("Remove initiators from PowerStore host %(host_name)s. " LOG.debug("Remove initiators from PowerStore host %(host_name)s. "
"Initiators: %(initiators_to_remove)s. " "Initiators: %(initiators_to_remove)s. "
"PowerStore host id: %(host_provider_id)s.", "PowerStore host id: %(host_provider_id)s.",
{ {
"host_name": host["name"], "host_name": host["name"],
"initiators_to_remove": initiators_to_remove, "initiators_to_remove": initiators_to_remove,
"host_provider_id": host["id"], "host_provider_id": host["id"],
}) })
self.client.modify_host_initiators( self.client.modify_host_initiators(
skipping to change at line 515 skipping to change at line 538
"host_name": host["name"], "host_name": host["name"],
"initiators_to_remove": initiators_to_remove, "initiators_to_remove": initiators_to_remove,
"host_provider_id": host["id"], "host_provider_id": host["id"],
}) })
if initiators_to_add: if initiators_to_add:
LOG.debug("Add initiators to PowerStore host %(host_name)s. " LOG.debug("Add initiators to PowerStore host %(host_name)s. "
"Initiators: %(initiators_to_add)s. PowerStore host id: " "Initiators: %(initiators_to_add)s. PowerStore host id: "
"%(host_provider_id)s.", "%(host_provider_id)s.",
{ {
"host_name": host["name"], "host_name": host["name"],
"initiators_to_add": initiators_to_add, "initiators_to_add": strutils.mask_password(
initiators_to_add
),
"host_provider_id": host["id"], "host_provider_id": host["id"],
}) })
self.client.modify_host_initiators( self.client.modify_host_initiators(
host["id"], host["id"],
add_initiators=initiators_to_add add_initiators=initiators_to_add
) )
LOG.debug("Successfully added initiators to PowerStore host " LOG.debug("Successfully added initiators to PowerStore host "
"%(host_name)s. Initiators: %(initiators_to_add)s. " "%(host_name)s. Initiators: %(initiators_to_add)s. "
"PowerStore host id: %(host_provider_id)s.", "PowerStore host id: %(host_provider_id)s.",
{ {
"host_name": host["name"], "host_name": host["name"],
"initiators_to_add": initiators_to_add, "initiators_to_add": strutils.mask_password(
initiators_to_add
),
"host_provider_id": host["id"],
})
if initiators_to_modify:
LOG.debug("Modify initiators of PowerStore host %(host_name)s. "
"Initiators: %(initiators_to_modify)s. "
"PowerStore host id: %(host_provider_id)s.",
{
"host_name": host["name"],
"initiators_to_modify": strutils.mask_password(
initiators_to_modify
),
"host_provider_id": host["id"],
})
self.client.modify_host_initiators(
host["id"],
modify_initiators=initiators_to_modify
)
LOG.debug("Successfully modified initiators of PowerStore host "
"%(host_name)s. Initiators: %(initiators_to_modify)s. "
"PowerStore host id: %(host_provider_id)s.",
{
"host_name": host["name"],
"initiators_to_modify": strutils.mask_password(
initiators_to_modify
),
"host_provider_id": host["id"], "host_provider_id": host["id"],
}) })
def _attach_volume_to_host(self, host, volume): def _attach_volume_to_host(self, host, volume):
"""Attach PowerStore volume to host. """Attach PowerStore volume to host.
:param host: PowerStore host object :param host: PowerStore host object
:param volume: OpenStack volume object :param volume: OpenStack volume object
:return: attached volume logical number :return: attached volume logical number
""" """
skipping to change at line 573 skipping to change at line 625
"host_provider_id": host["id"], "host_provider_id": host["id"],
"volume_lun": volume_lun, "volume_lun": volume_lun,
}) })
return volume_lun return volume_lun
def _create_host_and_attach(self, connector, volume): def _create_host_and_attach(self, connector, volume):
"""Create PowerStore host and attach volume. """Create PowerStore host and attach volume.
:param connector: connection properties :param connector: connection properties
:param volume: OpenStack volume object :param volume: OpenStack volume object
:return: attached volume logical number :return: iSCSI CHAP credentials, volume logical number
""" """
host = self._create_host_if_not_exist(connector) host, chap_credentials = self._create_host_if_not_exist(connector)
return self._attach_volume_to_host(host, volume) return chap_credentials, self._attach_volume_to_host(host, volume)
def _connect_volume(self, volume, connector): def _connect_volume(self, volume, connector):
"""Attach PowerStore volume and return it's connection properties. """Attach PowerStore volume and return it's connection properties.
:param volume: OpenStack volume object :param volume: OpenStack volume object
:param connector: connection properties :param connector: connection properties
:return: volume connection properties :return: volume connection properties
""" """
appliance_name = volume_utils.extract_host(volume.host, "pool") appliance_name = volume_utils.extract_host(volume.host, "pool")
appliance_id = self.appliances_to_ids_map[appliance_name] appliance_id = self.appliances_to_ids_map[appliance_name]
volume_lun = self._create_host_and_attach( chap_credentials, volume_lun = self._create_host_and_attach(
connector, connector,
volume volume
) )
return self._get_connection_properties(appliance_id, connection_properties = self._get_connection_properties(appliance_id,
volume_lun) volume_lun)
if self.use_chap_auth:
connection_properties["data"]["auth_method"] = "CHAP"
connection_properties["data"]["auth_username"] = (
chap_credentials.get("chap_single_username")
)
connection_properties["data"]["auth_password"] = (
chap_credentials.get("chap_single_password")
)
return connection_properties
def _detach_volume_from_hosts(self, volume, hosts_to_detach=None): def _detach_volume_from_hosts(self, volume, hosts_to_detach=None):
"""Detach volume from PowerStore hosts. """Detach volume from PowerStore hosts.
If hosts_to_detach is None, detach volume from all hosts. If hosts_to_detach is None, detach volume from all hosts.
:param volume: OpenStack volume object :param volume: OpenStack volume object
:param hosts_to_detach: list of hosts to detach from :param hosts_to_detach: list of hosts to detach from
:return: None :return: None
""" """
skipping to change at line 731 skipping to change at line 792
:param appliance_id: PowerStore appliance id :param appliance_id: PowerStore appliance id
:param volume_lun: attached volume logical unit number :param volume_lun: attached volume logical unit number
:return: connection properties :return: connection properties
""" """
target_wwns = self._get_fc_targets(appliance_id) target_wwns = self._get_fc_targets(appliance_id)
return { return {
"driver_volume_type": self.driver_volume_type, "driver_volume_type": self.driver_volume_type,
"data": { "data": {
"target_discovered": True, "target_discovered": False,
"target_lun": volume_lun, "target_lun": volume_lun,
"target_wwn": target_wwns, "target_wwn": target_wwns,
} }
} }
class iSCSIAdapter(CommonAdapter): class iSCSIAdapter(CommonAdapter):
def __init__(self, active_backend_id, configuration): def __init__(self, active_backend_id, configuration):
super(iSCSIAdapter, self).__init__(active_backend_id, configuration) super(iSCSIAdapter, self).__init__(active_backend_id, configuration)
self.storage_protocol = PROTOCOL_ISCSI self.storage_protocol = PROTOCOL_ISCSI
self.driver_volume_type = "iscsi" self.driver_volume_type = "iscsi"
skipping to change at line 781 skipping to change at line 842
:param appliance_id: PowerStore appliance id :param appliance_id: PowerStore appliance id
:param volume_lun: attached volume logical unit number :param volume_lun: attached volume logical unit number
:return: connection properties :return: connection properties
""" """
iqns, portals = self._get_iscsi_targets(appliance_id) iqns, portals = self._get_iscsi_targets(appliance_id)
return { return {
"driver_volume_type": self.driver_volume_type, "driver_volume_type": self.driver_volume_type,
"data": { "data": {
"target_discovered": True, "target_discovered": False,
"target_portal": portals[0],
"target_iqn": iqns[0],
"target_lun": volume_lun,
"target_portals": portals, "target_portals": portals,
"target_iqns": iqns, "target_iqns": iqns,
"target_luns": [volume_lun] * len(portals), "target_luns": [volume_lun] * len(portals),
}, },
} }
 End of changes. 25 change blocks. 
22 lines changed or deleted 86 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)