summaryrefslogtreecommitdiffstats
path: root/common/recipes-rest/rest-api/files
diff options
context:
space:
mode:
Diffstat (limited to 'common/recipes-rest/rest-api/files')
-rw-r--r--common/recipes-rest/rest-api/files/node.py42
-rw-r--r--common/recipes-rest/rest-api/files/node_api.py31
-rw-r--r--common/recipes-rest/rest-api/files/node_bmc.py95
-rw-r--r--common/recipes-rest/rest-api/files/node_config.py65
-rw-r--r--common/recipes-rest/rest-api/files/node_fruid.py58
-rw-r--r--common/recipes-rest/rest-api/files/node_sensors.py60
-rw-r--r--common/recipes-rest/rest-api/files/node_server.py69
-rw-r--r--common/recipes-rest/rest-api/files/node_spb.py52
-rw-r--r--common/recipes-rest/rest-api/files/pal.py94
-rw-r--r--common/recipes-rest/rest-api/files/rest.py105
-rw-r--r--common/recipes-rest/rest-api/files/tree.py46
11 files changed, 717 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
OpenPOWER on IntegriCloud