Merge "Improve Hitachi HNAS volume drivers log messages"

This commit is contained in:
Jenkins 2016-08-24 23:30:37 +00:00 committed by Gerrit Code Review
commit dbebca66b0
5 changed files with 188 additions and 121 deletions

View File

@ -254,10 +254,20 @@ class HNASiSCSIDriverTest(test.TestCase):
'172.17.39.133': {'evs_number': 2}, '172.17.39.133': {'evs_number': 2},
'172.17.39.134': {'evs_number': 3}} '172.17.39.134': {'evs_number': 3}}
version_info = {
'mac': '83-68-96-AA-DA-5D',
'model': 'HNAS 4040',
'version': '12.4.3924.11',
'hardware': 'NAS Platform',
'serial': 'B1339109',
}
self.mock_object(HNASSSHBackend, 'get_fs_info', self.mock_object(HNASSSHBackend, 'get_fs_info',
mock.Mock(return_value=True)) mock.Mock(return_value=True))
self.mock_object(HNASSSHBackend, 'get_evs_info', self.mock_object(HNASSSHBackend, 'get_evs_info',
mock.Mock(return_value=evs_info)) mock.Mock(return_value=evs_info))
self.mock_object(HNASSSHBackend, 'get_version',
mock.Mock(return_value=version_info))
self.driver.do_setup(None) self.driver.do_setup(None)
@ -269,10 +279,20 @@ class HNASiSCSIDriverTest(test.TestCase):
'172.17.39.133': {'evs_number': 2}, '172.17.39.133': {'evs_number': 2},
'172.17.39.134': {'evs_number': 3}} '172.17.39.134': {'evs_number': 3}}
version_info = {
'mac': '83-68-96-AA-DA-5D',
'model': 'HNAS 4040',
'version': '12.4.3924.11',
'hardware': 'NAS Platform',
'serial': 'B1339109',
}
self.mock_object(HNASSSHBackend, 'get_fs_info', self.mock_object(HNASSSHBackend, 'get_fs_info',
mock.Mock(return_value=True)) mock.Mock(return_value=True))
self.mock_object(HNASSSHBackend, 'get_evs_info', self.mock_object(HNASSSHBackend, 'get_evs_info',
mock.Mock(return_value=evs_info)) mock.Mock(return_value=evs_info))
self.mock_object(HNASSSHBackend, 'get_version',
mock.Mock(return_value=version_info))
self.assertRaises(exception.InvalidParameterValue, self.assertRaises(exception.InvalidParameterValue,
self.driver.do_setup, None) self.driver.do_setup, None)

View File

@ -82,12 +82,12 @@ class HNASSSHBackend(object):
return out, err return out, err
except putils.ProcessExecutionError as e: except putils.ProcessExecutionError as e:
if 'Failed to establish SSC connection' in e.stderr: if 'Failed to establish SSC connection' in e.stderr:
LOG.debug("SSC connection error!") msg = _("Failed to establish SSC connection!")
msg = _("Failed to establish SSC connection.") LOG.exception(msg)
raise exception.HNASConnError(msg) raise exception.HNASConnError(msg)
elif 'Connection reset' in e.stderr: elif 'Connection reset' in e.stderr:
LOG.debug("HNAS connection reset!") msg = _("HNAS connection reset!")
msg = _("HNAS has disconnected SSC") LOG.exception(msg)
raise exception.HNASConnError(msg) raise exception.HNASConnError(msg)
else: else:
raise raise
@ -124,6 +124,7 @@ class HNASSSHBackend(object):
self.storage_version = version_info self.storage_version = version_info
LOG.debug("version_info: %(info)s", {'info': self.storage_version})
return self.storage_version return self.storage_version
def get_evs_info(self): def get_evs_info(self):
@ -236,7 +237,10 @@ class HNASSSHBackend(object):
# When the FS is found in the list of known FS, returns the EVS ID # When the FS is found in the list of known FS, returns the EVS ID
for key in self.fslist: for key in self.fslist:
if fs_label == self.fslist[key]['label']: if fs_label == self.fslist[key]['label']:
LOG.debug("EVS ID for fs %(fs)s: %(id)s.",
{'fs': fs_label, 'id': self.fslist[key]['evsid']})
return self.fslist[key]['evsid'] return self.fslist[key]['evsid']
LOG.debug("Can't find EVS ID for fs %(fs)s.", {'fs': fs_label})
def _get_targets(self, evs_id, tgt_alias=None, refresh=False): def _get_targets(self, evs_id, tgt_alias=None, refresh=False):
"""Gets the target list of an EVS. """Gets the target list of an EVS.
@ -365,11 +369,13 @@ class HNASSSHBackend(object):
if not fs: if not fs:
LOG.error(_LE("Can't find file %(file)s in FS %(label)s"), LOG.error(_LE("Can't find file %(file)s in FS %(label)s"),
{'file': src, 'label': fs_label}) {'file': src, 'label': fs_label})
msg = _('FS label: %s') % fs_label msg = _('FS label: %(fs_label)s') % {'fs_label': fs_label}
raise exception.InvalidParameterValue(err=msg) raise exception.InvalidParameterValue(err=msg)
self._run_cmd("console-context", "--evs", fs['evsid'], self._run_cmd("console-context", "--evs", fs['evsid'],
'file-clone-create', '-f', fs_label, src, name) 'file-clone-create', '-f', fs_label, src, name)
LOG.debug('file_clone: fs:%(fs_label)s %(src)s/src: -> %(name)s/dst',
{'fs_label': fs_label, 'src': src, 'name': name})
def extend_lu(self, fs_label, new_size, lu_name): def extend_lu(self, fs_label, new_size, lu_name):
"""Extends an iSCSI volume. """Extends an iSCSI volume.
@ -433,6 +439,7 @@ class HNASSSHBackend(object):
LOG.debug('add_iscsi_conn: LU %(lu)s added to %(tgt)s.', LOG.debug('add_iscsi_conn: LU %(lu)s added to %(tgt)s.',
{'lu': lu_name, 'tgt': tgt_alias}) {'lu': lu_name, 'tgt': tgt_alias})
LOG.debug('conn_info: %(conn_info)s', {'conn_info': conn_info})
return conn_info return conn_info
@ -487,7 +494,10 @@ class HNASSSHBackend(object):
for line in lines: for line in lines:
if 'Globally unique name' in line: if 'Globally unique name' in line:
full_iqn = line.split()[3] full_iqn = line.split()[3]
LOG.debug('get_target_iqn: %(iqn)s', {'iqn': full_iqn})
return full_iqn return full_iqn
LOG.debug("Could not find iqn for alias %(alias)s on fs %(fs_label)s",
{'alias': tgt_alias, 'fs_label': fs_label})
def set_target_secret(self, targetalias, fs_label, secret): def set_target_secret(self, targetalias, fs_label, secret):
"""Sets the chap secret for the specified target. """Sets the chap secret for the specified target.
@ -598,7 +608,8 @@ class HNASSSHBackend(object):
lu_info['id'] = 0 lu_info['id'] = 0
lu_info['tgt'] = None lu_info['tgt'] = None
LOG.debug("LU %(lu)s not attached.", {'lu': vol_name}) LOG.debug("LU %(lu)s not attached. lu_info: %(lu_info)s",
{'lu': vol_name, 'lu_info': lu_info})
return lu_info return lu_info
@ -769,6 +780,7 @@ class HNASSSHBackend(object):
export_list.append(export_info) export_list.append(export_info)
LOG.debug("get_export_list: %(exp_list)s", {'exp_list': export_list})
return export_list return export_list
def create_cloned_lu(self, src_lu, fs_label, clone_name): def create_cloned_lu(self, src_lu, fs_label, clone_name):
@ -799,3 +811,5 @@ class HNASSSHBackend(object):
'iscsi-target', 'add', tgt_alias, secret) 'iscsi-target', 'add', tgt_alias, secret)
self._get_targets(_evs_id, refresh=True) self._get_targets(_evs_id, refresh=True)
LOG.debug("create_target: alias: %(alias)s fs_label: %(fs_label)s",
{'alias': tgt_alias, 'fs_label': fs_label})

View File

@ -140,15 +140,15 @@ class HNASISCSIDriver(driver.ISCSIDriver):
configuration is found. configuration is found.
:raises: ParameterNotFound :raises: ParameterNotFound
""" """
LOG.debug("Available services: %(svc)s.",
{'svc': self.config['services'].keys()})
label = utils.extract_host(volume.host, level='pool') label = utils.extract_host(volume.host, level='pool')
LOG.info(_LI("Using service label: %(lbl)s."), {'lbl': label})
if label in self.config['services'].keys(): if label in self.config['services'].keys():
svc = self.config['services'][label] svc = self.config['services'][label]
LOG.info(_LI("Using service label: %(lbl)s."), {'lbl': label})
return svc['hdp'] return svc['hdp']
else: else:
LOG.info(_LI("Available services: %(svc)s."),
{'svc': self.config['services'].keys()})
LOG.error(_LE("No configuration found for service: %(lbl)s."), LOG.error(_LE("No configuration found for service: %(lbl)s."),
{'lbl': label}) {'lbl': label})
raise exception.ParameterNotFound(param=label) raise exception.ParameterNotFound(param=label)
@ -176,6 +176,10 @@ class HNASISCSIDriver(driver.ISCSIDriver):
service = ( service = (
svc['iscsi_ip'], svc['iscsi_port'], svc['evs'], svc['port'], svc['iscsi_ip'], svc['iscsi_port'], svc['evs'], svc['port'],
fs_label, lu_info['tgt']['alias'], lu_info['tgt']['secret']) fs_label, lu_info['tgt']['alias'], lu_info['tgt']['secret'])
LOG.info(_LI("Volume %(vol_name)s already mapped on target "
"%(tgt)s to LUN %(lunid)s."),
{'vol_name': volume.name, 'tgt': lu_info['tgt']['alias'],
'lunid': lu_info['id']})
return service return service
# Each EVS can have up to 32 targets. Each target can have up to 32 # Each EVS can have up to 32 targets. Each target can have up to 32
@ -291,11 +295,11 @@ class HNASISCSIDriver(driver.ISCSIDriver):
hnas_stat['pools'] = self.pools hnas_stat['pools'] = self.pools
LOG.info(_LI("stats: %(stat)s."), {'stat': hnas_stat}) LOG.debug("stats: %(stat)s.", {'stat': hnas_stat})
return hnas_stat return hnas_stat
def _check_fs_list(self): def _check_fs_list(self):
"""Verifies the FSs in HNAS array. """Verifies the FSs list in HNAS.
Verify that all FSs specified in the configuration files actually Verify that all FSs specified in the configuration files actually
exists on the storage. exists on the storage.
@ -304,8 +308,7 @@ class HNASISCSIDriver(driver.ISCSIDriver):
for fs in fs_list: for fs in fs_list:
if not self.backend.get_fs_info(fs): if not self.backend.get_fs_info(fs):
msg = ( msg = (_("File system not found or not mounted: %(fs)s") %
_("File system not found or not mounted: %(fs)s") %
{'fs': fs}) {'fs': fs})
LOG.error(msg) LOG.error(msg)
raise exception.ParameterNotFound(param=msg) raise exception.ParameterNotFound(param=msg)
@ -324,22 +327,22 @@ class HNASISCSIDriver(driver.ISCSIDriver):
pool_from_vol_type = hnas_utils.get_pool(self.config, volume) pool_from_vol_type = hnas_utils.get_pool(self.config, volume)
pool_from_host = utils.extract_host(volume.host, level='pool') pool_from_host = utils.extract_host(volume.host, level='pool')
pool = self.config['services'][pool_from_vol_type]['hdp']
if self.config['services'][pool_from_vol_type]['hdp'] != fs_label: if pool != fs_label:
msg = (_("Failed to manage existing volume because the pool of " msg = (_("Failed to manage existing volume because the "
"the volume type chosen does not match the file system " "pool %(pool)s of the volume type chosen does not "
"passed in the volume reference."), "match the file system %(fs_label)s passed in the "
{'File System passed': fs_label, "volume reference.")
'File System for volume type': % {'pool': pool, 'fs_label': fs_label})
self.config['services'][pool_from_vol_type]['hdp']}) LOG.error(msg)
raise exception.ManageExistingVolumeTypeMismatch(reason=msg) raise exception.ManageExistingVolumeTypeMismatch(reason=msg)
if pool_from_host != pool_from_vol_type: if pool_from_host != pool_from_vol_type:
msg = (_("Failed to manage existing volume because the pool of " msg = (_("Failed to manage existing volume because the pool "
"the volume type chosen does not match the pool of " "%(pool)s of the volume type chosen does not match the "
"the host."), "pool %(pool_host)s of the host.") %
{'Pool of the volume type': pool_from_vol_type, {'pool': pool_from_vol_type, 'pool_host': pool_from_host})
'Pool of the host': pool_from_host}) LOG.error(msg)
raise exception.ManageExistingVolumeTypeMismatch(reason=msg) raise exception.ManageExistingVolumeTypeMismatch(reason=msg)
def _get_info_from_vol_ref(self, vol_ref): def _get_info_from_vol_ref(self, vol_ref):
@ -360,9 +363,10 @@ class HNASISCSIDriver(driver.ISCSIDriver):
return fs_label, vol_name return fs_label, vol_name
else: else:
msg = (_("The reference to the volume in the backend should have " msg = _("The reference to the volume in the backend should have "
"the format file_system/volume_name (volume_name cannot " "the format file_system/volume_name (volume_name cannot "
"contain '/')")) "contain '/')")
LOG.error(msg)
raise exception.ManageExistingInvalidReference( raise exception.ManageExistingInvalidReference(
existing_ref=vol_ref, reason=msg) existing_ref=vol_ref, reason=msg)
@ -374,6 +378,14 @@ class HNASISCSIDriver(driver.ISCSIDriver):
self.context = context self.context = context
self._check_fs_list() self._check_fs_list()
version_info = self.backend.get_version()
LOG.info(_LI("HNAS iSCSI driver."))
LOG.info(_LI("HNAS model: %(mdl)s"), {'mdl': version_info['model']})
LOG.info(_LI("HNAS version: %(version)s"),
{'version': version_info['version']})
LOG.info(_LI("HNAS hardware: %(hw)s"),
{'hw': version_info['hardware']})
LOG.info(_LI("HNAS S/N: %(sn)s"), {'sn': version_info['serial']})
service_list = self.config['services'].keys() service_list = self.config['services'].keys()
for svc in service_list: for svc in service_list:
svc = self.config['services'][svc] svc = self.config['services'][svc]
@ -384,7 +396,7 @@ class HNASISCSIDriver(driver.ISCSIDriver):
self.pools.append(pool) self.pools.append(pool)
LOG.info(_LI("Configured pools: %(pool)s"), {'pool': self.pools}) LOG.debug("Configured pools: %(pool)s", {'pool': self.pools})
evs_info = self.backend.get_evs_info() evs_info = self.backend.get_evs_info()
LOG.info(_LI("Configured EVSs: %(evs)s"), {'evs': evs_info}) LOG.info(_LI("Configured EVSs: %(evs)s"), {'evs': evs_info})
@ -392,7 +404,8 @@ class HNASISCSIDriver(driver.ISCSIDriver):
for svc in self.config['services'].keys(): for svc in self.config['services'].keys():
svc_ip = self.config['services'][svc]['iscsi_ip'] svc_ip = self.config['services'][svc]['iscsi_ip']
if svc_ip in evs_info.keys(): if svc_ip in evs_info.keys():
LOG.info(_LI("iSCSI portal found for service: %s"), svc_ip) LOG.info(_LI("iSCSI portal found for service: %(svc_ip)s"),
{'svc_ip': svc_ip})
self.config['services'][svc]['evs'] = ( self.config['services'][svc]['evs'] = (
evs_info[svc_ip]['evs_number']) evs_info[svc_ip]['evs_number'])
self.config['services'][svc]['iscsi_port'] = '3260' self.config['services'][svc]['iscsi_port'] = '3260'
@ -401,6 +414,7 @@ class HNASISCSIDriver(driver.ISCSIDriver):
LOG.error(_LE("iSCSI portal not found " LOG.error(_LE("iSCSI portal not found "
"for service: %(svc)s"), {'svc': svc_ip}) "for service: %(svc)s"), {'svc': svc_ip})
raise exception.InvalidParameterValue(err=svc_ip) raise exception.InvalidParameterValue(err=svc_ip)
LOG.info(_LI("HNAS iSCSI Driver loaded successfully."))
def ensure_export(self, context, volume): def ensure_export(self, context, volume):
pass pass
@ -411,6 +425,7 @@ class HNASISCSIDriver(driver.ISCSIDriver):
def remove_export(self, context, volume): def remove_export(self, context, volume):
pass pass
@cinder_utils.trace
def create_volume(self, volume): def create_volume(self, volume):
"""Creates a LU on HNAS. """Creates a LU on HNAS.
@ -422,11 +437,9 @@ class HNASISCSIDriver(driver.ISCSIDriver):
self.backend.create_lu(fs, size, volume.name) self.backend.create_lu(fs, size, volume.name)
LOG.info(_LI("LU %(lu)s of size %(sz)s GB is created."),
{'lu': volume.name, 'sz': volume.size})
return {'provider_location': self._get_provider_location(volume)} return {'provider_location': self._get_provider_location(volume)}
@cinder_utils.trace
def create_cloned_volume(self, dst, src): def create_cloned_volume(self, dst, src):
"""Creates a clone of a volume. """Creates a clone of a volume.
@ -439,14 +452,14 @@ class HNASISCSIDriver(driver.ISCSIDriver):
self.backend.create_cloned_lu(src.name, fs_label, dst.name) self.backend.create_cloned_lu(src.name, fs_label, dst.name)
if src.size < dst.size: if src.size < dst.size:
size = dst.size LOG.debug("Increasing dest size from %(old_size)s to "
self.extend_volume(dst, size) "%(new_size)s",
{'old_size': src.size, 'new_size': dst.size})
LOG.debug("LU %(lu)s of size %(size)d GB is cloned.", self.extend_volume(dst, dst.size)
{'lu': src.name, 'size': src.size})
return {'provider_location': self._get_provider_location(dst)} return {'provider_location': self._get_provider_location(dst)}
@cinder_utils.trace
def extend_volume(self, volume, new_size): def extend_volume(self, volume, new_size):
"""Extends an existing volume. """Extends an existing volume.
@ -456,9 +469,7 @@ class HNASISCSIDriver(driver.ISCSIDriver):
fs = self._get_service(volume) fs = self._get_service(volume)
self.backend.extend_lu(fs, new_size, volume.name) self.backend.extend_lu(fs, new_size, volume.name)
LOG.info(_LI("LU %(lu)s extended to %(size)s GB."), @cinder_utils.trace
{'lu': volume.name, 'size': new_size})
def delete_volume(self, volume): def delete_volume(self, volume):
"""Deletes the volume on HNAS. """Deletes the volume on HNAS.
@ -467,9 +478,8 @@ class HNASISCSIDriver(driver.ISCSIDriver):
fs = self._get_service(volume) fs = self._get_service(volume)
self.backend.delete_lu(fs, volume.name) self.backend.delete_lu(fs, volume.name)
LOG.debug("Delete LU %(lu)s", {'lu': volume.name})
@cinder_utils.synchronized('volume_mapping') @cinder_utils.synchronized('volume_mapping')
@cinder_utils.trace
def initialize_connection(self, volume, connector): def initialize_connection(self, volume, connector):
"""Maps the created volume to connector['initiator']. """Maps the created volume to connector['initiator'].
@ -478,9 +488,6 @@ class HNASISCSIDriver(driver.ISCSIDriver):
:returns: The connection information :returns: The connection information
:raises: ISCSITargetAttachFailed :raises: ISCSITargetAttachFailed
""" """
LOG.info(_LI("initialize volume %(vol)s connector %(conn)s"),
{'vol': volume, 'conn': connector})
service_info = self._get_service_target(volume) service_info = self._get_service_target(volume)
(ip, ipp, evs, port, _fs, tgtalias, secret) = service_info (ip, ipp, evs, port, _fs, tgtalias, secret) = service_info
@ -492,7 +499,8 @@ class HNASISCSIDriver(driver.ISCSIDriver):
except processutils.ProcessExecutionError: except processutils.ProcessExecutionError:
msg = (_("Error attaching volume %(vol)s. " msg = (_("Error attaching volume %(vol)s. "
"Target limit might be reached!") % {'vol': volume.id}) "Target limit might be reached!") % {'vol': volume.id})
raise exception.ISCSITargetAttachFailed(message=msg) LOG.error(msg)
raise exception.ISCSITargetAttachFailed(volume_id=volume.id)
hnas_portal = ip + ':' + ipp hnas_portal = ip + ':' + ipp
lu_id = six.text_type(conn['lu_id']) lu_id = six.text_type(conn['lu_id'])
@ -501,7 +509,7 @@ class HNASISCSIDriver(driver.ISCSIDriver):
volume.provider_location + ',' + evs + ',' + volume.provider_location + ',' + evs + ',' +
port + ',' + lu_id) port + ',' + lu_id)
LOG.info(_LI("initiate: connection %s"), tgt) LOG.info(_LI("initiate: connection %(tgt)s"), {'tgt': tgt})
properties = {} properties = {}
properties['provider_location'] = tgt properties['provider_location'] = tgt
@ -517,12 +525,11 @@ class HNASISCSIDriver(driver.ISCSIDriver):
properties['auth_password'] = secret properties['auth_password'] = secret
conn_info = {'driver_volume_type': 'iscsi', 'data': properties} conn_info = {'driver_volume_type': 'iscsi', 'data': properties}
LOG.debug("initialize_connection: conn_info: %(conn)s.",
{'conn': conn_info})
return conn_info return conn_info
@cinder_utils.synchronized('volume_mapping') @cinder_utils.synchronized('volume_mapping')
@cinder_utils.trace
def terminate_connection(self, volume, connector, **kwargs): def terminate_connection(self, volume, connector, **kwargs):
"""Terminate a connection to a volume. """Terminate a connection to a volume.
@ -535,9 +542,7 @@ class HNASISCSIDriver(driver.ISCSIDriver):
self.backend.del_iscsi_conn(evs, tgtalias, lu_info['id']) self.backend.del_iscsi_conn(evs, tgtalias, lu_info['id'])
LOG.info(_LI("terminate_connection: %(vol)s"), @cinder_utils.trace
{'vol': volume.provider_location})
def create_volume_from_snapshot(self, volume, snapshot): def create_volume_from_snapshot(self, volume, snapshot):
"""Creates a volume from a snapshot. """Creates a volume from a snapshot.
@ -549,11 +554,9 @@ class HNASISCSIDriver(driver.ISCSIDriver):
self.backend.create_cloned_lu(snapshot.name, fs, volume.name) self.backend.create_cloned_lu(snapshot.name, fs, volume.name)
LOG.info(_LI("LU %(lu)s of size %(sz)d MB is created."),
{'lu': snapshot.name, 'sz': snapshot.volume_size})
return {'provider_location': self._get_provider_location(snapshot)} return {'provider_location': self._get_provider_location(snapshot)}
@cinder_utils.trace
def create_snapshot(self, snapshot): def create_snapshot(self, snapshot):
"""Creates a snapshot. """Creates a snapshot.
@ -564,11 +567,9 @@ class HNASISCSIDriver(driver.ISCSIDriver):
self.backend.create_cloned_lu(snapshot.volume_name, fs, snapshot.name) self.backend.create_cloned_lu(snapshot.volume_name, fs, snapshot.name)
LOG.debug("LU %(lu)s of size %(size)d GB is created.",
{'lu': snapshot.name, 'size': snapshot.volume_size})
return {'provider_location': self._get_provider_location(snapshot)} return {'provider_location': self._get_provider_location(snapshot)}
@cinder_utils.trace
def delete_snapshot(self, snapshot): def delete_snapshot(self, snapshot):
"""Deletes a snapshot. """Deletes a snapshot.
@ -577,8 +578,6 @@ class HNASISCSIDriver(driver.ISCSIDriver):
fs = self._get_service(snapshot.volume) fs = self._get_service(snapshot.volume)
self.backend.delete_lu(fs, snapshot.name) self.backend.delete_lu(fs, snapshot.name)
LOG.debug("Delete lu %(lu)s", {'lu': snapshot.name})
def get_volume_stats(self, refresh=False): def get_volume_stats(self, refresh=False):
"""Gets the volume driver stats. """Gets the volume driver stats.
@ -590,6 +589,7 @@ class HNASISCSIDriver(driver.ISCSIDriver):
return self.driver_stats return self.driver_stats
@cinder_utils.trace
def manage_existing_get_size(self, volume, existing_vol_ref): def manage_existing_get_size(self, volume, existing_vol_ref):
"""Gets the size to manage_existing. """Gets the size to manage_existing.
@ -627,6 +627,7 @@ class HNASISCSIDriver(driver.ISCSIDriver):
'If your volume name contains "/", please rename it ' 'If your volume name contains "/", please rename it '
'and try to manage again.')) 'and try to manage again.'))
@cinder_utils.trace
def manage_existing(self, volume, existing_vol_ref): def manage_existing(self, volume, existing_vol_ref):
"""Manages an existing volume. """Manages an existing volume.
@ -641,13 +642,13 @@ class HNASISCSIDriver(driver.ISCSIDriver):
volume volume
:returns: the provider location of the volume managed :returns: the provider location of the volume managed
""" """
LOG.info(_LI("Asked to manage ISCSI volume %(vol)s, with vol "
"ref %(ref)s."), {'vol': volume.id,
'ref': existing_vol_ref['source-name']})
fs_label, vol_name = ( fs_label, vol_name = (
self._get_info_from_vol_ref(existing_vol_ref['source-name'])) self._get_info_from_vol_ref(existing_vol_ref['source-name']))
LOG.debug("Asked to manage ISCSI volume %(vol)s, with vol "
"ref %(ref)s.", {'vol': volume.id,
'ref': existing_vol_ref['source-name']})
if volume.volume_type is not None: if volume.volume_type is not None:
self._check_pool_and_fs(volume, fs_label) self._check_pool_and_fs(volume, fs_label)
@ -658,6 +659,7 @@ class HNASISCSIDriver(driver.ISCSIDriver):
return {'provider_location': self._get_provider_location(volume)} return {'provider_location': self._get_provider_location(volume)}
@cinder_utils.trace
def unmanage(self, volume): def unmanage(self, volume):
"""Unmanages a volume from cinder. """Unmanages a volume from cinder.
@ -674,9 +676,10 @@ class HNASISCSIDriver(driver.ISCSIDriver):
self.backend.rename_existing_lu(fslabel, volume.name, new_name) self.backend.rename_existing_lu(fslabel, volume.name, new_name)
LOG.info(_LI("Cinder ISCSI volume with current path %(path)s is " LOG.info(_LI("The volume with path %(old)s is no longer being managed "
"no longer being managed. The new name is %(unm)s."), "by Cinder. However, it was not deleted and can be found "
{'path': vol_path, 'unm': new_name}) "with the new name %(cr)s on backend."),
{'old': vol_path, 'cr': new_name})
def _get_provider_location(self, volume): def _get_provider_location(self, volume):
"""Gets the provider location of a given volume """Gets the provider location of a given volume

View File

@ -130,7 +130,7 @@ class HNASNFSDriver(nfs.NfsDriver):
if label in self.config['services'].keys(): if label in self.config['services'].keys():
svc = self.config['services'][label] svc = self.config['services'][label]
LOG.info(_LI("_get_service: %(lbl)s->%(svc)s"), LOG.debug("_get_service: %(lbl)s->%(svc)s",
{'lbl': label, 'svc': svc['export']['fs']}) {'lbl': label, 'svc': svc['export']['fs']})
service = (svc['hdp'], svc['export']['path'], svc['export']['fs']) service = (svc['hdp'], svc['export']['path'], svc['export']['fs'])
else: else:
@ -142,6 +142,7 @@ class HNASNFSDriver(nfs.NfsDriver):
return service return service
@cutils.trace
def extend_volume(self, volume, new_size): def extend_volume(self, volume, new_size):
"""Extend an existing volume. """Extend an existing volume.
@ -153,7 +154,7 @@ class HNASNFSDriver(nfs.NfsDriver):
path = self._get_volume_path(nfs_mount, volume.name) path = self._get_volume_path(nfs_mount, volume.name)
# Resize the image file on share to new size. # Resize the image file on share to new size.
LOG.debug("Checking file for resize") LOG.info(_LI("Checking file for resize."))
if not self._is_file_size_equal(path, new_size): if not self._is_file_size_equal(path, new_size):
LOG.info(_LI("Resizing file to %(sz)sG"), {'sz': new_size}) LOG.info(_LI("Resizing file to %(sz)sG"), {'sz': new_size})
@ -163,7 +164,9 @@ class HNASNFSDriver(nfs.NfsDriver):
LOG.info(_LI("LUN %(id)s extended to %(size)s GB."), LOG.info(_LI("LUN %(id)s extended to %(size)s GB."),
{'id': volume.id, 'size': new_size}) {'id': volume.id, 'size': new_size})
else: else:
raise exception.InvalidResults(_("Resizing image file failed.")) msg = _("Resizing image file failed.")
LOG.error(msg)
raise exception.InvalidResults(msg)
def _is_file_size_equal(self, path, size): def _is_file_size_equal(self, path, size):
"""Checks if file size at path is equal to size.""" """Checks if file size at path is equal to size."""
@ -175,6 +178,7 @@ class HNASNFSDriver(nfs.NfsDriver):
else: else:
return False return False
@cutils.trace
def create_volume_from_snapshot(self, volume, snapshot): def create_volume_from_snapshot(self, volume, snapshot):
"""Creates a volume from a snapshot. """Creates a volume from a snapshot.
@ -182,13 +186,12 @@ class HNASNFSDriver(nfs.NfsDriver):
:param snapshot: source snapshot :param snapshot: source snapshot
:returns: the provider_location of the volume created :returns: the provider_location of the volume created
""" """
LOG.debug("create_volume_from %(vol)s", {'vol': volume})
self._clone_volume(snapshot.volume, volume.name, snapshot.name) self._clone_volume(snapshot.volume, volume.name, snapshot.name)
share = snapshot.volume.provider_location share = snapshot.volume.provider_location
return {'provider_location': share} return {'provider_location': share}
@cutils.trace
def create_snapshot(self, snapshot): def create_snapshot(self, snapshot):
"""Create a snapshot. """Create a snapshot.
@ -203,12 +206,12 @@ class HNASNFSDriver(nfs.NfsDriver):
# returns the mount point (not path) # returns the mount point (not path)
return {'provider_location': share} return {'provider_location': share}
@cutils.trace
def delete_snapshot(self, snapshot): def delete_snapshot(self, snapshot):
"""Deletes a snapshot. """Deletes a snapshot.
:param snapshot: dictionary snapshot reference :param snapshot: dictionary snapshot reference
""" """
nfs_mount = snapshot.volume.provider_location nfs_mount = snapshot.volume.provider_location
if self._volume_not_present(nfs_mount, snapshot.name): if self._volume_not_present(nfs_mount, snapshot.name):
@ -244,6 +247,7 @@ class HNASNFSDriver(nfs.NfsDriver):
return os.path.join(self._get_mount_point_for_share(nfs_share), return os.path.join(self._get_mount_point_for_share(nfs_share),
volume_name) volume_name)
@cutils.trace
def create_cloned_volume(self, volume, src_vref): def create_cloned_volume(self, volume, src_vref):
"""Creates a clone of the specified volume. """Creates a clone of the specified volume.
@ -277,6 +281,8 @@ class HNASNFSDriver(nfs.NfsDriver):
'reserved_percentage': percentage of size reserved 'reserved_percentage': percentage of size reserved
} }
""" """
LOG.info(_LI("Getting volume stats"))
_stats = super(HNASNFSDriver, self).get_volume_stats(refresh) _stats = super(HNASNFSDriver, self).get_volume_stats(refresh)
_stats["vendor_name"] = 'Hitachi' _stats["vendor_name"] = 'Hitachi'
_stats["driver_version"] = HNAS_NFS_VERSION _stats["driver_version"] = HNAS_NFS_VERSION
@ -292,18 +298,20 @@ class HNASNFSDriver(nfs.NfsDriver):
_stats['pools'] = self.pools _stats['pools'] = self.pools
LOG.info(_LI('Driver stats: %(stat)s'), {'stat': _stats}) LOG.debug('Driver stats: %(stat)s', {'stat': _stats})
return _stats return _stats
def do_setup(self, context): def do_setup(self, context):
"""Perform internal driver setup.""" """Perform internal driver setup."""
version_info = self.backend.get_version() version_info = self.backend.get_version()
LOG.info(_LI("HNAS Array NFS driver")) LOG.info(_LI("HNAS NFS driver."))
LOG.info(_LI("HNAS model: %s"), version_info['model']) LOG.info(_LI("HNAS model: %(mdl)s"), {'mdl': version_info['model']})
LOG.info(_LI("HNAS version: %s"), version_info['version']) LOG.info(_LI("HNAS version: %(ver)s"),
LOG.info(_LI("HNAS hardware: %s"), version_info['hardware']) {'ver': version_info['version']})
LOG.info(_LI("HNAS S/N: %s"), version_info['serial']) LOG.info(_LI("HNAS hardware: %(hw)s"),
{'hw': version_info['hardware']})
LOG.info(_LI("HNAS S/N: %(sn)s"), {'sn': version_info['serial']})
self.context = context self.context = context
self._load_shares_config( self._load_shares_config(
@ -328,7 +336,7 @@ class HNASNFSDriver(nfs.NfsDriver):
try: try:
out, err = self._execute('showmount', '-e', server_ip) out, err = self._execute('showmount', '-e', server_ip)
except processutils.ProcessExecutionError: except processutils.ProcessExecutionError:
LOG.error(_LE("NFS server %(srv)s not reachable!"), LOG.exception(_LE("NFS server %(srv)s not reachable!"),
{'srv': server_ip}) {'srv': server_ip})
raise raise
@ -342,7 +350,7 @@ class HNASNFSDriver(nfs.NfsDriver):
LOG.error(_LE("Configured share %(share)s is not present" LOG.error(_LE("Configured share %(share)s is not present"
"in %(srv)s."), "in %(srv)s."),
{'share': mountpoint, 'srv': server_ip}) {'share': mountpoint, 'srv': server_ip})
msg = _('Section: %s') % svc_name msg = _('Section: %(svc_name)s') % {'svc_name': svc_name}
raise exception.InvalidParameterValue(err=msg) raise exception.InvalidParameterValue(err=msg)
LOG.debug("Loading services: %(svc)s", { LOG.debug("Loading services: %(svc)s", {
@ -358,7 +366,8 @@ class HNASNFSDriver(nfs.NfsDriver):
self.pools.append(pool) self.pools.append(pool)
LOG.info(_LI("Configured pools: %(pool)s"), {'pool': self.pools}) LOG.debug("Configured pools: %(pool)s", {'pool': self.pools})
LOG.info(_LI("HNAS NFS Driver loaded successfully."))
def _clone_volume(self, src_vol, clone_name, src_name=None): def _clone_volume(self, src_vol, clone_name, src_name=None):
"""Clones mounted volume using the HNAS file_clone. """Clones mounted volume using the HNAS file_clone.
@ -387,6 +396,7 @@ class HNASNFSDriver(nfs.NfsDriver):
self.backend.file_clone(fs_label, source_path, target_path) self.backend.file_clone(fs_label, source_path, target_path)
@cutils.trace
def create_volume(self, volume): def create_volume(self, volume):
"""Creates a volume. """Creates a volume.
@ -424,7 +434,7 @@ class HNASNFSDriver(nfs.NfsDriver):
try: try:
vol_ref_share_ip = cutils.resolve_hostname(share_split[0]) vol_ref_share_ip = cutils.resolve_hostname(share_split[0])
except socket.gaierror as e: except socket.gaierror as e:
LOG.error(_LE('Invalid hostname %(host)s'), LOG.exception(_LE('Invalid hostname %(host)s'),
{'host': share_split[0]}) {'host': share_split[0]})
LOG.debug('error: %(err)s', {'err': e.strerror}) LOG.debug('error: %(err)s', {'err': e.strerror})
raise raise
@ -468,8 +478,8 @@ class HNASNFSDriver(nfs.NfsDriver):
file_path) = vol_ref_share.partition(cfg_share) file_path) = vol_ref_share.partition(cfg_share)
if work_share == cfg_share: if work_share == cfg_share:
file_path = file_path[1:] # strip off leading path divider file_path = file_path[1:] # strip off leading path divider
LOG.debug("Found possible share %s; checking mount.", LOG.debug("Found possible share %(shr)s; checking mount.",
work_share) {'shr': work_share})
nfs_mount = self._get_mount_point_for_share(nfs_share) nfs_mount = self._get_mount_point_for_share(nfs_share)
vol_full_path = os.path.join(nfs_mount, file_path) vol_full_path = os.path.join(nfs_mount, file_path)
if os.path.isfile(vol_full_path): if os.path.isfile(vol_full_path):
@ -486,6 +496,7 @@ class HNASNFSDriver(nfs.NfsDriver):
existing_ref=vol_ref, existing_ref=vol_ref,
reason=_('Volume not found on configured storage backend.')) reason=_('Volume not found on configured storage backend.'))
@cutils.trace
def manage_existing(self, volume, existing_vol_ref): def manage_existing(self, volume, existing_vol_ref):
"""Manages an existing volume. """Manages an existing volume.
@ -507,7 +518,8 @@ class HNASNFSDriver(nfs.NfsDriver):
(nfs_share, nfs_mount, vol_name (nfs_share, nfs_mount, vol_name
) = self._get_share_mount_and_vol_from_vol_ref(existing_vol_ref) ) = self._get_share_mount_and_vol_from_vol_ref(existing_vol_ref)
LOG.debug("Asked to manage NFS volume %(vol)s, with vol ref %(ref)s.", LOG.info(_LI("Asked to manage NFS volume %(vol)s, "
"with vol ref %(ref)s."),
{'vol': volume.id, {'vol': volume.id,
'ref': existing_vol_ref['source-name']}) 'ref': existing_vol_ref['source-name']})
@ -526,12 +538,13 @@ class HNASNFSDriver(nfs.NfsDriver):
"to %(vol)s.", {'vol': volume.name}) "to %(vol)s.", {'vol': volume.name})
self._set_rw_permissions_for_all(dst_vol) self._set_rw_permissions_for_all(dst_vol)
except (OSError, processutils.ProcessExecutionError) as err: except (OSError, processutils.ProcessExecutionError) as err:
exception_msg = (_("Failed to manage existing volume " msg = (_("Failed to manage existing volume "
"%(name)s, because rename operation " "%(name)s, because rename operation "
"failed: Error msg: %(msg)s."), "failed: Error msg: %(msg)s.") %
{'name': existing_vol_ref['source-name'], {'name': existing_vol_ref['source-name'],
'msg': six.text_type(err)}) 'msg': six.text_type(err)})
raise exception.VolumeBackendAPIException(data=exception_msg) LOG.error(msg)
raise exception.VolumeBackendAPIException(data=msg)
return {'provider_location': nfs_share} return {'provider_location': nfs_share}
def _check_pool_and_share(self, volume, nfs_share): def _check_pool_and_share(self, volume, nfs_share):
@ -548,23 +561,25 @@ class HNASNFSDriver(nfs.NfsDriver):
pool_from_vol_type = hnas_utils.get_pool(self.config, volume) pool_from_vol_type = hnas_utils.get_pool(self.config, volume)
pool_from_host = utils.extract_host(volume.host, level='pool') pool_from_host = utils.extract_host(volume.host, level='pool')
pool = self.config['services'][pool_from_vol_type]['hdp']
if self.config['services'][pool_from_vol_type]['hdp'] != nfs_share: if pool != nfs_share:
msg = (_("Failed to manage existing volume because the pool of " msg = (_("Failed to manage existing volume because the pool of "
"the volume type chosen does not match the NFS share " "the volume type chosen (%(pool)s) does not match the "
"passed in the volume reference."), "NFS share passed in the volume reference (%(share)s).")
{'Share passed': nfs_share, 'Share for volume type': % {'share': nfs_share, 'pool': pool})
self.config['services'][pool_from_vol_type]['hdp']}) LOG.error(msg)
raise exception.ManageExistingVolumeTypeMismatch(reason=msg) raise exception.ManageExistingVolumeTypeMismatch(reason=msg)
if pool_from_host != pool_from_vol_type: if pool_from_host != pool_from_vol_type:
msg = (_("Failed to manage existing volume because the pool of " msg = (_("Failed to manage existing volume because the pool of "
"the volume type chosen does not match the pool of " "the volume type chosen (%(pool)s) does not match the "
"the host."), "pool of the host %(pool_host)s") %
{'Pool of the volume type': pool_from_vol_type, {'pool': pool_from_vol_type,
'Pool of the host': pool_from_host}) 'pool_host': pool_from_host})
LOG.error(msg)
raise exception.ManageExistingVolumeTypeMismatch(reason=msg) raise exception.ManageExistingVolumeTypeMismatch(reason=msg)
@cutils.trace
def manage_existing_get_size(self, volume, existing_vol_ref): def manage_existing_get_size(self, volume, existing_vol_ref):
"""Returns the size of volume to be managed by manage_existing. """Returns the size of volume to be managed by manage_existing.
@ -595,6 +610,7 @@ class HNASNFSDriver(nfs.NfsDriver):
"%(name)s, because of error in getting " "%(name)s, because of error in getting "
"volume size."), "volume size."),
{'name': existing_vol_ref['source-name']}) {'name': existing_vol_ref['source-name']})
LOG.exception(exception_message)
raise exception.VolumeBackendAPIException(data=exception_message) raise exception.VolumeBackendAPIException(data=exception_message)
LOG.debug("Reporting size of NFS volume ref %(ref)s as %(size)d GB.", LOG.debug("Reporting size of NFS volume ref %(ref)s as %(size)d GB.",
@ -602,6 +618,7 @@ class HNASNFSDriver(nfs.NfsDriver):
return vol_size return vol_size
@cutils.trace
def unmanage(self, volume): def unmanage(self, volume):
"""Removes the specified volume from Cinder management. """Removes the specified volume from Cinder management.
@ -623,9 +640,11 @@ class HNASNFSDriver(nfs.NfsDriver):
self._try_execute("mv", vol_path, new_path, self._try_execute("mv", vol_path, new_path,
run_as_root=False, check_exit_code=True) run_as_root=False, check_exit_code=True)
LOG.info(_LI("Cinder NFS volume with current path %(cr)s is " LOG.info(_LI("The volume with path %(old)s is no longer being "
"no longer being managed."), {'cr': new_path}) "managed by Cinder. However, it was not deleted "
"and can be found in the new path %(cr)s."),
{'old': vol_path, 'cr': new_path})
except (OSError, ValueError): except (OSError, ValueError):
LOG.error(_LE("The NFS Volume %(cr)s does not exist."), LOG.exception(_LE("The NFS Volume %(cr)s does not exist."),
{'cr': new_path}) {'cr': vol_path})

View File

@ -26,8 +26,7 @@ import six
from xml.etree import ElementTree as ETree from xml.etree import ElementTree as ETree
from cinder import exception from cinder import exception
from cinder.i18n import _, _LW, _LE
from cinder.i18n import _, _LW
from cinder.volume import volume_types from cinder.volume import volume_types
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -45,7 +44,7 @@ drivers_common_opts = [
'the SMU IP.'), 'the SMU IP.'),
cfg.StrOpt('hnas_ssc_cmd', cfg.StrOpt('hnas_ssc_cmd',
default='ssc', default='ssc',
help='Command to communicate to HNAS array.'), help='Command to communicate to HNAS.'),
cfg.StrOpt('hnas_username', cfg.StrOpt('hnas_username',
help='HNAS username.'), help='HNAS username.'),
cfg.StrOpt('hnas_password', cfg.StrOpt('hnas_password',
@ -96,6 +95,7 @@ def _check_conf_params(config, vol_type, dv_type, idx):
if config['username'] is None: if config['username'] is None:
msg = (_("The config parameter hnas_username " msg = (_("The config parameter hnas_username "
"is not set in the cinder.conf.")) "is not set in the cinder.conf."))
LOG.error(msg)
raise exception.InvalidParameterValue(err=msg) raise exception.InvalidParameterValue(err=msg)
if (config['password'] is None and if (config['password'] is None and
@ -104,11 +104,13 @@ def _check_conf_params(config, vol_type, dv_type, idx):
"missing: you need to set hnas_password " "missing: you need to set hnas_password "
"or hnas_ssh_private_key " "or hnas_ssh_private_key "
"in the cinder.conf.")) "in the cinder.conf."))
LOG.error(msg)
raise exception.InvalidParameterValue(err=msg) raise exception.InvalidParameterValue(err=msg)
if config['mgmt_ip0'] is None: if config['mgmt_ip0'] is None:
msg = (_("The config parameter hnas_mgmt_ip0 " msg = (_("The config parameter hnas_mgmt_ip0 "
"is not set in the cinder.conf.")) "is not set in the cinder.conf."))
LOG.error(msg)
raise exception.InvalidParameterValue(err=msg) raise exception.InvalidParameterValue(err=msg)
if config['services'][vol_type]['hdp'] is None: if config['services'][vol_type]['hdp'] is None:
@ -116,6 +118,7 @@ def _check_conf_params(config, vol_type, dv_type, idx):
"not set in the cinder.conf. Note that you need to " "not set in the cinder.conf. Note that you need to "
"have at least one pool configured.") % "have at least one pool configured.") %
{'idx': idx}) {'idx': idx})
LOG.error(msg)
raise exception.InvalidParameterValue(err=msg) raise exception.InvalidParameterValue(err=msg)
if config['services'][vol_type]['volume_type'] is None: if config['services'][vol_type]['volume_type'] is None:
@ -124,6 +127,7 @@ def _check_conf_params(config, vol_type, dv_type, idx):
"in the cinder.conf. Note that you need to " "in the cinder.conf. Note that you need to "
"have at least one pool configured.") % "have at least one pool configured.") %
{'idx': idx}) {'idx': idx})
LOG.error(msg)
raise exception.InvalidParameterValue(err=msg) raise exception.InvalidParameterValue(err=msg)
if (dv_type == 'iscsi' and if (dv_type == 'iscsi' and
@ -132,6 +136,7 @@ def _check_conf_params(config, vol_type, dv_type, idx):
"hnas_svc%(idx)s_iscsi_ip is not set " "hnas_svc%(idx)s_iscsi_ip is not set "
"in the cinder.conf. Note that you need to " "in the cinder.conf. Note that you need to "
"have at least one pool configured.") % {'idx': idx}) "have at least one pool configured.") % {'idx': idx})
LOG.error(msg)
raise exception.InvalidParameterValue(err=msg) raise exception.InvalidParameterValue(err=msg)
@ -147,6 +152,7 @@ def _xml_read(root, element, check=None):
# mandatory parameter not found # mandatory parameter not found
if val is None and check: if val is None and check:
LOG.error(_LE("Mandatory parameter not found: %(p)s"), {'p': element})
raise exception.ParameterNotFound(param=element) raise exception.ParameterNotFound(param=element)
# tag not found # tag not found
@ -158,6 +164,7 @@ def _xml_read(root, element, check=None):
if not val.strip(): if not val.strip():
if svc_tag_pattern.search(element): if svc_tag_pattern.search(element):
return "" return ""
LOG.error(_LE("Parameter not found: %(param)s"), {'param': element})
raise exception.ParameterNotFound(param=element) raise exception.ParameterNotFound(param=element)
LOG.debug("%(element)s: %(val)s", LOG.debug("%(element)s: %(val)s",
@ -180,6 +187,7 @@ def read_xml_config(xml_config_file, svc_params, optional_params):
if not os.access(xml_config_file, os.R_OK): if not os.access(xml_config_file, os.R_OK):
msg = (_("Can't find HNAS configurations on cinder.conf neither " msg = (_("Can't find HNAS configurations on cinder.conf neither "
"on the path %(xml)s.") % {'xml': xml_config_file}) "on the path %(xml)s.") % {'xml': xml_config_file})
LOG.error(msg)
raise exception.ConfigNotFound(message=msg) raise exception.ConfigNotFound(message=msg)
else: else:
LOG.warning(_LW("This XML configuration file %(xml)s is deprecated. " LOG.warning(_LW("This XML configuration file %(xml)s is deprecated. "
@ -191,7 +199,9 @@ def read_xml_config(xml_config_file, svc_params, optional_params):
try: try:
root = ETree.parse(xml_config_file).getroot() root = ETree.parse(xml_config_file).getroot()
except ETree.ParseError: except ETree.ParseError:
msg = (_("Error parsing config file: %s") % xml_config_file) msg = (_("Error parsing config file: %(xml_config_file)s") %
{'xml_config_file': xml_config_file})
LOG.error(msg)
raise exception.ConfigNotFound(message=msg) raise exception.ConfigNotFound(message=msg)
# mandatory parameters for NFS and iSCSI # mandatory parameters for NFS and iSCSI
@ -210,7 +220,8 @@ def read_xml_config(xml_config_file, svc_params, optional_params):
config['password'] = _xml_read(root, 'password') config['password'] = _xml_read(root, 'password')
if config['ssh_private_key'] is None and config['password'] is None: if config['ssh_private_key'] is None and config['password'] is None:
msg = (_("Missing authentication option (passw or private key file).")) msg = _("Missing authentication option (passw or private key file).")
LOG.error(msg)
raise exception.ConfigNotFound(message=msg) raise exception.ConfigNotFound(message=msg)
if _xml_read(root, 'ssh_port') is not None: if _xml_read(root, 'ssh_port') is not None:
@ -235,8 +246,8 @@ def read_xml_config(xml_config_file, svc_params, optional_params):
# at least one service required! # at least one service required!
if not config['services'].keys(): if not config['services'].keys():
msg = (_("svc_0")) LOG.error(_LE("No service found in xml config file"))
raise exception.ParameterNotFound(param=msg) raise exception.ParameterNotFound(param="svc_0")
return config return config