diff options
Diffstat (limited to 'common/recipes-rest')
-rw-r--r-- | common/recipes-rest/rest-api/files/node.py | 42 | ||||
-rw-r--r-- | common/recipes-rest/rest-api/files/node_api.py | 31 | ||||
-rw-r--r-- | common/recipes-rest/rest-api/files/node_bmc.py | 95 | ||||
-rw-r--r-- | common/recipes-rest/rest-api/files/node_config.py | 65 | ||||
-rw-r--r-- | common/recipes-rest/rest-api/files/node_fruid.py | 58 | ||||
-rw-r--r-- | common/recipes-rest/rest-api/files/node_sensors.py | 60 | ||||
-rw-r--r-- | common/recipes-rest/rest-api/files/node_server.py | 69 | ||||
-rw-r--r-- | common/recipes-rest/rest-api/files/node_spb.py | 52 | ||||
-rw-r--r-- | common/recipes-rest/rest-api/files/pal.py | 94 | ||||
-rw-r--r-- | common/recipes-rest/rest-api/files/rest.py | 105 | ||||
-rw-r--r-- | common/recipes-rest/rest-api/files/tree.py | 46 | ||||
-rw-r--r-- | common/recipes-rest/rest-api/rest-api_0.2.bb | 36 |
12 files changed, 753 insertions, 0 deletions
diff --git a/common/recipes-rest/rest-api/files/node.py b/common/recipes-rest/rest-api/files/node.py new file mode 100644 index 0000000..41e0a3e --- /dev/null +++ b/common/recipes-rest/rest-api/files/node.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python +# +# Copyright 2015-present Facebook. All Rights Reserved. +# +# This program file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +# Class Definition for Resource + +class node: + def __init__(self, info = None, actions = None): + if info == None: + self.info = {} + else: + self.info = info + + if actions == None: + self.actions = [] + else: + self.actions = actions + + def getInformation(self): + return self.info + + def getActions(self): + return self.actions + + def doAction(self, action): + result = { "result": 'failure', "reason": 'not supported'} diff --git a/common/recipes-rest/rest-api/files/node_api.py b/common/recipes-rest/rest-api/files/node_api.py new file mode 100644 index 0000000..ca5cc5c --- /dev/null +++ b/common/recipes-rest/rest-api/files/node_api.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python +# +# Copyright 2015-present Facebook. All Rights Reserved. +# +# This program file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +from node import node +from pal import * + +def get_node_api(): + + name = pal_get_platform_name() + info = { + "Description": name + " RESTful API Entry", + } + + return node(info) diff --git a/common/recipes-rest/rest-api/files/node_bmc.py b/common/recipes-rest/rest-api/files/node_bmc.py new file mode 100644 index 0000000..14b51e7 --- /dev/null +++ b/common/recipes-rest/rest-api/files/node_bmc.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python +# +# Copyright 2015-present Facebook. All Rights Reserved. +# +# This program file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + + +from subprocess import * +import re +from node import node +from pal import * + +class bmcNode(node): + def __init__(self, info = None, actions = None): + if info == None: + self.info = {} + else: + self.info = info + if actions == None: + self.actions = [] + else: + self.actions = actions + + def getInformation(self): + # Get Platform Name + name = pal_get_platform_name() + + # Get BMC Reset Reason + wdt_counter = Popen('devmem 0x1e785010', \ + shell=True, stdout=PIPE).stdout.read() + wdt_counter = int(wdt_counter, 0) + + wdt_counter &= 0xff00 + + if wdt_counter: + por_flag = 0 + else: + por_flag = 1 + + if por_flag: + reset_reason = "Power ON Reset" + else: + reset_reason = "User Initiated Reset or WDT Reset" + + # Get BMC's Up Time + uptime = Popen('uptime', \ + shell=True, stdout=PIPE).stdout.read() + + # Get Usage information + data = Popen('top -b n1', \ + shell=True, stdout=PIPE).stdout.read() + adata = data.split('\n') + mem_usage = adata[0] + cpu_usage = adata[1] + + # Get OpenBMC version + version = "" + data = Popen('cat /etc/issue', \ + shell=True, stdout=PIPE).stdout.read() + #Version might start with 'v'(wedge) or 'V'(Yosemite) + if name == 'Yosemite': + ver = re.search(r'V([\w\d._-]*)\s', data) + else: + ver = re.search(r'v([\w\d._-]*)\s', data) + if ver: + version = ver.group(1) + + + info = { + "Description": name + " BMC", + "Reset Reason": reset_reason, + "Uptime": uptime, + "Memory Usage": mem_usage, + "CPU Usage": cpu_usage, + "OpenBMC Version": version, + } + + return info; + +def get_node_bmc(): + return bmcNode() diff --git a/common/recipes-rest/rest-api/files/node_config.py b/common/recipes-rest/rest-api/files/node_config.py new file mode 100644 index 0000000..d37cc25 --- /dev/null +++ b/common/recipes-rest/rest-api/files/node_config.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python +# +# Copyright 2015-present Facebook. All Rights Reserved. +# +# This program file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + + +import os +from subprocess import * +from node import node +from pal import * + +class configNode(node): + def __init__(self, name = None, actions = None): + self.name = name + + if actions == None: + self.actions = [] + else: + self.actions = actions + + def getInformation(self): + result = {} + cmd = '/usr/local/bin/cfg-util dump-all' + data = Popen(cmd, shell=True, stdout=PIPE).stdout.read() + sdata = data.split('\n'); + for line in sdata: + # skip lines that does not start with name + if line.startswith(self.name): + kv = line.split(':') + result[kv[0].strip()] = kv[1].strip() + return result + + def doAction(self, data): + res = "success" + # Get the list of parameters to be updated + params = data["update"] + for key in params.keys(): + # update only if the key starts with the name + if key.startswith(self.name): + ret = pal_set_key_value(key, params[key]) + if ret: + res = "failure" + + result = {"result": res} + + return result + +def get_node_config(name): + actions = ["update"] + return configNode(name = name, actions = actions) diff --git a/common/recipes-rest/rest-api/files/node_fruid.py b/common/recipes-rest/rest-api/files/node_fruid.py new file mode 100644 index 0000000..d7a1dc3 --- /dev/null +++ b/common/recipes-rest/rest-api/files/node_fruid.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# +# Copyright 2015-present Facebook. All Rights Reserved. +# +# This program file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +from subprocess import * +from node import node + +class fruidNode(node): + def __init__(self, name, info = None, actions = None): + self.name = name + + if info == None: + self.info = {} + else: + self.info = info + if actions == None: + self.actions = [] + else: + self.actions = actions + + def getInformation(self): + result = {} + cmd = '/usr/local/bin/fruid-util ' + self.name + data = Popen(cmd, shell=True, stdout=PIPE).stdout.read() + sdata = data.split('\n') + for line in sdata: + # skip lines with --- or startin with FRU + if line.find("FRU") != -1: + continue + if line.find("-----") != -1: + continue + + kv = line.split(':') + if (len(kv) < 2): + continue + + result[kv[0].strip()] = kv[1].strip() + + return result + +def get_node_fruid(name): + return fruidNode(name) diff --git a/common/recipes-rest/rest-api/files/node_sensors.py b/common/recipes-rest/rest-api/files/node_sensors.py new file mode 100644 index 0000000..0e7ffc1 --- /dev/null +++ b/common/recipes-rest/rest-api/files/node_sensors.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python +# +# Copyright 2015-present Facebook. All Rights Reserved. +# +# This program file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +from subprocess import * +import json +import os +import re +from node import node + +class sensorsNode(node): + def __init__(self, name, info = None, actions = None): + self.name = name + if info == None: + self.info = {} + else: + self.info = info + if actions == None: + self.actions = [] + else: + self.actions = actions + + def getInformation(self): + result = {} + cmd = '/usr/local/bin/sensor-util ' + self.name + data = Popen(cmd, shell=True, stdout=PIPE).stdout.read() + sdata = data.split('\n') + for line in sdata: + # skip lines with " or startin with FRU + if line.find("bic_read_sensor_wrapper") != -1: + continue + if line.find("failed") != -1: + continue + + kv = line.split(':') + if (len(kv) < 2): + continue + + result[kv[0].strip()] = kv[1].strip() + + return result + +def get_node_sensors(name): + return sensorsNode(name) diff --git a/common/recipes-rest/rest-api/files/node_server.py b/common/recipes-rest/rest-api/files/node_server.py new file mode 100644 index 0000000..57a5c42 --- /dev/null +++ b/common/recipes-rest/rest-api/files/node_server.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python +# +# Copyright 2015-present Facebook. All Rights Reserved. +# +# This program file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + + +import os +from subprocess import * +from node import node +from pal import * + +class serverNode(node): + def __init__(self, num = None, info = None, actions = None): + self.num = num + + if info == None: + self.info = {} + else: + self.info = info + if actions == None: + self.actions = [] + else: + self.actions = actions + + def getInformation(self): + ret = pal_get_server_power(self.num) + if ret == 0: + status = 'power-off' + elif ret == 1: + status = 'power-on' + else: + status = 'error' + + info = { "status": status } + + return info + + def doAction(self, data): + if pal_set_server_power(self.num, data["action"]) == -1: + res = 'failure' + else: + res = 'success' + + result = { "result": res } + + return result + +def get_node_server(num): + actions = ["power-on", + "power-off", + "power-cycle", + "graceful-shutdown" + ] + return serverNode(num = num, actions = actions) diff --git a/common/recipes-rest/rest-api/files/node_spb.py b/common/recipes-rest/rest-api/files/node_spb.py new file mode 100644 index 0000000..a9fe4e6 --- /dev/null +++ b/common/recipes-rest/rest-api/files/node_spb.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python +# +# Copyright 2015-present Facebook. All Rights Reserved. +# +# This program file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# +from node import node +from pal import * + +class spbNode(node): + def __init__(self, info = None, actions = None): + if info == None: + self.info = {} + else: + self.info = info + + if actions == None: + self.actions = [] + else: + self.actions = actions + + def doAction(self, data): + if pal_sled_cycle(data["action"]) == -1: + res = 'failure' + else: + res = 'success' + + result = { "result": res } + + return result + +def get_node_spb(): + name = pal_get_platform_name() + info = { + "Description": name + " Side Plane", + } + + actions = [ "sled-cycle" ] + return spbNode(info, actions) diff --git a/common/recipes-rest/rest-api/files/pal.py b/common/recipes-rest/rest-api/files/pal.py new file mode 100644 index 0000000..8faef30 --- /dev/null +++ b/common/recipes-rest/rest-api/files/pal.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python +# +# Copyright 2015-present Facebook. All Rights Reserved. +# +# This program file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +from ctypes import * + +lpal_hndl = CDLL("libpal.so") + +def pal_get_platform_name(): + name = create_string_buffer(16) + ret = lpal_hndl.pal_get_platform_name(name) + if ret: + return None + else: + return name.value + +def pal_get_num_slots(): + num = c_ubyte() + p_num = pointer(num) + ret = lpal_hndl.pal_get_num_slots(p_num) + if ret: + return None + else: + return num.value + +def pal_is_server_prsnt(slot_id): + status = c_ubyte() + p_status = pointer(status) + ret = lpal_hndl.pal_is_server_prsnt(slot_id, p_status) + if ret: + return None + else: + return status.value + +def pal_get_server_power(slot_id): + status = c_ubyte() + p_status = pointer(status) + ret = lpal_hndl.pal_get_server_power(slot_id, p_status) + if ret: + return None + else: + return status.value + +def pal_set_server_power(slot_id, command): + cmd = c_ubyte() + if command == 'power-off': + cmd.value = 0 + elif command == 'power-on': + cmd.value = 1 + elif command == 'power-cycle': + cmd.value = 2 + elif command == 'graceful-shutdown': + cmd.value = 3 + ret = lpal_hndl.pal_set_server_power(slot_id, cmd) + if ret: + return -1 + else: + return 0 + +def pal_sled_cycle(command): + if command != 'sled-cycle': + return -1 + + ret = lpal_hndl.pal_sled_cycle() + if ret: + return -1 + else: + return 0 + +def pal_set_key_value(key, value): + pkey = create_string_buffer(key) + pvalue = create_string_buffer(value) + + ret = lpal_hndl.pal_set_key_value(pkey, pvalue) + if ret: + return -1; + else: + return 0; diff --git a/common/recipes-rest/rest-api/files/rest.py b/common/recipes-rest/rest-api/files/rest.py new file mode 100644 index 0000000..0a90d54 --- /dev/null +++ b/common/recipes-rest/rest-api/files/rest.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python +# +# Copyright 2015-present Facebook. All Rights Reserved. +# +# This program file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +from ctypes import * +from bottle import route, run, template, request, response, ServerAdapter +from bottle import abort +from wsgiref.simple_server import make_server, WSGIRequestHandler, WSGIServer +import json +import ssl +import socket +import os +from tree import tree +from node import node +from plat_tree import init_plat_tree + +CONSTANTS = { + 'certificate': '/usr/lib/ssl/certs/rest_server.pem', +} + +root = init_plat_tree() + +# Generic router for incoming requests +@route('/<path:path>', method='ANY') +def url_router(path): + token = path.split('/') + # Find the Node + r = root + for t in token: + r = r.getChildByName(t) + if r == None: + return r + c = r.data + + # Handle GET request + if request.method == 'GET': + # Gather info/actions directly from respective node + info = c.getInformation() + actions = c.getActions() + + # Create list of resources from tree structure + resources = [] + ca = r.getChildren() + for t in ca: + resources.append(t.name) + result = {'Information': info, + 'Actions': actions, + 'Resources': resources } + + return result + + # Handle POST request + if request.method == 'POST': + return c.doAction(json.load(request.body)) + + return None + +run(host = "::", port = 8080) + +# TODO: Test the https connection with proper certificates +# SSL Wrapper for Rest API +class SSLWSGIRefServer(ServerAdapter): + def run(self, handler): + if self.quiet: + class QuietHandler(WSGIRequestHandler): + def log_request(*args, **kw): pass + self.options['handler_class'] = QuietHandler + + # IPv6 Support + server_cls = self.options.get('server_class', WSGIServer) + + if ':' in self.host: + if getattr(server_cls, 'address_family') == socket.AF_INET: + class server_cls(server_cls): + address_family = socket.AF_INET6 + + srv = make_server(self.host, self.port, handler, + server_class=server_cls, **self.options) + srv.socket = ssl.wrap_socket ( + srv.socket, + certfile=CONSTANTS['certificate'], + server_side=True) + srv.serve_forever() + +# Use SSL if the certificate exists. Otherwise, run without SSL. +if os.access(CONSTANTS['certificate'], os.R_OK): + run(server=SSLWSGIRefServer(host="::", port=8443)) +else: + run(host = "::", port = 8080) diff --git a/common/recipes-rest/rest-api/files/tree.py b/common/recipes-rest/rest-api/files/tree.py new file mode 100644 index 0000000..ca81510 --- /dev/null +++ b/common/recipes-rest/rest-api/files/tree.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python +# +# Copyright 2015-present Facebook. All Rights Reserved. +# +# This program file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +# Class Definition for Tree + +class tree: + def __init__(self, name, data = None): + self.name = name + self.data = data + self.children = [] + + def addChild(self, child): + self.children.append(child) + + def addChildren(self, children): + for child in children: + self.children.append(child) + + def getChildren(self): + return self.children + + def getChildByName(self, name): + if self.name == name: + return self + + for child in self.children: + if child.name == name: + return child + return None diff --git a/common/recipes-rest/rest-api/rest-api_0.2.bb b/common/recipes-rest/rest-api/rest-api_0.2.bb new file mode 100644 index 0000000..1956cb2 --- /dev/null +++ b/common/recipes-rest/rest-api/rest-api_0.2.bb @@ -0,0 +1,36 @@ +# Copyright 2015-present Facebook. All Rights Reserved. +# +# This program file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +SUMMARY = "Rest API Daemon" +DESCRIPTION = "Daemon to handle RESTful interface." +SECTION = "base" +PR = "r1" +LICENSE = "GPLv2" +LIC_FILES_CHKSUM = "file://rest.py;beginline=5;endline=18;md5=0b1ee7d6f844d472fa306b2fee2167e0" + + +SRC_URI = "file://rest.py \ + file://node.py \ + file://tree.py \ + file://pal.py \ + " +DEPENDS += "libpal" + + +binfiles = "rest.py node.py tree.py pal.py" + +pkgdir = "rest-api" +RDEPENDS_${PN} += "libpal" |