diff --git a/xCAT-openbmc-py/lib/python/agent/hwctl/executor/openbmc_bmcconfig.py b/xCAT-openbmc-py/lib/python/agent/hwctl/executor/openbmc_bmcconfig.py index b7ae94bed..8b9c90f81 100644 --- a/xCAT-openbmc-py/lib/python/agent/hwctl/executor/openbmc_bmcconfig.py +++ b/xCAT-openbmc-py/lib/python/agent/hwctl/executor/openbmc_bmcconfig.py @@ -5,19 +5,27 @@ # -*- coding: utf-8 -*- # from __future__ import print_function -import gevent -import time +import os, stat +from common import utils from common.task import ParallelNodesCommand from common.exceptions import SelfClientException, SelfServerException from hwctl import openbmc_client as openbmc +#For rspconfig sshcfg +from pssh.ssh_client import SSHClient +from pssh.exceptions import UnknownHostException, AuthenticationException, \ + ConnectionErrorException, SSHException +from scp import SCPClient + import logging logger = logging.getLogger('xcatagent') RSPCONFIG_GET_NETINFO=['ip', 'netmask', 'gateway', 'vlan', 'ipsrc', 'hostname'] RSPCONFIG_SET_NETINFO=['ip', 'netmask', 'gateway', 'vlan'] + + class OpenBMCBmcConfigTask(ParallelNodesCommand): def dump_list(self, **kw): @@ -35,11 +43,74 @@ class OpenBMCBmcConfigTask(ParallelNodesCommand): def dump_process(self, **kw): return self.callback.info("dump_process: trigger, list and download") + def pre_set_sshcfg(self, *arg, **kw): + local_home_dir=os.path.expanduser('~') + self.local_ssh_dir = local_home_dir + "/.ssh/" + self.local_public_key = self.local_ssh_dir + "id_rsa.pub" + self.copy_sh_file = self.local_ssh_dir + "./copy.sh" + f = open(self.copy_sh_file, 'w') + f.write("#!/bin/sh \n\ +umask 0077 \n\ +userid=$1 \n\ +home=`egrep \"^$userid:\" /etc/passwd | cut -f6 -d :` \n\ +if [ -n \"$home\" ]; then \n\ + dest_dir=\"$home/.ssh\" \n\ +else \n\ + home=`su - root -c pwd` \n\ + dest_dir=\"$home/.ssh\" \n\ +fi \n\ +mkdir -p $dest_dir \n\ +cat /tmp/$userid/.ssh/id_rsa.pub >> $home/.ssh/authorized_keys 2>&1 \n\ +rm -f /tmp/$userid/.ssh/* 2>&1 \n\ +rmdir \"/tmp/$userid/.ssh\" \n\ +rmdir \"/tmp/$userid\" \n") + + f.close() + os.chmod(self.copy_sh_file,stat.S_IRWXU) + if self.verbose: + self.callback.info("Prepared %s file done" % self.copy_sh_file) + def set_sshcfg(self, **kw): - return self.callback.info("set_sshcfg") + node = kw['node'] + nodeinfo = kw['nodeinfo'] + tmp_remote_dir = "/tmp/%s/.ssh/" % nodeinfo['username'] + #try: + ssh_client = SSHClient(nodeinfo['bmcip'], user=nodeinfo['username'], password=nodeinfo['password']) + #except (SSHException, NoValidConnectionsError,BadHostKeyException) as e: + # self.callback.info("%s: %s" % (node, e)) + if not ssh_client.client.get_transport().is_active(): + self.callback.info("SSH session is not active") + if not ssh_client.client.get_transport().is_authenticated(): + self.callback.info("SSH session is not authenticated") + try: + ssh_client.client.exec_command("/bin/mkdir -p %s\n" % tmp_remote_dir) + except (SSHException, ConnectionErrorException) as e: + self.callback.info("%s: ----%s------" % (host, e)) + scp = SCPClient(ssh_client.client.get_transport()) + scp.put(self.copy_sh_file, tmp_remote_dir + "copy.sh") + scp.put(self.local_public_key, tmp_remote_dir + "id_rsa.pub") + ssh_client.client.exec_command("%s/copy.sh %s" % (tmp_remote_dir, nodeinfo['username'])) + ssh_client.client.close() + return self.callback.info("ssh keys copied to %s" % nodeinfo['bmcip']) + + def set_ipdhcp(self, **kw): - return self.callback.info("set_ipdhcp") + node = kw['node'] + obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback, + debugmode=self.debugmode, verbose=self.verbose) + try: + obmc.login() + obmc.set_ipdhcp() + except (SelfServerException, SelfClientException) as e: + self.callback.info("%s: %s" % (node, e.message)) + return + + self.callback.info("%s: BMC Setting IP to DHCP..." % (node)) + try: + obmc.reboot_bmc() + except (SelfServerException, SelfClientException) as e: + self.callback.info("%s: %s" % (node, e.message)) def get_attributes(self, attributes, **kw): netinfo_dict={} @@ -47,13 +118,14 @@ class OpenBMCBmcConfigTask(ParallelNodesCommand): if attr in RSPCONFIG_GET_NETINFO: netinfo_dict[attr]=True getnet=1 - elif openbmc.RSPCONFIG_APIS.has_key(attr): + elif attr in openbmc.RSPCONFIG_APIS: self._get_apis_values(attr, **kw) else: self.callback.error("get_attributes can not deal with attr %s" % attr) if len(netinfo_dict): - self._get_netinfo(netinfo_dict.has_key('ip'), netinfo_dict.has_key('ipsrc'), netinfo_dict.has_key('netmask'), - netinfo_dict.has_key('gateway'), netinfo_dict.has_key('vlan'), netinfo_dict.has_key('hostname'), **kw) + self._get_netinfo(ip=netinfo_dict.get('ip', False), ipsrc=netinfo_dict.get('ipsrc', False), netmask=netinfo_dict.get('netmask', False), + gateway=netinfo_dict.get('gateway', False),vlan= netinfo_dict.get('vlan', False), + hostname=netinfo_dict.get('hostname', False), **kw) def set_attributes(self, attributes, **kw): netinfo_dict={'vlan':False} @@ -63,24 +135,28 @@ class OpenBMCBmcConfigTask(ParallelNodesCommand): netinfo_dict[k] = v elif k == 'hostname': self._set_hostname(v, **kw) - elif openbmc.RSPCONFIG_APIS.has_key(k): + elif k in openbmc.RSPCONFIG_APIS: self._set_apis_values(k, v, **kw) else: return self.callback.error("set_attributes unsupported attribute:%s" % k) - if len(netinfo_dict) > 1 and (not netinfo_dict.has_key('ip') or not netinfo_dict.has_key('netmask') or not netinfo_dict.has_key('gateway')): + if len(netinfo_dict) > 1 and ('ip' not in netinfo_dict or 'netmask' not in netinfo_dict or 'gateway' not in netinfo_dict): self.callback.info("set_attributes miss either ip, netmask or gateway to set network information") + elif len(netinfo_dict) <= 1: + return else: self._set_netinfo(netinfo_dict['ip'], netinfo_dict['netmask'], netinfo_dict['gateway'], netinfo_dict['vlan']) def _set_hostname(self, hostname, **kw): + node = kw['node'] if hostname == '*': - if kw['nodeinfo']['bmc'] != kw['nodeinfo']['bmcip']: - hostname = kw['nodeinfo']['bmc'] - else: - hostname = '%s-bmc' % kw['node'] - return self.callback.info("set_hostname: %s" % hostname) - + if kw['nodeinfo']['bmc'] == kw['nodeinfo']['bmcip']: + self.callback.info("%s: set BMC ip as BMC Hostname" % node) + hostname = kw['nodeinfo']['bmc'] + self._set_apis_values("hostname", hostname, **kw) + self._get_netinfo(hostname=True, ntpserver=False, **kw) + return + def _set_apis_values(self, key, value, **kw): node = kw['node'] obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback, @@ -115,18 +191,58 @@ class OpenBMCBmcConfigTask(ParallelNodesCommand): result = "set net(%s, %s, %s) for eth0" % (ip, netmask, gateway) return self.callback.info("set_netinfo %s" % result) - def _get_netinfo(self, ip=False, ipsrc=False, netmask=False, gateway=False, vlan=False, hostname=False, **kw): - result = '' - if ip: - result += "Get IP, " - if netmask: - result += "Get Mask, " - if gateway: - result += "Get Gateway, " - if ipsrc: - result += "Get IP source, " + def _get_netinfo(self, ip=False, ipsrc=False, netmask=False, gateway=False, vlan=False, hostname=False, ntpserver=True, **kw): + node = kw['node'] + obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback, + debugmode=self.debugmode, verbose=self.verbose) + try: + obmc.login() + netinfo = obmc.get_netinfo() + except (SelfServerException, SelfClientException) as e: + self.callback.info('%s: %s' % (node, e.message)) + return + if not netinfo: + return self.callback.error("%s: No network information get" % node) + defaultgateway = "n/a" + bmchostname = "" + if 'defaultgateway' in netinfo: + defaultgateway = netinfo["defaultgateway"] + del netinfo["defaultgateway"] + if 'hostname' in netinfo: + bmchostname = netinfo["hostname"] + del netinfo["hostname"] + if hostname: - result += "Get BMC hostname, " + self.callback.info("%s: BMC Hostname: %s" %(node, bmchostname)) + dic_length = len(netinfo) + netinfodict = {'ip':[], 'netmask':[], 'gateway':[], + 'vlan':[], 'ipsrc':[], 'ntpserver':[]} + for nic,attrs in netinfo.items(): + addon_string = '' + if dic_length > 1: + addon_string = " for %s" % nic + netinfodict['ip'].append("BMC IP"+addon_string+": %s" % attrs["ip"]) + netinfodict['netmask'].append("BMC Netmask"+addon_string+": %s" % attrs["netmask"]) + netinfodict['gateway'].append("BMC Gateway"+addon_string+": %s (default: %s)" % (attrs["gateway"], defaultgateway)) + netinfodict['vlan'].append("BMC VLAN ID"+addon_string+": %s" % attrs["vlanid"]) + netinfodict['ipsrc'].append("BMC IP Source"+addon_string+": %s" % attrs["ipsrc"]) + netinfodict['ntpserver'].append("BMC NTP Servers"+addon_string+": %s" % attrs["ntpservers"]) + if ip: + for i in netinfodict['ip']: + self.callback.info("%s: %s" % (node, i)) + if netmask: + for i in netinfodict['netmask']: + self.callback.info("%s: %s" % (node, i)) + if gateway: + for i in netinfodict['gateway']: + self.callback.info("%s: %s" % (node, i)) + if ipsrc: + for i in netinfodict['ipsrc']: + self.callback.info("%s: %s" % (node, i)) if vlan: - result += "Get BMC vlan." - return self.callback.info("get_netinfo: %s" % result) + for i in netinfodict['vlan']: + self.callback.info("%s: %s" % (node, i)) + if ntpserver: + for i in netinfodict['netserver']: + self.callback.info("%s: %s" % (node, i)) + return netinfo diff --git a/xCAT-openbmc-py/lib/python/agent/hwctl/openbmc_client.py b/xCAT-openbmc-py/lib/python/agent/hwctl/openbmc_client.py index f1fa55057..8ebfc7831 100644 --- a/xCAT-openbmc-py/lib/python/agent/hwctl/openbmc_client.py +++ b/xCAT-openbmc-py/lib/python/agent/hwctl/openbmc_client.py @@ -9,7 +9,7 @@ import requests import json import time -from common import rest +from common import utils, rest from common.exceptions import SelfClientException, SelfServerException import logging @@ -141,7 +141,20 @@ FIRM_URLS = { } } +RSPCONFIG_NETINFO_URL = { + 'get_netinfo': "/network/enumerate", + 'nic_ip': "/network/#NIC#/action/IP", + 'vlan': "/network/action/VLAN", + 'ipdhcp': "/network/action/Reset", + 'ntpserver': "/network/#NIC#/attr/NTPServers", +} + RSPCONFIG_APIS = { + 'hostname': { + 'baseurl': "/network/config/", + 'set_url': "attr/HostName", + 'display_name': "BMC Hostname", + }, 'autoreboot' : { 'baseurl': "/control/host0/auto_reboot/", 'set_url': "attr/AutoReboot", @@ -488,10 +501,10 @@ class OpenBMCRest(object): def set_apis_values(self, key, value): attr_info = RSPCONFIG_APIS[key] - if not attr_info.has_key('set_url'): + if 'set_url' not in attr_info: raise SelfServerException("config %s failed, not url available" % key) set_url = attr_info['baseurl']+attr_info['set_url'] - if attr_info.has_key('attr_values') and attr_info['attr_values'].has_key(value): + if 'attr_values' in attr_info and value in attr_info['attr_values']: data = attr_info['attr_values'][value] else: data = value @@ -499,18 +512,60 @@ class OpenBMCRest(object): def get_apis_values(self, key): attr_info = RSPCONFIG_APIS[key] - if not attr_info.has_key('get_url'): + if 'get_url' not in attr_info: raise SelfServerException("Reading %s failed, not url available" % key) get_url = attr_info['baseurl']+attr_info['get_url'] method = 'GET' - if attr_info.has_key('get_method'): + if 'get_method' in attr_info: method = attr_info['get_method'] data = None - if attr_info.has_key('get_data'): + if 'get_data' in attr_info: data={"data": attr_info['get_data']} return self.request(method, get_url, payload=data, cmd="get_%s" % key) + def get_netinfo(self): + data = self.request('GET', RSPCONFIG_NETINFO_URL['get_netinfo'], cmd="get_netinfo") + try: + netinfo = {} + for k, v in data.items(): + if 'network/config' in k: + if 'HostName' in v: + netinfo["hostname"] = v["HostName"] + if 'DefaultGateway' in v: + netinfo["defaultgateway"] = v["DefaultGateway"] + continue + dev,match,netid = k.partition("/ipv4/") + if netid: + if 'LinkLocal' in v["Origin"] or v["Address"].startswith("169.254"): + msg = "Found LinkLocal address %s for interface %s, Ignoring..." % (v["Address"], dev) + self._print_record_log(msg, 'get_netinfo') + continue + nicid = dev.split('/')[-1] + if nicid not in netinfo: + netinfo[nicid] = {} + if 'ip' in netinfo[nicid]: + msg = "%s: Another valid ip %s found." % (node, v["Address"]) + self._print_record_log(msg, 'get_netinfo') + continue + utils.update2Ddict(netinfo, nicid, "ipsrc", v["Origin"].split('.')[-1]) + utils.update2Ddict(netinfo, nicid, "netmask", v["PrefixLength"]) + utils.update2Ddict(netinfo, nicid, "gateway", v["Gateway"]) + utils.update2Ddict(netinfo, nicid, "ip", v["Address"]) + if dev in data: + info = data[dev] + utils.update2Ddict(netinfo, nicid, "vlanid", info.get("Id", "Disable")) + utils.update2Ddict(netinfo, nicid, "mac", info["MACAddress"]) + utils.update2Ddict(netinfo, nicid, "ntpservers", info["NTPServers"]) + return netinfo + except KeyError: + error = 'Error: Received wrong format response: %s' % data + raise SelfServerException(error) + + + def set_ipdhcp(self): + return self.request('PUT', RSPCONFIG_NETINFO_URL['ipdhcp'], cmd="set_bmcip_dhcp") + class OpenBMCImage(object): def __init__(self, rawid, data=None): self.id = rawid.split('/')[-1] diff --git a/xCAT-openbmc-py/lib/python/agent/xcatagent/openbmc.py b/xCAT-openbmc-py/lib/python/agent/xcatagent/openbmc.py index 621e7301f..d6442e8e3 100644 --- a/xCAT-openbmc-py/lib/python/agent/xcatagent/openbmc.py +++ b/xCAT-openbmc-py/lib/python/agent/xcatagent/openbmc.py @@ -736,7 +736,7 @@ class OpenBMCManager(base.BaseManager): elif opts['get']: unsupport_list=list(set(opts['']) - set(RSPCONFIG_GET_OPTIONS)) if len(unsupport_list) > 0: - self.messager.error("Have unsupported option: %s" % unsupport_args) + self.messager.error("Have unsupported option: %s" % unsupport_list) return else: DefaultBmcConfigManager().get_attributes(runner, opts['']) @@ -744,7 +744,7 @@ class OpenBMCManager(base.BaseManager): rc=0 for attr in opts['']: k,v = attr.split('=') - if not RSPCONFIG_SET_OPTIONS.has_key(k): + if k not in RSPCONFIG_SET_OPTIONS: self.messager.error("The attribute %s is not support to set" % k) rc=1 elif not re.match(RSPCONFIG_SET_OPTIONS[k], v):