Huang Rui cf77385929 The init commmit of stackforge/zvm-driver
Including all python modules for nova-zvm-virt-driver and
neutron-zvm-plugin.

Change-Id: I72dd9f64fc412cbf10f5e7ab6e4ac465a977e849
2014-11-04 17:03:02 +08:00

775 lines
32 KiB
Python
Executable File

# Copyright 2013 IBM Corp.
#
# 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 contextlib
import os
from random import randint
import re
import time
from oslo.config import cfg
import nova.context
from nova.objects import block_device as block_device_obj
from nova.objects import instance as instance_obj
from nova.openstack.common.gettextutils import _
from nova.openstack.common import jsonutils
from nova.openstack.common import log as logging
from nova.virt.zvm import exception
from nova.virt.zvm import utils as zvmutils
from nova import volume
LOG = logging.getLogger(__name__)
CONF = cfg.CONF
class VolumeOperator(object):
"""Volume operator on IBM z/VM platform."""
def __init__(self):
self._svc_driver = SVCDriver()
def init_host(self, host_stats):
try:
self._svc_driver.init_host(host_stats)
except (exception.ZVMDriverError, exception.ZVMVolumeError) as err:
LOG.warning(_("Initialize zhcp failed. Reason: %s") % err)
def attach_volume_to_instance(self, context, connection_info, instance,
mountpoint, is_active, rollback=True):
"""Attach a volume to an instance."""
if None in [connection_info, instance, is_active]:
errmsg = _("Missing required parameters.")
raise exception.ZVMDriverError(msg=errmsg)
LOG.debug(_("Attach a volume to an instance. conn_info: %(info)s; " +
"instance: %(name)s; mountpoint: %(point)s") %
{'info': connection_info, 'name': instance['name'],
'point': mountpoint})
if is_active:
self._svc_driver.attach_volume_active(context, connection_info,
instance, mountpoint,
rollback)
else:
self._svc_driver.attach_volume_inactive(context, connection_info,
instance, mountpoint,
rollback)
def detach_volume_from_instance(self, connection_info, instance,
mountpoint, is_active, rollback=True):
"""Detach a volume from an instance."""
if None in [connection_info, instance, is_active]:
errmsg = _("Missing required parameters.")
raise exception.ZVMDriverError(msg=errmsg)
LOG.debug(_("Detach a volume from an instance. conn_info: %(info)s; " +
"instance: %(name)s; mountpoint: %(point)s") %
{'info': connection_info, 'name': instance['name'],
'point': mountpoint})
if is_active:
self._svc_driver.detach_volume_active(connection_info, instance,
mountpoint, rollback)
else:
self._svc_driver.detach_volume_inactive(connection_info, instance,
mountpoint, rollback)
def get_volume_connector(self, instance):
if not instance:
errmsg = _("Instance must be provided.")
raise exception.ZVMDriverError(msg=errmsg)
return self._svc_driver.get_volume_connector(instance)
def has_persistent_volume(self, instance):
if not instance:
errmsg = _("Instance must be provided.")
raise exception.ZVMDriverError(msg=errmsg)
return self._svc_driver.has_persistent_volume(instance)
@contextlib.contextmanager
def wrap_internal_errors():
"""Wrap internal exceptions to ZVMVolumeError."""
try:
yield
except exception.ZVMBaseException:
raise
except Exception as err:
raise exception.ZVMVolumeError(msg=err)
class DriverAPI(object):
"""DriverAPI for implement volume_attach on IBM z/VM platform."""
def init_host(self, host_stats):
"""Initialize host environment."""
raise NotImplementedError
def get_volume_connector(self, instance):
"""Get volume connector for current driver."""
raise NotImplementedError
def attach_volume_active(self, context, connection_info, instance,
mountpoint, rollback):
"""Attach a volume to an running instance."""
raise NotImplementedError
def detach_volume_active(self, connection_info, instance, mountpoint,
rollback):
"""Detach a volume from an running instance."""
raise NotImplementedError
def attach_volume_inactive(self, context, connection_info, instance,
mountpoint, rollback):
"""Attach a volume to an shutdown instance."""
raise NotImplementedError
def detach_volume_inactive(self, connection_info, instance, mountpoint,
rollback):
"""Detach a volume from an shutdown instance."""
raise NotImplementedError
def has_persistent_volume(self, instance):
"""Decide if the specified instance has persistent volumes attached."""
raise NotImplementedError
class SVCDriver(DriverAPI):
"""SVC volume operator on IBM z/VM platform."""
def __init__(self):
self._xcat_url = zvmutils.XCATUrl()
self._path_utils = zvmutils.PathUtils()
self._host = CONF.zvm_host
self._pool_name = CONF.zvm_scsi_pool
self._fcp_pool = set()
self._instance_fcp_map = {}
self._is_instance_fcp_map_locked = False
self._volume_api = volume.API()
self._actions = {'attach_volume': 'addScsiVolume',
'detach_volume': 'removeScsiVolume',
'create_mountpoint': 'createfilesysnode',
'remove_mountpoint': 'removefilesysnode'}
self._RESERVE = 0
self._INCREASE = 1
self._DECREASE = 2
self._REMOVE = 3
def init_host(self, host_stats):
"""Initialize host environment."""
if not host_stats:
errmsg = _("Can not obtain host stats.")
raise exception.ZVMDriverError(msg=errmsg)
zhcp_fcp_list = CONF.zvm_zhcp_fcp_list
fcp_devices = self._expand_fcp_list(zhcp_fcp_list)
hcpnode = host_stats[0]['zhcp']['nodename']
for _fcp in fcp_devices:
with zvmutils.ignore_errors():
self._attach_device(hcpnode, _fcp)
with zvmutils.ignore_errors():
self._online_device(hcpnode, _fcp)
fcp_list = CONF.zvm_fcp_list
if (fcp_list is None):
errmsg = _("At least one fcp list should be given")
LOG.error(errmsg)
raise exception.ZVMVolumeError(msg=errmsg)
self._init_fcp_pool(fcp_list)
def _init_fcp_pool(self, fcp_list):
"""Map all instances and their fcp devices, and record all free fcps.
One instance should use only one fcp device so far.
"""
self._fcp_pool = self._expand_fcp_list(fcp_list)
self._instance_fcp_map = {}
# Any other functions should not modify _instance_fcp_map during
# FCP pool initialization
self._is_instance_fcp_map_locked = True
compute_host_bdms = self._get_host_volume_bdms()
for instance_bdms in compute_host_bdms:
instance_name = instance_bdms['instance']['name']
for _bdm in instance_bdms['instance_bdms']:
connection_info = self._build_connection_info(_bdm)
try:
_fcp = connection_info['data']['zvm_fcp']
if _fcp and _fcp in self._fcp_pool:
self._update_instance_fcp_map(instance_name, _fcp,
self._INCREASE)
if _fcp and _fcp not in self._fcp_pool:
errmsg = _("FCP device %s is not configured but " +
"is used by %s.") % (_fcp, instance_name)
LOG.warning(errmsg)
except (TypeError, KeyError):
pass
for _key in self._instance_fcp_map.keys():
fcp = self._instance_fcp_map.get(_key)['fcp']
self._fcp_pool.remove(fcp)
self._is_instance_fcp_map_locked = False
def _update_instance_fcp_map_if_unlocked(self, instance_name, fcp, action):
while self._is_instance_fcp_map_locked:
time.sleep(1)
self._update_instance_fcp_map(instance_name, fcp, action)
def _update_instance_fcp_map(self, instance_name, fcp, action):
fcp = fcp.lower()
if instance_name in self._instance_fcp_map:
# One instance should use only one fcp device so far
current_fcp = self._instance_fcp_map.get(instance_name)['fcp']
if fcp != current_fcp:
errmsg = _("Instance %(ins_name)s has multiple FCP devices " +
"attached! FCP1: %(fcp1)s, FCP2: %(fcp2)s"
) % {'ins_name': instance_name, 'fcp1': fcp,
'fcp2': current_fcp}
LOG.warning(errmsg)
return
if action == self._RESERVE:
if instance_name in self._instance_fcp_map:
count = self._instance_fcp_map[instance_name]['count']
if count > 0:
errmsg = _("Try to reserve a fcp device which already " +
"has volumes attached on: %(ins_name)s:%(fcp)s"
) % {'ins_name': instance_name, 'fcp': fcp}
LOG.warning(errmsg)
else:
new_item = {instance_name: {'fcp': fcp, 'count': 0}}
self._instance_fcp_map.update(new_item)
elif action == self._INCREASE:
if instance_name in self._instance_fcp_map:
count = self._instance_fcp_map[instance_name]['count']
new_item = {instance_name: {'fcp': fcp, 'count': count + 1}}
self._instance_fcp_map.update(new_item)
else:
new_item = {instance_name: {'fcp': fcp, 'count': 1}}
self._instance_fcp_map.update(new_item)
elif action == self._DECREASE:
if instance_name in self._instance_fcp_map:
count = self._instance_fcp_map[instance_name]['count']
if count > 0:
new_item = {instance_name: {'fcp': fcp,
'count': count - 1}}
self._instance_fcp_map.update(new_item)
else:
fcp = self._instance_fcp_map[instance_name]['fcp']
self._instance_fcp_map.pop(instance_name)
self._fcp_pool.add(fcp)
else:
errmsg = _("Try to decrease an inexistent map item: " +
"%(ins_name)s:%(fcp)s"
) % {'ins_name': instance_name, 'fcp': fcp}
LOG.warning(errmsg)
elif action == self._REMOVE:
if instance_name in self._instance_fcp_map:
count = self._instance_fcp_map[instance_name]['count']
if count > 0:
errmsg = _("Try to remove a map item while some volumes " +
"are still attached on: %(ins_name)s:%(fcp)s"
) % {'ins_name': instance_name, 'fcp': fcp}
LOG.warning(errmsg)
else:
fcp = self._instance_fcp_map[instance_name]['fcp']
self._instance_fcp_map.pop(instance_name)
self._fcp_pool.add(fcp)
else:
errmsg = _("Try to remove an inexistent map item: " +
"%(ins_name)s:%(fcp)s"
) % {'ins_name': instance_name, 'fcp': fcp}
LOG.warning(errmsg)
else:
errmsg = _("Unrecognized option: %s") % action
LOG.warning(errmsg)
def _get_host_volume_bdms(self):
"""Return all block device mappings on a compute host."""
compute_host_bdms = []
instances = self._get_all_instances()
for instance in instances:
instance_bdms = self._get_instance_bdms(instance)
compute_host_bdms.append(dict(instance=instance,
instance_bdms=instance_bdms))
return compute_host_bdms
def _get_all_instances(self):
context = nova.context.get_admin_context()
return instance_obj.InstanceList.get_by_host(context, self._host)
def _get_instance_bdms(self, instance):
context = nova.context.get_admin_context()
instance_bdms = [bdm for bdm in
(block_device_obj.BlockDeviceMappingList.
get_by_instance_uuid(context, instance['uuid']))
if bdm.is_volume]
return instance_bdms
def has_persistent_volume(self, instance):
return bool(self._get_instance_bdms(instance))
def _build_connection_info(self, bdm):
try:
connection_info = jsonutils.loads(bdm['connection_info'])
return connection_info
except (TypeError, KeyError, ValueError):
return None
def get_volume_connector(self, instance):
try:
fcp = self._instance_fcp_map.get(instance['name'])['fcp']
except Exception:
fcp = None
if not fcp:
fcp = self._get_fcp_from_pool()
if fcp:
self._update_instance_fcp_map_if_unlocked(instance['name'],
fcp, self._RESERVE)
if not fcp:
errmsg = _("No available FCP device found.")
LOG.error(errmsg)
raise exception.ZVMVolumeError(msg=errmsg)
fcp = fcp.lower()
wwpn = self._get_wwpn(fcp)
if not wwpn:
errmsg = _("FCP device %s has no available WWPN.") % fcp
LOG.error(errmsg)
raise exception.ZVMVolumeError(msg=errmsg)
wwpn = wwpn.lower()
return {'zvm_fcp': fcp, 'wwpns': [wwpn], 'host': CONF.zvm_host}
def _get_wwpn(self, fcp):
states = ['active', 'free']
for _state in states:
fcps_info = self._list_fcp_details(_state)
if not fcps_info:
continue
wwpn = self._extract_wwpn_from_fcp_info(fcp, fcps_info)
if wwpn:
return wwpn
def _list_fcp_details(self, state):
fields = '&field=--fcpdevices&field=' + state + '&field=details'
rsp = self._xcat_rinv(fields)
try:
fcp_details = rsp['info'][0][0].splitlines()
return fcp_details
except (TypeError, KeyError):
return None
def _extract_wwpn_from_fcp_info(self, fcp, fcps_info):
"""The FCP infomation would look like this:
host: FCP device number: xxxx
host: Status: Active
host: NPIV world wide port number: xxxxxxxx
host: Channel path ID: xx
host: Physical world wide port number: xxxxxxxx
......
host: FCP device number: xxxx
host: Status: Active
host: NPIV world wide port number: xxxxxxxx
host: Channel path ID: xx
host: Physical world wide port number: xxxxxxxx
"""
lines_per_item = 5
num_fcps = len(fcps_info) / lines_per_item
fcp = fcp.upper()
for _cur in range(0, num_fcps):
# Find target FCP device
if fcp not in fcps_info[_cur * lines_per_item]:
continue
# Try to get NPIV WWPN first
wwpn_info = fcps_info[(_cur + 1) * lines_per_item - 3]
wwpn = self._get_wwpn_from_line(wwpn_info)
if not wwpn:
# Get physical WWPN if NPIV WWPN is none
wwpn_info = fcps_info[(_cur + 1) * lines_per_item - 1]
wwpn = self._get_wwpn_from_line(wwpn_info)
return wwpn
def _get_wwpn_from_line(self, info_line):
wwpn = info_line.split(':')[-1].strip()
if wwpn and wwpn.upper() != 'NONE':
return wwpn
else:
return None
def _get_fcp_from_pool(self):
if self._fcp_pool:
return self._fcp_pool.pop()
self._init_fcp_pool(CONF.zvm_fcp_list)
if self._fcp_pool:
return self._fcp_pool.pop()
def _extract_connection_info(self, context, connection_info):
with wrap_internal_errors():
LOG.debug(_("Extract connection_info: %s") % connection_info)
lun = connection_info['data']['target_lun']
lun = "%04x000000000000" % int(lun)
wwpn = connection_info['data']['target_wwn']
size = '0G'
# There is no context in detach case
if context:
volume_id = connection_info['data']['volume_id']
volume = self._get_volume_by_id(context, volume_id)
size = str(volume['size']) + 'G'
fcp = connection_info['data']['zvm_fcp']
return (lun.lower(), wwpn.lower(), size, fcp.lower())
def _get_volume_by_id(self, context, volume_id):
volume = self._volume_api.get(context, volume_id)
return volume
def attach_volume_active(self, context, connection_info, instance,
mountpoint, rollback=True):
"""Attach a volume to an running instance."""
(lun, wwpn, size, fcp) = self._extract_connection_info(context,
connection_info)
try:
self._update_instance_fcp_map_if_unlocked(instance['name'], fcp,
self._INCREASE)
self._add_zfcp_to_pool(fcp, wwpn, lun, size)
self._add_zfcp(instance, fcp, wwpn, lun, size)
if mountpoint:
self._create_mountpoint(instance, fcp, wwpn, lun, mountpoint)
except (exception.ZVMXCATRequestFailed,
exception.ZVMInvalidXCATResponseDataError,
exception.ZVMXCATInternalError,
exception.ZVMVolumeError):
self._update_instance_fcp_map_if_unlocked(instance['name'], fcp,
self._DECREASE)
do_detach = not self._is_fcp_in_use(instance, fcp)
if rollback:
with zvmutils.ignore_errors():
self._remove_mountpoint(instance, mountpoint)
with zvmutils.ignore_errors():
self._remove_zfcp(instance, fcp, wwpn, lun)
with zvmutils.ignore_errors():
self._remove_zfcp_from_pool(wwpn, lun)
with zvmutils.ignore_errors():
if do_detach:
self._detach_device(instance['name'], fcp)
raise
def detach_volume_active(self, connection_info, instance, mountpoint,
rollback=True):
"""Detach a volume from an running instance."""
(lun, wwpn, size, fcp) = self._extract_connection_info(None,
connection_info)
try:
self._update_instance_fcp_map_if_unlocked(instance['name'], fcp,
self._DECREASE)
do_detach = not self._is_fcp_in_use(instance, fcp)
if mountpoint:
self._remove_mountpoint(instance, mountpoint)
self._remove_zfcp(instance, fcp, wwpn, lun)
self._remove_zfcp_from_pool(wwpn, lun)
if do_detach:
self._detach_device(instance['name'], fcp)
self._update_instance_fcp_map_if_unlocked(instance['name'],
fcp, self._REMOVE)
except (exception.ZVMXCATRequestFailed,
exception.ZVMInvalidXCATResponseDataError,
exception.ZVMXCATInternalError,
exception.ZVMVolumeError):
self._update_instance_fcp_map_if_unlocked(instance['name'], fcp,
self._INCREASE)
if rollback:
with zvmutils.ignore_errors():
self._add_zfcp_to_pool(fcp, wwpn, lun, size)
with zvmutils.ignore_errors():
self._add_zfcp(instance, fcp, wwpn, lun, size)
if mountpoint:
with zvmutils.ignore_errors():
self._create_mountpoint(instance, fcp, wwpn, lun,
mountpoint)
raise
def attach_volume_inactive(self, context, connection_info, instance,
mountpoint, rollback=True):
"""Attach a volume to an shutdown instance."""
(lun, wwpn, size, fcp) = self._extract_connection_info(context,
connection_info)
try:
do_attach = not self._is_fcp_in_use(instance, fcp)
self._update_instance_fcp_map_if_unlocked(instance['name'], fcp,
self._INCREASE)
self._add_zfcp_to_pool(fcp, wwpn, lun, size)
self._allocate_zfcp(instance, fcp, size, wwpn, lun)
self._notice_attach(instance, fcp, wwpn, lun, mountpoint)
if do_attach:
self._attach_device(instance['name'], fcp)
except (exception.ZVMXCATRequestFailed,
exception.ZVMInvalidXCATResponseDataError,
exception.ZVMXCATInternalError,
exception.ZVMVolumeError):
self._update_instance_fcp_map_if_unlocked(instance['name'], fcp,
self._DECREASE)
do_detach = not self._is_fcp_in_use(instance, fcp)
if rollback:
with zvmutils.ignore_errors():
self._notice_detach(instance, fcp, wwpn, lun, mountpoint)
with zvmutils.ignore_errors():
self._remove_zfcp_from_pool(wwpn, lun)
with zvmutils.ignore_errors():
if do_detach:
self._detach_device(instance['name'], fcp)
self._update_instance_fcp_map_if_unlocked(
instance['name'], fcp, self._REMOVE)
raise
def detach_volume_inactive(self, connection_info, instance, mountpoint,
rollback=True):
"""Detach a volume from an shutdown instance."""
(lun, wwpn, size, fcp) = self._extract_connection_info(None,
connection_info)
try:
self._update_instance_fcp_map_if_unlocked(instance['name'], fcp,
self._DECREASE)
do_detach = not self._is_fcp_in_use(instance, fcp)
self._remove_zfcp(instance, fcp, wwpn, lun)
self._remove_zfcp_from_pool(wwpn, lun)
self._notice_detach(instance, fcp, wwpn, lun, mountpoint)
if do_detach:
self._detach_device(instance['name'], fcp)
self._update_instance_fcp_map_if_unlocked(instance['name'],
fcp, self._REMOVE)
except (exception.ZVMXCATRequestFailed,
exception.ZVMInvalidXCATResponseDataError,
exception.ZVMXCATInternalError,
exception.ZVMVolumeError):
self._update_instance_fcp_map_if_unlocked(instance['name'], fcp,
self._INCREASE)
if rollback:
with zvmutils.ignore_errors():
self._attach_device(instance['name'], fcp)
with zvmutils.ignore_errors():
self._notice_attach(instance, fcp, wwpn, lun, mountpoint)
with zvmutils.ignore_errors():
self._add_zfcp_to_pool(fcp, wwpn, lun, size)
with zvmutils.ignore_errors():
self._allocate_zfcp(instance, fcp, size, wwpn, lun)
raise
def _expand_fcp_list(self, fcp_list):
"""Expand fcp list string into a python list object which contains
each fcp devices in the list string. A fcp list is composed of fcp
device addresses, range indicator '-', and split indicator ';'.
For example, if fcp_list is
"0011-0013;0015;0017-0018", expand_fcp_list(fcp_list) will return
[0011, 0012, 0013, 0015, 0017, 0018].
"""
LOG.debug(_("Expand FCP list %s") % fcp_list)
if not fcp_list:
return set()
range_pattern = '[0-9a-fA-F]{1,4}(-[0-9a-fA-F]{1,4})?'
match_pattern = "^(%(range)s)(;%(range)s)*$" % {'range': range_pattern}
if not re.match(match_pattern, fcp_list):
errmsg = _("Invalid FCP address %s") % fcp_list
raise exception.ZVMDriverError(msg=errmsg)
fcp_devices = set()
for _range in fcp_list.split(';'):
if '-' not in _range:
# single device
fcp_addr = int(_range, 16)
fcp_devices.add("%04x" % fcp_addr)
else:
# a range of address
(_min, _max) = _range.split('-')
_min = int(_min, 16)
_max = int(_max, 16)
for fcp_addr in range(_min, _max + 1):
fcp_devices.add("%04x" % fcp_addr)
# remove duplicate entries
return fcp_devices
def _attach_device(self, node, addr, mode='0'):
"""Attach a device to a node."""
body = [' '.join(['--dedicatedevice', addr, addr, mode])]
self._xcat_chvm(node, body)
def _detach_device(self, node, vdev):
"""Detach a device from a node."""
body = [' '.join(['--undedicatedevice', vdev])]
self._xcat_chvm(node, body)
def _online_device(self, node, dev):
"""After attaching a device to a node, the device should be made
online before it being in use.
"""
body = ["command=cio_ignore -r %s" % dev]
self._xcat_xdsh(node, body)
body = ["command=chccwdev -e %s" % dev]
self._xcat_xdsh(node, body)
def _is_fcp_in_use(self, instance, fcp):
if instance['name'] in self._instance_fcp_map:
count = self._instance_fcp_map.get(instance['name'])['count']
if count > 0:
return True
return False
def _notice_attach(self, instance, fcp, wwpn, lun, mountpoint):
file_path = self._get_file_for_punch(instance)
# Create and send volume file
action = self._actions['attach_volume']
lines = self._get_volume_lines(action, fcp, wwpn, lun)
self._send_notice(instance, file_path, lines)
# Create and send mount point file
action = self._actions['create_mountpoint']
lines = self._get_mountpoint_lines(action, fcp, wwpn, lun, mountpoint)
self._send_notice(instance, file_path, lines)
def _notice_detach(self, instance, fcp, wwpn, lun, mountpoint):
file_path = self._get_file_for_punch(instance)
# Create and send volume file
action = self._actions['detach_volume']
lines = self._get_volume_lines(action, fcp, wwpn, lun)
self._send_notice(instance, file_path, lines)
# Create and send mount point file
action = self._actions['remove_mountpoint']
lines = self._get_mountpoint_lines(action, fcp, wwpn, lun, mountpoint)
self._send_notice(instance, file_path, lines)
def _get_volume_lines(self, action, fcp, wwpn, lun):
comments = '# xCAT Init\n'
action_line = "action=%s\n" % action
fcp_line = "fcpAddr=%s\n" % fcp
wwpn_line = "wwpn=%s\n" % wwpn
lun_line = "lun=%s\n" % lun
return [comments, action_line, fcp_line, wwpn_line, lun_line]
def _get_mountpoint_lines(self, action, fcp, wwpn, lun, mountpoint):
comments = '# xCAT Init\n'
action_line = "action=%s\n" % action
mountpoint_line = "tgtFile=%s\n" % mountpoint
if action == self._actions['create_mountpoint']:
path = self._get_zfcp_path_pattern()
srcdev = path % {'fcp': fcp, 'wwpn': wwpn, 'lun': lun}
srcdev_line = "srcFile=%s\n" % srcdev
return [comments, action_line, mountpoint_line, srcdev_line]
else:
return [comments, action_line, mountpoint_line]
def _get_file_for_punch(self, instance):
dir_path = self._path_utils.get_punch_time_path()
file_name = "%08x.disk" % randint(0, int('FFFFFFFF', 16))
file_path = os.path.join(dir_path, file_name)
return file_path
def _send_notice(self, instance, file_path, lines):
with wrap_internal_errors():
with open(file_path, 'w') as f:
f.writelines(lines)
# zvmutils.punch_file will remove the file after punching
zvmutils.punch_file(instance['name'], file_path, 'X')
def _add_zfcp_to_pool(self, fcp, wwpn, lun, size):
body = [' '.join(['--addzfcp2pool', self._pool_name, 'free', wwpn,
lun, size, fcp])]
self._xcat_chhy(body)
def _remove_zfcp_from_pool(self, wwpn, lun):
body = [' '.join(['--removezfcpfrompool', CONF.zvm_scsi_pool, lun,
wwpn])]
self._xcat_chhy(body)
def _add_zfcp(self, instance, fcp, wwpn, lun, size):
body = [' '.join(['--addzfcp', CONF.zvm_scsi_pool, fcp, str(0), size,
str(0), wwpn, lun])]
self._xcat_chvm(instance['name'], body)
def _remove_zfcp(self, instance, fcp, wwpn, lun):
body = [' '.join(['--removezfcp', fcp, wwpn, lun, '1'])]
self._xcat_chvm(instance['name'], body)
def _create_mountpoint(self, instance, fcp, wwpn, lun, mountpoint):
path = self._get_zfcp_path_pattern()
srcdev = path % {'fcp': fcp, 'wwpn': wwpn, 'lun': lun}
body = [" ".join(['--createfilesysnode', srcdev, mountpoint])]
self._xcat_chvm(instance['name'], body)
def _remove_mountpoint(self, instance, mountpoint):
body = [' '.join(['--removefilesysnode', mountpoint])]
self._xcat_chvm(instance['name'], body)
def _allocate_zfcp(self, instance, fcp, size, wwpn, lun):
body = [" ".join(['--reservezfcp', CONF.zvm_scsi_pool, 'used',
instance['name'], fcp, size, wwpn, lun])]
self._xcat_chhy(body)
def _xcat_chvm(self, node, body):
url = self._xcat_url.chvm('/' + node)
zvmutils.xcat_request('PUT', url, body)
def _xcat_chhy(self, body):
url = self._xcat_url.chhv('/' + self._host)
zvmutils.xcat_request('PUT', url, body)
def _xcat_xdsh(self, node, body):
url = self._xcat_url.xdsh('/' + node)
zvmutils.xcat_request('PUT', url, body)
def _xcat_rinv(self, fields):
url = self._xcat_url.rinv('/' + self._host, fields)
return zvmutils.xcat_request('GET', url)
def _get_zfcp_path_pattern(self):
return '/dev/disk/by-path/ccw-0.0.%(fcp)s-zfcp-0x%(wwpn)s:0x%(lun)s'