Add support for multiple hpe3par backends

This update adds support for configuring up to 12 HPE 3PAR backends at the same
time. Typical large 3PAR SANs have multiple volume types to take advantage of
different price points and performance. A separate backend configuration is
required for each volume type.

Change-Id: I8acd6865d5ca33bf72f9e0d2cb4d88020082e7b8
Story: 2002996
Task: 23011
Signed-off-by: Elena Taivan <elena.taivan@windriver.com>
This commit is contained in:
David Dunlap
2018-09-05 12:42:35 +00:00
committed by Elena Taivan
parent 4cbc961dc8
commit f5c0244460
9 changed files with 144 additions and 61 deletions

View File

@@ -1,2 +1,2 @@
SRC_DIR="src"
TIS_PATCH_VER=62
TIS_PATCH_VER=63

View File

@@ -245,7 +245,7 @@ class openstack::cinder::backup
class openstack::cinder::backends::san
inherits ::openstack::cinder::params {
include ::openstack::cinder::emc_vnx
include ::openstack::cinder::hpe3par
include ::openstack::cinder::backends::hpe3par
include ::openstack::cinder::hpelefthand
}
@@ -520,23 +520,29 @@ class openstack::cinder::emc_vnx(
}
class openstack::cinder::hpe3par(
$feature_enabled,
$config_params
) inherits ::openstack::cinder::params {
create_resources('cinder_config', hiera_hash('openstack::cinder::hpe3par::config_params', {}))
define openstack::cinder::backend::hpe3par
{
$hiera_params = "openstack::cinder::${name}::config_params"
$feature_enabled = "openstack::cinder::${name}::feature_enabled"
create_resources('cinder_config', hiera_hash($hiera_params, {}))
# As HP SANs are addon PS supported options, make sure we have explicit
# logging showing this is being included when the feature is enabled.
if $feature_enabled {
exec {'Including hpe3par configuration':
exec {"Including $name configuration":
path => [ '/usr/bin', '/usr/sbin', '/bin', '/sbin' ],
command => 'echo Including hpe3par configuration',
command => "echo Including $name configuration",
}
}
}
class openstack::cinder::backends::hpe3par (
$sections = []
) inherits ::openstack::cinder::params {
::openstack::cinder::backend::hpe3par {$sections:}
}
class openstack::cinder::hpelefthand(
$feature_enabled,
$config_params

View File

@@ -1,2 +1,2 @@
SRC_DIR="sysinv"
TIS_PATCH_VER=280
TIS_PATCH_VER=281

View File

@@ -134,6 +134,21 @@ class ServiceParameterController(rest.RestController):
def __init__(self, parent=None, **kwargs):
self._parent = parent
# Add additional hpe3par backends
for i in range(2, constants.SERVICE_PARAM_MAX_HPE3PAR + 1):
section = "{0}{1}".format(constants.SERVICE_PARAM_SECTION_CINDER_HPE3PAR, i)
service_parameter.SERVICE_PARAMETER_SCHEMA[constants.SERVICE_TYPE_CINDER][section] = {
service_parameter.SERVICE_PARAM_MANDATORY:
service_parameter.CINDER_HPE3PAR_PARAMETER_MANDATORY,
service_parameter.SERVICE_PARAM_PROTECTED:
service_parameter.CINDER_HPE3PAR_PARAMETER_PROTECTED,
service_parameter.SERVICE_PARAM_OPTIONAL:
service_parameter.CINDER_HPE3PAR_PARAMETER_OPTIONAL,
service_parameter.SERVICE_PARAM_VALIDATOR:
service_parameter.CINDER_HPE3PAR_PARAMETER_VALIDATOR,
service_parameter.SERVICE_PARAM_RESOURCE:
service_parameter.CINDER_HPE3PAR_PARAMETER_RESOURCE,
}
def _get_service_parameter_collection(self, marker=None, limit=None,
sort_key=None, sort_dir=None,
@@ -952,8 +967,12 @@ class ServiceParameterController(rest.RestController):
self._service_parameter_apply_semantic_check_cinder_emc_vnx()
self._emc_vnx_ip_addresses_reservation()
self._service_parameter_apply_semantic_check_cinder_hpe3par()
self._hpe3par_reserve_ip_addresses()
self._service_parameter_apply_semantic_check_cinder_hpe3par(constants.SERVICE_PARAM_SECTION_CINDER_HPE3PAR)
self._hpe3par_reserve_ip_addresses(constants.SERVICE_PARAM_SECTION_CINDER_HPE3PAR)
for i in range(2, constants.SERVICE_PARAM_MAX_HPE3PAR + 1):
section = "{0}{1}".format(constants.SERVICE_PARAM_SECTION_CINDER_HPE3PAR, i)
self._service_parameter_apply_semantic_check_cinder_hpe3par(section)
self._hpe3par_reserve_ip_addresses(section)
self._service_parameter_apply_semantic_check_cinder_hpelefthand()
self._hpelefthand_reserve_ip_addresses()
@@ -986,7 +1005,7 @@ class ServiceParameterController(rest.RestController):
LOG.exception(e)
@staticmethod
def _hpe3par_reserve_ip_addresses():
def _hpe3par_reserve_ip_addresses(section):
"""
We need to keep the address information between service_parameter
@@ -997,11 +1016,11 @@ class ServiceParameterController(rest.RestController):
Service Parameter | Address DB Entry Name
---------------------------------------------------------------
hpe3par_api_url | hpe3par-api-ip
hpe3par_api_url | <section>-api-ip
---------------------------------------------------------------
hpe3par_iscsi_ips | hpe3par-iscsi-ip<n>
hpe3par_iscsi_ips | <section>-iscsi-ip<n>
---------------------------------------------------------------
san_ip | hpe3par-san-ip
san_ip | <section>-san-ip
---------------------------------------------------------------
"""
@@ -1011,7 +1030,7 @@ class ServiceParameterController(rest.RestController):
# feature is enabled.
#
name = "hpe3par-api-ip"
name = section + "-api-ip"
try:
addr = pecan.request.dbapi.address_get_by_name(name)
LOG.debug("Removing address %s" % name)
@@ -1021,7 +1040,7 @@ class ServiceParameterController(rest.RestController):
i = 0
while True:
name = "hpe3par-iscsi-ip" + str(i)
name = section + "-iscsi-ip" + str(i)
try:
addr = pecan.request.dbapi.address_get_by_name(name)
LOG.debug("Removing address %s" % name)
@@ -1030,7 +1049,7 @@ class ServiceParameterController(rest.RestController):
except exception.AddressNotFoundByName:
break
name = "hpe3par-san-ip"
name = section + "-san-ip"
try:
addr = pecan.request.dbapi.address_get_by_name(name)
LOG.debug("Removing address %s" % name)
@@ -1040,7 +1059,7 @@ class ServiceParameterController(rest.RestController):
enabled = pecan.request.dbapi.service_parameter_get_one(
service=constants.SERVICE_TYPE_CINDER,
section=constants.SERVICE_PARAM_SECTION_CINDER_HPE3PAR,
section=section,
name="enabled")
if enabled.value.lower() == 'false':
@@ -1051,7 +1070,7 @@ class ServiceParameterController(rest.RestController):
#
api_url = pecan.request.dbapi.service_parameter_get_one(
service=constants.SERVICE_TYPE_CINDER,
section=constants.SERVICE_PARAM_SECTION_CINDER_HPE3PAR,
section=section,
name="hpe3par_api_url")
url = urlparse.urlparse(api_url.value)
@@ -1063,7 +1082,7 @@ class ServiceParameterController(rest.RestController):
#
if pool is not None:
try:
name = "hpe3par-api-ip"
name = section + "-api-ip"
address = {'address': str(ip),
'prefix': pool['prefix'],
'family': pool['family'],
@@ -1099,7 +1118,7 @@ class ServiceParameterController(rest.RestController):
#
if pool is not None:
try:
name = "hpe3par-iscsi-ip" + str(i)
name = section + "-iscsi-ip" + str(i)
address = {'address': str(ip),
'prefix': pool['prefix'],
'family': pool['family'],
@@ -1122,7 +1141,7 @@ class ServiceParameterController(rest.RestController):
try:
san_ip = pecan.request.dbapi.service_parameter_get_one(
service=constants.SERVICE_TYPE_CINDER,
section=constants.SERVICE_PARAM_SECTION_CINDER_HPE3PAR,
section=section,
name="san_ip")
except exception.NotFound:
return
@@ -1135,7 +1154,7 @@ class ServiceParameterController(rest.RestController):
#
if pool is not None:
try:
name = "hpe3par-san-ip"
name = section + "-san-ip"
address = {'address': str(ip),
'prefix': pool['prefix'],
'family': pool['family'],
@@ -1219,12 +1238,12 @@ class ServiceParameterController(rest.RestController):
raise wsme.exc.ClientSideError(msg)
@staticmethod
def _service_parameter_apply_semantic_check_cinder_hpe3par():
def _service_parameter_apply_semantic_check_cinder_hpe3par(section):
"""Semantic checks for the Cinder Service Type """
feature_enabled = pecan.request.dbapi.service_parameter_get_one(
service=constants.SERVICE_TYPE_CINDER,
section=constants.SERVICE_PARAM_SECTION_CINDER_HPE3PAR,
name=constants.SERVICE_PARAM_CINDER_HPE3PAR_ENABLED)
section=section,
name=constants.SERVICE_PARAM_CINDER_SAN_CHANGE_STATUS_ENABLED)
if feature_enabled.value.lower() == 'true':
# Client library installed? If not fail.
@@ -1237,21 +1256,21 @@ class ServiceParameterController(rest.RestController):
try:
pecan.request.dbapi.service_parameter_get_one(
service=constants.SERVICE_TYPE_CINDER,
section=constants.SERVICE_PARAM_SECTION_CINDER_HPE3PAR,
section=section,
name=name)
except exception.NotFound:
msg = _("Unable to apply service parameters. "
"Missing service parameter '%s' for service '%s' "
"in section '%s'." % (name,
constants.SERVICE_TYPE_CINDER,
constants.SERVICE_PARAM_SECTION_CINDER_HPE3PAR))
section))
raise wsme.exc.ClientSideError(msg)
else:
if not pecan.request.rpcapi.validate_hpe3par_removal(
pecan.request.context):
pecan.request.context, section):
msg = _("Unable to apply service parameters. Can not disable "
"%s while in use. Remove any HPE3PAR volumes."
% constants.SERVICE_PARAM_SECTION_CINDER_HPE3PAR)
% section)
raise wsme.exc.ClientSideError(msg)
@staticmethod
@@ -1260,7 +1279,7 @@ class ServiceParameterController(rest.RestController):
feature_enabled = pecan.request.dbapi.service_parameter_get_one(
service=constants.SERVICE_TYPE_CINDER,
section=constants.SERVICE_PARAM_SECTION_CINDER_HPELEFTHAND,
name=constants.SERVICE_PARAM_CINDER_HPELEFTHAND_ENABLED)
name=constants.SERVICE_PARAM_CINDER_SAN_CHANGE_STATUS_ENABLED)
if feature_enabled.value.lower() == 'true':
# Client library installed? If not fail.

View File

@@ -815,12 +815,11 @@ SERVICE_PARAM_SECTION_CINDER_EMC_VNX = 'emc_vnx'
SERVICE_PARAM_CINDER_EMC_VNX_ENABLED = 'enabled'
SERVICE_PARAM_SECTION_CINDER_EMC_VNX_STATE = 'emc_vnx.state'
SERVICE_PARAM_MAX_HPE3PAR = 12
SERVICE_PARAM_SECTION_CINDER_HPE3PAR = 'hpe3par'
SERVICE_PARAM_CINDER_HPE3PAR_ENABLED = 'enabled'
SERVICE_PARAM_SECTION_CINDER_HPE3PAR_STATE = 'hpe3par.state'
SERVICE_PARAM_SECTION_CINDER_HPELEFTHAND = 'hpelefthand'
SERVICE_PARAM_CINDER_HPELEFTHAND_ENABLED = 'enabled'
SERVICE_PARAM_SECTION_CINDER_HPELEFTHAND_STATE = 'hpelefthand.state'
SERVICE_PARAM_CINDER_SAN_CHANGE_STATUS = 'status'

View File

@@ -1173,7 +1173,7 @@ HPE_DATA_NETWORKS = [
#
CINDER_HPE3PAR_PARAMETER_MANDATORY = [
constants.SERVICE_PARAM_CINDER_HPE3PAR_ENABLED,
constants.SERVICE_PARAM_CINDER_SAN_CHANGE_STATUS_ENABLED,
]
CINDER_HPE3PAR_PARAMETER_PROTECTED = [
@@ -1205,7 +1205,7 @@ CINDER_HPE3PAR_PARAMETER_OPTIONAL = (
CINDER_HPE3PAR_PARAMETER_VALIDATOR = {
# Mandatory parameters
constants.SERVICE_PARAM_CINDER_HPE3PAR_ENABLED: _validate_boolean,
constants.SERVICE_PARAM_CINDER_SAN_CHANGE_STATUS_ENABLED: _validate_boolean,
# Required parameters
'hpe3par_api_url': _validate_hpe_api_url,
'hpe3par_username': _validate_not_empty,
@@ -1224,7 +1224,7 @@ CINDER_HPE3PAR_PARAMETER_VALIDATOR = {
CINDER_HPE3PAR_PARAMETER_RESOURCE = {
# Mandatory parameters
constants.SERVICE_PARAM_CINDER_HPE3PAR_ENABLED: None,
constants.SERVICE_PARAM_CINDER_SAN_CHANGE_STATUS_ENABLED: None,
# Required parameters
'hpe3par_api_url': None,
'hpe3par_username': None,
@@ -1246,7 +1246,7 @@ CINDER_HPE3PAR_PARAMETER_RESOURCE = {
#
CINDER_HPELEFTHAND_PARAMETER_MANDATORY = [
constants.SERVICE_PARAM_CINDER_HPELEFTHAND_ENABLED,
constants.SERVICE_PARAM_CINDER_SAN_CHANGE_STATUS_ENABLED,
]
CINDER_HPELEFTHAND_PARAMETER_PROTECTED = []
@@ -1275,7 +1275,7 @@ CINDER_HPELEFTHAND_PARAMETER_OPTIONAL = (
CINDER_HPELEFTHAND_PARAMETER_VALIDATOR = {
# Mandatory parameters
constants.SERVICE_PARAM_CINDER_HPELEFTHAND_ENABLED: _validate_boolean,
constants.SERVICE_PARAM_CINDER_SAN_CHANGE_STATUS_ENABLED: _validate_boolean,
# Required parameters
'hpelefthand_api_url': _validate_hpe_api_url,
'hpelefthand_username': _validate_not_empty,
@@ -1289,7 +1289,7 @@ CINDER_HPELEFTHAND_PARAMETER_VALIDATOR = {
CINDER_HPELEFTHAND_PARAMETER_RESOURCE = {
# Mandatory parameters
constants.SERVICE_PARAM_CINDER_HPELEFTHAND_ENABLED: None,
constants.SERVICE_PARAM_CINDER_SAN_CHANGE_STATUS_ENABLED: None,
# Required parameters
'hpelefthand_api_url': None,
'hpelefthand_username': None,

View File

@@ -443,12 +443,12 @@ class ConductorManager(service.PeriodicService):
},
{'service': constants.SERVICE_TYPE_CINDER,
'section': constants.SERVICE_PARAM_SECTION_CINDER_HPE3PAR,
'name': constants.SERVICE_PARAM_CINDER_HPE3PAR_ENABLED,
'name': constants.SERVICE_PARAM_CINDER_SAN_CHANGE_STATUS_ENABLED,
'value': False
},
{'service': constants.SERVICE_TYPE_CINDER,
'section': constants.SERVICE_PARAM_SECTION_CINDER_HPELEFTHAND,
'name': constants.SERVICE_PARAM_CINDER_HPELEFTHAND_ENABLED,
'name': constants.SERVICE_PARAM_CINDER_SAN_CHANGE_STATUS_ENABLED,
'value': False
},
{'service': constants.SERVICE_TYPE_CINDER,
@@ -510,6 +510,16 @@ class ConductorManager(service.PeriodicService):
'value': constants.SERVICE_PARAM_SWIFT_FS_SIZE_MB_DEFAULT},
]
for i in range(2, constants.SERVICE_PARAM_MAX_HPE3PAR + 1):
section = "{0}{1}".format(constants.SERVICE_PARAM_SECTION_CINDER_HPE3PAR, i)
DEFAULT_PARAMETERS.extend([
{'service': constants.SERVICE_TYPE_CINDER,
'section': section,
'name': constants.SERVICE_PARAM_CINDER_SAN_CHANGE_STATUS_ENABLED,
'value': False
}]
)
def _create_default_service_parameter(self):
""" Populate the default service parameters"""
for p in ConductorManager.DEFAULT_PARAMETERS:
@@ -4740,18 +4750,32 @@ class ConductorManager(service.PeriodicService):
of cinder services.
"""
# Only run audit of either one of the backends is enabled
# Only run audit if any one of the backends is enabled
hpe3par_enabled = False
try:
param = self.dbapi.service_parameter_get_one(constants.SERVICE_TYPE_CINDER,
constants.SERVICE_PARAM_SECTION_CINDER_HPE3PAR, 'enabled')
constants.SERVICE_PARAM_SECTION_CINDER_HPE3PAR,
constants.SERVICE_PARAM_CINDER_SAN_CHANGE_STATUS_ENABLED)
hpe3par_enabled = param.value.lower() == 'true'
except exception.NotFound:
hpe3par_enabled = False
pass
if not hpe3par_enabled:
for i in range(2, constants.SERVICE_PARAM_MAX_HPE3PAR + 1):
section = "{0}{1}".format(constants.SERVICE_PARAM_SECTION_CINDER_HPE3PAR, i)
try:
param = self.dbapi.service_parameter_get_one(constants.SERVICE_TYPE_CINDER,
constants.SERVICE_PARAM_SECTION_CINDER_HPELEFTHAND, 'enabled')
section,
constants.SERVICE_PARAM_CINDER_SAN_CHANGE_STATUS_ENABLED)
hpe3par_enabled = param.value.lower() == 'true'
except exception.NotFound:
pass
if hpe3par_enabled:
break
try:
param = self.dbapi.service_parameter_get_one(constants.SERVICE_TYPE_CINDER,
constants.SERVICE_PARAM_SECTION_CINDER_HPELEFTHAND,
constants.SERVICE_PARAM_CINDER_SAN_CHANGE_STATUS_ENABLED)
hpelefthand_enabled = param.value.lower() == 'true'
except exception.NotFound:
hpelefthand_enabled = False
@@ -6991,12 +7015,28 @@ class ConductorManager(service.PeriodicService):
status_param = self._hpe_get_state(name)
status = status_param.value
enabled = False
try:
enabled_param = self.dbapi.service_parameter_get_one(
constants.SERVICE_TYPE_CINDER, name,
constants.SERVICE_PARAM_CINDER_SAN_CHANGE_STATUS_ENABLED
)
enabled = (enabled_param.value.lower() == 'true')
except exception.NotFound:
pass
if not enabled and name == constants.SERVICE_PARAM_SECTION_CINDER_HPE3PAR:
for i in range(2, constants.SERVICE_PARAM_MAX_HPE3PAR + 1):
section = "{0}{1}".format(name, i)
try:
enabled_param = self.dbapi.service_parameter_get_one(
constants.SERVICE_TYPE_CINDER, section,
constants.SERVICE_PARAM_CINDER_SAN_CHANGE_STATUS_ENABLED
)
enabled = (enabled_param.value.lower() == 'true')
except exception.NotFound:
pass
if enabled:
break
if enabled and status == constants.SERVICE_PARAM_CINDER_SAN_CHANGE_STATUS_DISABLED:
do_update = True
new_state = constants.SERVICE_PARAM_CINDER_SAN_CHANGE_STATUS_ENABLED
@@ -9231,7 +9271,7 @@ class ConductorManager(service.PeriodicService):
return not emc_volume_found
def validate_hpe3par_removal(self, context):
def validate_hpe3par_removal(self, context, backend):
"""
Check that it is safe to remove the HPE3PAR SAN
Ensure there are no volumes using the HPE3PAR endpoint
@@ -9240,7 +9280,7 @@ class ConductorManager(service.PeriodicService):
for volume in self._openstack.get_cinder_volumes():
end_point = getattr(volume, 'os-vol-host-attr:host', '')
if end_point and '@hpe3par' in end_point:
if end_point and '@' + backend + '#' in end_point:
volume_found = True
break

View File

@@ -1368,11 +1368,13 @@ class ConductorAPI(sysinv.openstack.common.rpc.proxy.RpcProxy):
"""
return self.call(context, self.make_msg('validate_emc_removal'))
def validate_hpe3par_removal(self, context):
def validate_hpe3par_removal(self, context, backend):
"""
Check that it is safe to remove the HPE 3PAR storage array
"""
return self.call(context, self.make_msg('validate_hpe3par_removal'))
return self.call(context,
self.make_msg('validate_hpe3par_removal',
backend=backend))
def validate_hpelefthand_removal(self, context):
"""

View File

@@ -250,7 +250,7 @@ def sp_hpe3par_post_process(config, section, section_map,
if provided_params.get('enabled', 'false').lower() == 'true':
# Hardcoded params must exist in cinder.conf.
provided_params['volume_backend_name'] = SP_CINDER_HPE3PAR
provided_params['volume_backend_name'] = section
provided_params['volume_driver'] = (
'cinder.volume.drivers.hpe.hpe_3par_iscsi.HPE3PARISCSIDriver')
@@ -345,6 +345,18 @@ class CinderPuppet(openstack.OpenstackBasePuppet):
SERVICE_PATH_V3 = 'v3/%(tenant_id)s'
PROXY_SERVICE_PORT = '28776'
def __init__(self, *args, **kwargs):
super(CinderPuppet, self).__init__(*args, **kwargs)
# Update the section mapping for multiple HPE3PAR backends
for i in range(2, constants.SERVICE_PARAM_MAX_HPE3PAR + 1):
section = "{0}{1}".format(SP_CINDER_HPE3PAR, i)
prefix = "{0}{1}".format(SP_CINDER_HPE3PAR_PREFIX, i)
SP_CINDER_SECTION_MAPPING[section] = {
SP_CONF_NAME_KEY: prefix,
SP_PARAM_PROCESS_KEY: sp_common_param_process,
SP_POST_PROCESS_KEY: sp_hpe3par_post_process,
}
def get_static_config(self):
dbuser = self._get_database_username(self.SERVICE_NAME)
@@ -755,6 +767,11 @@ class CinderPuppet(openstack.OpenstackBasePuppet):
config, section, sp_section_map,
is_service_enabled, enabled_backends)
# Build the list of possible HPE3PAR backends
possible_hpe3pars = filter(
lambda s: constants.SERVICE_PARAM_SECTION_CINDER_HPE3PAR in s,
SP_CINDER_SECTION_MAPPING.keys())
config.update({'openstack::cinder::backends::hpe3par::sections': possible_hpe3pars})
return config
def is_service_enabled(self):