1587 lines
59 KiB
Python
1587 lines
59 KiB
Python
# Copyright (C) 2014, Hitachi, Ltd.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
import functools
|
|
import os
|
|
import re
|
|
import shlex
|
|
import threading
|
|
import time
|
|
|
|
from oslo_concurrency import processutils as putils
|
|
from oslo_config import cfg
|
|
from oslo_utils import excutils
|
|
from oslo_utils import units
|
|
import six
|
|
|
|
from cinder import exception
|
|
from cinder.i18n import _LE, _LW
|
|
from cinder.openstack.common import log as logging
|
|
from cinder.openstack.common import loopingcall
|
|
from cinder import utils
|
|
from cinder.volume.drivers.hitachi import hbsd_basiclib as basic_lib
|
|
|
|
GETSTORAGEARRAY_ONCE = 100
|
|
MAX_SNAPSHOT_COUNT = 1021
|
|
SNAP_LAST_PATH_SSB = '0xB958,0x020A'
|
|
HOST_IO_SSB = '0xB958,0x0233'
|
|
INVALID_LUN_SSB = '0x2E20,0x0000'
|
|
INTERCEPT_LDEV_SSB = '0x2E22,0x0001'
|
|
HOSTGROUP_INSTALLED = '0xB956,0x3173'
|
|
|
|
LDEV_STATUS_WAITTIME = 120
|
|
LUN_DELETE_WAITTIME = basic_lib.DEFAULT_PROCESS_WAITTIME
|
|
LUN_DELETE_INTERVAL = 3
|
|
EXEC_MAX_WAITTIME = 30
|
|
EXEC_RETRY_INTERVAL = 5
|
|
HORCM_WAITTIME = 1
|
|
PAIR_TYPE = ('HORC', 'MRCF', 'QS')
|
|
PERMITTED_TYPE = ('CVS', 'HDP', 'HDT')
|
|
|
|
RAIDCOM_LOCK_FILE = basic_lib.LOCK_DIR + 'raidcom_'
|
|
HORCMGR_LOCK_FILE = basic_lib.LOCK_DIR + 'horcmgr_'
|
|
RESOURCE_LOCK_FILE = basic_lib.LOCK_DIR + 'raidcom_resource_'
|
|
|
|
STATUS_TABLE = {
|
|
'SMPL': basic_lib.SMPL,
|
|
'COPY': basic_lib.COPY,
|
|
'RCPY': basic_lib.COPY,
|
|
'PAIR': basic_lib.PAIR,
|
|
'PFUL': basic_lib.PAIR,
|
|
'PSUS': basic_lib.PSUS,
|
|
'PFUS': basic_lib.PSUS,
|
|
'SSUS': basic_lib.PSUS,
|
|
'PSUE': basic_lib.PSUE,
|
|
}
|
|
NOT_SET = '-'
|
|
HORCM_RUNNING = 1
|
|
COPY_GROUP = basic_lib.NAME_PREFIX + '%s%s%03X%d'
|
|
SNAP_NAME = basic_lib.NAME_PREFIX + 'snap'
|
|
LDEV_NAME = basic_lib.NAME_PREFIX + 'ldev-%d-%d'
|
|
MAX_MUNS = 3
|
|
|
|
EX_ENAUTH = 202
|
|
EX_ENOOBJ = 205
|
|
EX_CMDRJE = 221
|
|
EX_CMDIOE = 237
|
|
EX_INVCMD = 240
|
|
EX_INVMOD = 241
|
|
EX_ENODEV = 246
|
|
EX_ENOENT = 247
|
|
EX_OPTINV = 248
|
|
EX_ATTDBG = 250
|
|
EX_ATTHOR = 251
|
|
EX_COMERR = 255
|
|
EX_UNKOWN = -1
|
|
|
|
NO_SUCH_DEVICE = (EX_ENODEV, EX_ENOENT)
|
|
|
|
COMMAND_IO_TO_RAID = (EX_CMDRJE, EX_CMDIOE, EX_INVCMD, EX_INVMOD, EX_OPTINV)
|
|
|
|
HORCM_ERROR = (EX_ATTDBG, EX_ATTHOR, EX_COMERR)
|
|
|
|
MAX_HOSTGROUPS = 254
|
|
MAX_HLUN = 2047
|
|
|
|
DEFAULT_PORT_BASE = 31000
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
volume_opts = [
|
|
cfg.StrOpt('hitachi_horcm_numbers',
|
|
default='200,201',
|
|
help='Instance numbers for HORCM'),
|
|
cfg.StrOpt('hitachi_horcm_user',
|
|
default=None,
|
|
help='Username of storage system for HORCM'),
|
|
cfg.StrOpt('hitachi_horcm_password',
|
|
default=None,
|
|
help='Password of storage system for HORCM'),
|
|
cfg.BoolOpt('hitachi_horcm_add_conf',
|
|
default=True,
|
|
help='Add to HORCM configuration'),
|
|
]
|
|
|
|
CONF = cfg.CONF
|
|
CONF.register_opts(volume_opts)
|
|
|
|
|
|
def horcm_synchronized(function):
|
|
@functools.wraps(function)
|
|
def wrapper(*args, **kargs):
|
|
if len(args) == 1:
|
|
inst = args[0].conf.hitachi_horcm_numbers[0]
|
|
raidcom_obj_lock = args[0].raidcom_lock
|
|
else:
|
|
inst = args[1]
|
|
raidcom_obj_lock = args[0].raidcom_pair_lock
|
|
raidcom_lock_file = '%s%d' % (RAIDCOM_LOCK_FILE, inst)
|
|
lock = basic_lib.get_process_lock(raidcom_lock_file)
|
|
with raidcom_obj_lock, lock:
|
|
return function(*args, **kargs)
|
|
return wrapper
|
|
|
|
|
|
def storage_synchronized(function):
|
|
@functools.wraps(function)
|
|
def wrapper(*args, **kargs):
|
|
serial = args[0].conf.hitachi_serial_number
|
|
resource_lock = args[0].resource_lock
|
|
resource_lock_file = '%s%s' % (RESOURCE_LOCK_FILE, serial)
|
|
lock = basic_lib.get_process_lock(resource_lock_file)
|
|
with resource_lock, lock:
|
|
return function(*args, **kargs)
|
|
return wrapper
|
|
|
|
|
|
class HBSDHORCM(basic_lib.HBSDBasicLib):
|
|
|
|
def __init__(self, conf):
|
|
super(HBSDHORCM, self).__init__(conf=conf)
|
|
|
|
self.copy_groups = [None] * MAX_MUNS
|
|
self.raidcom_lock = threading.Lock()
|
|
self.raidcom_pair_lock = threading.Lock()
|
|
self.horcmgr_lock = threading.Lock()
|
|
self.horcmgr_flock = None
|
|
self.resource_lock = threading.Lock()
|
|
|
|
def check_param(self):
|
|
numbers = self.conf.hitachi_horcm_numbers.split(',')
|
|
if len(numbers) != 2:
|
|
msg = basic_lib.output_err(601, param='hitachi_horcm_numbers')
|
|
raise exception.HBSDError(message=msg)
|
|
for i in numbers:
|
|
if not i.isdigit():
|
|
msg = basic_lib.output_err(601, param='hitachi_horcm_numbers')
|
|
raise exception.HBSDError(message=msg)
|
|
self.conf.hitachi_horcm_numbers = map(int, numbers)
|
|
inst = self.conf.hitachi_horcm_numbers[0]
|
|
pair_inst = self.conf.hitachi_horcm_numbers[1]
|
|
if inst == pair_inst:
|
|
msg = basic_lib.output_err(601, param='hitachi_horcm_numbers')
|
|
raise exception.HBSDError(message=msg)
|
|
for param in ('hitachi_horcm_user', 'hitachi_horcm_password'):
|
|
if not getattr(self.conf, param):
|
|
msg = basic_lib.output_err(601, param=param)
|
|
raise exception.HBSDError(message=msg)
|
|
if self.conf.hitachi_thin_pool_id == self.conf.hitachi_pool_id:
|
|
msg = basic_lib.output_err(601, param='hitachi_thin_pool_id')
|
|
raise exception.HBSDError(message=msg)
|
|
for opt in volume_opts:
|
|
getattr(self.conf, opt.name)
|
|
|
|
def set_copy_groups(self, host_ip):
|
|
serial = self.conf.hitachi_serial_number
|
|
inst = self.conf.hitachi_horcm_numbers[1]
|
|
|
|
for mun in range(MAX_MUNS):
|
|
copy_group = COPY_GROUP % (host_ip, serial, inst, mun)
|
|
self.copy_groups[mun] = copy_group
|
|
|
|
def set_pair_flock(self):
|
|
inst = self.conf.hitachi_horcm_numbers[1]
|
|
name = '%s%d' % (HORCMGR_LOCK_FILE, inst)
|
|
self.horcmgr_flock = basic_lib.FileLock(name, self.horcmgr_lock)
|
|
return self.horcmgr_flock
|
|
|
|
def check_horcm(self, inst):
|
|
args = 'HORCMINST=%d horcmgr -check' % inst
|
|
ret, _stdout, _stderr = self.exec_command('env', args=args,
|
|
printflag=False)
|
|
return ret
|
|
|
|
def shutdown_horcm(self, inst):
|
|
ret, stdout, stderr = self.exec_command(
|
|
'horcmshutdown.sh', args=six.text_type(inst), printflag=False)
|
|
return ret
|
|
|
|
def start_horcm(self, inst):
|
|
return self.exec_command('horcmstart.sh', args=six.text_type(inst),
|
|
printflag=False)
|
|
|
|
def _wait_for_horcm_shutdown(self, inst):
|
|
if self.check_horcm(inst) != HORCM_RUNNING:
|
|
raise loopingcall.LoopingCallDone()
|
|
|
|
if self.shutdown_horcm(inst):
|
|
LOG.error(_LE("Failed to shutdown horcm."))
|
|
raise loopingcall.LoopingCallDone()
|
|
|
|
@horcm_synchronized
|
|
def restart_horcm(self, inst=None):
|
|
if inst is None:
|
|
inst = self.conf.hitachi_horcm_numbers[0]
|
|
|
|
loop = loopingcall.FixedIntervalLoopingCall(
|
|
self._wait_for_horcm_shutdown, inst)
|
|
|
|
loop.start(interval=HORCM_WAITTIME).wait()
|
|
|
|
ret, stdout, stderr = self.start_horcm(inst)
|
|
if ret:
|
|
msg = basic_lib.output_err(
|
|
600, cmd='horcmstart.sh', ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
|
|
def restart_pair_horcm(self):
|
|
inst = self.conf.hitachi_horcm_numbers[1]
|
|
self.restart_horcm(inst=inst)
|
|
|
|
def setup_horcmgr(self, host_ip):
|
|
pair_inst = self.conf.hitachi_horcm_numbers[1]
|
|
self.set_copy_groups(host_ip)
|
|
if self.conf.hitachi_horcm_add_conf:
|
|
self.create_horcmconf()
|
|
self.create_horcmconf(inst=pair_inst)
|
|
self.restart_horcm()
|
|
with self.horcmgr_flock:
|
|
self.restart_pair_horcm()
|
|
ret, stdout, stderr = self.comm_login()
|
|
if ret:
|
|
msg = basic_lib.output_err(
|
|
600, cmd='raidcom -login', ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
|
|
def _wait_for_exec_horcm(self, cmd, args, printflag, start):
|
|
if cmd == 'raidcom':
|
|
serial = self.conf.hitachi_serial_number
|
|
inst = self.conf.hitachi_horcm_numbers[0]
|
|
raidcom_obj_lock = self.raidcom_lock
|
|
args = '%s -s %s -I%d' % (args, serial, inst)
|
|
else:
|
|
inst = self.conf.hitachi_horcm_numbers[1]
|
|
raidcom_obj_lock = self.raidcom_pair_lock
|
|
args = '%s -ISI%d' % (args, inst)
|
|
user = self.conf.hitachi_horcm_user
|
|
passwd = self.conf.hitachi_horcm_password
|
|
raidcom_lock_file = '%s%d' % (RAIDCOM_LOCK_FILE, inst)
|
|
lock = basic_lib.get_process_lock(raidcom_lock_file)
|
|
|
|
with raidcom_obj_lock, lock:
|
|
ret, stdout, stderr = self.exec_command(cmd, args=args,
|
|
printflag=printflag)
|
|
|
|
if not ret or ret <= 127:
|
|
raise loopingcall.LoopingCallDone((ret, stdout, stderr))
|
|
|
|
if time.time() - start >= EXEC_MAX_WAITTIME:
|
|
LOG.error(_LE("horcm command timeout."))
|
|
raise loopingcall.LoopingCallDone((ret, stdout, stderr))
|
|
|
|
if (ret == EX_ENAUTH and
|
|
not re.search("-login %s %s" % (user, passwd), args)):
|
|
_ret, _stdout, _stderr = self.comm_login()
|
|
if _ret:
|
|
LOG.error(_LE("Failed to authenticate user."))
|
|
raise loopingcall.LoopingCallDone((ret, stdout, stderr))
|
|
|
|
elif ret in HORCM_ERROR:
|
|
_ret = 0
|
|
with raidcom_obj_lock, lock:
|
|
if self.check_horcm(inst) != HORCM_RUNNING:
|
|
_ret, _stdout, _stderr = self.start_horcm(inst)
|
|
if _ret and _ret != HORCM_RUNNING:
|
|
LOG.error(_LE("Failed to start horcm."))
|
|
raise loopingcall.LoopingCallDone((ret, stdout, stderr))
|
|
|
|
elif ret not in COMMAND_IO_TO_RAID:
|
|
LOG.error(_LE("Unexpected error occurs in horcm."))
|
|
raise loopingcall.LoopingCallDone((ret, stdout, stderr))
|
|
|
|
def exec_raidcom(self, cmd, args, printflag=True):
|
|
loop = loopingcall.FixedIntervalLoopingCall(
|
|
self._wait_for_exec_horcm, cmd, args, printflag, time.time())
|
|
|
|
return loop.start(interval=EXEC_RETRY_INTERVAL).wait()
|
|
|
|
def comm_login(self):
|
|
rmi_user = self.conf.hitachi_horcm_user
|
|
rmi_pass = self.conf.hitachi_horcm_password
|
|
args = '-login %s %s' % (rmi_user, rmi_pass)
|
|
return self.exec_raidcom('raidcom', args, printflag=False)
|
|
|
|
def comm_lock(self):
|
|
ret, _stdout, stderr = self.exec_raidcom('raidcom', 'lock resource')
|
|
if ret:
|
|
msg = basic_lib.output_err(
|
|
603, serial=self.conf.hitachi_serial_number,
|
|
inst=self.conf.hitachi_horcm_numbers[0], ret=ret, err=stderr)
|
|
raise exception.HBSDError(message=msg)
|
|
|
|
def comm_unlock(self):
|
|
self.exec_raidcom('raidcom', 'unlock resource')
|
|
|
|
def comm_reset_status(self):
|
|
self.exec_raidcom('raidcom', 'reset command_status')
|
|
|
|
def comm_get_status(self):
|
|
return self.exec_raidcom('raidcom', 'get command_status')
|
|
|
|
def get_command_error(self, stdout):
|
|
lines = stdout.splitlines()
|
|
line = shlex.split(lines[1])
|
|
return int(line[3])
|
|
|
|
def comm_get_ldev(self, ldev):
|
|
opt = 'get ldev -ldev_id %s' % ldev
|
|
ret, stdout, stderr = self.exec_raidcom('raidcom', opt,
|
|
printflag=False)
|
|
if ret:
|
|
opt = 'raidcom %s' % opt
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
return stdout
|
|
|
|
def add_used_hlun(self, port, gid, used_list):
|
|
opt = 'get lun -port %s-%d' % (port, gid)
|
|
ret, stdout, stderr = self.exec_raidcom('raidcom', opt,
|
|
printflag=False)
|
|
if ret:
|
|
opt = 'raidcom %s' % opt
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
lines = stdout.splitlines()
|
|
for line in lines[1:]:
|
|
lun = int(shlex.split(line)[3])
|
|
if lun not in used_list:
|
|
used_list.append(lun)
|
|
|
|
def get_unused_ldev(self, ldev_range):
|
|
start = ldev_range[0]
|
|
end = ldev_range[1]
|
|
|
|
while start < end:
|
|
if end - start + 1 > GETSTORAGEARRAY_ONCE:
|
|
cnt = GETSTORAGEARRAY_ONCE
|
|
else:
|
|
cnt = end - start + 1
|
|
opt = 'get ldev -ldev_id %d -cnt %d' % (start, cnt)
|
|
ret, stdout, stderr = self.exec_raidcom('raidcom', opt,
|
|
printflag=False)
|
|
if ret:
|
|
opt = 'raidcom %s' % opt
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
|
|
lines = stdout.splitlines()
|
|
ldev_num = None
|
|
for line in lines:
|
|
if re.match("LDEV :", line):
|
|
ldev_num = int(shlex.split(line)[2])
|
|
continue
|
|
if re.match("VOL_TYPE : NOT DEFINED", line):
|
|
return ldev_num
|
|
|
|
start += GETSTORAGEARRAY_ONCE
|
|
else:
|
|
msg = basic_lib.output_err(648, resource='LDEV')
|
|
raise exception.HBSDError(message=msg)
|
|
|
|
def get_hgname_gid(self, port, host_grp_name):
|
|
opt = 'get host_grp -port %s -key host_grp' % port
|
|
ret, stdout, stderr = self.exec_raidcom('raidcom', opt,
|
|
printflag=False)
|
|
if ret:
|
|
opt = 'raidcom %s' % opt
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
lines = stdout.splitlines()
|
|
for line in lines[1:]:
|
|
line = shlex.split(line)
|
|
if line[2] == host_grp_name:
|
|
return int(line[1])
|
|
return None
|
|
|
|
def get_unused_gid(self, range, port):
|
|
_min = range[0]
|
|
_max = range[1]
|
|
opt = 'get host_grp -port %s -key host_grp' % port
|
|
ret, stdout, stderr = self.exec_raidcom('raidcom', opt,
|
|
printflag=False)
|
|
if ret:
|
|
opt = 'raidcom %s' % opt
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
|
|
lines = stdout.splitlines()
|
|
free_gid = None
|
|
for line in lines[_min + 1:]:
|
|
line = shlex.split(line)
|
|
if int(line[1]) > _max:
|
|
break
|
|
if line[2] == '-':
|
|
free_gid = int(line[1])
|
|
break
|
|
if free_gid is None:
|
|
msg = basic_lib.output_err(648, resource='GID')
|
|
raise exception.HBSDError(message=msg)
|
|
return free_gid
|
|
|
|
def comm_set_target_wwns(self, target_ports):
|
|
opt = 'get port'
|
|
ret, stdout, stderr = self.exec_raidcom('raidcom', opt,
|
|
printflag=False)
|
|
if ret:
|
|
opt = 'raidcom %s' % opt
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
|
|
target_wwns = {}
|
|
lines = stdout.splitlines()
|
|
for line in lines[1:]:
|
|
line = shlex.split(line)
|
|
port = line[0][:5]
|
|
if target_ports and port not in target_ports:
|
|
continue
|
|
|
|
target_wwns[port] = line[10]
|
|
LOG.debug('target wwns: %s' % target_wwns)
|
|
return target_wwns
|
|
|
|
def comm_get_hbawwn(self, hostgroups, wwns, port, is_detected):
|
|
opt = 'get host_grp -port %s' % port
|
|
ret, stdout, stderr = self.exec_raidcom('raidcom', opt,
|
|
printflag=False)
|
|
if ret:
|
|
opt = 'raidcom %s' % opt
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
|
|
lines = stdout.splitlines()
|
|
found_wwns = 0
|
|
for line in lines[1:]:
|
|
line = shlex.split(line)
|
|
if not re.match(basic_lib.NAME_PREFIX, line[2]):
|
|
continue
|
|
gid = line[1]
|
|
opt = 'get hba_wwn -port %s-%s' % (port, gid)
|
|
ret, stdout, stderr = self.exec_raidcom(
|
|
'raidcom', opt, printflag=False)
|
|
if ret:
|
|
opt = 'raidcom %s' % opt
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
|
|
lines = stdout.splitlines()
|
|
for line in lines[1:]:
|
|
hba_info = shlex.split(line)
|
|
|
|
if hba_info[3] in wwns:
|
|
hostgroups.append({'port': six.text_type(port),
|
|
'gid': int(hba_info[1]),
|
|
'initiator_wwn': hba_info[3],
|
|
'detected': is_detected})
|
|
found_wwns += 1
|
|
if len(wwns) == found_wwns:
|
|
break
|
|
|
|
if len(wwns) == found_wwns:
|
|
break
|
|
|
|
def comm_chk_login_wwn(self, wwns, port):
|
|
opt = 'get port -port %s' % port
|
|
ret, stdout, stderr = self.exec_raidcom('raidcom', opt,
|
|
printflag=False)
|
|
|
|
if ret:
|
|
opt = 'raidcom %s' % opt
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
|
|
lines = stdout.splitlines()
|
|
for line in lines[1:]:
|
|
login_info = shlex.split(line)
|
|
if login_info[1] in wwns:
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def comm_get_hostgroup_info(self, hgs, wwns, target_ports, login=True):
|
|
security_ports = []
|
|
hostgroups = []
|
|
|
|
opt = 'get port'
|
|
ret, stdout, stderr = self.exec_raidcom('raidcom', opt,
|
|
printflag=False)
|
|
if ret:
|
|
opt = 'raidcom %s' % opt
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
|
|
lines = stdout.splitlines()
|
|
|
|
for line in lines[1:]:
|
|
line = shlex.split(line)
|
|
port = line[0][:5]
|
|
if target_ports and port not in target_ports:
|
|
continue
|
|
security = True if line[7] == 'Y' else False
|
|
|
|
is_detected = None
|
|
if login:
|
|
is_detected = self.comm_chk_login_wwn(wwns, port)
|
|
|
|
if security:
|
|
self.comm_get_hbawwn(hostgroups, wwns, port, is_detected)
|
|
security_ports.append(port)
|
|
|
|
for hostgroup in hostgroups:
|
|
hgs.append(hostgroup)
|
|
|
|
return security_ports
|
|
|
|
def _get_lun(self, port, gid, ldev):
|
|
lun = None
|
|
|
|
opt = 'get lun -port %s-%d' % (port, gid)
|
|
ret, stdout, stderr = self.exec_raidcom('raidcom', opt,
|
|
printflag=False)
|
|
if ret:
|
|
opt = 'raidcom %s' % opt
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
|
|
lines = stdout.splitlines()
|
|
for line in lines[1:]:
|
|
line = shlex.split(line)
|
|
if line[5] == six.text_type(ldev):
|
|
lun = int(line[3])
|
|
break
|
|
|
|
return lun
|
|
|
|
def _wait_for_delete_lun(self, hostgroup, ldev, start):
|
|
opt = 'delete lun -port %s-%d -ldev_id %d' % (hostgroup['port'],
|
|
hostgroup['gid'], ldev)
|
|
ret, stdout, stderr = self.exec_raidcom('raidcom', opt)
|
|
if not ret:
|
|
raise loopingcall.LoopingCallDone()
|
|
|
|
if (re.search('SSB=%s' % SNAP_LAST_PATH_SSB, stderr) and
|
|
not self.comm_get_snapshot(ldev) or
|
|
re.search('SSB=%s' % HOST_IO_SSB, stderr)):
|
|
msg = basic_lib.set_msg(310, ldev=ldev, reason=stderr)
|
|
LOG.warning(msg)
|
|
|
|
if time.time() - start >= LUN_DELETE_WAITTIME:
|
|
msg = basic_lib.output_err(
|
|
637, method='_wait_for_delete_lun',
|
|
timeout=LUN_DELETE_WAITTIME)
|
|
raise exception.HBSDError(message=msg)
|
|
else:
|
|
opt = 'raidcom %s' % opt
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
|
|
def comm_delete_lun_core(self, hostgroup, ldev):
|
|
loop = loopingcall.FixedIntervalLoopingCall(
|
|
self._wait_for_delete_lun, hostgroup, ldev, time.time())
|
|
|
|
loop.start(interval=LUN_DELETE_INTERVAL).wait()
|
|
|
|
@storage_synchronized
|
|
def comm_delete_lun(self, hostgroups, ldev):
|
|
try:
|
|
deleted_hostgroups = []
|
|
self.comm_lock()
|
|
no_ldev_cnt = 0
|
|
for hostgroup in hostgroups:
|
|
port = hostgroup['port']
|
|
gid = hostgroup['gid']
|
|
is_deleted = False
|
|
for deleted in deleted_hostgroups:
|
|
if port == deleted['port'] and gid == deleted['gid']:
|
|
is_deleted = True
|
|
if is_deleted:
|
|
continue
|
|
try:
|
|
self.comm_delete_lun_core(hostgroup, ldev)
|
|
except exception.HBSDCmdError as ex:
|
|
no_ldev_cnt += 1
|
|
if ex.ret == EX_ENOOBJ:
|
|
if no_ldev_cnt != len(hostgroups):
|
|
continue
|
|
raise exception.HBSDNotFound
|
|
else:
|
|
raise
|
|
deleted_hostgroups.append({'port': port, 'gid': gid})
|
|
finally:
|
|
self.comm_unlock()
|
|
|
|
def _check_ldev_status(self, ldev, status):
|
|
opt = ('get ldev -ldev_id %s -check_status %s -time %s' %
|
|
(ldev, status, LDEV_STATUS_WAITTIME))
|
|
ret, _stdout, _stderr = self.exec_raidcom('raidcom', opt)
|
|
return ret
|
|
|
|
@storage_synchronized
|
|
def comm_add_ldev(self, pool_id, ldev, capacity, is_vvol):
|
|
emulation = 'OPEN-V'
|
|
if is_vvol:
|
|
opt = ('add ldev -pool snap -ldev_id %d '
|
|
'-capacity %dG -emulation %s'
|
|
% (ldev, capacity, emulation))
|
|
else:
|
|
opt = ('add ldev -pool %d -ldev_id %d '
|
|
'-capacity %dG -emulation %s'
|
|
% (pool_id, ldev, capacity, emulation))
|
|
|
|
try:
|
|
self.comm_lock()
|
|
self.comm_reset_status()
|
|
ret, stdout, stderr = self.exec_raidcom('raidcom', opt)
|
|
if ret:
|
|
if re.search('SSB=%s' % INTERCEPT_LDEV_SSB, stderr):
|
|
raise exception.HBSDNotFound
|
|
opt = 'raidcom %s' % opt
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
|
|
if self._check_ldev_status(ldev, "NML"):
|
|
msg = basic_lib.output_err(653, ldev=ldev)
|
|
raise exception.HBSDError(message=msg)
|
|
finally:
|
|
self.comm_unlock()
|
|
|
|
@storage_synchronized
|
|
def comm_add_hostgrp(self, port, gid, host_grp_name):
|
|
opt = 'add host_grp -port %s-%d -host_grp_name %s' % (port, gid,
|
|
host_grp_name)
|
|
try:
|
|
self.comm_lock()
|
|
ret, stdout, stderr = self.exec_raidcom('raidcom', opt)
|
|
if ret:
|
|
if re.search('SSB=%s' % HOSTGROUP_INSTALLED, stderr):
|
|
raise exception.HBSDNotFound
|
|
else:
|
|
opt = 'raidcom %s' % opt
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(
|
|
message=msg, ret=ret, err=stderr)
|
|
finally:
|
|
self.comm_unlock()
|
|
|
|
@storage_synchronized
|
|
def comm_del_hostgrp(self, port, gid, host_grp_name):
|
|
opt = 'delete host_grp -port %s-%d %s' % (port, gid, host_grp_name)
|
|
try:
|
|
self.comm_lock()
|
|
ret, stdout, stderr = self.exec_raidcom('raidcom', opt)
|
|
if ret:
|
|
opt = 'raidcom %s' % opt
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
finally:
|
|
self.comm_unlock()
|
|
|
|
@storage_synchronized
|
|
def comm_add_hbawwn(self, port, gid, wwn):
|
|
opt = 'add hba_wwn -port %s-%s -hba_wwn %s' % (port, gid, wwn)
|
|
try:
|
|
self.comm_lock()
|
|
ret, stdout, stderr = self.exec_raidcom('raidcom', opt)
|
|
if ret:
|
|
opt = 'raidcom %s' % opt
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
finally:
|
|
self.comm_unlock()
|
|
|
|
@storage_synchronized
|
|
def comm_add_lun(self, unused_command, hostgroups, ldev, is_once=False):
|
|
tmp_hostgroups = hostgroups[:]
|
|
is_ok = False
|
|
used_list = []
|
|
lun = None
|
|
old_lun = None
|
|
|
|
for hostgroup in hostgroups:
|
|
port = hostgroup['port']
|
|
gid = hostgroup['gid']
|
|
self.add_used_hlun(port, gid, used_list)
|
|
lun = self._get_lun(port, gid, ldev)
|
|
|
|
# When 'lun' or 'old_lun' is 0, it should be true.
|
|
# So, it cannot remove 'is not None'.
|
|
if lun is not None:
|
|
if old_lun is not None and old_lun != lun:
|
|
msg = basic_lib.output_err(648, resource='LUN (HLUN)')
|
|
raise exception.HBSDError(message=msg)
|
|
is_ok = True
|
|
hostgroup['lun'] = lun
|
|
tmp_hostgroups.remove(hostgroup)
|
|
old_lun = lun
|
|
|
|
if is_once:
|
|
# When 'lun' is 0, it should be true.
|
|
# So, it cannot remove 'is not None'.
|
|
if lun is not None:
|
|
return
|
|
elif len(used_list) < MAX_HLUN + 1:
|
|
break
|
|
else:
|
|
tmp_hostgroups.remove(hostgroup)
|
|
if tmp_hostgroups:
|
|
used_list = []
|
|
|
|
if not used_list:
|
|
lun = 0
|
|
elif lun is None:
|
|
for i in range(MAX_HLUN + 1):
|
|
if i not in used_list:
|
|
lun = i
|
|
break
|
|
else:
|
|
raise exception.HBSDNotFound
|
|
|
|
opt = None
|
|
ret = 0
|
|
stdout = None
|
|
stderr = None
|
|
invalid_hgs_str = None
|
|
|
|
try:
|
|
self.comm_lock()
|
|
for hostgroup in tmp_hostgroups:
|
|
port = hostgroup['port']
|
|
gid = hostgroup['gid']
|
|
if not hostgroup['detected']:
|
|
if invalid_hgs_str:
|
|
invalid_hgs_str = '%s, %s:%d' % (invalid_hgs_str,
|
|
port, gid)
|
|
else:
|
|
invalid_hgs_str = '%s:%d' % (port, gid)
|
|
continue
|
|
opt = 'add lun -port %s-%d -ldev_id %d -lun_id %d' % (
|
|
port, gid, ldev, lun)
|
|
ret, stdout, stderr = self.exec_raidcom('raidcom', opt)
|
|
if not ret:
|
|
is_ok = True
|
|
hostgroup['lun'] = lun
|
|
if is_once:
|
|
break
|
|
else:
|
|
msg = basic_lib.set_msg(
|
|
314, ldev=ldev, lun=lun, port=port, id=gid)
|
|
LOG.warning(msg)
|
|
|
|
finally:
|
|
self.comm_unlock()
|
|
|
|
if not is_ok:
|
|
if stderr:
|
|
opt = 'raidcom %s' % opt
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
else:
|
|
msg = basic_lib.output_err(659, gid=invalid_hgs_str)
|
|
raise exception.HBSDError(message=msg)
|
|
|
|
@storage_synchronized
|
|
def comm_delete_ldev(self, ldev, is_vvol):
|
|
ret = -1
|
|
stdout = ""
|
|
stderr = ""
|
|
try:
|
|
self.comm_lock()
|
|
self.comm_reset_status()
|
|
opt = 'delete ldev -ldev_id %d' % ldev
|
|
ret, stdout, stderr = self.exec_raidcom('raidcom', opt)
|
|
if ret:
|
|
if re.search('SSB=%s' % INVALID_LUN_SSB, stderr):
|
|
raise exception.HBSDNotFound
|
|
opt = 'raidcom %s' % opt
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
ret, stdout, stderr = self.comm_get_status()
|
|
if ret or self.get_command_error(stdout):
|
|
opt = 'raidcom %s' % opt
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
finally:
|
|
self.comm_unlock()
|
|
|
|
@storage_synchronized
|
|
def comm_extend_ldev(self, ldev, old_size, new_size):
|
|
ret = -1
|
|
stdout = ""
|
|
stderr = ""
|
|
extend_size = new_size - old_size
|
|
try:
|
|
self.comm_lock()
|
|
self.comm_reset_status()
|
|
opt = 'extend ldev -ldev_id %d -capacity %dG' % (ldev, extend_size)
|
|
ret, stdout, stderr = self.exec_raidcom('raidcom', opt)
|
|
if ret:
|
|
opt = 'raidcom %s' % opt
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
ret, stdout, stderr = self.comm_get_status()
|
|
if ret or self.get_command_error(stdout):
|
|
opt = 'raidcom %s' % opt
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
finally:
|
|
self.comm_unlock()
|
|
|
|
def comm_get_dp_pool(self, pool_id):
|
|
opt = 'get dp_pool'
|
|
ret, stdout, stderr = self.exec_raidcom('raidcom', opt,
|
|
printflag=False)
|
|
if ret:
|
|
opt = 'raidcom %s' % opt
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
|
|
lines = stdout.splitlines()
|
|
for line in lines[1:]:
|
|
if int(shlex.split(line)[0]) == pool_id:
|
|
free_gb = int(shlex.split(line)[3]) / 1024
|
|
total_gb = int(shlex.split(line)[4]) / 1024
|
|
return total_gb, free_gb
|
|
|
|
msg = basic_lib.output_err(640, pool_id=pool_id)
|
|
raise exception.HBSDError(message=msg)
|
|
|
|
@storage_synchronized
|
|
def comm_modify_ldev(self, ldev):
|
|
args = 'modify ldev -ldev_id %d -status discard_zero_page' % ldev
|
|
try:
|
|
self.comm_lock()
|
|
ret, stdout, stderr = self.exec_raidcom('raidcom', args)
|
|
if ret:
|
|
msg = basic_lib.set_msg(315, ldev=ldev, reason=stderr)
|
|
LOG.warning(msg)
|
|
finally:
|
|
self.comm_unlock()
|
|
|
|
def is_detected(self, port, wwn):
|
|
return self.comm_chk_login_wwn([wwn], port)
|
|
|
|
def discard_zero_page(self, ldev):
|
|
try:
|
|
self.comm_modify_ldev(ldev)
|
|
except Exception as e:
|
|
LOG.warning(_LW('Failed to discard zero page: %s') %
|
|
six.text_type(e))
|
|
|
|
@storage_synchronized
|
|
def comm_add_snapshot(self, pvol, svol):
|
|
pool = self.conf.hitachi_thin_pool_id
|
|
copy_size = self.conf.hitachi_copy_speed
|
|
args = ('add snapshot -ldev_id %d %d -pool %d '
|
|
'-snapshot_name %s -copy_size %d'
|
|
% (pvol, svol, pool, SNAP_NAME, copy_size))
|
|
try:
|
|
self.comm_lock()
|
|
ret, stdout, stderr = self.exec_raidcom('raidcom', args)
|
|
if ret:
|
|
opt = 'raidcom %s' % args
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
finally:
|
|
self.comm_unlock()
|
|
|
|
@storage_synchronized
|
|
def comm_delete_snapshot(self, ldev):
|
|
args = 'delete snapshot -ldev_id %d' % ldev
|
|
try:
|
|
self.comm_lock()
|
|
ret, stdout, stderr = self.exec_raidcom('raidcom', args)
|
|
if ret:
|
|
opt = 'raidcom %s' % args
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
finally:
|
|
self.comm_unlock()
|
|
|
|
@storage_synchronized
|
|
def comm_modify_snapshot(self, ldev, op):
|
|
args = ('modify snapshot -ldev_id %d -snapshot_data %s' % (ldev, op))
|
|
try:
|
|
self.comm_lock()
|
|
ret, stdout, stderr = self.exec_raidcom('raidcom', args)
|
|
if ret:
|
|
opt = 'raidcom %s' % args
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
finally:
|
|
self.comm_unlock()
|
|
|
|
def _wait_for_snap_status(self, pvol, svol, status, timeout, start):
|
|
if (self.get_snap_pvol_status(pvol, svol) in status and
|
|
self.get_snap_svol_status(svol) in status):
|
|
raise loopingcall.LoopingCallDone()
|
|
|
|
if time.time() - start >= timeout:
|
|
msg = basic_lib.output_err(
|
|
637, method='_wait_for_snap_status', timuout=timeout)
|
|
raise exception.HBSDError(message=msg)
|
|
|
|
def wait_snap(self, pvol, svol, status, timeout, interval):
|
|
loop = loopingcall.FixedIntervalLoopingCall(
|
|
self._wait_for_snap_status, pvol,
|
|
svol, status, timeout, time.time())
|
|
|
|
loop.start(interval=interval).wait()
|
|
|
|
def comm_get_snapshot(self, ldev):
|
|
args = 'get snapshot -ldev_id %d' % ldev
|
|
ret, stdout, stderr = self.exec_raidcom('raidcom', args,
|
|
printflag=False)
|
|
if ret:
|
|
opt = 'raidcom %s' % args
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
return stdout
|
|
|
|
def check_snap_count(self, ldev):
|
|
stdout = self.comm_get_snapshot(ldev)
|
|
if not stdout:
|
|
return
|
|
lines = stdout.splitlines()
|
|
if len(lines) >= MAX_SNAPSHOT_COUNT + 1:
|
|
msg = basic_lib.output_err(
|
|
615, copy_method=basic_lib.THIN, pvol=ldev)
|
|
raise exception.HBSDBusy(message=msg)
|
|
|
|
def get_snap_pvol_status(self, pvol, svol):
|
|
stdout = self.comm_get_snapshot(pvol)
|
|
if not stdout:
|
|
return basic_lib.SMPL
|
|
lines = stdout.splitlines()
|
|
for line in lines[1:]:
|
|
line = shlex.split(line)
|
|
if int(line[6]) == svol:
|
|
return STATUS_TABLE[line[2]]
|
|
else:
|
|
return basic_lib.SMPL
|
|
|
|
def get_snap_svol_status(self, ldev):
|
|
stdout = self.comm_get_snapshot(ldev)
|
|
if not stdout:
|
|
return basic_lib.SMPL
|
|
lines = stdout.splitlines()
|
|
line = shlex.split(lines[1])
|
|
return STATUS_TABLE[line[2]]
|
|
|
|
@horcm_synchronized
|
|
def create_horcmconf(self, inst=None):
|
|
if inst is None:
|
|
inst = self.conf.hitachi_horcm_numbers[0]
|
|
|
|
serial = self.conf.hitachi_serial_number
|
|
filename = '/etc/horcm%d.conf' % inst
|
|
|
|
port = DEFAULT_PORT_BASE + inst
|
|
|
|
found = False
|
|
|
|
if not os.path.exists(filename):
|
|
file_str = """
|
|
HORCM_MON
|
|
#ip_address service poll(10ms) timeout(10ms)
|
|
127.0.0.1 %16d 6000 3000
|
|
HORCM_CMD
|
|
""" % port
|
|
else:
|
|
file_str = utils.read_file_as_root(filename)
|
|
|
|
lines = file_str.splitlines()
|
|
for line in lines:
|
|
if re.match(r'\\\\.\\CMD-%s:/dev/sd' % serial, line):
|
|
found = True
|
|
break
|
|
|
|
if not found:
|
|
insert_str = r'\\\\.\\CMD-%s:/dev/sd' % serial
|
|
file_str = re.sub(r'(\n\bHORCM_CMD.*|^\bHORCM_CMD.*)',
|
|
r'\1\n%s\n' % insert_str, file_str)
|
|
|
|
try:
|
|
utils.execute('tee', filename, process_input=file_str,
|
|
run_as_root=True)
|
|
except putils.ProcessExecutionError as ex:
|
|
msg = basic_lib.output_err(
|
|
632, file=filename, ret=ex.exit_code, err=ex.stderr)
|
|
raise exception.HBSDError(message=msg)
|
|
|
|
def comm_get_copy_grp(self):
|
|
ret, stdout, stderr = self.exec_raidcom('raidcom', 'get copy_grp',
|
|
printflag=False)
|
|
if ret:
|
|
opt = 'raidcom get copy_grp'
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
return stdout
|
|
|
|
def comm_add_copy_grp(self, copy_group, pvol_group, svol_group, mun):
|
|
args = ('add copy_grp -copy_grp_name %s %s %s -mirror_id %d'
|
|
% (copy_group, pvol_group, svol_group, mun))
|
|
ret, stdout, stderr = self.exec_raidcom('raidcom', args,
|
|
printflag=False)
|
|
if ret:
|
|
opt = 'raidcom %s' % args
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
|
|
def comm_delete_copy_grp(self, copy_group):
|
|
args = 'delete copy_grp -copy_grp_name %s' % copy_group
|
|
ret, stdout, stderr = self.exec_raidcom('raidcom', args,
|
|
printflag=False)
|
|
if ret:
|
|
opt = 'raidcom %s' % args
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
|
|
def comm_get_device_grp(self, group_name):
|
|
args = 'get device_grp -device_grp_name %s' % group_name
|
|
ret, stdout, stderr = self.exec_raidcom('raidcom', args,
|
|
printflag=False)
|
|
if ret:
|
|
opt = 'raidcom %s' % args
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
return stdout
|
|
|
|
def comm_add_device_grp(self, group_name, ldev_name, ldev):
|
|
args = ('add device_grp -device_grp_name %s %s -ldev_id %d'
|
|
% (group_name, ldev_name, ldev))
|
|
ret, stdout, stderr = self.exec_raidcom('raidcom', args,
|
|
printflag=False)
|
|
if ret:
|
|
opt = 'raidcom %s' % args
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
|
|
def comm_delete_device_grp(self, group_name, ldev):
|
|
args = ('delete device_grp -device_grp_name %s -ldev_id %d'
|
|
% (group_name, ldev))
|
|
ret, stdout, stderr = self.exec_raidcom('raidcom', args,
|
|
printflag=False)
|
|
if ret:
|
|
opt = 'raidcom %s' % args
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
|
|
def comm_paircreate(self, copy_group, ldev_name):
|
|
args = ('-g %s -d %s -split -fq quick -c %d -vl'
|
|
% (copy_group, ldev_name, self.conf.hitachi_copy_speed))
|
|
ret, stdout, stderr = self.exec_raidcom('paircreate', args)
|
|
if ret:
|
|
opt = 'paircreate %s' % args
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
|
|
def comm_pairsplit(self, copy_group, ldev_name):
|
|
args = '-g %s -d %s -S' % (copy_group, ldev_name)
|
|
ret, stdout, stderr = self.exec_raidcom('pairsplit', args)
|
|
if ret:
|
|
opt = 'pairsplit %s' % args
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
|
|
def comm_pairevtwait(self, copy_group, ldev_name, check_svol):
|
|
if not check_svol:
|
|
option = '-nowait'
|
|
else:
|
|
option = '-nowaits'
|
|
args = '-g %s -d %s %s' % (copy_group, ldev_name, option)
|
|
ret, stdout, stderr = self.exec_raidcom('pairevtwait', args,
|
|
printflag=False)
|
|
if ret > 127:
|
|
opt = 'pairevtwait %s' % args
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
return ret
|
|
|
|
def comm_pairdisplay(self, copy_group, ldev_name=None):
|
|
if not ldev_name:
|
|
args = '-g %s -CLI' % copy_group
|
|
else:
|
|
args = '-g %s -d %s -CLI' % (copy_group, ldev_name)
|
|
ret, stdout, stderr = self.exec_raidcom('pairdisplay', args,
|
|
printflag=False)
|
|
if ret and ret not in NO_SUCH_DEVICE:
|
|
opt = 'pairdisplay %s' % args
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
return ret, stdout, stderr
|
|
|
|
def check_copy_grp(self, copy_group):
|
|
stdout = self.comm_get_copy_grp()
|
|
lines = stdout.splitlines()
|
|
count = 0
|
|
for line in lines[1:]:
|
|
line = shlex.split(line)
|
|
if line[0] == copy_group:
|
|
count += 1
|
|
if count == 2:
|
|
break
|
|
return count
|
|
|
|
def check_device_grp(self, group_name, ldev, ldev_name=None):
|
|
stdout = self.comm_get_device_grp(group_name)
|
|
lines = stdout.splitlines()
|
|
for line in lines[1:]:
|
|
line = shlex.split(line)
|
|
if int(line[2]) == ldev:
|
|
if not ldev_name:
|
|
return True
|
|
else:
|
|
return line[1] == ldev_name
|
|
else:
|
|
return False
|
|
|
|
def is_smpl(self, copy_group, ldev_name):
|
|
ret, stdout, stderr = self.comm_pairdisplay(copy_group,
|
|
ldev_name=ldev_name)
|
|
if not stdout:
|
|
return True
|
|
|
|
lines = stdout.splitlines()
|
|
for line in lines[1:]:
|
|
line = shlex.split(line)
|
|
if line[9] in [NOT_SET, 'SMPL']:
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def get_copy_groups(self):
|
|
copy_groups = []
|
|
stdout = self.comm_get_copy_grp()
|
|
lines = stdout.splitlines()
|
|
for line in lines[1:]:
|
|
line = shlex.split(line)
|
|
if line[0] in self.copy_groups and line[0] not in copy_groups:
|
|
copy_groups.append(line[0])
|
|
return copy_groups
|
|
|
|
def get_matched_copy_group(self, pvol, svol, ldev_name):
|
|
for copy_group in self.get_copy_groups():
|
|
pvol_group = '%sP' % copy_group
|
|
if self.check_device_grp(pvol_group, pvol, ldev_name=ldev_name):
|
|
return copy_group
|
|
else:
|
|
return None
|
|
|
|
def get_paired_info(self, ldev, only_flag=False):
|
|
paired_info = {'pvol': None, 'svol': []}
|
|
pvol = None
|
|
is_svol = False
|
|
|
|
stdout = self.comm_get_snapshot(ldev)
|
|
if stdout:
|
|
lines = stdout.splitlines()
|
|
line = shlex.split(lines[1])
|
|
status = STATUS_TABLE.get(line[2], basic_lib.UNKN)
|
|
|
|
if line[1] == 'P-VOL':
|
|
pvol = ldev
|
|
svol = int(line[6])
|
|
else:
|
|
is_svol = True
|
|
pvol = int(line[6])
|
|
svol = ldev
|
|
|
|
if status == basic_lib.PSUS:
|
|
status = self.get_snap_pvol_status(pvol, svol)
|
|
|
|
svol_info = {'lun': svol, 'status': status, 'is_vvol': True}
|
|
paired_info['svol'].append(svol_info)
|
|
paired_info['pvol'] = pvol
|
|
|
|
if only_flag or is_svol:
|
|
return paired_info
|
|
|
|
for copy_group in self.get_copy_groups():
|
|
ldev_name = None
|
|
pvol_status = basic_lib.UNKN
|
|
svol_status = basic_lib.UNKN
|
|
|
|
ret, stdout, stderr = self.comm_pairdisplay(copy_group)
|
|
if not stdout:
|
|
continue
|
|
|
|
lines = stdout.splitlines()
|
|
for line in lines[1:]:
|
|
line = shlex.split(line)
|
|
if line[9] not in ['P-VOL', 'S-VOL']:
|
|
continue
|
|
|
|
ldev0 = int(line[8])
|
|
ldev1 = int(line[12])
|
|
if ldev not in [ldev0, ldev1]:
|
|
continue
|
|
|
|
ldev_name = line[1]
|
|
|
|
if line[9] == 'P-VOL':
|
|
pvol = ldev0
|
|
svol = ldev1
|
|
pvol_status = STATUS_TABLE.get(line[10], basic_lib.UNKN)
|
|
else:
|
|
svol = ldev0
|
|
pvol = ldev1
|
|
svol_status = STATUS_TABLE.get(line[10], basic_lib.UNKN)
|
|
|
|
if svol == ldev:
|
|
is_svol = True
|
|
|
|
if not ldev_name:
|
|
continue
|
|
|
|
pvol_group = '%sP' % copy_group
|
|
pvol_ok = self.check_device_grp(pvol_group, pvol,
|
|
ldev_name=ldev_name)
|
|
|
|
svol_group = '%sS' % copy_group
|
|
svol_ok = self.check_device_grp(svol_group, svol,
|
|
ldev_name=ldev_name)
|
|
|
|
if pvol_ok and svol_ok:
|
|
if pvol_status == basic_lib.PSUS:
|
|
status = svol_status
|
|
else:
|
|
status = pvol_status
|
|
|
|
svol_info = {'lun': svol, 'status': status, 'is_vvol': False}
|
|
paired_info['svol'].append(svol_info)
|
|
|
|
if is_svol:
|
|
break
|
|
|
|
# When 'pvol' is 0, it should be true.
|
|
# So, it cannot remove 'is not None'.
|
|
if pvol is not None and paired_info['pvol'] is None:
|
|
paired_info['pvol'] = pvol
|
|
|
|
return paired_info
|
|
|
|
@storage_synchronized
|
|
def add_pair_config(self, pvol, svol, copy_group, ldev_name, mun):
|
|
pvol_group = '%sP' % copy_group
|
|
svol_group = '%sS' % copy_group
|
|
try:
|
|
self.comm_lock()
|
|
self.comm_add_device_grp(pvol_group, ldev_name, pvol)
|
|
self.comm_add_device_grp(svol_group, ldev_name, svol)
|
|
nr_copy_groups = self.check_copy_grp(copy_group)
|
|
if nr_copy_groups == 1:
|
|
self.comm_delete_copy_grp(copy_group)
|
|
if nr_copy_groups != 2:
|
|
self.comm_add_copy_grp(copy_group, pvol_group,
|
|
svol_group, mun)
|
|
finally:
|
|
self.comm_unlock()
|
|
|
|
@storage_synchronized
|
|
def delete_pair_config(self, pvol, svol, copy_group, ldev_name):
|
|
pvol_group = '%sP' % copy_group
|
|
svol_group = '%sS' % copy_group
|
|
try:
|
|
self.comm_lock()
|
|
if self.check_device_grp(pvol_group, pvol, ldev_name=ldev_name):
|
|
self.comm_delete_device_grp(pvol_group, pvol)
|
|
if self.check_device_grp(svol_group, svol, ldev_name=ldev_name):
|
|
self.comm_delete_device_grp(svol_group, svol)
|
|
finally:
|
|
self.comm_unlock()
|
|
|
|
def _wait_for_pair_status(self, copy_group, ldev_name,
|
|
status, timeout, check_svol, start):
|
|
if self.comm_pairevtwait(copy_group, ldev_name,
|
|
check_svol) in status:
|
|
raise loopingcall.LoopingCallDone()
|
|
|
|
if time.time() - start >= timeout:
|
|
msg = basic_lib.output_err(
|
|
637, method='_wait_for_pair_status', timout=timeout)
|
|
raise exception.HBSDError(message=msg)
|
|
|
|
def wait_pair(self, copy_group, ldev_name, status, timeout,
|
|
interval, check_svol=False):
|
|
loop = loopingcall.FixedIntervalLoopingCall(
|
|
self._wait_for_pair_status, copy_group, ldev_name,
|
|
status, timeout, check_svol, time.time())
|
|
|
|
loop.start(interval=interval).wait()
|
|
|
|
def comm_create_pair(self, pvol, svol, is_vvol):
|
|
timeout = basic_lib.DEFAULT_PROCESS_WAITTIME
|
|
interval = self.conf.hitachi_copy_check_interval
|
|
if not is_vvol:
|
|
restart = False
|
|
create = False
|
|
ldev_name = LDEV_NAME % (pvol, svol)
|
|
mun = 0
|
|
for mun in range(MAX_MUNS):
|
|
copy_group = self.copy_groups[mun]
|
|
pvol_group = '%sP' % copy_group
|
|
|
|
if not self.check_device_grp(pvol_group, pvol):
|
|
break
|
|
else:
|
|
msg = basic_lib.output_err(
|
|
615, copy_method=basic_lib.FULL, pvol=pvol)
|
|
raise exception.HBSDBusy(message=msg)
|
|
try:
|
|
self.add_pair_config(pvol, svol, copy_group, ldev_name, mun)
|
|
self.restart_pair_horcm()
|
|
restart = True
|
|
self.comm_paircreate(copy_group, ldev_name)
|
|
create = True
|
|
self.wait_pair(copy_group, ldev_name, [basic_lib.PSUS],
|
|
timeout, interval)
|
|
self.wait_pair(copy_group, ldev_name,
|
|
[basic_lib.PSUS, basic_lib.COPY],
|
|
timeout, interval, check_svol=True)
|
|
except Exception:
|
|
with excutils.save_and_reraise_exception():
|
|
if create:
|
|
try:
|
|
self.wait_pair(copy_group, ldev_name,
|
|
[basic_lib.PSUS], timeout,
|
|
interval)
|
|
self.wait_pair(copy_group, ldev_name,
|
|
[basic_lib.PSUS], timeout,
|
|
interval, check_svol=True)
|
|
except Exception as ex:
|
|
LOG.warning(_LW('Failed to create pair: %s') %
|
|
six.text_type(ex))
|
|
|
|
try:
|
|
self.comm_pairsplit(copy_group, ldev_name)
|
|
self.wait_pair(
|
|
copy_group, ldev_name,
|
|
[basic_lib.SMPL], timeout,
|
|
self.conf.hitachi_async_copy_check_interval)
|
|
except Exception as ex:
|
|
LOG.warning(_LW('Failed to create pair: %s') %
|
|
six.text_type(ex))
|
|
|
|
if self.is_smpl(copy_group, ldev_name):
|
|
try:
|
|
self.delete_pair_config(pvol, svol, copy_group,
|
|
ldev_name)
|
|
except Exception as ex:
|
|
LOG.warning(_LW('Failed to create pair: %s') %
|
|
six.text_type(ex))
|
|
|
|
if restart:
|
|
try:
|
|
self.restart_pair_horcm()
|
|
except Exception as ex:
|
|
LOG.warning(_LW('Failed to restart horcm: %s') %
|
|
six.text_type(ex))
|
|
|
|
else:
|
|
self.check_snap_count(pvol)
|
|
self.comm_add_snapshot(pvol, svol)
|
|
|
|
try:
|
|
self.wait_snap(pvol, svol, [basic_lib.PAIR], timeout, interval)
|
|
self.comm_modify_snapshot(svol, 'create')
|
|
self.wait_snap(pvol, svol, [basic_lib.PSUS], timeout, interval)
|
|
except Exception:
|
|
with excutils.save_and_reraise_exception():
|
|
try:
|
|
self.comm_delete_snapshot(svol)
|
|
self.wait_snap(
|
|
pvol, svol, [basic_lib.SMPL], timeout,
|
|
self.conf.hitachi_async_copy_check_interval)
|
|
except Exception as ex:
|
|
LOG.warning(_LW('Failed to create pair: %s') %
|
|
six.text_type(ex))
|
|
|
|
def delete_pair(self, pvol, svol, is_vvol):
|
|
timeout = basic_lib.DEFAULT_PROCESS_WAITTIME
|
|
interval = self.conf.hitachi_async_copy_check_interval
|
|
if not is_vvol:
|
|
ldev_name = LDEV_NAME % (pvol, svol)
|
|
copy_group = self.get_matched_copy_group(pvol, svol, ldev_name)
|
|
if not copy_group:
|
|
return
|
|
try:
|
|
self.comm_pairsplit(copy_group, ldev_name)
|
|
self.wait_pair(copy_group, ldev_name, [basic_lib.SMPL],
|
|
timeout, interval)
|
|
finally:
|
|
if self.is_smpl(copy_group, ldev_name):
|
|
self.delete_pair_config(pvol, svol, copy_group, ldev_name)
|
|
else:
|
|
self.comm_delete_snapshot(svol)
|
|
self.wait_snap(pvol, svol, [basic_lib.SMPL], timeout, interval)
|
|
|
|
def comm_raidqry(self):
|
|
ret, stdout, stderr = self.exec_command('raidqry', '-h')
|
|
if ret:
|
|
opt = 'raidqry -h'
|
|
msg = basic_lib.output_err(
|
|
600, cmd=opt, ret=ret, out=stdout, err=stderr)
|
|
raise exception.HBSDCmdError(message=msg, ret=ret, err=stderr)
|
|
return stdout
|
|
|
|
def get_comm_version(self):
|
|
stdout = self.comm_raidqry()
|
|
lines = stdout.splitlines()
|
|
return shlex.split(lines[1])[1]
|
|
|
|
def output_param_to_log(self, conf):
|
|
for opt in volume_opts:
|
|
if not opt.secret:
|
|
value = getattr(conf, opt.name)
|
|
LOG.info('\t%-35s%s' % (opt.name + ': ',
|
|
six.text_type(value)))
|
|
|
|
def create_lock_file(self):
|
|
inst = self.conf.hitachi_horcm_numbers[0]
|
|
pair_inst = self.conf.hitachi_horcm_numbers[1]
|
|
serial = self.conf.hitachi_serial_number
|
|
raidcom_lock_file = '%s%d' % (RAIDCOM_LOCK_FILE, inst)
|
|
raidcom_pair_lock_file = '%s%d' % (RAIDCOM_LOCK_FILE, pair_inst)
|
|
horcmgr_lock_file = '%s%d' % (HORCMGR_LOCK_FILE, pair_inst)
|
|
resource_lock_file = '%s%s' % (RESOURCE_LOCK_FILE, serial)
|
|
|
|
basic_lib.create_empty_file(raidcom_lock_file)
|
|
basic_lib.create_empty_file(raidcom_pair_lock_file)
|
|
basic_lib.create_empty_file(horcmgr_lock_file)
|
|
basic_lib.create_empty_file(resource_lock_file)
|
|
|
|
def connect_storage(self):
|
|
properties = utils.brick_get_connector_properties()
|
|
self.setup_horcmgr(properties['ip'])
|
|
|
|
def get_max_hostgroups(self):
|
|
"""return the maximum value of hostgroup id."""
|
|
return MAX_HOSTGROUPS
|
|
|
|
def get_hostgroup_luns(self, port, gid):
|
|
list = []
|
|
self.add_used_hlun(port, gid, list)
|
|
|
|
return list
|
|
|
|
def get_ldev_size_in_gigabyte(self, ldev, existing_ref):
|
|
param = 'serial_number'
|
|
|
|
if param not in existing_ref:
|
|
msg = basic_lib.output_err(700, param=param)
|
|
raise exception.HBSDError(data=msg)
|
|
|
|
storage = existing_ref.get(param)
|
|
if storage != self.conf.hitachi_serial_number:
|
|
msg = basic_lib.output_err(648, resource=param)
|
|
raise exception.HBSDError(data=msg)
|
|
|
|
stdout = self.comm_get_ldev(ldev)
|
|
if not stdout:
|
|
msg = basic_lib.output_err(648, resource='LDEV')
|
|
raise exception.HBSDError(data=msg)
|
|
|
|
sts_line = vol_type = ""
|
|
vol_attrs = []
|
|
size = num_port = 1
|
|
|
|
lines = stdout.splitlines()
|
|
for line in lines:
|
|
if line.startswith("STS :"):
|
|
sts_line = line
|
|
|
|
elif line.startswith("VOL_TYPE :"):
|
|
vol_type = shlex.split(line)[2]
|
|
|
|
elif line.startswith("VOL_ATTR :"):
|
|
vol_attrs = shlex.split(line)[2:]
|
|
|
|
elif line.startswith("VOL_Capacity(BLK) :"):
|
|
size = int(shlex.split(line)[2])
|
|
|
|
elif line.startswith("NUM_PORT :"):
|
|
num_port = int(shlex.split(line)[2])
|
|
|
|
if 'NML' not in sts_line:
|
|
msg = basic_lib.output_err(648, resource='LDEV')
|
|
|
|
raise exception.HBSDError(data=msg)
|
|
|
|
if 'OPEN-V' not in vol_type:
|
|
msg = basic_lib.output_err(702, ldev=ldev)
|
|
raise exception.HBSDError(data=msg)
|
|
|
|
if 'HDP' not in vol_attrs:
|
|
msg = basic_lib.output_err(702, ldev=ldev)
|
|
raise exception.HBSDError(data=msg)
|
|
|
|
for vol_attr in vol_attrs:
|
|
if vol_attr == ':':
|
|
continue
|
|
|
|
if vol_attr in PAIR_TYPE:
|
|
msg = basic_lib.output_err(705, ldev=ldev)
|
|
raise exception.HBSDError(data=msg)
|
|
|
|
if vol_attr not in PERMITTED_TYPE:
|
|
msg = basic_lib.output_err(702, ldev=ldev)
|
|
raise exception.HBSDError(data=msg)
|
|
|
|
# Hitachi storage calculates volume sizes in a block unit, 512 bytes.
|
|
# So, units.Gi is divided by 512.
|
|
if size % (units.Gi / 512):
|
|
msg = basic_lib.output_err(703, ldev=ldev)
|
|
raise exception.HBSDError(data=msg)
|
|
|
|
if num_port:
|
|
msg = basic_lib.output_err(704, ldev=ldev)
|
|
raise exception.HBSDError(data=msg)
|
|
|
|
return size / (units.Gi / 512)
|