Add persistence and more refactoring
- persist configuration in a file that can be set on the command line
- check for valid JSON inputs
- fix example curl commands
- add a main() function
Change-Id: I7504455d85472799ad6d0cfbb6e7cb35eb5ea17d
diff --git a/tools/test/bin/onos-distributed-manager b/tools/test/bin/onos-distributed-manager
index dade54f..1a17f2d 100755
--- a/tools/test/bin/onos-distributed-manager
+++ b/tools/test/bin/onos-distributed-manager
@@ -15,9 +15,14 @@
"""
from flask import Flask, jsonify, request
+import argparse
+import json
+import sys
+import httplib
+from httplib import OK, NOT_FOUND, BAD_REQUEST
+import jsonschema
+from jsonschema import validate
-app = Flask(__name__)
-controller_list = {}
"""
Onos Distributed Manager
@@ -28,118 +33,196 @@
curl -H "Content-Type: application/json" -X POST
--data '{"Id":"1.2.3.4","IpAddress":"1.2.3.4","Port":3456,"IsEnable":true}' http://localhost:5000
--Updating node
-curl -H "Content-Type: application/json" -X PUT --data '{"Id":"1.2.3.4","IsEnable":false}' http://localhost:5000
+curl -H "Content-Type: application/json" -X PUT --data '{"Id":"1.2.3.4","IpAddress":"1.2.3.4","Port":3456,"IsEnable":true}' http://localhost:5000
--Deleting node
-curl -H "Content-Type: application/json" -X DELETE --data '{"Id":"1.2.3.4","IsEnable":false}' http://localhost:5000
+curl -H "Content-Type: application/json" -X DELETE --data '{"Id":"1.2.3.4","IpAddress":"1.2.3.4","Port":3456,"IsEnable":true}' http://localhost:5000
--Getting node data
curl -X GET http://10.15.176.228:5000/cluster.json
"""
-httpStatusOK = 200
-httpStatusNotFound = 404
-httpStatusBadRequest = 400
+
+schema = {
+ "type": "object",
+ "properties": {
+ "Id": {"type": "string"},
+ "Port": {"type": "number"},
+ "IsEnable": {"type": "boolean"},
+ "IpAddress": {"type": "string"},
+ },
+ "required": ["Id", "Port", "IsEnable", "IpAddress"]
+}
+
+
+def is_valid_node_json(content):
+ try:
+ validate(content, schema)
+ except Exception as validation_error:
+ return False
+
+ return True
+
+class Manager:
+ controller_list = {}
+ persistence_filename = ""
+
+ def save_to_file(self):
+ data = json.dumps(self.controller_list)
+ try:
+ with open(self.persistence_filename, 'w') as file:
+ file.write(data)
+ file.close()
+ except Exception as error:
+ print error
+ sys.exit()
+
+ def load_from_file(self):
+ try:
+ with open(self.persistence_filename, 'r') as file:
+ data = file.read()
+ self.controller_list = json.loads(data)
+ except Exception:
+ self.save_to_file()
+
+ def data_get_handler(self):
+
+ pagereturn = "<h2> Onos Distributed Controller Manager2 </h2>"
+ pagereturn += "<br><h3> Status of Added controllers </h3><br>"
+ pagereturn += " Id,  Ip,  Port,  Is Active <br> "
+
+ for key in self.controller_list.keys():
+ pagereturn += self.controller_list[key]["Id"] + ",  " + \
+ self.controller_list[key]["IpAddress"] + ",  " + \
+ str(self.controller_list[key]["Port"]) + ",  " + \
+ str(self.controller_list[key]["IsEnable"])
+ pagereturn += " <br>"
+
+ return pagereturn, OK
+
+ def data_post_handler(self, content):
+ if not is_valid_node_json(content):
+ return "Id, IpAddress, Port, and IsEnable must be specified", \
+ BAD_REQUEST
+
+ if content["Id"] in self.controller_list:
+ return "Content Id is already in the list", BAD_REQUEST
+
+ else:
+ self.controller_list[content["Id"]] = content
+ self.save_to_file()
+
+ return "POST called with content", OK
+
+ def data_put_handler(self, content):
+ if not is_valid_node_json(content):
+ return "Id, IpAddress, Port, and IsEnable must be specified", \
+ BAD_REQUEST
+
+ if content["Id"] in self.controller_list:
+ self.controller_list[content["Id"]] = content
+ self.save_to_file()
+ return "Update succeeded", OK
+
+ else:
+ return "Id %s is not found " % (content["Id"]), NOT_FOUND
+
+ def data_delete_handler(self, content):
+ if content["Id"] in self.controller_list:
+ del self.controller_list[content["Id"]]
+ self.save_to_file()
+ return "Deletion succeed.", OK
+
+ else:
+ return "Id is not found", NOT_FOUND
+
+ """
+ This function returns onos cluster information
+ based on data in memory
+ """
+
+ def cluster_responder(self):
+
+ cluster_info = dict()
+ nodes = list()
+ partition = dict()
+ # Todo: For first release , only 1 partition implemented
+ cluster_members = list()
+
+ # "nodes" array
+ for controller_id in self.controller_list:
+ controller_node = self.controller_list[controller_id]
+ if controller_node["IsEnable"]:
+ node_data = dict()
+ node_data["ip"] = controller_node["IpAddress"]
+ node_data["id"] = controller_node["Id"]
+ node_data["port"] = controller_node["Port"]
+ nodes.append(node_data)
+ cluster_members.append(controller_node["Id"])
+
+ partition["id"] = 1 # Todo: this will be updated .
+ partition["members"] = cluster_members
+
+ cluster_info["nodes"] = nodes
+ cluster_info["name"] = -1394421542720337000 # Todo: add a real value here
+ cluster_info["partitions"] = partition
+ return jsonify(cluster_info), OK
+
+app = Flask(__name__)
+manager = Manager()
+
@app.route('/', methods=['GET'])
def data_get_handler():
-
- pagereturn = "<h2> Onos Distributed Controller Manager2 </h2>"
- pagereturn += "<br><h3> Status of Added controllers </h3><br>"
- pagereturn += " Id,  Ip,  Port,  Is Active <br> "
-
- for key in controller_list.keys():
- pagereturn += controller_list[key]["Id"] + ",  " + \
- controller_list[key]["IpAddress"] + ",  " + \
- str(controller_list[key]["Port"]) + ",  " + \
- str(controller_list[key]["IsEnable"])
- pagereturn += " <br>"
-
- return pagereturn, httpStatusOK
-
-
-@app.route('/', methods=['POST'])
-def data_post_handler():
-
- if request.is_json:
- content = dict(request.json)
-
- if content["Id"] in controller_list:
- return "Content Id is already in the list", httpStatusBadRequest
-
- else:
- controller_list[content["Id"]] = content
-
- else:
- return "json required", httpStatusBadRequest
-
- return "POST called with content", httpStatusOK
-
-
-@app.route('/', methods=['PUT'])
-def data_put_handler():
-
- if request.is_json:
- content = dict(request.json)
-
- if content["Id"] in controller_list:
- controller_list[content["Id"]] = content
- return "Update succeeded", httpStatusOK
-
- else:
- return "Id %s is not found " %(content["Id"]), httpStatusNotFound
- else:
- return "json data is missing", httpStatusBadRequest
-
-
-@app.route('/', methods=['DELETE'])
-def data_delete_handler():
-
- if request.is_json:
- content = dict(request.json)
-
- else:
- return "No json is found", httpStatusBadRequest
-
- if content["Id"] in controller_list:
- del controller_list[content["Id"]]
- return "Deletion succeed.", httpStatusOK
-
- else:
- return "Id is not found", httpStatusNotFound
-
-"""
-This function returns onos cluster information
-based on data in memory
-"""
+ return manager.data_get_handler()
@app.route('/cluster.json', methods=['GET'])
def cluster_responder():
+ return manager.cluster_responder()
- cluster_info = dict()
- nodes = list()
- partition = dict()
- # Todo: For first release , only 1 partition implemented
- cluster_members = list()
- # "nodes" array
- for controller_id in controller_list:
- controller_node = controller_list[controller_id]
- if controller_node["IsEnable"]:
- node_data = dict()
- node_data["ip"] = controller_node["IpAddress"]
- node_data["id"] = controller_node["Id"]
- node_data["port"] = controller_node["Port"]
- nodes.append(node_data)
- cluster_members.append(controller_node["Id"])
+@app.route('/', methods=['POST'])
+def data_post_handler():
+ if request.is_json:
+ content = dict(request.json)
+ return manager.data_post_handler(content)
+ else:
+ return "json required", BAD_REQUEST
- partition["id"] = 1 # Todo: this will be updated .
- partition["members"] = cluster_members
- cluster_info["nodes"] = nodes
- cluster_info["name"] = -1394421542720337000
- cluster_info["partitions"] = partition
- return jsonify(cluster_info), httpStatusOK
+@app.route('/', methods=['PUT'])
+def data_put_handler():
+ if request.is_json:
+ content = dict(request.json)
+ return manager.data_put_handler(content)
+ else:
+ return "json data is missing", BAD_REQUEST
+
+
+@app.route('/', methods=['DELETE'])
+def data_delete_handler():
+ if request.is_json:
+ content = dict(request.json)
+ return manager.data_delete_handler(content)
+ else:
+ return "No json is found", BAD_REQUEST
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ description="Web server and app to maintain ONOS cluster state.")
+ parser.add_argument(
+ '-p', '--persistence-filename',
+ default='./onos-distributed-manager-persistence.json',
+ help="Filename used to store persistence information." )
+
+ args = parser.parse_args()
+ manager.persistence_filename = args.persistence_filename
+ manager.load_from_file()
+
+ app.run(host="0.0.0.0", debug=True)
+
if __name__ == '__main__':
- app.run(host="0.0.0.0", debug=True)
+ manager = Manager()
+ main()