nova-zvm-virt-driver/nova_zvm/virt/zvm/dist.py

678 lines
27 KiB
Python

# Copyright 2015 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 abc
from nova.i18n import _
from oslo_config import cfg
from oslo_log import log as logging
import six
from nova_zvm.virt.zvm import exception
CONF = cfg.CONF
LOG = logging.getLogger(__name__)
@six.add_metaclass(abc.ABCMeta)
class LinuxDist(object):
"""Linux distribution base class
Due to we need to interact with linux dist and inject different files
according to the dist version. Currently only RHEL and SLES are supported
"""
def create_network_configuration_files(self, file_path, network_info,
base_vdev):
"""Generate network configuration files to instance."""
device_num = 0
cfg_files = []
cmd_strings = ''
udev_cfg_str = ''
dns_cfg_str = ''
route_cfg_str = ''
cmd_str = None
file_path = self._get_network_file_path()
file_name_route = file_path + 'routes'
file_name_dns = self._get_dns_filename()
for vif in network_info:
file_name = self._get_device_filename(device_num)
network = vif['network']
(cfg_str, cmd_str, dns_str,
route_str) = self._generate_network_configuration(network,
base_vdev, device_num)
target_net_conf_file_name = file_path + file_name
cfg_str_for_log = cfg_str.replace('\n', ' ')
LOG.debug('Network configure file[%s] content is: %s',
(target_net_conf_file_name, cfg_str_for_log))
cfg_files.append((target_net_conf_file_name, cfg_str))
udev_cfg_str += self._get_udev_configuration(device_num,
'0.0.' + str(base_vdev).zfill(4))
self._append_udev_rules_file(cfg_files, base_vdev)
if cmd_str is not None:
cmd_strings += cmd_str
if len(dns_str) > 0:
dns_cfg_str += dns_str
if len(route_str) > 0:
route_cfg_str += route_str
base_vdev = str(hex(int(base_vdev, 16) + 3))[2:]
device_num += 1
if len(dns_cfg_str) > 0:
cfg_files.append((file_name_dns, dns_cfg_str))
self._append_udev_info(cfg_files, file_name_route, route_cfg_str,
udev_cfg_str)
return cfg_files, cmd_strings
def _generate_network_configuration(self, network, vdev, device_num):
ip_v4 = dns_str = ''
subnets_v4 = [s for s in network['subnets'] if s['version'] == 4]
if len(subnets_v4[0]['ips']) > 0:
ip_v4 = subnets_v4[0]['ips'][0]['address']
if len(subnets_v4[0]['dns']) > 0:
for dns in subnets_v4[0]['dns']:
dns_str += 'nameserver ' + dns['address'] + '\n'
netmask_v4 = str(subnets_v4[0].as_netaddr().netmask)
gateway_v4 = subnets_v4[0]['gateway']['address'] or ''
broadcast_v4 = str(subnets_v4[0].as_netaddr().broadcast)
device = self._get_device_name(device_num)
address_read = str(vdev).zfill(4)
address_write = str(hex(int(vdev, 16) + 1))[2:].zfill(4)
address_data = str(hex(int(vdev, 16) + 2))[2:].zfill(4)
subchannels = '0.0.%s' % address_read.lower()
subchannels += ',0.0.%s' % address_write.lower()
subchannels += ',0.0.%s' % address_data.lower()
cfg_str = self._get_cfg_str(device, broadcast_v4, gateway_v4,
ip_v4, netmask_v4, address_read,
subchannels)
cmd_str = self._get_cmd_str(address_read, address_write,
address_data)
route_str = self._get_route_str(gateway_v4)
return cfg_str, cmd_str, dns_str, route_str
def assemble_zfcp_srcdev(self, fcp, wwpn, lun):
path = '/dev/disk/by-path/ccw-0.0.%(fcp)s-zfcp-0x%(wwpn)s:0x%(lun)s'
srcdev = path % {'fcp': fcp, 'wwpn': wwpn, 'lun': lun}
return srcdev
@abc.abstractmethod
def _get_network_file_path(self):
"""Get network file configuration path."""
pass
def get_change_passwd_command(self, admin_password):
"""construct change password command
:admin_password: the password to be changed to
"""
return "echo 'root:%s' | chpasswd" % admin_password
@abc.abstractmethod
def _get_cfg_str(self, device, broadcast_v4, gateway_v4, ip_v4,
netmask_v4, address_read, subchannels):
"""construct configuration file of network device."""
pass
@abc.abstractmethod
def _get_device_filename(self, device_num):
"""construct the name of a network device file."""
pass
@abc.abstractmethod
def _get_route_str(self, gateway_v4):
"""construct a router string."""
pass
@abc.abstractmethod
def _get_cmd_str(self, address_read, address_write, address_data):
"""construct network startup command string."""
pass
@abc.abstractmethod
def _get_dns_filename(self):
"""construct the name of dns file."""
pass
@abc.abstractmethod
def get_znetconfig_contents(self):
"""construct znetconfig file will be called during first boot."""
pass
@abc.abstractmethod
def _get_device_name(self, device_num):
"""construct the name of a network device."""
pass
@abc.abstractmethod
def _get_udev_configuration(self, device, dev_channel):
"""construct udev configuration info."""
pass
@abc.abstractmethod
def _get_udev_rules(self, channel_read, channel_write, channel_data):
"""construct udev rules info."""
pass
@abc.abstractmethod
def _append_udev_info(self, cfg_files, file_name_route, route_cfg_str,
udev_cfg_str):
pass
@abc.abstractmethod
def _append_udev_rules_file(self, cfg_files, base_vdev):
pass
@abc.abstractmethod
def get_scp_string(self, root, fcp, wwpn, lun):
"""construct scp_data string for ipl parameter"""
pass
@abc.abstractmethod
def get_zipl_script_lines(self, image, ramdisk, root, fcp, wwpn, lun):
"""construct the lines composing the script to generate
the /etc/zipl.conf file
"""
pass
class rhel(LinuxDist):
def _get_network_file_path(self):
return '/etc/sysconfig/network-scripts/'
def _get_cfg_str(self, device, broadcast_v4, gateway_v4, ip_v4,
netmask_v4, address_read, subchannels):
cfg_str = 'DEVICE=\"' + device + '\"\n'
cfg_str += 'BOOTPROTO=\"static\"\n'
cfg_str += 'BROADCAST=\"' + broadcast_v4 + '\"\n'
cfg_str += 'GATEWAY=\"' + gateway_v4 + '\"\n'
cfg_str += 'IPADDR=\"' + ip_v4 + '\"\n'
cfg_str += 'NETMASK=\"' + netmask_v4 + '\"\n'
cfg_str += 'NETTYPE=\"qeth\"\n'
cfg_str += 'ONBOOT=\"yes\"\n'
cfg_str += 'PORTNAME=\"PORT' + address_read + '\"\n'
cfg_str += 'OPTIONS=\"layer2=1\"\n'
cfg_str += 'SUBCHANNELS=\"' + subchannels + '\"\n'
return cfg_str
def _get_route_str(self, gateway_v4):
return ''
def _get_cmd_str(self, address_read, address_write, address_data):
return ''
def _get_dns_filename(self):
return '/etc/resolv.conf'
def _get_device_name(self, device_num):
return 'eth' + str(device_num)
def _get_udev_configuration(self, device, dev_channel):
return ''
def _append_udev_info(self, cfg_files, file_name_route, route_cfg_str,
udev_cfg_str):
pass
def _get_udev_rules(self, channel_read, channel_write, channel_data):
"""construct udev rules info."""
return ''
def _append_udev_rules_file(self, cfg_files, base_vdev):
pass
class rhel6(rhel):
def get_znetconfig_contents(self):
return '\n'.join(('cio_ignore -R',
'znetconf -R -n',
'udevadm trigger',
'udevadm settle',
'sleep 2',
'znetconf -A',
'service network restart',
'cio_ignore -u'))
def _get_device_filename(self, device_num):
return 'ifcfg-eth' + str(device_num)
def _get_device_name(self, device_num):
return 'eth' + str(device_num)
def get_scp_string(self, root, fcp, wwpn, lun):
return ("=root=%(root)s selinux=0 zfcp.allow_lun_scan=0 "
"rd_ZFCP=0.0.%(fcp)s,0x%(wwpn)s,0x%(lun)s") % {
'root': root, 'fcp': fcp, 'wwpn': wwpn, 'lun': lun}
def get_zipl_script_lines(self, image, ramdisk, root, fcp, wwpn, lun):
return ['#!/bin/bash\n',
('echo -e "[defaultboot]\\n'
'timeout=5\\n'
'default=boot-from-volume\\n'
'target=/boot/\\n'
'[boot-from-volume]\\n'
'image=%(image)s\\n'
'ramdisk=%(ramdisk)s\\n'
'parameters=\\"root=%(root)s '
'rd_ZFCP=0.0.%(fcp)s,0x%(wwpn)s,0x%(lun)s '
'zfcp.allow_lun_scan=0 selinux=0\\""'
'>/etc/zipl_volume.conf\n'
'zipl -c /etc/zipl_volume.conf')
% {'image': image, 'ramdisk': ramdisk, 'root': root,
'fcp': fcp, 'wwpn': wwpn, 'lun': lun}]
class rhel7(rhel):
def get_znetconfig_contents(self):
return '\n'.join(('cio_ignore -R',
'znetconf -R -n',
'udevadm trigger',
'udevadm settle',
'sleep 2',
'znetconf -A',
'cio_ignore -u'))
def _get_device_filename(self, device_num):
# Construct a device like ifcfg-enccw0.0.1000, ifcfg-enccw0.0.1003
base = int(CONF.zvm_default_nic_vdev, 16)
device = str(hex(base + device_num * 3))[2:]
return 'ifcfg-enccw0.0.' + str(device).zfill(4)
def _get_device_name(self, device_num):
# Construct a device like enccw0.0.1000, enccw0.0.1003
base = int(CONF.zvm_default_nic_vdev, 16)
device = str(hex(base + device_num * 3))[2:]
return 'enccw0.0.' + str(device).zfill(4)
def get_scp_string(self, root, fcp, wwpn, lun):
return ("=root=%(root)s selinux=0 zfcp.allow_lun_scan=0 "
"rd.zfcp=0.0.%(fcp)s,0x%(wwpn)s,0x%(lun)s") % {
'root': root, 'fcp': fcp, 'wwpn': wwpn, 'lun': lun}
def get_zipl_script_lines(self, image, ramdisk, root, fcp, wwpn, lun):
return ['#!/bin/bash\n',
('echo -e "[defaultboot]\\n'
'timeout=5\\n'
'default=boot-from-volume\\n'
'target=/boot/\\n'
'[boot-from-volume]\\n'
'image=%(image)s\\n'
'ramdisk=%(ramdisk)s\\n'
'parameters=\\"root=%(root)s '
'rd.zfcp=0.0.%(fcp)s,0x%(wwpn)s,0x%(lun)s '
'zfcp.allow_lun_scan=0 selinux=0\\""'
'>/etc/zipl_volume.conf\n'
'zipl -c /etc/zipl_volume.conf')
% {'image': image, 'ramdisk': ramdisk, 'root': root,
'fcp': fcp, 'wwpn': wwpn, 'lun': lun}]
class sles(LinuxDist):
def _get_network_file_path(self):
return '/etc/sysconfig/network/'
def _get_cidr_from_ip_netmask(self, ip, netmask):
netmask_fields = netmask.split('.')
bin_str = ''
for octet in netmask_fields:
bin_str += bin(int(octet))[2:].zfill(8)
mask = str(len(bin_str.rstrip('0')))
cidr_v4 = ip + '/' + mask
return cidr_v4
def _get_cfg_str(self, device, broadcast_v4, gateway_v4, ip_v4,
netmask_v4, address_read, subchannels):
cidr_v4 = self._get_cidr_from_ip_netmask(ip_v4, netmask_v4)
cfg_str = "BOOTPROTO=\'static\'\n"
cfg_str += "IPADDR=\'%s\'\n" % cidr_v4
cfg_str += "BROADCAST=\'%s\'\n" % broadcast_v4
cfg_str += "STARTMODE=\'onboot\'\n"
cfg_str += ("NAME=\'OSA Express Network card (%s)\'\n" %
address_read)
return cfg_str
def _get_route_str(self, gateway_v4):
route_str = 'default %s - -\n' % gateway_v4
return route_str
def _get_cmd_str(self, address_read, address_write, address_data):
cmd_str = 'qeth_configure -l 0.0.%s ' % address_read.lower()
cmd_str += '0.0.%(write)s 0.0.%(data)s 1\n' % {'write':
address_write.lower(), 'data': address_data.lower()}
cmd_str += ('echo "0.0.%(read)s,0.0.%(write)s,0.0.%(data)s #`date`"'
' >>/boot/zipl/active_devices.txt\n' % {'read':
address_read.lower(), 'write': address_write.lower(),
'data': address_data.lower()})
return cmd_str
def _get_dns_filename(self):
return '/etc/resolv.conf'
def _get_device_filename(self, device_num):
return 'ifcfg-eth' + str(device_num)
def _get_device_name(self, device_num):
return 'eth' + str(device_num)
def _append_udev_info(self, cfg_files, file_name_route, route_cfg_str,
udev_cfg_str):
udev_file_name = '/etc/udev/rules.d/70-persistent-net.rules'
cfg_files.append((udev_file_name, udev_cfg_str))
if len(route_cfg_str) > 0:
cfg_files.append((file_name_route, route_cfg_str))
def _get_udev_configuration(self, device, dev_channel):
cfg_str = 'SUBSYSTEM==\"net\", ACTION==\"add\", DRIVERS==\"qeth\",'
cfg_str += ' KERNELS==\"%s\", ATTR{type}==\"1\",' % dev_channel
cfg_str += ' KERNEL==\"eth*\", NAME=\"eth%s\"\n' % device
return cfg_str
def _append_udev_rules_file(self, cfg_files, base_vdev):
rules_file_name = '/etc/udev/rules.d/51-qeth-0.0.%s.rules' % base_vdev
read_ch = '0.0.' + base_vdev
write_ch = '0.0.' + str(hex(int(base_vdev, 16) + 1))[2:]
data_ch = '0.0.' + str(hex(int(base_vdev, 16) + 2))[2:]
udev_rules_str = self._get_udev_rules(read_ch, write_ch, data_ch)
cfg_files.append((rules_file_name, udev_rules_str))
def _get_udev_rules(self, channel_read, channel_write, channel_data):
"""construct udev rules info."""
sub_str = '%(read)s %%k %(read)s %(write)s %(data)s qeth' % {
'read': channel_read,
'read': channel_read,
'write': channel_write,
'data': channel_data}
rules_str = '# Configure qeth device at'
rules_str += ' %(read)s/%(write)s/%(data)s\n' % {
'read': channel_read,
'write': channel_write,
'data': channel_data}
rules_str += ('ACTION==\"add\", SUBSYSTEM==\"drivers\", KERNEL=='
'\"qeth\", IMPORT{program}=\"collect %s\"\n') % sub_str
rules_str += ('ACTION==\"add\", SUBSYSTEM==\"ccw\", KERNEL==\"'
'%(read)s\", IMPORT{program}="collect %(channel)s\"\n') % {
'read': channel_read, 'channel': sub_str}
rules_str += ('ACTION==\"add\", SUBSYSTEM==\"ccw\", KERNEL==\"'
'%(write)s\", IMPORT{program}=\"collect %(channel)s\"\n') % {
'write': channel_write, 'channel': sub_str}
rules_str += ('ACTION==\"add\", SUBSYSTEM==\"ccw\", KERNEL==\"'
'%(data)s\", IMPORT{program}=\"collect %(channel)s\"\n') % {
'data': channel_data, 'channel': sub_str}
rules_str += ('ACTION==\"remove\", SUBSYSTEM==\"drivers\", KERNEL==\"'
'qeth\", IMPORT{program}=\"collect --remove %s\"\n') % sub_str
rules_str += ('ACTION==\"remove\", SUBSYSTEM==\"ccw\", KERNEL==\"'
'%(read)s\", IMPORT{program}=\"collect --remove %(channel)s\"\n'
) % {'read': channel_read, 'channel': sub_str}
rules_str += ('ACTION==\"remove\", SUBSYSTEM==\"ccw\", KERNEL==\"'
'%(write)s\", IMPORT{program}=\"collect --remove %(channel)s\"\n'
) % {'write': channel_write, 'channel': sub_str}
rules_str += ('ACTION==\"remove\", SUBSYSTEM==\"ccw\", KERNEL==\"'
'%(data)s\", IMPORT{program}=\"collect --remove %(channel)s\"\n'
) % {'data': channel_data, 'channel': sub_str}
rules_str += ('TEST==\"[ccwgroup/%(read)s]\", GOTO=\"qeth-%(read)s'
'-end\"\n') % {'read': channel_read, 'read': channel_read}
rules_str += ('ACTION==\"add\", SUBSYSTEM==\"ccw\", ENV{COLLECT_'
'%(read)s}==\"0\", ATTR{[drivers/ccwgroup:qeth]group}=\"'
'%(read)s,%(write)s,%(data)s\"\n') % {
'read': channel_read, 'read': channel_read,
'write': channel_write, 'data': channel_data}
rules_str += ('ACTION==\"add\", SUBSYSTEM==\"drivers\", KERNEL==\"qeth'
'\", ENV{COLLECT_%(read)s}==\"0\", ATTR{[drivers/'
'ccwgroup:qeth]group}=\"%(read)s,%(write)s,%(data)s\"\n'
'LABEL=\"qeth-%(read)s-end\"\n') % {
'read': channel_read, 'read': channel_read, 'write': channel_write,
'data': channel_data, 'read': channel_read}
rules_str += ('ACTION==\"add\", SUBSYSTEM==\"ccwgroup\", KERNEL=='
'\"%s\", ATTR{layer2}=\"1\"\n') % channel_read
rules_str += ('ACTION==\"add\", SUBSYSTEM==\"ccwgroup\", KERNEL=='
'\"%s\", ATTR{online}=\"1\"\n') % channel_read
return rules_str
def get_scp_string(self, root, fcp, wwpn, lun):
return ("=root=%(root)s zfcp.allow_lun_scan=0 "
"zfcp.device=0.0.%(fcp)s,0x%(wwpn)s,0x%(lun)s") % {
'root': root, 'fcp': fcp, 'wwpn': wwpn, 'lun': lun}
def get_zipl_script_lines(self, image, ramdisk, root, fcp, wwpn, lun):
return ['#!/bin/bash\n',
('echo -e "[defaultboot]\\n'
'default=boot-from-volume\\n'
'[boot-from-volume]\\n'
'image=%(image)s\\n'
'target = /boot/zipl\\n'
'ramdisk=%(ramdisk)s\\n'
'parameters=\\"root=%(root)s '
'zfcp.device=0.0.%(fcp)s,0x%(wwpn)s,0x%(lun)s '
'zfcp.allow_lun_scan=0\\""'
'>/etc/zipl_volume.conf\n'
'mkinitrd\n'
'zipl -c /etc/zipl_volume.conf')
% {'image': image, 'ramdisk': ramdisk, 'root': root,
'fcp': fcp, 'wwpn': wwpn, 'lun': lun}]
class sles11(sles):
def get_znetconfig_contents(self):
return '\n'.join(('cio_ignore -R',
'znetconf -R -n',
'sleep 2',
'udevadm trigger',
'udevadm settle',
'sleep 2',
'znetconf -A',
'service network restart',
'cio_ignore -u'))
class sles12(sles):
def get_znetconfig_contents(self):
remove_route = 'rm -f %s/ifroute-eth*' % self._get_network_file_path()
return '\n'.join(('cio_ignore -R',
'znetconf -R -n',
'sleep 2',
remove_route,
'udevadm trigger',
'udevadm settle',
'sleep 2',
'znetconf -A',
'cio_ignore -u'))
class ubuntu(LinuxDist):
def create_network_configuration_files(self, file_path, network_info,
base_vdev):
"""Generate network configuration files to instance."""
cfg_files = []
cmd_strings = ''
network_config_file_name = self._get_network_file()
network_cfg_str = 'auto lo\n'
network_cfg_str += 'iface lo inet loopback\n'
for vif in network_info:
network_hw_config_fname = self._get_device_filename(base_vdev)
network_hw_config_str = self._get_network_hw_config_str(base_vdev)
cfg_files.append((network_hw_config_fname, network_hw_config_str))
network = vif['network']
(cfg_str, dns_str) = self._generate_network_configuration(network,
base_vdev)
LOG.debug('Network configure file content is: %s', cfg_str)
network_cfg_str += cfg_str
if len(dns_str) > 0:
network_cfg_str += dns_str
base_vdev = str(hex(int(base_vdev, 16) + 3))[2:]
cfg_files.append((network_config_file_name, network_cfg_str))
return cfg_files, cmd_strings
def _get_network_file(self):
return '/etc/network/interfaces'
def _get_cfg_str(self, device, broadcast_v4, gateway_v4, ip_v4,
netmask_v4):
cfg_str = 'auto ' + device + '\n'
cfg_str += 'iface ' + device + ' inet static\n'
cfg_str += 'address ' + ip_v4 + '\n'
cfg_str += 'netmask ' + netmask_v4 + '\n'
cfg_str += 'broadcast ' + broadcast_v4 + '\n'
cfg_str += 'gateway ' + gateway_v4 + '\n'
return cfg_str
def _generate_network_configuration(self, network, vdev):
ip_v4 = dns_str = ''
subnets_v4 = [s for s in network['subnets'] if s['version'] == 4]
if len(subnets_v4[0]['ips']) > 0:
ip_v4 = subnets_v4[0]['ips'][0]['address']
if len(subnets_v4[0]['dns']) > 0:
for dns in subnets_v4[0]['dns']:
dns_str += 'dns-nameservers ' + dns['address'] + '\n'
netmask_v4 = str(subnets_v4[0].as_netaddr().netmask)
gateway_v4 = subnets_v4[0]['gateway']['address'] or ''
broadcast_v4 = str(subnets_v4[0].as_netaddr().broadcast)
device = self._get_device_name(vdev)
cfg_str = self._get_cfg_str(device, broadcast_v4, gateway_v4,
ip_v4, netmask_v4)
return cfg_str, dns_str
def _get_route_str(self, gateway_v4):
return ''
def _get_cmd_str(self, address_read, address_write, address_data):
return ''
def _get_device_name(self, device_num):
return 'enc' + str(device_num)
def _get_dns_filename(self):
return ''
def _get_device_filename(self, device_num):
return '/etc/sysconfig/hardware/config-ccw-0.0.' + str(device_num)
def _get_network_hw_config_str(self, base_vdev):
ccwgroup_chans_str = ' '.join((
'0.0.' + str(hex(int(base_vdev, 16)))[2:],
'0.0.' + str(hex(int(base_vdev, 16) + 1))[2:],
'0.0.' + str(hex(int(base_vdev, 16) + 2))[2:]))
return '\n'.join(('CCWGROUP_CHANS=(' + ccwgroup_chans_str + ')',
'QETH_OPTIONS=layer2'))
def _get_network_file_path(self):
pass
def get_znetconfig_contents(self):
return '\n'.join(('cio_ignore -R',
'znetconf -R -n',
'sleep 2',
'udevadm trigger',
'udevadm settle',
'sleep 2',
'znetconf -A',
'/etc/init.d/networking restart',
'cio_ignore -u'))
def _get_udev_configuration(self, device, dev_channel):
return ''
def _append_udev_info(self, cfg_files, file_name_route, route_cfg_str,
udev_cfg_str):
pass
def get_scp_string(self, root, fcp, wwpn, lun):
# Although the content is the same as SLES, I don't want to merge them.
# Because they are NOT logically related, and it's very likely that
# they evolve separately in the future.
return ("=root=%(root)s zfcp.allow_lun_scan=0 "
"zfcp.device=0.0.%(fcp)s,0x%(wwpn)s,0x%(lun)s") % {
'root': root, 'fcp': fcp, 'wwpn': wwpn, 'lun': lun}
def get_zipl_script_lines(self, image, ramdisk, root, fcp, wwpn, lun):
return ['#!/bin/bash\n',
('echo -e "[defaultboot]\\n'
'default=boot-from-volume\\n'
'[boot-from-volume]\\n'
'image=%(image)s\\n'
'target = /boot/zipl\\n'
'ramdisk=%(ramdisk)s\\n'
'parameters=\\"root=%(root)s '
'zfcp.device=0.0.%(fcp)s,0x%(wwpn)s,0x%(lun)s '
'zfcp.allow_lun_scan=0\\""'
'>/etc/zipl_volume.conf\n'
'mkinitrd\n'
'zipl -c /etc/zipl_volume.conf')
% {'image': image, 'ramdisk': ramdisk, 'root': root,
'fcp': fcp, 'wwpn': wwpn, 'lun': lun}]
def assemble_zfcp_srcdev(self, fcp, wwpn, lun):
path = '/dev/disk/by-path/ccw-0.0.%(fcp)s-fc-0x%(wwpn)s-lun-%(lun)s'
lun = int(lun[0:4], 16)
srcdev = path % {'fcp': fcp, 'wwpn': wwpn, 'lun': lun}
return srcdev
def _get_udev_rules(self, channel_read, channel_write, channel_data):
"""construct udev rules info."""
return ''
def _append_udev_rules_file(self, cfg_files, base_vdev):
pass
class ubuntu16(ubuntu):
pass
class ListDistManager(object):
def get_linux_dist(self, os_version):
distro, release = self.parse_dist(os_version)
return globals()[distro + release]
def _parse_release(self, os_version, distro, remain):
supported = {'rhel': ['6', '7'],
'sles': ['11', '12'],
'ubuntu': ['16']}
releases = supported[distro]
for r in releases:
if remain.startswith(r):
return r
else:
msg = _('Can not handle os: %s') % os_version
raise exception.ZVMImageError(msg=msg)
def parse_dist(self, os_version):
"""Separate os and version from os_version.
Possible return value are only:
('rhel', x.y) and ('sles', x.y) where x.y may not be digits
"""
supported = {'rhel': ['rhel', 'redhat', 'red hat'],
'sles': ['suse', 'sles'],
'ubuntu': ['ubuntu']}
os_version = os_version.lower()
for distro, patterns in supported.items():
for i in patterns:
if os_version.startswith(i):
# Not guarrentee the version is digital
remain = os_version.split(i, 2)[1]
release = self._parse_release(os_version, distro, remain)
return distro, release
msg = _('Can not handle os: %s') % os_version
raise exception.ZVMImageError(msg=msg)