mirror of
https://github.com/xcat2/xcat-core.git
synced 2025-05-21 19:22:05 +00:00
packaging xCAT-openbmc-py method
This commit is contained in:
parent
a41e138fc0
commit
3f0a152acc
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
|
||||
|
Loading…
x
Reference in New Issue
Block a user