mirror of
				https://github.com/xcat2/xcat-core.git
				synced 2025-10-27 01:15:34 +00:00 
			
		
		
		
	packaging xCAT-openbmc-py method
This commit is contained in:
		
							
								
								
									
										38
									
								
								makepythonrpm
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										38
									
								
								makepythonrpm
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| #!/bin/bash | ||||
|  | ||||
| # IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html | ||||
|  | ||||
| function makepythonrpm { | ||||
|     RPMNAME="$1" | ||||
|     SPEC_FILE="$RPMNAME.spec" | ||||
|     tar --exclude .svn -czvf $RPMROOT/SOURCES/$RPMNAME-${VER}.tar.gz $RPMNAME | ||||
|     rm -f $RPMROOT/SRPMS/$RPMNAME-$VER*rpm $RPMROOT/RPMS/noarch/$RPMNAME-$VER*rpm | ||||
|     echo "Building $RPMROOT/RPMS/noarch/$RPMNAME-$VER-snap*.noarch.rpm $EMBEDTXT..." | ||||
|     rpmbuild --quiet -ta $RPMROOT/SOURCES/$RPMNAME-${VER}.tar.gz --define "version $VER" $REL "$EASE" | ||||
|     if [ $? -eq 0 ]; then | ||||
|         exit 0 | ||||
|     else   | ||||
|         exit 1 | ||||
|     fi | ||||
| }	 | ||||
| 	 | ||||
| # Main code.... | ||||
| OSNAME=$(uname) | ||||
| VER=`cat Version` | ||||
| REL="--define" | ||||
| EASE='usedate 1' | ||||
| RPMROOT=/root/rpmbuild | ||||
|  | ||||
| rpmbuild --version > /dev/null | ||||
| if [ $? -gt 0 ]; then | ||||
|     echo "Error: rpmbuild does not appear to be installed or working." | ||||
|     exit 2 | ||||
| fi | ||||
|  | ||||
| if [ -n "$1" -a "$1" = "xCAT-openbmc-py" ]; then | ||||
|     makepythonrpm $1 | ||||
| else | ||||
|     echo 'Usage: makepythonrpm xCAT-openbmc-py' | ||||
|     exit 1 | ||||
| fi | ||||
|  | ||||
							
								
								
									
										52
									
								
								xCAT-openbmc-py/lib/python/agent/agent.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										52
									
								
								xCAT-openbmc-py/lib/python/agent/agent.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| #!/usr/bin/env python | ||||
| # -*- encoding: utf-8 -*- | ||||
| from __future__ import print_function | ||||
| import argparse | ||||
| import sys | ||||
| from xcatagent import server | ||||
|  | ||||
|  | ||||
| class AgentShell(object): | ||||
|     def get_base_parser(self): | ||||
|         parser = argparse.ArgumentParser( | ||||
|             prog='xcatagent', | ||||
|             add_help=False, | ||||
|             formatter_class=HelpFormatter, | ||||
|         ) | ||||
|         parser.add_argument('-h', '--help', | ||||
|                             action='store_true', | ||||
|                             help=argparse.SUPPRESS, | ||||
|                             ) | ||||
|         parser.add_argument('--standalone', | ||||
|                             help="Start xcat agent as a standalone service, " | ||||
|                                  "mostly work for test purpose. ", | ||||
|                             action='store_true') | ||||
|         parser.add_argument('--sock', | ||||
|                             help="The unix domain sock file to communicate " | ||||
|                                  "with the client", | ||||
|                             default='/var/run/xcat/agent.sock', | ||||
|                             type=str) | ||||
|         return parser | ||||
|  | ||||
|     def do_help(self, args): | ||||
|         self.parser.print_help() | ||||
|  | ||||
|     def main(self, argv): | ||||
|         self.parser = self.get_base_parser() | ||||
|         (options, args) = self.parser.parse_known_args(argv) | ||||
|  | ||||
|         if options.help: | ||||
|             self.do_help(options) | ||||
|             return 0 | ||||
|         s = server.Server(options.sock, options.standalone) | ||||
|         s.start() | ||||
|  | ||||
| class HelpFormatter(argparse.HelpFormatter): | ||||
|     def start_section(self, heading): | ||||
|         # Title-case the headings | ||||
|         heading = '%s%s' % (heading[0].upper(), heading[1:]) | ||||
|         super(HelpFormatter, self).start_section(heading) | ||||
|  | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     AgentShell().main(sys.argv[1:]) | ||||
							
								
								
									
										76
									
								
								xCAT-openbmc-py/lib/python/agent/client.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										76
									
								
								xCAT-openbmc-py/lib/python/agent/client.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,76 @@ | ||||
| #!/usr/bin/env python | ||||
| # -*- encoding: utf-8 -*- | ||||
| # just for test | ||||
| from __future__ import print_function | ||||
|  | ||||
| import argparse | ||||
| import json | ||||
| import os | ||||
| import socket | ||||
| import sys | ||||
| from xcatagent import utils | ||||
|  | ||||
| class ClientShell(object): | ||||
|     def get_base_parser(self): | ||||
|         parser = argparse.ArgumentParser( | ||||
|             prog='agentclient', | ||||
|             add_help=False, | ||||
|             formatter_class=HelpFormatter, | ||||
|         ) | ||||
|         parser.add_argument('-h', '--help', | ||||
|                             action='store_true', | ||||
|                             help=argparse.SUPPRESS, | ||||
|                             ) | ||||
|         parser.add_argument('--sock', | ||||
|                             help="The unix domain sock file to communicate " | ||||
|                                  "with the server", | ||||
|                             default='/var/run/xcat/agent.sock', | ||||
|                             type=str) | ||||
|         return parser | ||||
|  | ||||
|     def do_help(self, args): | ||||
|         self.parser.print_help() | ||||
|  | ||||
|     def main(self, argv): | ||||
|         self.parser = self.get_base_parser() | ||||
|         (options, args) = self.parser.parse_known_args(argv) | ||||
|  | ||||
|         if options.help: | ||||
|             self.do_help(options) | ||||
|             return 0 | ||||
|  | ||||
|         s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) | ||||
|         nodes = ['node1', 'node2'] | ||||
|         nodeinfo = {'node1':{'bmc':'10.0.0.1', 'bmcip':'10.0.0.1', 'username':'root', 'password': 'xxxxxx'}, | ||||
|                     'node2':{'bmc':'10.0.0.2', 'bmcip':'10.0.0.2', 'username':'root', 'password': 'xxxxxx'}} | ||||
|  | ||||
|         s.connect(options.sock) | ||||
|         req = {'module': 'openbmc', | ||||
|                'command': 'rpower', | ||||
|                'args': ['state'], | ||||
|                'cwd': os.getcwd(), | ||||
|                'nodes': nodes, | ||||
|                'nodeinfo': nodeinfo, | ||||
|                'envs': {'debugmode': 1}} | ||||
|  | ||||
|         buf = json.dumps(req) | ||||
|         s.send(utils.int2bytes(len(buf))) | ||||
|         s.send(buf) | ||||
|         while True: | ||||
|             sz = s.recv(4) | ||||
|             if len(sz) == 0: | ||||
|                 break | ||||
|             sz = utils.bytes2int(sz) | ||||
|             data = s.recv(sz) | ||||
|             print(data) | ||||
|  | ||||
|  | ||||
| class HelpFormatter(argparse.HelpFormatter): | ||||
|     def start_section(self, heading): | ||||
|         # Title-case the headings | ||||
|         heading = '%s%s' % (heading[0].upper(), heading[1:]) | ||||
|         super(HelpFormatter, self).start_section(heading) | ||||
|  | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     ClientShell().main(sys.argv[1:]) | ||||
							
								
								
									
										2
									
								
								xCAT-openbmc-py/lib/python/agent/xcatagent/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								xCAT-openbmc-py/lib/python/agent/xcatagent/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| from gevent import monkey | ||||
| monkey.patch_all(thread=False) | ||||
							
								
								
									
										47
									
								
								xCAT-openbmc-py/lib/python/agent/xcatagent/base.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								xCAT-openbmc-py/lib/python/agent/xcatagent/base.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| from xcatagent import utils | ||||
| import gevent | ||||
| from gevent.pool import Pool | ||||
|  | ||||
| MODULE_MAP = {"openbmc": "OpenBMCManager"} | ||||
|  | ||||
|  | ||||
| class BaseManager(object): | ||||
|     def __init__(self, messager, cwd): | ||||
|         self.messager = messager | ||||
|         self.cwd = cwd | ||||
|  | ||||
|     @classmethod | ||||
|     def get_manager_func(self, name): | ||||
|         module_name = 'xcatagent.%s' % name | ||||
|         try: | ||||
|             __import__(module_name) | ||||
|         except ImportError: | ||||
|             return None | ||||
|  | ||||
|         class_name = MODULE_MAP[name] | ||||
|         return utils.class_func(module_name, class_name) | ||||
|  | ||||
|     def process_nodes_worker(self, name, classname, nodes, nodeinfo, command, args): | ||||
|          | ||||
|         module_name = 'xcatagent.%s' % name | ||||
|         obj_func = utils.class_func(module_name, classname) | ||||
|  | ||||
|         gevent_pool = Pool(1000) | ||||
|  | ||||
|         for node in nodes: | ||||
|             obj = obj_func(self.messager, node, nodeinfo[node]) | ||||
|             if not hasattr(obj, command): | ||||
|                 self.messager.error('%s: command %s is not supported for %s' % (node, command, classname)) | ||||
|             func = getattr(obj, command) | ||||
|             try: | ||||
|                 gevent_pool.add( gevent.spawn(func, args) ) | ||||
|             except Exception: | ||||
|                 error = '%s: Internel Error occured in gevent' % node | ||||
|                 self.messager.error(error) | ||||
|  | ||||
|         gevent_pool.join() | ||||
|  | ||||
|  | ||||
| class BaseDriver(object): | ||||
|     def __init__(self, messager): | ||||
|         self.messager = messager | ||||
							
								
								
									
										242
									
								
								xCAT-openbmc-py/lib/python/agent/xcatagent/openbmc.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										242
									
								
								xCAT-openbmc-py/lib/python/agent/xcatagent/openbmc.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,242 @@ | ||||
| from xcatagent import base | ||||
| import time | ||||
| import sys | ||||
| import gevent | ||||
|  | ||||
| import xcat_exception | ||||
| import rest | ||||
|  | ||||
| HTTP_PROTOCOL = "https://" | ||||
| PROJECT_URL = "/xyz/openbmc_project" | ||||
|  | ||||
| RESULT_OK = 'ok' | ||||
|  | ||||
| DEBUGMODE = False | ||||
|  | ||||
| POWER_SET_OPTIONS = ('on', 'off', 'bmcreboot', 'softoff') | ||||
| POWER_GET_OPTIONS = ('bmcstate', 'state', 'stat', 'status') | ||||
|  | ||||
| RPOWER_URLS = { | ||||
|     "on"        : { | ||||
|         "url"   : PROJECT_URL + "/state/host0/attr/RequestedHostTransition", | ||||
|         "field" : "xyz.openbmc_project.State.Host.Transition.On", | ||||
|     }, | ||||
|     "off"       : { | ||||
|         "url"   : PROJECT_URL + "/state/chassis0/attr/RequestedPowerTransition", | ||||
|         "field" : "xyz.openbmc_project.State.Chassis.Transition.Off", | ||||
|     }, | ||||
|     "softoff"   : { | ||||
|         "url"   : PROJECT_URL + "/state/host0/attr/RequestedHostTransition", | ||||
|         "field" : "xyz.openbmc_project.State.Host.Transition.Off", | ||||
|     }, | ||||
|     "bmcreboot" : { | ||||
|         "url"   : PROJECT_URL + "/state/bmc0/attr/RequestedBMCTransition", | ||||
|         "field" : "xyz.openbmc_project.State.BMC.Transition.Reboot", | ||||
|     }, | ||||
|     "state"     : { | ||||
|         "url"   : PROJECT_URL + "/state/enumerate", | ||||
|     }, | ||||
| } | ||||
|  | ||||
| RPOWER_STATE = { | ||||
|     "on"        : "on", | ||||
|     "off"       : "off", | ||||
|     "Off"       : "off", | ||||
|     "softoff"   : "softoff", | ||||
|     "boot"      : "reset", | ||||
|     "reset"     : "reset", | ||||
|     "bmcreboot" : "BMC reboot", | ||||
|     "Ready"     : "BMC Ready", | ||||
|     "NotReady"  : "BMC NotReady", | ||||
|     "chassison" : "on (Chassis)", | ||||
|     "Running"   : "on", | ||||
|     "Quiesced"  : "quiesced", | ||||
| } | ||||
|  | ||||
| POWER_STATE_DB = { | ||||
|     "on"      : "powering-on", | ||||
|     "off"     : "powering-off", | ||||
|     "softoff" : "powering-off", | ||||
|     "boot"    : "powering-on", | ||||
|     "reset"   : "powering-on", | ||||
| } | ||||
|  | ||||
| class OpenBMC(base.BaseDriver): | ||||
|  | ||||
|     headers = {'Content-Type': 'application/json'} | ||||
|  | ||||
|     def __init__(self, messager, name, node_info): | ||||
|         super(OpenBMC, self).__init__(messager)         | ||||
|         self.node = name | ||||
|         for key, value in node_info.items() : | ||||
|             setattr(self, key, value) | ||||
|         global DEBUGMODE | ||||
|         self.client = rest.RestSession(messager, DEBUGMODE) | ||||
|  | ||||
|     def _login(self) : | ||||
|         """ Login | ||||
|         :raise: error message if failed | ||||
|         """ | ||||
|         url = HTTP_PROTOCOL + self.bmcip + '/login' | ||||
|         data = { "data": [ self.username, self.password ] } | ||||
|         self.client.request('POST', url, OpenBMC.headers, data, self.node, 'login') | ||||
|         return RESULT_OK | ||||
|  | ||||
|     def _set_power_onoff(self, subcommand) : | ||||
|         """ Set power on/off/softoff/bmcreboot | ||||
|         :param subcommand: subcommand for rpower | ||||
|         :returns: ok if success | ||||
|         :raise: error message if failed | ||||
|         """ | ||||
|         url = HTTP_PROTOCOL + self.bmcip + RPOWER_URLS[subcommand]['url'] | ||||
|         data = { "data": RPOWER_URLS[subcommand]['field'] } | ||||
|         try : | ||||
|             response = self.client.request('PUT', url, OpenBMC.headers, data, self.node, 'rpower_' + subcommand) | ||||
|         except (xcat_exception.SelfServerException, | ||||
|                 xcat_exception.SelfClientException) as e : | ||||
|             if subcommand != 'bmcreboot': | ||||
|                 result = e.message | ||||
|             return result | ||||
|  | ||||
|         return RESULT_OK | ||||
|  | ||||
|     def _get_power_state(self, subcommand) : | ||||
|         """ Get power current state | ||||
|         :param subcommand: state/stat/status/bmcstate | ||||
|         :returns: current state if success | ||||
|         :raise: error message if failed | ||||
|         """ | ||||
|         result = '' | ||||
|         bmc_not_ready = 'NotReady' | ||||
|         url = HTTP_PROTOCOL + self.bmcip + RPOWER_URLS['state']['url'] | ||||
|         try : | ||||
|             response = self.client.request('GET', url, OpenBMC.headers, '', self.node, 'rpower_' + subcommand) | ||||
|         except xcat_exception.SelfServerException, e : | ||||
|             if subcommand == 'bmcstate': | ||||
|                 result = bmc_not_ready | ||||
|             else : | ||||
|                 result = e.message | ||||
|         except xcat_exception.SelfClientException, e : | ||||
|             result = e.message | ||||
|  | ||||
|         if result :  | ||||
|             return result | ||||
|  | ||||
|         for key in response['data'] : | ||||
|             key_type = key.split('/')[-1] | ||||
|             if key_type == 'bmc0' : | ||||
|                 bmc_current_state = response['data'][key]['CurrentBMCState'].split('.')[-1] | ||||
|             if key_type == 'chassis0' : | ||||
|                 chassis_current_state = response['data'][key]['CurrentPowerState'].split('.')[-1] | ||||
|             if key_type == 'host0' : | ||||
|                 host_current_state = response['data'][key]['CurrentHostState'].split('.')[-1] | ||||
|  | ||||
|         if subcommand == 'bmcstate' : | ||||
|             if bmc_current_state == 'Ready' : | ||||
|                 return bmc_current_state  | ||||
|             else : | ||||
|                 return bmc_not_ready | ||||
|  | ||||
|         if chassis_current_state == 'Off' : | ||||
|             return chassis_current_state | ||||
|         elif chassis_current_state == 'On' : | ||||
|             if host_current_state == 'Off' : | ||||
|                 return 'chassison' | ||||
|             elif host_current_state == 'Quiesced' : | ||||
|                 return host_current_state | ||||
|             elif host_current_state == 'Running' : | ||||
|                 return host_current_state | ||||
|             else : | ||||
|                 return 'Unexpected chassis state=' + host_current_state | ||||
|         else : | ||||
|             return 'Unexpected chassis state=' + chassis_current_state | ||||
|  | ||||
|  | ||||
|     def _rpower_boot(self) : | ||||
|         """Power boot | ||||
|         :returns: 'reset' if success | ||||
|         :raise: error message if failed | ||||
|         """ | ||||
|         result = self._set_power_onoff('off') | ||||
|         if result != RESULT_OK : | ||||
|             return result | ||||
|         self.messager.update_node_attributes('status', self.node, POWER_STATE_DB['off']) | ||||
|  | ||||
|         start_timeStamp = int(time.time()) | ||||
|         for i in range (0,30) : | ||||
|             status = self._get_power_state('state') | ||||
|             if status in RPOWER_STATE and RPOWER_STATE[status] == 'off': | ||||
|                 break | ||||
|             gevent.sleep( 2 ) | ||||
|  | ||||
|         end_timeStamp = int(time.time()) | ||||
|  | ||||
|         if status not in RPOWER_STATE or RPOWER_STATE[status] != 'off': | ||||
|             wait_time = str(end_timeStamp - start_timeStamp) | ||||
|             result = 'Error: Sent power-off command but state did not change to off after waiting ' + wait_time + ' seconds. (State=' + status + ').' | ||||
|             return result | ||||
|  | ||||
|         result = self._set_power_onoff('on') | ||||
|         return result | ||||
|  | ||||
|  | ||||
|     def rpower(self, args) : | ||||
|         """handle rpower command | ||||
|         :param args: subcommands for rpower | ||||
|         """ | ||||
|         subcommand = args[0] | ||||
|         try : | ||||
|             result = self._login() | ||||
|         except xcat_exception.SelfServerException as e : | ||||
|             if subcommand == 'bmcstate' : | ||||
|                 result = '%s: %s' % (self.node, RPOWER_STATE['NotReady']) | ||||
|             else : | ||||
|                 result = '%s: %s'  % (self.node, e.message) | ||||
|         except xcat_exception.SelfClientException as e : | ||||
|             result = '%s: %s'  % (self.node, e.message) | ||||
|  | ||||
|         if result != RESULT_OK : | ||||
|             self.messager.info(result) | ||||
|             self._update2Ddict(node_rst, self.node, 'rst', result) | ||||
|             return | ||||
|         new_status = '' | ||||
|         if subcommand in POWER_SET_OPTIONS : | ||||
|             result = self._set_power_onoff(subcommand) | ||||
|             if result == RESULT_OK : | ||||
|                 result = RPOWER_STATE[subcommand] | ||||
|                 new_status = POWER_STATE_DB.get(subcommand, '') | ||||
|  | ||||
|         if subcommand in POWER_GET_OPTIONS : | ||||
|             tmp_result = self._get_power_state(subcommand) | ||||
|             result = RPOWER_STATE.get(tmp_result, tmp_result) | ||||
|  | ||||
|         if subcommand == 'boot' : | ||||
|             result = self._rpower_boot() | ||||
|             if result == RESULT_OK : | ||||
|                 result = RPOWER_STATE[subcommand] | ||||
|                 new_status = POWER_STATE_DB.get(subcommand, '') | ||||
|  | ||||
|         if subcommand == 'reset' : | ||||
|             status = self._get_power_state('state') | ||||
|             if status == 'Off' or status == 'chassison': | ||||
|                 result = RPOWER_STATE['Off'] | ||||
|             else : | ||||
|                 result = self._rpower_boot() | ||||
|                 if result == RESULT_OK : | ||||
|                     result = RPOWER_STATE[subcommand] | ||||
|                     new_status = POWER_STATE_DB.get(subcommand, '') | ||||
|  | ||||
|         message = '%s: %s' % (self.node, result) | ||||
|         self.messager.info(message) | ||||
|         if new_status : | ||||
|             self.messager.update_node_attributes('status', self.node, new_status) | ||||
|  | ||||
| class OpenBMCManager(base.BaseManager): | ||||
|     def __init__(self, messager, cwd, nodes, envs): | ||||
|         super(OpenBMCManager, self).__init__(messager, cwd) | ||||
|         self.nodes = nodes | ||||
|         global DEBUGMODE | ||||
|         DEBUGMODE = envs['debugmode'] | ||||
|  | ||||
|     def rpower(self, nodeinfo, args): | ||||
|         super(OpenBMCManager, self).process_nodes_worker('openbmc', 'OpenBMC', self.nodes, nodeinfo, 'rpower', args) | ||||
							
								
								
									
										84
									
								
								xCAT-openbmc-py/lib/python/agent/xcatagent/rest.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								xCAT-openbmc-py/lib/python/agent/xcatagent/rest.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,84 @@ | ||||
| #!/usr/bin/env python | ||||
| import requests | ||||
| import json | ||||
| import time | ||||
| import urllib3 | ||||
| urllib3.disable_warnings() | ||||
|  | ||||
| import xcat_exception | ||||
|  | ||||
| class RestSession : | ||||
|  | ||||
|     def __init__(self, messager, debugmode) : | ||||
|         self.session = requests.Session() | ||||
|         self.messager = messager | ||||
|         self.debugmode = debugmode | ||||
|  | ||||
|     def _print_record_log (self, node, log_string, status) : | ||||
|         if self.debugmode : | ||||
|             localtime = time.asctime( time.localtime(time.time()) ) | ||||
|             log = node + ': [openbmc_debug] ' + status + ' ' + log_string | ||||
|             self.messager.info(localtime + ' ' + log) | ||||
|             self.messager.syslog(log) | ||||
|  | ||||
|     def _request_log (self, method, url, headers, data): | ||||
|         log_string = 'curl -k -c cjar' | ||||
|         log_string += ' -X %s' % method | ||||
|         for key,value in headers.items() : | ||||
|             header_data = key + ": " + value  | ||||
|         log_string += ' -H "' + header_data + '"' | ||||
|         log_string += ' %s' % url | ||||
|  | ||||
|         if data : | ||||
|             log_string += ' -d \'%s\'' % data | ||||
|  | ||||
|         return log_string | ||||
|  | ||||
|     def request (self, method, url, headers, in_data, node, status) : | ||||
|         if in_data : | ||||
|             data = json.dumps(in_data) | ||||
|         else : | ||||
|             data = '' | ||||
|  | ||||
|         if status == 'login' : | ||||
|             in_data['data'][1] = 'xxxxxx' | ||||
|             log_data = json.dumps(in_data) | ||||
|         else : | ||||
|             log_data = data | ||||
|  | ||||
|         log_string = self._request_log(method, url, headers, log_data) | ||||
|         self._print_record_log(node, log_string, status) | ||||
|  | ||||
|         response = '' | ||||
|         error = '' | ||||
|         try : | ||||
|             response = self.session.request(method, url, | ||||
|                                         data=data, | ||||
|                                         headers=headers, | ||||
|                                         verify=False, | ||||
|                                         timeout=30) | ||||
|         except requests.exceptions.ConnectionError : | ||||
|             error = 'Error: BMC did not respond. Validate BMC configuration and retry the command.' | ||||
|         except requests.exceptions.Timeout : | ||||
|             error = 'Error: Timeout to connect to server' | ||||
|  | ||||
|         if error : | ||||
|             self._print_record_log(node, error, status) | ||||
|             raise xcat_exception.SelfServerException(error) | ||||
|  | ||||
|         try : | ||||
|             response_dict = response.json() | ||||
|         except ValueError : | ||||
|             error = 'Error: Received wrong format response:' + response_dict | ||||
|             self._print_record_log(node, error, status) | ||||
|             raise xcat_exception.SelfServerException(error) | ||||
|  | ||||
|         if response.status_code != requests.codes.ok : | ||||
|             description = ''.join(response_dict['data']['description']) | ||||
|             error = 'Error: [%d] %s' % (response.status_code, description) | ||||
|             self._print_record_log(node, error, status) | ||||
|             raise xcat_exception.SelfClientException(error) | ||||
|         else : | ||||
|             self._print_record_log(node, response_dict['message'], status) | ||||
|  | ||||
|         return response_dict | ||||
							
								
								
									
										123
									
								
								xCAT-openbmc-py/lib/python/agent/xcatagent/server.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								xCAT-openbmc-py/lib/python/agent/xcatagent/server.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,123 @@ | ||||
| # -*- encoding: utf-8 -*- | ||||
| from __future__ import print_function | ||||
| import json | ||||
| import sys | ||||
| import os | ||||
| import threading | ||||
| import fcntl | ||||
| import traceback | ||||
| from gevent import socket | ||||
| from gevent.server import StreamServer | ||||
| from gevent.lock import BoundedSemaphore | ||||
| from xcatagent import utils | ||||
| from xcatagent import base as xcat_manager | ||||
|  | ||||
| MSG_TYPE = 'message' | ||||
| DB_TYPE  = 'db' | ||||
| LOCK_FILE = '/var/lock/xcat/agent.lock' | ||||
|  | ||||
|  | ||||
| class Messager(object): | ||||
|     def __init__(self, sock): | ||||
|         self.sock = sock | ||||
|         self.sem = BoundedSemaphore(1) | ||||
|  | ||||
|     def _send(self, d): | ||||
|         buf = json.dumps(d) | ||||
|         self.sem.acquire() | ||||
|         self.sock.sendall(utils.int2bytes(len(buf)) + buf) | ||||
|         self.sem.release() | ||||
|  | ||||
|     def info(self, msg): | ||||
|         d = {'type': MSG_TYPE, 'msg': {'type': 'info', 'data': msg}} | ||||
|         self._send(d) | ||||
|  | ||||
|     def warn(self, msg): | ||||
|         d = {'type': MSG_TYPE, 'msg': {'type': 'warning', 'data': msg}} | ||||
|         self._send(d) | ||||
|  | ||||
|     def error(self, msg): | ||||
|         d = {'type': MSG_TYPE, 'msg': {'type': 'error', 'data': msg}} | ||||
|         self._send(d) | ||||
|  | ||||
|     def syslog(self, msg): | ||||
|         d = {'type': MSG_TYPE, 'msg': {'type': 'syslog', 'data': msg}} | ||||
|         self._send(d) | ||||
|  | ||||
|     def update_node_attributes(self, attribute, node, data): | ||||
|         d = {'type': DB_TYPE, 'attribute': {'name': attribute, 'method': 'set', 'type': 'node', 'node': node, 'value': data}} | ||||
|         self._send(d) | ||||
|  | ||||
|  | ||||
| class Server(object): | ||||
|     def __init__(self, address, standalone): | ||||
|         try: | ||||
|             os.unlink(address) | ||||
|         except OSError: | ||||
|             if os.path.exists(address): | ||||
|                 raise | ||||
|         self.address = address | ||||
|         self.standalone = standalone | ||||
|         self.server = StreamServer(self._serve(), self._handle) | ||||
|  | ||||
|     def _serve(self): | ||||
|         listener = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) | ||||
|         listener.bind(self.address) | ||||
|         listener.listen(1) | ||||
|         return listener | ||||
|  | ||||
|     def _handle(self, sock, address): | ||||
|         try: | ||||
|             messager = Messager(sock) | ||||
|             buf = sock.recv(4) | ||||
|             sz = utils.bytes2int(buf) | ||||
|             buf = utils.recv_all(sock, sz) | ||||
|             req = json.loads(buf) | ||||
|             if not 'command' in req: | ||||
|                 messager.error("Could not find command") | ||||
|                 return | ||||
|             if not 'module' in req: | ||||
|                 messager.error("Please specify the request module") | ||||
|                 return | ||||
|             if not 'cwd' in req: | ||||
|                 messager.error("Please specify the cwd parameter") | ||||
|                 return | ||||
|             manager_func = xcat_manager.BaseManager.get_manager_func( | ||||
|                 req['module']) | ||||
|             if manager_func is None: | ||||
|                 messager.error("Could not find manager for %s" % req['module']) | ||||
|                 return | ||||
|             nodes = req.get("nodes", None) | ||||
|             manager = manager_func(messager, req['cwd'], nodes, req['envs']) | ||||
|             if not hasattr(manager, req['command']): | ||||
|                 messager.error("command %s is not supported" % req['command']) | ||||
|             func = getattr(manager, req['command']) | ||||
|             # call the function in the specified manager | ||||
|             func(req['nodeinfo'], req['args']) | ||||
|             # after the method returns, the request should be handled | ||||
|             # completely, close the socket for client | ||||
|             if not self.standalone: | ||||
|                 sock.close() | ||||
|                 self.server.stop() | ||||
|                 os._exit(0) | ||||
|         except Exception: | ||||
|             print(traceback.format_exc(), file=sys.stderr) | ||||
|             self.server.stop() | ||||
|             os._exit(1) | ||||
|  | ||||
|     def keep_peer_alive(self): | ||||
|         def acquire(): | ||||
|             fd = open(LOCK_FILE, "r+") | ||||
|             fcntl.flock(fd.fileno(), fcntl.LOCK_EX) | ||||
|             # if reach here, parent process may exit | ||||
|             print("xcat process exit unexpectedly.", file=sys.stderr) | ||||
|             self.server.stop() | ||||
|             os._exit(1) | ||||
|  | ||||
|         t = threading.Thread(target=acquire) | ||||
|         t.start() | ||||
|  | ||||
|     def start(self): | ||||
|         if not self.standalone: | ||||
|             self.keep_peer_alive() | ||||
|         self.server.serve_forever() | ||||
							
								
								
									
										41
									
								
								xCAT-openbmc-py/lib/python/agent/xcatagent/utils.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								xCAT-openbmc-py/lib/python/agent/xcatagent/utils.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| import struct | ||||
| import sys | ||||
| import inspect | ||||
|  | ||||
|  | ||||
| def int2bytes(num): | ||||
|     return struct.pack('i', num) | ||||
|  | ||||
|  | ||||
| def bytes2int(buf): | ||||
|     return struct.unpack('i', buf)[0] | ||||
|  | ||||
|  | ||||
| def get_classes(module_name): | ||||
|     ret = [] | ||||
|     for name, obj in inspect.getmembers(sys.modules[module_name]): | ||||
|         if inspect.isclass(obj): | ||||
|             ret.append(obj) | ||||
|  | ||||
|     return ret | ||||
|  | ||||
|  | ||||
| def class_func(module_name, class_name): | ||||
|     func = getattr(sys.modules[module_name], class_name) | ||||
|     return func | ||||
|  | ||||
|  | ||||
| def recv_all(sock, size): | ||||
|     recv_size = 4096 | ||||
|     buf_size = 0 | ||||
|     buf_parts = [] | ||||
|     while buf_size < size: | ||||
|         tmp_size = recv_size | ||||
|         left_size = size - buf_size | ||||
|         if left_size < recv_size: | ||||
|             tmp_size = left_size | ||||
|         buf_part = sock.recv(tmp_size) | ||||
|         buf_parts.append(buf_part) | ||||
|         buf_size += len(buf_part) | ||||
|     buf = ''.join(buf_parts) | ||||
|     return buf | ||||
| @@ -0,0 +1,7 @@ | ||||
| #!/usr/bin/env python | ||||
|  | ||||
| class SelfServerException(Exception) : | ||||
|     pass | ||||
|  | ||||
| class SelfClientException(Exception) : | ||||
|     pass | ||||
							
								
								
									
										54
									
								
								xCAT-openbmc-py/xCAT-openbmc-py.spec
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								xCAT-openbmc-py/xCAT-openbmc-py.spec
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | ||||
| Summary: xCAT openbmc python | ||||
| Name: xCAT-openbmc-py | ||||
| Version: %{?version:%{version}}%{!?version:%(cat Version)} | ||||
| Release: %{?release:%{release}}%{!?release:snap%(date +"%Y%m%d%H%M")} | ||||
| Epoch: 4 | ||||
| License: EPL | ||||
| Group: Applications/System | ||||
| Source: xCAT-openbmc-py-%{version}.tar.gz | ||||
| Packager: IBM Corp. | ||||
| Vendor: IBM Corp. | ||||
| Distribution: %{?_distribution:%{_distribution}}%{!?_distribution:%{_vendor}} | ||||
| Prefix: /opt/xcat | ||||
| BuildRoot: /var/tmp/%{name}-%{version}-%{release}-root | ||||
|  | ||||
| %ifnos linux | ||||
| AutoReqProv: no | ||||
| %endif | ||||
|  | ||||
| BuildArch: noarch | ||||
| Requires: xCAT-server, python-requests  | ||||
|  | ||||
| %description | ||||
| xCAT-openbmc-py provides openbmc related functions.  | ||||
|  | ||||
| %prep | ||||
| %setup -q -n xCAT-openbmc-py | ||||
| %build | ||||
|  | ||||
| %install | ||||
| rm -rf $RPM_BUILD_ROOT | ||||
| install -d $RPM_BUILD_ROOT/%{prefix}/lib/python/agent | ||||
| install -d $RPM_BUILD_ROOT/%{prefix}/lib/python/agent/xcatagent | ||||
| install -m644 lib/python/agent/*.py $RPM_BUILD_ROOT/%{prefix}/lib/python/agent | ||||
| install -m644 lib/python/agent/xcatagent/*.py $RPM_BUILD_ROOT/%{prefix}/lib/python/agent/xcatagent | ||||
|  | ||||
| %ifnos linux | ||||
| rm -rf $RPM_BUILD_ROOT/%{prefix}/lib/python | ||||
| %endif | ||||
|  | ||||
| %clean | ||||
| rm -rf $RPM_BUILD_ROOT | ||||
|  | ||||
| %files | ||||
| %defattr(-,root,root) | ||||
| %{prefix} | ||||
|  | ||||
| %changelog | ||||
|  | ||||
| %pre | ||||
|  | ||||
| %post | ||||
|  | ||||
| %preun | ||||
|  | ||||
		Reference in New Issue
	
	Block a user