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

831 lines
27 KiB
Python
Executable File

# vim: tabstop=4 shiftwidth=4 softtabstop=4
# 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 functools
import httplib
import os
import shutil
import socket
import time
from oslo.config import cfg
from nova import block_device
from nova.compute import power_state
from nova.openstack.common import excutils
from nova.openstack.common.gettextutils import _
from nova.openstack.common import jsonutils
from nova.openstack.common import log as logging
from nova.virt import driver
from nova.virt.zvm import const
from nova.virt.zvm import exception
LOG = logging.getLogger(__name__)
CONF = cfg.CONF
CONF.import_opt('instances_path', 'nova.compute.manager')
class XCATUrl(object):
"""To return xCAT url for invoking xCAT REST API."""
def __init__(self):
"""Set constant that used to form xCAT url."""
self.PREFIX = '/xcatws'
self.SUFFIX = '?userName=' + CONF.zvm_xcat_username + \
'&password=' + CONF.zvm_xcat_password + \
'&format=json'
self.NODES = '/nodes'
self.VMS = '/vms'
self.IMAGES = '/images'
self.OBJECTS = '/objects/osimage'
self.OS = '/OS'
self.TABLES = '/tables'
self.HV = '/hypervisor'
self.NETWORK = '/networks'
self.POWER = '/power'
self.INVENTORY = '/inventory'
self.STATUS = '/status'
self.MIGRATE = '/migrate'
self.CAPTURE = '/capture'
self.EXPORT = '/export'
self.IMGIMPORT = '/import'
self.BOOTSTAT = '/bootstate'
self.XDSH = '/dsh'
def _nodes(self, arg=''):
return self.PREFIX + self.NODES + arg + self.SUFFIX
def _vms(self, arg=''):
return self.PREFIX + self.VMS + arg + self.SUFFIX
def _hv(self, arg=''):
return self.PREFIX + self.HV + arg + self.SUFFIX
def rpower(self, arg=''):
return self.PREFIX + self.NODES + arg + self.POWER + self.SUFFIX
def nodels(self, arg=''):
return self._nodes(arg)
def rinv(self, arg='', addp=None):
rurl = self.PREFIX + self.NODES + arg + self.INVENTORY + self.SUFFIX
return self._append_addp(rurl, addp)
def mkdef(self, arg=''):
return self._nodes(arg)
def rmdef(self, arg=''):
return self._nodes(arg)
def nodestat(self, arg=''):
return self.PREFIX + self.NODES + arg + self.STATUS + self.SUFFIX
def chvm(self, arg=''):
return self._vms(arg)
def lsvm(self, arg=''):
return self._vms(arg)
def chhv(self, arg=''):
return self._hv(arg)
def mkvm(self, arg=''):
return self._vms(arg)
def rmvm(self, arg=''):
return self._vms(arg)
def tabdump(self, arg='', addp=None):
rurl = self.PREFIX + self.TABLES + arg + self.SUFFIX
return self._append_addp(rurl, addp)
def _append_addp(self, rurl, addp=None):
if addp is not None:
return rurl + addp
else:
return rurl
def imgcapture(self, arg=''):
return self.PREFIX + self.IMAGES + arg + self.CAPTURE + self.SUFFIX
def imgexport(self, arg=''):
return self.PREFIX + self.IMAGES + arg + self.EXPORT + self.SUFFIX
def rmimage(self, arg=''):
return self.PREFIX + self.IMAGES + arg + self.SUFFIX
def rmobject(self, arg=''):
return self.PREFIX + self.OBJECTS + arg + self.SUFFIX
def lsdef_node(self, arg='', addp=None):
rurl = self.PREFIX + self.NODES + arg + self.SUFFIX
return self._append_addp(rurl, addp)
def lsdef_image(self, arg='', addp=None):
rurl = self.PREFIX + self.IMAGES + arg + self.SUFFIX
return self._append_addp(rurl, addp)
def imgimport(self, arg=''):
return self.PREFIX + self.IMAGES + self.IMGIMPORT + arg + self.SUFFIX
def chtab(self, arg=''):
return self.PREFIX + self.NODES + arg + self.SUFFIX
def nodeset(self, arg=''):
return self.PREFIX + self.NODES + arg + self.BOOTSTAT + self.SUFFIX
def rmigrate(self, arg=''):
return self.PREFIX + self.NODES + arg + self.MIGRATE + self.SUFFIX
def gettab(self, arg='', addp=None):
rurl = self.PREFIX + self.TABLES + arg + self.SUFFIX
return self._append_addp(rurl, addp)
def tabch(self, arg='', addp=None):
"""Add/update/delete row(s) in table arg, with attribute addp."""
rurl = self.PREFIX + self.TABLES + arg + self.SUFFIX
return self._append_addp(rurl, addp)
def xdsh(self, arg=''):
"""Run shell command."""
return self.PREFIX + self.NODES + arg + self.XDSH + self.SUFFIX
def network(self, arg='', addp=None):
rurl = self.PREFIX + self.NETWORK + arg + self.SUFFIX
if addp is not None:
return rurl + addp
else:
return rurl
class XCATConnection():
"""Https requests to xCAT web service."""
def __init__(self):
"""Initialize https connection to xCAT service."""
self.host = CONF.zvm_xcat_server
self.conn = httplib.HTTPSConnection(self.host,
timeout=CONF.zvm_xcat_connection_timeout)
def request(self, method, url, body=None, headers={}):
"""Send https request to xCAT server.
Will return a python dictionary including:
{'status': http return code,
'reason': http reason,
'message': response message}
"""
if body is not None:
body = jsonutils.dumps(body)
headers = {'content-type': 'text/plain',
'content-length': len(body)}
try:
self.conn.request(method, url, body, headers)
except socket.gaierror as err:
msg = _("Failed to find address: %s") % err
raise exception.ZVMXCATRequestFailed(xcatserver=self.host, msg=msg)
except (socket.error, socket.timeout) as err:
msg = _("Communication error: %s") % err
raise exception.ZVMXCATRequestFailed(xcatserver=self.host, msg=msg)
try:
res = self.conn.getresponse()
except Exception as err:
msg = _("Failed to get response from xCAT: %s") % err
raise exception.ZVMXCATRequestFailed(xcatserver=self.host, msg=msg)
msg = res.read()
resp = {
'status': res.status,
'reason': res.reason,
'message': msg}
# Only "200" or "201" returned from xCAT can be considered
# as good status
err = None
if method == "POST":
if res.status != 201:
err = str(resp)
else:
if res.status != 200:
err = str(resp)
if err is not None:
raise exception.ZVMXCATRequestFailed(xcatserver=self.host,
msg=err)
return resp
def xcat_request(method, url, body=None, headers={}):
conn = XCATConnection()
resp = conn.request(method, url, body, headers)
return load_xcat_resp(resp['message'])
def jsonloads(jsonstr):
try:
return jsonutils.loads(jsonstr)
except ValueError:
errmsg = _("xCAT response data is not in JSON format")
LOG.error(errmsg)
raise exception.ZVMDriverError(msg=errmsg)
@contextlib.contextmanager
def expect_invalid_xcat_resp_data():
"""Catch exceptions when using xCAT response data."""
try:
yield
except (ValueError, TypeError, IndexError, AttributeError,
KeyError) as err:
raise exception.ZVMInvalidXCATResponseDataError(msg=err)
def wrap_invalid_xcat_resp_data_error(function):
"""Catch exceptions when using xCAT response data."""
@functools.wraps(function)
def decorated_function(*arg, **kwargs):
try:
return function(*arg, **kwargs)
except (ValueError, TypeError, IndexError, AttributeError,
KeyError) as err:
raise exception.ZVMInvalidXCATResponseDataError(msg=err)
return decorated_function
@contextlib.contextmanager
def ignore_errors():
"""Only execute the clauses and ignore the results."""
try:
yield
except Exception as err:
LOG.debug(_("Ignore an error: %s") % err)
pass
@contextlib.contextmanager
def except_xcat_call_failed_and_reraise(exc, **kwargs):
"""Catch all kinds of xCAT call failure and reraise.
exc: the exception that would be raised.
"""
try:
yield
except (exception.ZVMXCATRequestFailed,
exception.ZVMInvalidXCATResponseDataError,
exception.ZVMXCATInternalError) as err:
kwargs['msg'] = err
raise exc(**kwargs)
def convert_to_mb(s):
"""Convert memory size from GB to MB."""
s = s.upper()
try:
if s.endswith('G'):
return float(s[:-1].strip()) * 1024
else:
return float(s[:-1].strip())
except (IndexError, ValueError, KeyError, TypeError) as e:
errmsg = _("Invalid memory format: %s") % e
raise exception.ZVMDriverError(msg=errmsg)
@wrap_invalid_xcat_resp_data_error
def translate_xcat_resp(rawdata, dirt):
"""Translate xCAT response JSON stream to a python dictionary.
xCAT response example:
node: keyword1: value1\n
node: keyword2: value2\n
...
node: keywordn: valuen\n
Will return a python dictionary:
{keyword1: value1,
keyword2: value2,
...
keywordn: valuen,}
"""
data_list = rawdata.split("\n")
data = {}
for ls in data_list:
for k in dirt.keys():
if ls.__contains__(dirt[k]):
data[k] = ls[(ls.find(dirt[k]) + len(dirt[k])):].strip()
break
if data == {}:
msg = _("No value matched with keywords. Raw Data: %(raw)s; "
"Keywords: %(kws)s") % {'raw': rawdata, 'kws': str(dirt)}
raise exception.ZVMInvalidXCATResponseDataError(msg=msg)
return data
def mapping_power_stat(power_stat):
"""Translate power state to OpenStack defined constants."""
return const.ZVM_POWER_STAT.get(power_stat, power_state.NOSTATE)
@wrap_invalid_xcat_resp_data_error
def load_xcat_resp(message):
"""Abstract information from xCAT REST response body.
As default, xCAT response will in format of JSON and can be
converted to Python dictionary, would looks like:
{"data": [{"info": [info,]}, {"data": [data,]}, ..., {"error": [error,]}]}
Returns a Python dictionary, looks like:
{'info': [info,],
'data': [data,],
...
'error': [error,]}
"""
resp_list = jsonloads(message)['data']
keys = const.XCAT_RESPONSE_KEYS
resp = {}
for k in keys:
resp[k] = []
for d in resp_list:
for k in keys:
if d.get(k) is not None:
resp[k].append(d.get(k))
err = resp.get('error')
if err != []:
for e in err:
if _is_warning(str(e)):
# ignore known warnings
continue
else:
raise exception.ZVMXCATInternalError(msg=message)
_log_warnings(resp)
return resp
def _log_warnings(resp):
for msg in (resp['info'], resp['node'], resp['data']):
msgstr = str(msg)
if 'warn' in msgstr.lower():
LOG.warn(_("Warning from xCAT: %s") % msgstr)
def _is_warning(err_str):
ignore_list = (
'Warning: the RSA host key for',
'Warning: Permanently added',
'WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED',
)
for im in ignore_list:
if im in err_str:
return True
return False
def volume_in_mapping(mount_device, block_device_info):
block_device_list = [block_device.strip_dev(vol['mount_device'])
for vol in
driver.block_device_info_get_mapping(
block_device_info)]
swap = driver.block_device_info_get_swap(block_device_info)
if driver.swap_is_usable(swap):
block_device_list.append(
block_device.strip_dev(swap['device_name']))
block_device_list += [block_device.strip_dev(ephemeral['device_name'])
for ephemeral in
driver.block_device_info_get_ephemerals(
block_device_info)]
LOG.debug(_("block_device_list %s"), block_device_list)
return block_device.strip_dev(mount_device) in block_device_list
def get_host():
return ''.join([os.environ["USER"], '@', CONF.my_ip])
def get_userid(node_name):
"""Returns z/VM userid for the xCAT node."""
url = XCATUrl().lsdef_node(''.join(['/', node_name]))
info = xcat_request('GET', url)['info']
with expect_invalid_xcat_resp_data():
for s in info[0]:
if s.__contains__('userid='):
return s.strip().rpartition('=')[2]
def xdsh(node, commands):
""""Run command on xCAT node."""
LOG.debug(_('Run command %(cmd)s on xCAT node %(node)s') %
{'cmd': commands, 'node': node})
def xdsh_execute(node, commands):
"""Invoke xCAT REST API to execute command on node."""
xdsh_commands = 'command=%s' % commands
body = [xdsh_commands]
url = XCATUrl().xdsh('/' + node)
return xcat_request("PUT", url, body)
with except_xcat_call_failed_and_reraise(
exception.ZVMXCATXdshFailed):
res_dict = xdsh_execute(node, commands)
return res_dict
def punch_file(node, fn, fclass):
body = [" ".join(['--punchfile', fn, fclass, get_host()])]
url = XCATUrl().chvm('/' + node)
try:
xcat_request("PUT", url, body)
except Exception as err:
with excutils.save_and_reraise_exception():
LOG.error(_('Punch file to %(node)s failed: %(msg)s') %
{'node': node, 'msg': err})
finally:
os.remove(fn)
def punch_adminpass_file(instance_path, instance_name, admin_password):
adminpass_fn = ''.join([instance_path, '/adminpwd.sh'])
_generate_adminpass_file(adminpass_fn, admin_password)
punch_file(instance_name, adminpass_fn, 'X')
def punch_xcat_auth_file(instance_path, instance_name):
"""Make xCAT MN authorized by virtual machines."""
mn_pub_key = get_mn_pub_key()
auth_fn = ''.join([instance_path, '/xcatauth.sh'])
_generate_auth_file(auth_fn, mn_pub_key)
punch_file(instance_name, auth_fn, 'X')
def punch_eph_info_file(instance_path, instance_name, vdev=None, fmt=None,
mntdir=None):
if not fmt:
fmt = CONF.default_ephemeral_format or const.DEFAULT_EPH_DISK_FMT
eph_fn = ''.join([instance_path, '/eph.disk'])
_generate_ephinfo_file(eph_fn, vdev, fmt, mntdir)
punch_file(instance_name, eph_fn, 'X')
def generate_vdev(base, offset=1):
"""Generate virtual device number base on base vdev.
:param base: base virtual device number, string of 4 bit hex.
:param offset: offset to base, integer.
:output: virtual device number, string of 4 bit hex.
"""
vdev = hex(int(base, 16) + offset)[2:]
return vdev.rjust(4, '0')
def generate_eph_vdev(offset=1):
"""Generate virtual device number for ephemeral disks.
:parm offset: offset to zvm_user_adde_vdev.
:output: virtual device number, string of 4 bit hex.
"""
vdev = generate_vdev(CONF.zvm_user_adde_vdev, offset + 1)
if offset >= 0 and offset < 254:
return vdev
else:
msg = _("Invalid virtual device number for ephemeral disk: %s") % vdev
LOG.error(msg)
raise exception.ZVMDriverError(msg=msg)
def _generate_ephinfo_file(fname, vdev, fmt, mntdir):
vdev = vdev or CONF.zvm_user_adde_vdev
mntdir = mntdir or CONF.zvm_default_ephemeral_mntdir
lines = [
'# xCAT Init\n',
'action=addMdisk\n',
'vaddr=' + vdev + '\n',
'filesys=' + fmt + '\n',
'mntdir=' + mntdir + '\n'
]
with open(fname, 'w') as genfile:
try:
genfile.writelines(lines)
except Exception as err:
with excutils.save_and_reraise_exception():
LOG.error(_('Generate ephemeral info file failed: %s') % err)
def _generate_auth_file(fn, pub_key):
lines = ['#!/bin/bash\n',
'echo "%s" >> /root/.ssh/authorized_keys' % pub_key]
with open(fn, 'w') as f:
f.writelines(lines)
def _generate_adminpass_file(fn, admin_password):
lines = ['#! /bin/bash\n',
'echo %s|passwd --stdin root' % admin_password]
with open(fn, 'w') as f:
f.writelines(lines)
@wrap_invalid_xcat_resp_data_error
def get_mn_pub_key():
cmd = 'cat /root/.ssh/id_rsa.pub'
resp = xdsh(CONF.zvm_xcat_master, cmd)
key = resp['data'][0][0]
start_idx = key.find('ssh-rsa')
key = key[start_idx:]
return key
def parse_os_version(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']}
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
return distro, os_version.split(i, 2)[1]
else:
raise exception.ZVMImageError(msg='Unknown os_version property')
class PathUtils(object):
def open(self, path, mode):
"""Wrapper on __builin__.open used to simplify unit testing."""
import __builtin__
return __builtin__.open(path, mode)
def _get_image_tmp_path(self):
image_tmp_path = os.path.normpath(CONF.zvm_image_tmp_path)
if not os.path.exists(image_tmp_path):
LOG.debug(_('Creating folder %s for image temp files') %
image_tmp_path)
os.makedirs(image_tmp_path)
return image_tmp_path
def get_bundle_tmp_path(self, tmp_file_fn):
bundle_tmp_path = os.path.join(self._get_image_tmp_path(), "spawn_tmp",
tmp_file_fn)
if not os.path.exists(bundle_tmp_path):
LOG.debug(_('Creating folder %s for image bundle temp file') %
bundle_tmp_path)
os.makedirs(bundle_tmp_path)
return bundle_tmp_path
def get_img_path(self, bundle_file_path, image_name):
return os.path.join(bundle_file_path, image_name)
def _get_snapshot_path(self):
snapshot_folder = os.path.join(self._get_image_tmp_path(),
"snapshot_tmp")
if not os.path.exists(snapshot_folder):
LOG.debug(_("Creating the snapshot folder %s") % snapshot_folder)
os.makedirs(snapshot_folder)
return snapshot_folder
def _get_punch_path(self):
punch_folder = os.path.join(self._get_image_tmp_path(), "punch_tmp")
if not os.path.exists(punch_folder):
LOG.debug(_("Creating the punch folder %s") % punch_folder)
os.makedirs(punch_folder)
return punch_folder
def _make_short_time_stamp(self):
# tmp_file_fn = time.strftime('%d%H%M%S',
# time.localtime(time.time()))
# return tmp_file_fn
return '0'
def get_punch_time_path(self):
punch_time_path = os.path.join(self._get_punch_path(),
self._make_short_time_stamp())
if not os.path.exists(punch_time_path):
LOG.debug(_("Creating punch time folder %s") % punch_time_path)
os.makedirs(punch_time_path)
return punch_time_path
def get_spawn_folder(self):
spawn_folder = os.path.join(self._get_image_tmp_path(), "spawn_tmp")
if not os.path.exists(spawn_folder):
LOG.debug(_("Creating the spawn folder %s") % spawn_folder)
os.makedirs(spawn_folder)
return spawn_folder
def make_time_stamp(self):
tmp_file_fn = time.strftime('%Y%m%d%H%M%S',
time.localtime(time.time()))
return tmp_file_fn
def get_snapshot_time_path(self):
snapshot_time_path = os.path.join(self._get_snapshot_path(),
self.make_time_stamp())
if not os.path.exists(snapshot_time_path):
LOG.debug(_('Creating folder %s for image bundle temp file') %
snapshot_time_path)
os.makedirs(snapshot_time_path)
return snapshot_time_path
def clean_temp_folder(self, tmp_file_fn):
if os.path.isdir(tmp_file_fn):
LOG.debug(_('Removing existing folder %s '), tmp_file_fn)
shutil.rmtree(tmp_file_fn)
def _get_instances_path(self):
return os.path.normpath(CONF.instances_path)
def get_instance_path(self, os_node, instance_name):
instance_folder = os.path.join(self._get_instances_path(), os_node,
instance_name)
if not os.path.exists(instance_folder):
LOG.debug(_("Creating the instance path %s") % instance_folder)
os.makedirs(instance_folder)
return instance_folder
def get_console_log_path(self, os_node, instance_name):
return os.path.join(self.get_instance_path(os_node, instance_name),
"console.log")
class NetworkUtils(object):
"""Utilities for z/VM network operator."""
def validate_ip_address(self, ip_address):
"""Check whether ip_address is valid."""
# TODO(Leon): check IP address format
pass
def validate_network_mask(self, mask):
"""Check whether mask is valid."""
# TODO(Leon): check network mask format
pass
def create_network_configuration_files(self, file_path, network_info,
base_vdev, os_type):
"""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
cfg_str = ''
# Red Hat
file_path_rhel = '/etc/sysconfig/network-scripts/'
# SuSE
file_path_sles = '/etc/sysconfig/network/'
file_name_route = file_path_sles + 'routes'
# Check the OS type
if (os_type == 'sles'):
file_path = file_path_sles
else:
file_path = file_path_rhel
file_name_dns = '/etc/resolv.conf'
for vif in network_info:
file_name = 'ifcfg-eth' + str(device_num)
network = vif['network']
(cfg_str, cmd_str, dns_str, route_str) =\
self.generate_network_configration(network,
base_vdev, device_num, os_type)
LOG.debug(_('Network configure file content is: %s') % cfg_str)
target_net_conf_file_name = file_path + file_name
cfg_files.append((target_net_conf_file_name, cfg_str))
udev_cfg_str += self.generate_udev_configuration(device_num,
'0.0.' + str(base_vdev).zfill(4))
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))
if os_type == 'sles':
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))
return cfg_files, cmd_strings
def generate_network_configration(self, network, vdev, device_num,
os_type):
"""Generate network configuration items."""
ip_v4 = netmask_v4 = gateway_v4 = broadcast_v4 = ''
subchannels = None
device = None
cidr_v4 = None
cmd_str = None
dns_str = ''
route_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']
broadcast_v4 = str(subnets_v4[0].as_netaddr().broadcast)
device = "eth" + str(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 = 'DEVICE=\"' + device + '\"\n' + 'BOOTPROTO=\"static\"\n'
cfg_str += 'BROADCAST=\"' + broadcast_v4 + '\"\n'
cfg_str += 'GATEWAY=\"' + gateway_v4 + '\"\nIPADDR=\"' + ip_v4 + '\"\n'
cfg_str += 'NETMASK=\"' + netmask_v4 + '\"\n'
cfg_str += 'NETTYPE=\"qeth\"\nONBOOT=\"yes\"\n'
cfg_str += 'PORTNAME=\"PORT' + address_read + '\"\n'
cfg_str += 'OPTIONS=\"layer2=1\"\n'
cfg_str += 'SUBCHANNELS=\"' + subchannels + '\"\n'
if os_type == 'sles':
cidr_v4 = self._get_cidr_from_ip_netmask(ip_v4, netmask_v4)
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()}
cfg_str = "BOOTPROTO=\'static\'\nIPADDR=\'%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
route_str += 'default %s - -\n' % gateway_v4
return cfg_str, cmd_str, dns_str, route_str
def generate_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 _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