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

416 lines
17 KiB
Python
Executable File

# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2014 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 xcatutils
from oslo.config import cfg
from neutron.openstack.common import log as logging
from neutron.openstack.common.gettextutils import _
from neutron.plugins.zvm.common import exception
CONF = cfg.CONF
LOG = logging.getLogger(__name__)
class zvmUtils(object):
_MAX_REGRANT_USER_NUMBER = 1000
def __init__(self):
self._xcat_url = xcatutils.xCatURL()
self._zhcp_userid = None
self._userid_map = {}
self._xcat_node_name = self._get_xcat_node_name()
def get_node_from_port(self, port_id):
return self._get_nic_settings(port_id, get_node=True)
def get_nic_ids(self):
addp = ''
url = self._xcat_url.tabdump("/switch", addp)
nic_settings = xcatutils.xcat_request("GET", url)
# remove table header
nic_settings['data'][0].pop(0)
# it's possible to return empty array
return nic_settings['data'][0]
def _get_nic_settings(self, port_id, field=None, get_node=False):
"""Get NIC information from xCat switch table."""
LOG.debug(_("Get nic information for port: %s"), port_id)
addp = '&col=port&value=%s' % port_id + '&attribute=%s' % (
field and field or 'node')
url = self._xcat_url.gettab("/switch", addp)
nic_settings = xcatutils.xcat_request("GET", url)
ret_value = nic_settings['data'][0][0]
if field is None and not get_node:
ret_value = self.get_userid_from_node(ret_value)
return ret_value
def get_userid_from_node(self, node):
addp = '&col=node&value=%s&attribute=userid' % node
url = self._xcat_url.gettab("/zvm", addp)
user_info = xcatutils.xcat_request("GET", url)
return user_info['data'][0][0]
def couple_nic_to_vswitch(self, vswitch_name, switch_port_name,
zhcp, userid, dm=True, immdt=True):
"""Couple nic to vswitch."""
LOG.debug(_("Connect nic to switch: %s"), vswitch_name)
vdev = self._get_nic_settings(switch_port_name, "interface")
if vdev:
self._couple_nic(zhcp, vswitch_name, userid, vdev, dm, immdt)
else:
raise exception.zVMInvalidDataError(msg=('Cannot get vdev for '
'user %s, couple to port %s') %
(userid, switch_port_name))
return vdev
def uncouple_nic_from_vswitch(self, vswitch_name, switch_port_name,
zhcp, userid, dm=True, immdt=True):
"""Uncouple nic from vswitch."""
LOG.debug(_("Disconnect nic from switch: %s"), vswitch_name)
vdev = self._get_nic_settings(switch_port_name, "interface")
self._uncouple_nic(zhcp, userid, vdev, dm, immdt)
def set_vswitch_port_vlan_id(self, vlan_id, switch_port_name, vdev, zhcp,
vswitch_name):
userid = self._get_nic_settings(switch_port_name)
if not userid:
raise exception.zVMInvalidDataError(msg=('Cannot get userid by '
'port %s') % (switch_port_name))
url = self._xcat_url.xdsh("/%s" % zhcp)
commands = '/opt/zhcp/bin/smcli Virtual_Network_Vswitch_Set_Extended'
commands += " -T %s" % userid
commands += ' -k grant_userid=%s' % userid
commands += " -k switch_name=%s" % vswitch_name
commands += " -k user_vlan_id=%s" % vlan_id
xdsh_commands = 'command=%s' % commands
body = [xdsh_commands]
xcatutils.xcat_request("PUT", url, body)
def grant_user(self, zhcp, vswitch_name, userid):
"""Set vswitch to grant user."""
url = self._xcat_url.xdsh("/%s" % zhcp)
commands = '/opt/zhcp/bin/smcli Virtual_Network_Vswitch_Set_Extended'
commands += " -T %s" % userid
commands += " -k switch_name=%s" % vswitch_name
commands += " -k grant_userid=%s" % userid
xdsh_commands = 'command=%s' % commands
body = [xdsh_commands]
xcatutils.xcat_request("PUT", url, body)
def revoke_user(self, zhcp, vswitch_name, userid):
"""Set vswitch to grant user."""
url = self._xcat_url.xdsh("/%s" % zhcp)
commands = '/opt/zhcp/bin/smcli Virtual_Network_Vswitch_Set_Extended'
commands += " -T %s" % userid
commands += " -k switch_name=%s" % vswitch_name
commands += " -k revoke_userid=%s" % userid
xdsh_commands = 'command=%s' % commands
body = [xdsh_commands]
xcatutils.xcat_request("PUT", url, body)
def _couple_nic(self, zhcp, vswitch_name, userid, vdev, dm, immdt):
"""Couple NIC to vswitch by adding vswitch into user direct."""
url = self._xcat_url.xdsh("/%s" % zhcp)
if dm:
commands = '/opt/zhcp/bin/smcli'
commands += ' Virtual_Network_Adapter_Connect_Vswitch_DM'
commands += " -T %s " % userid + "-v %s" % vdev
commands += " -n %s" % vswitch_name
xdsh_commands = 'command=%s' % commands
body = [xdsh_commands]
xcatutils.xcat_request("PUT", url, body)
if immdt:
# the inst must be active, or this call will failed
commands = '/opt/zhcp/bin/smcli'
commands += ' Virtual_Network_Adapter_Connect_Vswitch'
commands += " -T %s " % userid + "-v %s" % vdev
commands += " -n %s" % vswitch_name
xdsh_commands = 'command=%s' % commands
body = [xdsh_commands]
xcatutils.xcat_request("PUT", url, body)
def _uncouple_nic(self, zhcp, userid, vdev, dm, immdt):
"""Couple NIC to vswitch by adding vswitch into user direct."""
url = self._xcat_url.xdsh("/%s" % zhcp)
if dm:
commands = '/opt/zhcp/bin/smcli'
commands += ' Virtual_Network_Adapter_Disconnect_DM'
commands += " -T %s " % userid + "-v %s" % vdev
xdsh_commands = 'command=%s' % commands
body = [xdsh_commands]
xcatutils.xcat_request("PUT", url, body)
if immdt:
# the inst must be active, or this call will failed
commands = '/opt/zhcp/bin/smcli'
commands += ' Virtual_Network_Adapter_Disconnect'
commands += " -T %s " % userid + "-v %s" % vdev
xdsh_commands = 'command=%s' % commands
body = [xdsh_commands]
xcatutils.xcat_request("PUT", url, body)
def put_user_direct_online(self, zhcp, userid):
url = self._xcat_url.xdsh("/%s" % zhcp)
commands = '/opt/zhcp/bin/smcli Static_Image_Changes_Immediate_DM'
commands += " -T %s" % userid
xdsh_commands = 'command=%s' % commands
body = [xdsh_commands]
xcatutils.xcat_request("PUT", url, body)
def get_zhcp_userid(self, zhcp):
if not self._zhcp_userid:
self._zhcp_userid = self.get_userid_from_node(zhcp)
return self._zhcp_userid
def add_vswitch(self, zhcp, name, rdev,
controller='*',
connection=1, queue_mem=8, router=0, network_type=2, vid=0,
port_type=1, update=1, gvrp=2, native_vid=1):
'''
connection:0-unspecified 1-Actice 2-non-Active
router:0-unspecified 1-nonrouter 2-prirouter
type:0-unspecified 1-IP 2-ethernet
vid:1-4094 for access port defaut vlan
port_type:0-unspecified 1-access 2-trunk
update:0-unspecified 1-create 2-create and add to system
configuration file
gvrp:0-unspecified 1-gvrp 2-nogvrp
'''
if (self._does_vswitch_exist(zhcp, name)):
LOG.info(_('Vswitch %s already exists.'), name)
return
# if vid = 0, port_type, gvrp and native_vlanid are not
# allowed to specified
if not len(vid):
vid = 0
port_type = 0
gvrp = 0
native_vid = -1
else:
vid = str(vid[0][0]) + '-' + str(vid[0][1])
userid = self.get_zhcp_userid(zhcp)
url = self._xcat_url.xdsh("/%s" % zhcp)
commands = '/opt/zhcp/bin/smcli Virtual_Network_Vswitch_Create'
commands += " -T %s" % userid
commands += ' -n %s' % name
if rdev:
commands += " -r %s" % rdev.replace(',', ' ')
#commands += " -a %s" % osa_name
if controller != '*':
commands += " -i %s" % controller
commands += " -c %s" % connection
commands += " -q %s" % queue_mem
commands += " -e %s" % router
commands += " -t %s" % network_type
commands += " -v %s" % vid
commands += " -p %s" % port_type
commands += " -u %s" % update
commands += " -G %s" % gvrp
commands += " -V %s" % native_vid
xdsh_commands = 'command=%s' % commands
body = [xdsh_commands]
result = xcatutils.xcat_request("PUT", url, body)
if (result['errorcode'][0][0] != '0') or \
(not self._does_vswitch_exist(zhcp, name)):
raise exception.zvmException(
msg=("switch: %s add failed, %s") %
(name, result['data'][0][0]))
LOG.info(_('Created vswitch %s done.'), name)
def _does_vswitch_exist(self, zhcp, vsw):
userid = self.get_zhcp_userid(zhcp)
url = self._xcat_url.xdsh("/%s" % zhcp)
commands = '/opt/zhcp/bin/smcli Virtual_Network_Vswitch_Query'
commands += " -T %s" % userid
commands += " -s %s" % vsw
xdsh_commands = 'command=%s' % commands
body = [xdsh_commands]
result = xcatutils.xcat_request("PUT", url, body)
return (result['errorcode'][0][0] == '0')
def re_grant_user(self, zhcp):
"""Grant user again after z/VM is re-IPLed"""
ports_info = self._get_userid_vswitch_vlan_id_mapping(zhcp)
records_num = 0
cmd = ''
def run_command(command):
xdsh_commands = 'command=%s' % command
body = [xdsh_commands]
url = self._xcat_url.xdsh("/%s" % zhcp)
xcatutils.xcat_request("PUT", url, body)
for (port_id, port) in ports_info.items():
if port['userid'] is None or port['vswitch'] is None:
continue
if len(port['userid']) == 0 or len(port['vswitch']) == 0:
continue
cmd += '/opt/zhcp/bin/smcli '
cmd += 'Virtual_Network_Vswitch_Set_Extended '
cmd += '-T %s ' % port['userid']
cmd += '-k switch_name=%s ' % port['vswitch']
cmd += '-k grant_userid=%s' % port['userid']
try:
if int(port['vlan_id']) in range(1, 4094):
cmd += ' -k user_vlan_id=%s\n' % port['vlan_id']
else:
cmd += '\n'
except ValueError:
# just in case there are bad records of vlan info which
# could be a string
LOG.warn(_("Unknown vlan '%(vlan)s' for user %(user)s."),
{'vlan': port['vlan_id'], 'user': port['userid']})
cmd += '\n'
continue
records_num += 1
if records_num >= self._MAX_REGRANT_USER_NUMBER:
try:
commands = 'echo -e "#!/bin/sh\n%s" > grant.sh' % cmd[:-1]
run_command(commands)
commands = 'sh grant.sh;rm -f grant.sh'
run_command(commands)
records_num = 0
cmd = ''
except Exception:
LOG.warn(_("Grant user failed"))
if len(cmd) > 0:
commands = 'echo -e "#!/bin/sh\n%s" > grant.sh' % cmd[:-1]
run_command(commands)
commands = 'sh grant.sh;rm -f grant.sh'
run_command(commands)
return ports_info
def _get_userid_vswitch_vlan_id_mapping(self, zhcp):
ports_info = self.get_nic_ids()
ports = {}
for p in ports_info:
port_info = p.split(',')
target_host = port_info[5].strip('"')
port_vid = port_info[3].strip('"')
port_id = port_info[2].strip('"')
vswitch = port_info[1].strip('"')
nodename = port_info[0].strip('"')
if target_host == zhcp:
ports[port_id] = {'nodename': nodename,
'vswitch': vswitch,
'userid': None,
'vlan_id': port_vid}
def get_all_userid():
users = {}
addp = ''
url = self._xcat_url.tabdump("/zvm", addp)
all_userids = xcatutils.xcat_request("GET", url)
header = '#node,hcp,userid,nodetype,parent,comments,disable'
all_userids['data'][0].remove(header)
if len(all_userids) > 0:
for u in all_userids['data'][0]:
user_info = u.split(',')
userid = user_info[2].strip('"')
nodename = user_info[0].strip('"')
users[nodename] = {'userid': userid}
return users
users = get_all_userid()
for (port_id, port) in ports.items():
try:
ports[port_id]['userid'] = users[port['nodename']]['userid']
except Exception:
LOG.info(_("Garbage port found. port id: %s") % port_id)
return ports
def update_xcat_switch(self, port, vswitch, vlan):
"""Update information in xCAT switch table."""
commands = "port=%s" % port
commands += " switch.switch=%s" % vswitch
commands += " switch.vlan=%s" % (vlan and vlan or -1)
url = self._xcat_url.tabch("/switch")
body = [commands]
xcatutils.xcat_request("PUT", url, body)
def create_xcat_mgt_network(self, zhcp, mgt_ip, mgt_mask, mgt_vswitch):
url = self._xcat_url.xdsh("/%s" % zhcp)
xdsh_commands = ('command=smcli Virtual_Network_Adapter_Query'
' -T %s -v 0800') % self._xcat_node_name
body = [xdsh_commands]
result = xcatutils.xcat_request("PUT", url, body)['data'][0][0]
code = result.split("\n")
# return code 212: Adapter does not exist
new_nic = ''
if len(code) == 4 and code[1].split(': ')[2] == '212':
new_nic = ('vmcp define nic 0800 type qdio\n' +
'vmcp couple 0800 system %s\n' % (mgt_vswitch))
elif len(code) == 7:
status = code[4].split(': ')[2]
if status == 'Coupled and active':
# we just assign the IP/mask,
# no matter if it is assigned or not
LOG.info(_("Assign IP for NIC 800."))
else:
LOG.error(_("NIC 800 staus is unknown."))
return
else:
raise exception.zvmException(
msg="Unknown information from SMAPI")
url = self._xcat_url.xdsh("/%s") % self._xcat_node_name
cmd = new_nic + ('/usr/bin/perl /usr/sbin/sspqeth2.pl ' +
'-a %s -d 0800 0801 0802 -e eth2 -m %s -g %s'
% (mgt_ip, mgt_mask, mgt_ip))
xdsh_commands = 'command=%s' % cmd
body = [xdsh_commands]
xcatutils.xcat_request("PUT", url, body)
def _get_xcat_node_ip(self):
addp = '&col=key&value=master&attribute=value'
url = self._xcat_url.gettab("/site", addp)
return xcatutils.xcat_request("GET", url)['data'][0][0]
def _get_xcat_node_name(self):
xcat_ip = self._get_xcat_node_ip()
addp = '&col=ip&value=%s&attribute=node' % (xcat_ip)
url = self._xcat_url.gettab("/hosts", addp)
return (xcatutils.xcat_request("GET", url)['data'][0][0])
def query_xcat_uptime(self, zhcp):
url = self._xcat_url.xdsh("/%s" % zhcp)
cmd = '/opt/zhcp/bin/smcli Image_Query_Activate_Time'
cmd += " -T %s" % self.get_userid_from_node(
self._xcat_node_name)
# format 4: yyyy-mm-dd
cmd += " -f %s" % "4"
xdsh_commands = 'command=%s' % cmd
body = [xdsh_commands]
ret_str = xcatutils.xcat_request("PUT", url, body)['data'][0][0]
return ret_str.split('on ')[1]
def query_zvm_uptime(self, zhcp):
url = self._xcat_url.xdsh("/%s" % zhcp)
cmd = '/opt/zhcp/bin/smcli System_Info_Query'
xdsh_commands = 'command=%s' % cmd
body = [xdsh_commands]
ret_str = xcatutils.xcat_request("PUT", url, body)['data'][0][0]
return ret_str.split('\n')[4].split(': ', 3)[2]