blob: 0d3b1c3f2e0fa600c89ce7a6cf86a84741b5ee31 [file] [log] [blame]
#!/usr/bin/env python
"""
Copyright 2017-present Open Networking Foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
import argparse
import json
import subprocess
import sys
import os
from httplib import OK, NOT_FOUND, BAD_REQUEST
from subprocess import Popen
from flask import Flask, jsonify, request
from jsonschema import validate
"""
Onos Distributed Manager
this app handles controller information in system
Message Samples :
--Adding node
curl -H "Content-Type: application/json" -X POST --data '{"id":"node-1","ip":"1.2.3.4","port":3456}' http://localhost:5000
--Updating node
curl -H "Content-Type: application/json" -X PUT --data '{"id":"node-1","ip":"1.2.3.4","port":3456}' http://localhost:5000
--Deleting node
curl -H "Content-Type: application/json" -X DELETE --data '{"id":"node-1","ip":"1.2.3.4","port":3456}' http://localhost:5000
--Getting node data
curl -X GET http://10.15.176.228:5000/cluster.json
"""
schema = {
"type": "object",
"properties": {
"id": {"type": "string"},
"port": {"type": "number"},
"ip": {"type": "string"},
},
"required": ["id", "port", "ip"]
}
def is_valid_node_json(content):
try:
validate(content, schema)
except Exception as validation_error:
return False
return True
class Manager:
cluster_config = {
"nodes": [],
"name": 315256287,
"partitions": []
}
persistence_filename = ""
def found_node_index(self, content):
for index, node in enumerate(self.cluster_config["nodes"]):
if node["id"] == content["id"]:
return index
return None
def save_to_file(self):
config = self.cluster_config
if len(self.cluster_config["nodes"]) > 0:
command = ["/Users/ray/Documents/work/onos-next/tools/test/bin/onos-gen-partitions", "" ]
for controller_node in self.cluster_config["nodes"]:
node_string = controller_node["id"]
node_string += ":"
node_string += controller_node["ip"]
node_string += ":"
node_string += str(controller_node["port"])
command.append(node_string)
process = Popen(command, stdout=subprocess.PIPE)
config = json.load(process.stdout)
self.cluster_config = config
else:
self.cluster_config["nodes"] = []
self.cluster_config["partitions"] = []
try:
with open(self.persistence_filename, 'w') as file:
file.write(json.dumps(config))
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.cluster_config = 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,&emsp; Ip,&emsp; Port,&emsp; Is Active <br> "
for key in self.cluster_config["nodes"].keys():
pagereturn += self.cluster_config["nodes"][key]["id"] + ",&emsp; " + \
self.cluster_config["nodes"][key]["ip"] + ",&emsp; " + \
str(self.cluster_config["nodes"][key]["port"]) + ",&emsp; "
pagereturn += " <br>"
return pagereturn, OK
def data_post_handler(self, content):
if not is_valid_node_json(content):
return "id, ip, and port must be specified", \
BAD_REQUEST
if self.found_node_index(content) is not None:
return "Content Id is already in the list", BAD_REQUEST
else:
self.cluster_config["nodes"].append(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, ip, and port must be specified", \
BAD_REQUEST
node_index = self.found_node_index(content)
if node_index is not None:
self.cluster_config["nodes"][node_index] = 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):
node_index = self.found_node_index(content)
if node_index is not None:
del self.cluster_config["nodes"][node_index]
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):
return jsonify(self.cluster_config), OK
app = Flask(__name__)
manager = Manager()
@app.route('/', methods=['GET'])
def data_get_handler():
return manager.data_get_handler()
@app.route('/cluster.json', methods=['GET'])
def cluster_responder():
return manager.cluster_responder()
@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
@app.route('/exit', methods=['PUT'])
def data_exit_handler():
func = request.environ.get('werkzeug.server.shutdown')
if func is None:
raise RuntimeError('Not running with the Werkzeug Server')
func()
return "", OK
@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__':
manager = Manager()
main()