blob: 1a17f2d457bc4ad6657c50f83c05f5528cf56621 [file] [log] [blame]
Ray Milkey644472e2017-06-19 13:34:25 -07001#!/usr/bin/env python
2"""
3 Copyright 2017-present Open Networking Laboratory
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15"""
16
17from flask import Flask, jsonify, request
Ray Milkey589b8992017-06-20 12:02:01 -070018import argparse
19import json
20import sys
21import httplib
22from httplib import OK, NOT_FOUND, BAD_REQUEST
23import jsonschema
24from jsonschema import validate
Ray Milkey644472e2017-06-19 13:34:25 -070025
Ray Milkey644472e2017-06-19 13:34:25 -070026
27"""
28Onos Distributed Manager
29this app handles controller information in system
30
31Message Samples :
32--Adding node
33curl -H "Content-Type: application/json" -X POST
34 --data '{"Id":"1.2.3.4","IpAddress":"1.2.3.4","Port":3456,"IsEnable":true}' http://localhost:5000
35--Updating node
Ray Milkey589b8992017-06-20 12:02:01 -070036curl -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
Ray Milkey644472e2017-06-19 13:34:25 -070037--Deleting node
Ray Milkey589b8992017-06-20 12:02:01 -070038curl -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
Ray Milkey644472e2017-06-19 13:34:25 -070039--Getting node data
40curl -X GET http://10.15.176.228:5000/cluster.json
41
42"""
43
Ray Milkey589b8992017-06-20 12:02:01 -070044
45schema = {
46 "type": "object",
47 "properties": {
48 "Id": {"type": "string"},
49 "Port": {"type": "number"},
50 "IsEnable": {"type": "boolean"},
51 "IpAddress": {"type": "string"},
52 },
53 "required": ["Id", "Port", "IsEnable", "IpAddress"]
54}
55
56
57def is_valid_node_json(content):
58 try:
59 validate(content, schema)
60 except Exception as validation_error:
61 return False
62
63 return True
64
65class Manager:
66 controller_list = {}
67 persistence_filename = ""
68
69 def save_to_file(self):
70 data = json.dumps(self.controller_list)
71 try:
72 with open(self.persistence_filename, 'w') as file:
73 file.write(data)
74 file.close()
75 except Exception as error:
76 print error
77 sys.exit()
78
79 def load_from_file(self):
80 try:
81 with open(self.persistence_filename, 'r') as file:
82 data = file.read()
83 self.controller_list = json.loads(data)
84 except Exception:
85 self.save_to_file()
86
87 def data_get_handler(self):
88
89 pagereturn = "<h2> Onos Distributed Controller Manager2 </h2>"
90 pagereturn += "<br><h3> Status of Added controllers </h3><br>"
91 pagereturn += " Id,&emsp; Ip,&emsp; Port,&emsp; Is Active <br> "
92
93 for key in self.controller_list.keys():
94 pagereturn += self.controller_list[key]["Id"] + ",&emsp; " + \
95 self.controller_list[key]["IpAddress"] + ",&emsp; " + \
96 str(self.controller_list[key]["Port"]) + ",&emsp; " + \
97 str(self.controller_list[key]["IsEnable"])
98 pagereturn += " <br>"
99
100 return pagereturn, OK
101
102 def data_post_handler(self, content):
103 if not is_valid_node_json(content):
104 return "Id, IpAddress, Port, and IsEnable must be specified", \
105 BAD_REQUEST
106
107 if content["Id"] in self.controller_list:
108 return "Content Id is already in the list", BAD_REQUEST
109
110 else:
111 self.controller_list[content["Id"]] = content
112 self.save_to_file()
113
114 return "POST called with content", OK
115
116 def data_put_handler(self, content):
117 if not is_valid_node_json(content):
118 return "Id, IpAddress, Port, and IsEnable must be specified", \
119 BAD_REQUEST
120
121 if content["Id"] in self.controller_list:
122 self.controller_list[content["Id"]] = content
123 self.save_to_file()
124 return "Update succeeded", OK
125
126 else:
127 return "Id %s is not found " % (content["Id"]), NOT_FOUND
128
129 def data_delete_handler(self, content):
130 if content["Id"] in self.controller_list:
131 del self.controller_list[content["Id"]]
132 self.save_to_file()
133 return "Deletion succeed.", OK
134
135 else:
136 return "Id is not found", NOT_FOUND
137
138 """
139 This function returns onos cluster information
140 based on data in memory
141 """
142
143 def cluster_responder(self):
144
145 cluster_info = dict()
146 nodes = list()
147 partition = dict()
148 # Todo: For first release , only 1 partition implemented
149 cluster_members = list()
150
151 # "nodes" array
152 for controller_id in self.controller_list:
153 controller_node = self.controller_list[controller_id]
154 if controller_node["IsEnable"]:
155 node_data = dict()
156 node_data["ip"] = controller_node["IpAddress"]
157 node_data["id"] = controller_node["Id"]
158 node_data["port"] = controller_node["Port"]
159 nodes.append(node_data)
160 cluster_members.append(controller_node["Id"])
161
162 partition["id"] = 1 # Todo: this will be updated .
163 partition["members"] = cluster_members
164
165 cluster_info["nodes"] = nodes
166 cluster_info["name"] = -1394421542720337000 # Todo: add a real value here
167 cluster_info["partitions"] = partition
168 return jsonify(cluster_info), OK
169
170app = Flask(__name__)
171manager = Manager()
172
Ray Milkey644472e2017-06-19 13:34:25 -0700173
174@app.route('/', methods=['GET'])
175def data_get_handler():
Ray Milkey589b8992017-06-20 12:02:01 -0700176 return manager.data_get_handler()
Ray Milkey644472e2017-06-19 13:34:25 -0700177
178
179@app.route('/cluster.json', methods=['GET'])
180def cluster_responder():
Ray Milkey589b8992017-06-20 12:02:01 -0700181 return manager.cluster_responder()
Ray Milkey644472e2017-06-19 13:34:25 -0700182
Ray Milkey644472e2017-06-19 13:34:25 -0700183
Ray Milkey589b8992017-06-20 12:02:01 -0700184@app.route('/', methods=['POST'])
185def data_post_handler():
186 if request.is_json:
187 content = dict(request.json)
188 return manager.data_post_handler(content)
189 else:
190 return "json required", BAD_REQUEST
Ray Milkey644472e2017-06-19 13:34:25 -0700191
Ray Milkey644472e2017-06-19 13:34:25 -0700192
Ray Milkey589b8992017-06-20 12:02:01 -0700193@app.route('/', methods=['PUT'])
194def data_put_handler():
195 if request.is_json:
196 content = dict(request.json)
197 return manager.data_put_handler(content)
198 else:
199 return "json data is missing", BAD_REQUEST
200
201
202@app.route('/', methods=['DELETE'])
203def data_delete_handler():
204 if request.is_json:
205 content = dict(request.json)
206 return manager.data_delete_handler(content)
207 else:
208 return "No json is found", BAD_REQUEST
209
210
211def main():
212 parser = argparse.ArgumentParser(
213 description="Web server and app to maintain ONOS cluster state.")
214 parser.add_argument(
215 '-p', '--persistence-filename',
216 default='./onos-distributed-manager-persistence.json',
217 help="Filename used to store persistence information." )
218
219 args = parser.parse_args()
220 manager.persistence_filename = args.persistence_filename
221 manager.load_from_file()
222
223 app.run(host="0.0.0.0", debug=True)
224
Ray Milkey644472e2017-06-19 13:34:25 -0700225
226if __name__ == '__main__':
Ray Milkey589b8992017-06-20 12:02:01 -0700227 manager = Manager()
228 main()