cinder/cinder/volume/drivers/hitachi/hnas_backend.py

877 lines
34 KiB
Python

# Copyright (c) 2014 Hitachi Data Systems, Inc.
# 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.
#
"""
Hitachi Unified Storage (HUS-HNAS) platform. Backend operations.
"""
import re
from oslo_concurrency import processutils as putils
from oslo_log import log as logging
from oslo_utils import units
import six
from cinder.i18n import _, _LW, _LI, _LE
from cinder import exception
from cinder import ssh_utils
from cinder import utils
LOG = logging.getLogger("cinder.volume.driver")
HNAS_SSC_RETRIES = 5
class HnasBackend(object):
"""Back end. Talks to HUS-HNAS."""
def __init__(self, drv_configs):
self.drv_configs = drv_configs
self.sshpool = None
@utils.retry(exceptions=exception.HNASConnError, retries=HNAS_SSC_RETRIES,
wait_random=True)
def run_cmd(self, cmd, ip0, user, pw, *args, **kwargs):
"""Run a command on SMU or using SSH
:param cmd: ssc command name
:param ip0: string IP address of controller
:param user: string user authentication for array
:param pw: string password authentication for array
:returns: formated string with version information
"""
LOG.debug('Enable ssh: %s',
six.text_type(self.drv_configs['ssh_enabled']))
if self.drv_configs['ssh_enabled'] != 'True':
# Direct connection via ssc
args = (cmd, '--user', user, '--password', pw, ip0) + args
try:
out, err = utils.execute(*args, **kwargs)
LOG.debug("command %(cmd)s result: out = %(out)s - err = "
"%(err)s", {'cmd': cmd, 'out': out, 'err': err})
return out, err
except putils.ProcessExecutionError as e:
if 'Failed to establish SSC connection' in e.stderr:
LOG.debug("SSC connection error!")
msg = _("Failed to establish SSC connection.")
raise exception.HNASConnError(msg)
elif 'Connection reset' in e.stderr:
LOG.debug("HNAS connection reset!")
msg = _("HNAS has disconnected SSC")
raise exception.HNASConnError(msg)
else:
raise
else:
if self.drv_configs['cluster_admin_ip0'] is None:
# Connect to SMU through SSH and run ssc locally
args = (cmd, 'localhost') + args
else:
args = (cmd, '--smuauth',
self.drv_configs['cluster_admin_ip0']) + args
utils.check_ssh_injection(args)
command = ' '.join(args)
command = command.replace('"', '\\"')
if not self.sshpool:
server = self.drv_configs['mgmt_ip0']
port = int(self.drv_configs['ssh_port'])
username = self.drv_configs['username']
# We only accept private/public key auth
password = ""
privatekey = self.drv_configs['ssh_private_key']
self.sshpool = ssh_utils.SSHPool(server,
port,
None,
username,
password=password,
privatekey=privatekey)
with self.sshpool.item() as ssh:
try:
out, err = putils.ssh_execute(ssh, command,
check_exit_code=True)
LOG.debug("command %(cmd)s result: out = "
"%(out)s - err = %(err)s",
{'cmd': cmd, 'out': out, 'err': err})
return out, err
except putils.ProcessExecutionError as e:
if 'Failed to establish SSC connection' in e.stderr:
LOG.debug("SSC connection error!")
msg = _("Failed to establish SSC connection.")
raise exception.HNASConnError(msg)
else:
raise putils.ProcessExecutionError
def get_version(self, cmd, ver, ip0, user, pw):
"""Gets version information from the storage unit
:param cmd: ssc command name
:param ver: string driver version
:param ip0: string IP address of controller
:param user: string user authentication for array
:param pw: string password authentication for array
:returns: formatted string with version information
"""
out, err = self.run_cmd(cmd, ip0, user, pw, "cluster-getmac",
check_exit_code=True)
hardware = out.split()[2]
out, err = self.run_cmd(cmd, ip0, user, pw, "ver",
check_exit_code=True)
lines = out.split('\n')
model = ""
for line in lines:
if 'Model:' in line:
model = line.split()[1]
if 'Software:' in line:
ver = line.split()[1]
# If not using SSH, the local utility version can be different from the
# one used in HNAS
if self.drv_configs['ssh_enabled'] != 'True':
out, err = utils.execute(cmd, "-version", check_exit_code=True)
util = out.split()[1]
out = ("Array_ID: %(arr)s (%(mod)s) version: %(ver)s LU: 256 "
"RG: 0 RG_LU: 0 Utility_version: %(util)s" %
{'arr': hardware, 'mod': model, 'ver': ver, 'util': util})
else:
out = ("Array_ID: %(arr)s (%(mod)s) version: %(ver)s LU: 256 "
"RG: 0 RG_LU: 0" %
{'arr': hardware, 'mod': model, 'ver': ver})
LOG.debug('get_version: %(out)s -- %(err)s', {'out': out, 'err': err})
return out
def get_iscsi_info(self, cmd, ip0, user, pw):
"""Gets IP addresses for EVSs, use EVSID as controller.
:param cmd: ssc command name
:param ip0: string IP address of controller
:param user: string user authentication for array
:param pw: string password authentication for array
:returns: formated string with iSCSI information
"""
out, err = self.run_cmd(cmd, ip0, user, pw,
'evsipaddr', '-l',
check_exit_code=True)
lines = out.split('\n')
newout = ""
for line in lines:
if 'evs' in line and 'admin' not in line:
inf = line.split()
(evsnum, ip) = (inf[1], inf[3])
newout += "CTL: %s Port: 0 IP: %s Port: 3260 Link: Up\n" \
% (evsnum, ip)
LOG.debug('get_iscsi_info: %(out)s -- %(err)s',
{'out': out, 'err': err})
return newout
def get_hdp_info(self, cmd, ip0, user, pw, fslabel=None):
"""Gets the list of filesystems and fsids.
:param cmd: ssc command name
:param ip0: string IP address of controller
:param user: string user authentication for array
:param pw: string password authentication for array
:param fslabel: filesystem label we want to get info
:returns: formated string with filesystems and fsids
"""
if fslabel is None:
out, err = self.run_cmd(cmd, ip0, user, pw, 'df', '-a',
check_exit_code=True)
else:
out, err = self.run_cmd(cmd, ip0, user, pw, 'df', '-f', fslabel,
check_exit_code=True)
lines = out.split('\n')
single_evs = True
LOG.debug("Parsing output: %s", lines)
newout = ""
for line in lines:
if 'Not mounted' in line or 'Not determined' in line:
continue
if 'not' not in line and 'EVS' in line:
single_evs = False
if 'GB' in line or 'TB' in line:
LOG.debug("Parsing output: %s", line)
inf = line.split()
if not single_evs:
(fsid, fslabel, capacity) = (inf[0], inf[1], inf[3])
(used, perstr) = (inf[5], inf[7])
(availunit, usedunit) = (inf[4], inf[6])
else:
(fsid, fslabel, capacity) = (inf[0], inf[1], inf[2])
(used, perstr) = (inf[4], inf[6])
(availunit, usedunit) = (inf[3], inf[5])
if usedunit == 'GB':
usedmultiplier = units.Ki
else:
usedmultiplier = units.Mi
if availunit == 'GB':
availmultiplier = units.Ki
else:
availmultiplier = units.Mi
m = re.match("\((\d+)\%\)", perstr)
if m:
percent = m.group(1)
else:
percent = 0
newout += "HDP: %s %d MB %d MB %d %% LUs: 256 Normal %s\n" \
% (fsid, int(float(capacity) * availmultiplier),
int(float(used) * usedmultiplier),
int(percent), fslabel)
LOG.debug('get_hdp_info: %(out)s -- %(err)s',
{'out': newout, 'err': err})
return newout
def get_evs(self, cmd, ip0, user, pw, fsid):
"""Gets the EVSID for the named filesystem.
:param cmd: ssc command name
:param ip0: string IP address of controller
:param user: string user authentication for array
:param pw: string password authentication for array
:returns: EVS id of the file system
"""
out, err = self.run_cmd(cmd, ip0, user, pw, "evsfs", "list",
check_exit_code=True)
LOG.debug('get_evs: out %s.', out)
lines = out.split('\n')
for line in lines:
inf = line.split()
if fsid in line and (fsid == inf[0] or fsid == inf[1]):
return inf[3]
LOG.warning(_LW('get_evs: %(out)s -- No find for %(fsid)s'),
{'out': out, 'fsid': fsid})
return 0
def _get_evsips(self, cmd, ip0, user, pw, evsid):
"""Gets the EVS IPs for the named filesystem."""
out, err = self.run_cmd(cmd, ip0, user, pw,
'evsipaddr', '-e', evsid,
check_exit_code=True)
iplist = ""
lines = out.split('\n')
for line in lines:
inf = line.split()
if 'evs' in line:
iplist += inf[3] + ' '
LOG.debug('get_evsips: %s', iplist)
return iplist
def _get_fsid(self, cmd, ip0, user, pw, fslabel):
"""Gets the FSID for the named filesystem."""
out, err = self.run_cmd(cmd, ip0, user, pw, 'evsfs', 'list',
check_exit_code=True)
LOG.debug('get_fsid: out %s', out)
lines = out.split('\n')
for line in lines:
inf = line.split()
if fslabel in line and fslabel == inf[1]:
LOG.debug('get_fsid: %s', line)
return inf[0]
LOG.warning(_LW('get_fsid: %(out)s -- No info for %(fslabel)s'),
{'out': out, 'fslabel': fslabel})
return 0
def _get_targets(self, cmd, ip0, user, pw, evsid, tgtalias=None):
"""Get the target list of an EVS.
Get the target list of an EVS. Optionally can return the target
list of a specific target.
"""
LOG.debug("Getting target list for evs %s, tgtalias: %s.",
evsid, tgtalias)
try:
out, err = self.run_cmd(cmd, ip0, user, pw, "console-context",
"--evs", evsid, 'iscsi-target', 'list',
check_exit_code=True)
except putils.ProcessExecutionError as e:
LOG.error(_LE('Error getting iSCSI target info '
'from EVS %(evs)s.'), {'evs': evsid})
LOG.debug("_get_targets out: %(out)s, err: %(err)s.",
{'out': e.stdout, 'err': e.stderr})
return []
tgt_list = []
if 'No targets' in out:
LOG.debug("No targets found in EVS %(evsid)s.", {'evsid': evsid})
return tgt_list
tgt_raw_list = out.split('Alias')[1:]
for tgt_raw_info in tgt_raw_list:
tgt = {}
tgt['alias'] = tgt_raw_info.split('\n')[0].split(' ').pop()
tgt['iqn'] = tgt_raw_info.split('\n')[1].split(' ').pop()
tgt['secret'] = tgt_raw_info.split('\n')[3].split(' ').pop()
tgt['auth'] = tgt_raw_info.split('\n')[4].split(' ').pop()
luns = []
tgt_raw_info = tgt_raw_info.split('\n\n')[1]
tgt_raw_list = tgt_raw_info.split('\n')[2:]
for lun_raw_line in tgt_raw_list:
lun_raw_line = lun_raw_line.strip()
lun_raw_line = lun_raw_line.split(' ')
lun = {}
lun['id'] = lun_raw_line[0]
lun['name'] = lun_raw_line.pop()
luns.append(lun)
tgt['luns'] = luns
if tgtalias == tgt['alias']:
return [tgt]
tgt_list.append(tgt)
if tgtalias is not None:
# We tried to find 'tgtalias' but didn't find. Return an empty
# list.
LOG.debug("There's no target %(alias)s in EVS %(evsid)s.",
{'alias': tgtalias, 'evsid': evsid})
return []
LOG.debug("Targets in EVS %(evs)s: %(tgtl)s.",
{'evs': evsid, 'tgtl': tgt_list})
return tgt_list
def _get_unused_lunid(self, cmd, ip0, user, pw, tgt_info):
if len(tgt_info['luns']) == 0:
return 0
free_lun = 0
for lun in tgt_info['luns']:
if int(lun['id']) == free_lun:
free_lun += 1
if int(lun['id']) > free_lun:
# Found a free LUN number
break
return free_lun
def get_nfs_info(self, cmd, ip0, user, pw):
"""Gets information on each NFS export.
:param cmd: ssc command name
:param ip0: string IP address of controller
:param user: string user authentication for array
:param pw: string password authentication for array
:returns: formated string
"""
out, err = self.run_cmd(cmd, ip0, user, pw,
'for-each-evs', '-q',
'nfs-export', 'list',
check_exit_code=True)
lines = out.split('\n')
newout = ""
export = ""
path = ""
for line in lines:
inf = line.split()
if 'Export name' in line:
export = inf[2]
if 'Export path' in line:
path = inf[2]
if 'File system info' in line:
fs = ""
if 'File system label' in line:
fs = inf[3]
if 'Transfer setting' in line and fs != "":
fsid = self._get_fsid(cmd, ip0, user, pw, fs)
evsid = self.get_evs(cmd, ip0, user, pw, fsid)
ips = self._get_evsips(cmd, ip0, user, pw, evsid)
newout += "Export: %s Path: %s HDP: %s FSID: %s \
EVS: %s IPS: %s\n" \
% (export, path, fs, fsid, evsid, ips)
fs = ""
LOG.debug('get_nfs_info: %(out)s -- %(err)s',
{'out': newout, 'err': err})
return newout
def create_lu(self, cmd, ip0, user, pw, hdp, size, name):
"""Creates a new Logical Unit.
If the operation can not be performed for some reason, utils.execute()
throws an error and aborts the operation. Used for iSCSI only
:param cmd: ssc command name
:param ip0: string IP address of controller
:param user: string user authentication for array
:param pw: string password authentication for array
:param hdp: data Pool the logical unit will be created
:param size: Size (Mb) of the new logical unit
:param name: name of the logical unit
:returns: formated string with 'LUN %d HDP: %d size: %s MB, is
successfully created'
"""
_evsid = self.get_evs(cmd, ip0, user, pw, hdp)
out, err = self.run_cmd(cmd, ip0, user, pw, "console-context",
"--evs", _evsid,
'iscsi-lu', 'add', "-e",
name, hdp,
'/.cinder/' + name + '.iscsi',
size + 'M',
check_exit_code=True)
out = "LUN %s HDP: %s size: %s MB, is successfully created" \
% (name, hdp, size)
LOG.debug('create_lu: %s.', out)
return out
def delete_lu(self, cmd, ip0, user, pw, hdp, lun):
"""Delete an logical unit. Used for iSCSI only
:param cmd: ssc command name
:param ip0: string IP address of controller
:param user: string user authentication for array
:param pw: string password authentication for array
:param hdp: data Pool of the logical unit
:param lun: id of the logical unit being deleted
:returns: formated string 'Logical unit deleted successfully.'
"""
_evsid = self.get_evs(cmd, ip0, user, pw, hdp)
out, err = self.run_cmd(cmd, ip0, user, pw, "console-context",
"--evs", _evsid,
'iscsi-lu', 'del', '-d',
'-f', lun,
check_exit_code=True)
LOG.debug('delete_lu: %(out)s -- %(err)s.', {'out': out, 'err': err})
return out
def create_dup(self, cmd, ip0, user, pw, src_lun, hdp, size, name):
"""Clones a volume
Clone primitive used to support all iSCSI snapshot/cloning functions.
Used for iSCSI only.
:param cmd: ssc command name
:param ip0: string IP address of controller
:param user: string user authentication for array
:param pw: string password authentication for array
:param hdp: data Pool of the logical unit
:param src_lun: id of the logical unit being deleted
:param size: size of the LU being cloned. Only for logging purposes
:returns: formated string
"""
_evsid = self.get_evs(cmd, ip0, user, pw, hdp)
out, err = self.run_cmd(cmd, ip0, user, pw, "console-context",
"--evs", _evsid,
'iscsi-lu', 'clone', '-e',
src_lun, name,
'/.cinder/' + name + '.iscsi',
check_exit_code=True)
out = "LUN %s HDP: %s size: %s MB, is successfully created" \
% (name, hdp, size)
LOG.debug('create_dup: %(out)s -- %(err)s.', {'out': out, 'err': err})
return out
def file_clone(self, cmd, ip0, user, pw, fslabel, src, name):
"""Clones NFS files to a new one named 'name'
Clone primitive used to support all NFS snapshot/cloning functions.
:param cmd: ssc command name
:param ip0: string IP address of controller
:param user: string user authentication for array
:param pw: string password authentication for array
:param fslabel: file system label of the new file
:param src: source file
:param name: target path of the new created file
:returns: formated string
"""
_fsid = self._get_fsid(cmd, ip0, user, pw, fslabel)
_evsid = self.get_evs(cmd, ip0, user, pw, _fsid)
out, err = self.run_cmd(cmd, ip0, user, pw, "console-context",
"--evs", _evsid,
'file-clone-create', '-f', fslabel,
src, name,
check_exit_code=True)
out = "LUN %s HDP: %s Clone: %s -> %s" % (name, _fsid, src, name)
LOG.debug('file_clone: %(out)s -- %(err)s.', {'out': out, 'err': err})
return out
def extend_vol(self, cmd, ip0, user, pw, hdp, lun, new_size, name):
"""Extend a iSCSI volume.
:param cmd: ssc command name
:param ip0: string IP address of controller
:param user: string user authentication for array
:param pw: string password authentication for array
:param hdp: data Pool of the logical unit
:param lun: id of the logical unit being extended
:param new_size: new size of the LU
:param name: formated string
"""
_evsid = self.get_evs(cmd, ip0, user, pw, hdp)
out, err = self.run_cmd(cmd, ip0, user, pw, "console-context",
"--evs", _evsid,
'iscsi-lu', 'expand',
name, new_size + 'M',
check_exit_code=True)
out = ("LUN: %s successfully extended to %s MB" % (name, new_size))
LOG.debug('extend_vol: %s.', out)
return out
@utils.retry(putils.ProcessExecutionError, retries=HNAS_SSC_RETRIES,
wait_random=True)
def add_iscsi_conn(self, cmd, ip0, user, pw, lun_name, hdp,
port, tgtalias, initiator):
"""Setup the lun on on the specified target port
:param cmd: ssc command name
:param ip0: string IP address of controller
:param user: string user authentication for array
:param pw: string password authentication for array
:param lun_name: id of the logical unit being extended
:param hdp: data pool of the logical unit
:param port: iSCSI port
:param tgtalias: iSCSI qualified name
:param initiator: initiator address
"""
LOG.debug('Adding %(lun)s to %(tgt)s returns %(tgt)s.',
{'lun': lun_name, 'tgt': tgtalias})
found, lunid, tgt = self.check_lu(cmd, ip0, user, pw, lun_name, hdp)
evsid = self.get_evs(cmd, ip0, user, pw, hdp)
if found:
conn = (int(lunid), lun_name, initiator, int(lunid), tgt['iqn'],
int(lunid), hdp, port)
out = ("H-LUN: %d mapped LUN: %s, iSCSI Initiator: %s "
"@ index: %d, and Target: %s @ index %d is "
"successfully paired @ CTL: %s, Port: %s.") % conn
else:
tgt = self._get_targets(cmd, ip0, user, pw, evsid, tgtalias)
lunid = self._get_unused_lunid(cmd, ip0, user, pw, tgt[0])
out, err = self.run_cmd(cmd, ip0, user, pw, "console-context",
"--evs", evsid,
'iscsi-target', 'addlu',
tgtalias, lun_name, six.text_type(lunid),
check_exit_code=True)
conn = (int(lunid), lun_name, initiator, int(lunid), tgt[0]['iqn'],
int(lunid), hdp, port)
out = ("H-LUN: %d mapped LUN: %s, iSCSI Initiator: %s "
"@ index: %d, and Target: %s @ index %d is "
"successfully paired @ CTL: %s, Port: %s.") % conn
LOG.debug('add_iscsi_conn: returns %s.', out)
return out
def del_iscsi_conn(self, cmd, ip0, user, pw, evsid, iqn, hlun):
"""Remove the lun on on the specified target port
:param cmd: ssc command name
:param ip0: string IP address of controller
:param user: string user authentication for array
:param pw: string password authentication for array
:param evsid: EVSID for the file system
:param iqn: iSCSI qualified name
:param hlun: logical unit id
:returns: formated string
"""
out, err = self.run_cmd(cmd, ip0, user, pw, "console-context",
"--evs", evsid,
'iscsi-target', 'list', iqn,
check_exit_code=True)
lines = out.split('\n')
out = ("H-LUN: %d already deleted from target %s" % (int(hlun), iqn))
# see if lun is already detached
for line in lines:
if line.startswith(' '):
lunline = line.split()[0]
if lunline[0].isdigit() and lunline == hlun:
out = ""
break
if out != "":
# hlun wasn't found
LOG.info(_LI('del_iscsi_conn: hlun not found %s.'), out)
return out
# remove the LU from the target
out, err = self.run_cmd(cmd, ip0, user, pw, "console-context",
"--evs", evsid,
'iscsi-target', 'dellu',
'-f', iqn, hlun,
check_exit_code=True)
out = "H-LUN: %d successfully deleted from target %s" \
% (int(hlun), iqn)
LOG.debug('del_iscsi_conn: %s.', out)
return out
def get_targetiqn(self, cmd, ip0, user, pw, targetalias, hdp, secret):
"""Obtain the targets full iqn
Returns the target's full iqn rather than its alias.
:param cmd: ssc command name
:param ip0: string IP address of controller
:param user: string user authentication for array
:param pw: string password authentication for array
:param targetalias: alias of the target
:param hdp: data pool of the logical unit
:param secret: CHAP secret of the target
:returns: string with full IQN
"""
_evsid = self.get_evs(cmd, ip0, user, pw, hdp)
out, err = self.run_cmd(cmd, ip0, user, pw, "console-context",
"--evs", _evsid,
'iscsi-target', 'list', targetalias,
check_exit_code=True)
if "does not exist" in out:
if secret == "":
secret = '""'
out, err = self.run_cmd(cmd, ip0, user, pw, "console-context",
"--evs", _evsid,
'iscsi-target', 'add',
targetalias, secret,
check_exit_code=True)
else:
out, err = self.run_cmd(cmd, ip0, user, pw, "console-context",
"--evs", _evsid,
'iscsi-target', 'add',
targetalias, secret,
check_exit_code=True)
if "success" in out:
return targetalias
lines = out.split('\n')
# returns the first iqn
for line in lines:
if 'Alias' in line:
fulliqn = line.split()[2]
return fulliqn
def set_targetsecret(self, cmd, ip0, user, pw, targetalias, hdp, secret):
"""Sets the chap secret for the specified target.
:param cmd: ssc command name
:param ip0: string IP address of controller
:param user: string user authentication for array
:param pw: string password authentication for array
:param targetalias: alias of the target
:param hdp: data pool of the logical unit
:param secret: CHAP secret of the target
"""
_evsid = self.get_evs(cmd, ip0, user, pw, hdp)
out, err = self.run_cmd(cmd, ip0, user, pw, "console-context",
"--evs", _evsid,
'iscsi-target', 'list',
targetalias,
check_exit_code=False)
if "does not exist" in out:
out, err = self.run_cmd(cmd, ip0, user, pw, "console-context",
"--evs", _evsid,
'iscsi-target', 'add',
targetalias, secret,
check_exit_code=True)
else:
LOG.info(_LI('targetlist: %s'), targetalias)
out, err = self.run_cmd(cmd, ip0, user, pw, "console-context",
"--evs", _evsid,
'iscsi-target', 'mod',
'-s', secret, '-a', 'enable',
targetalias,
check_exit_code=True)
def get_targetsecret(self, cmd, ip0, user, pw, targetalias, hdp):
"""Returns the chap secret for the specified target.
:param cmd: ssc command name
:param ip0: string IP address of controller
:param user: string user authentication for array
:param pw: string password authentication for array
:param targetalias: alias of the target
:param hdp: data pool of the logical unit
:return secret: CHAP secret of the target
"""
_evsid = self.get_evs(cmd, ip0, user, pw, hdp)
out, err = self.run_cmd(cmd, ip0, user, pw, "console-context",
"--evs", _evsid,
'iscsi-target', 'list', targetalias,
check_exit_code=True)
enabled = ""
secret = ""
lines = out.split('\n')
for line in lines:
if 'Secret' in line:
if len(line.split()) > 2:
secret = line.split()[2]
if 'Authentication' in line:
enabled = line.split()[2]
if enabled == 'Enabled':
return secret
else:
return ""
def check_target(self, cmd, ip0, user, pw, hdp, target_alias):
"""Checks if a given target exists and gets its info
:param cmd: ssc command name
:param ip0: string IP address of controller
:param user: string user authentication for array
:param pw: string password authentication for array
:param hdp: pool name used
:param target_alias: alias of the target
:returns: True if target exists
:returns: list with the target info
"""
LOG.debug("Checking if target %(tgt)s exists.", {'tgt': target_alias})
evsid = self.get_evs(cmd, ip0, user, pw, hdp)
tgt_list = self._get_targets(cmd, ip0, user, pw, evsid)
for tgt in tgt_list:
if tgt['alias'] == target_alias:
attached_luns = len(tgt['luns'])
LOG.debug("Target %(tgt)s has %(lun)s volumes.",
{'tgt': target_alias, 'lun': attached_luns})
return True, tgt
LOG.debug("Target %(tgt)s does not exist.", {'tgt': target_alias})
return False, None
def check_lu(self, cmd, ip0, user, pw, volume_name, hdp):
"""Checks if a given LUN is already mapped
:param cmd: ssc command name
:param ip0: string IP address of controller
:param user: string user authentication for array
:param pw: string password authentication for array
:param volume_name: number of the LUN
:param hdp: storage pool of the LUN
:returns: True if the lun is attached
:returns: the LUN id
:returns: Info related to the target
"""
LOG.debug("Checking if vol %s (hdp: %s) is attached.",
volume_name, hdp)
evsid = self.get_evs(cmd, ip0, user, pw, hdp)
tgt_list = self._get_targets(cmd, ip0, user, pw, evsid)
for tgt in tgt_list:
if len(tgt['luns']) == 0:
continue
for lun in tgt['luns']:
lunid = lun['id']
lunname = lun['name']
if lunname[:29] == volume_name[:29]:
LOG.debug("LUN %(lun)s attached on %(lunid)s, "
"target: %(tgt)s.",
{'lun': volume_name, 'lunid': lunid, 'tgt': tgt})
return True, lunid, tgt
LOG.debug("LUN %(lun)s not attached.", {'lun': volume_name})
return False, 0, None
def get_existing_lu_info(self, cmd, ip0, user, pw, fslabel, lun):
"""Returns the information for the specified Logical Unit.
Returns the information of an existing Logical Unit on HNAS, according
to the name provided.
:param cmd: the command that will be run on SMU
:param ip0: string IP address of controller
:param user: string user authentication for array
:param pw: string password authentication for array
:param fslabel: label of the file system
:param lun: label of the logical unit
"""
evs = self.get_evs(cmd, ip0, user, pw, fslabel)
out, err = self.run_cmd(cmd, ip0, user, pw, "console-context", "--evs",
evs, 'iscsi-lu', 'list', lun)
return out
def rename_existing_lu(self, cmd, ip0, user, pw, fslabel,
new_name, vol_name):
"""Renames the specified Logical Unit.
Renames an existing Logical Unit on HNAS according to the new name
provided.
:param cmd: command that will be run on SMU
:param ip0: string IP address of controller
:param user: string user authentication for array
:param pw: string password authentication for array
:param fslabel: label of the file system
:param new_name: new name to the existing volume
:param vol_name: current name of the existing volume
"""
evs = self.get_evs(cmd, ip0, user, pw, fslabel)
out, err = self.run_cmd(cmd, ip0, user, pw, "console-context", "--evs",
evs, "iscsi-lu", "mod", "-n", new_name,
vol_name)
return out