3 from py2neo
import Graph, Path, remote
8 def __init__(self, db_addr, user, passwd, port, secure, scheme):
19 def _get_db_connection(self):
20 uri =
"{}:{}/db/data".
format(
31 def _find_all_affected_flow_segments(self, old_switch_id):
33 MATCH() -[rel:flow_segment]-> () 34 WHERE rel.dst_switch = "{}" OR rel.src_switch = "{}" 38 MATCH() -[rel:flow_segment]-> () 39 WHERE rel.dst_switch = "{sw_id}" OR rel.src_switch = "{sw_id}" 41 """.
format(sw_id=old_switch_id)
45 def _find_all_affected_flows(self, old_switch_id, links):
47 MATCH() -[rel:flow]-> () 48 WHERE rel.dst_switch = "{sw_id}" OR rel.src_switch = "{sw_id}" 49 OR rel.flowid IN [...] 53 MATCH() -[rel:flow]-> () 54 WHERE rel.dst_switch = "{sw_id}" OR rel.src_switch = "{sw_id}" OR rel.flowid IN {links} 56 """.
format(sw_id=old_switch_id, links=json.dumps(links))
60 def _migrate_segments(self, affected_segments, old_switch_id, new_switch_id,
62 for segment
in affected_segments:
63 if segment[
'rel'].
get(
'dst_switch') == old_switch_id:
64 segment[
'rel'][
'dst_switch'] = new_switch_id
65 segment[
'rel'][
'dst_port'] = replug_port_map[str(segment[
'rel'].
get(
'dst_port'))]
67 if segment[
'rel'].
get(
'src_switch') == old_switch_id:
68 segment[
'rel'][
'src_switch'] = new_switch_id
69 segment[
'rel'][
'src_port'] = replug_port_map[str(segment[
'rel'].
get(
'src_port'))]
71 return affected_segments
73 def _migrate_flows(self, affected_flows, old_switch_id, new_switch_id,
75 for flow
in affected_flows:
76 if flow[
'rel'].
get(
'dst_switch') == old_switch_id:
77 flow[
'rel'][
'dst_switch'] = new_switch_id
78 flow[
'rel'][
'dst_port'] = replug_port_map[str(flow[
'rel'].
get(
'dst_port'))]
80 if flow[
'rel'].
get(
'src_switch') == old_switch_id:
81 flow[
'rel'][
'src_switch'] = new_switch_id
82 flow[
'rel'][
'src_port'] = replug_port_map[str(flow[
'rel'].
get(
'src_port'))]
85 flow_path = json.loads(flow[
'rel'].
get(
"flowpath"))
86 for path_segment
in flow_path[
'path']:
87 if path_segment[
'switch_id'] == old_switch_id:
88 path_segment[
'switch_id'] = new_switch_id
89 path_segment[
'port_no'] = replug_port_map[str(
90 path_segment[
'port_no'])]
92 flow[
'rel'][
"flowpath"] = json.dumps(flow_path)
97 """ WARNING CLONED FROM KILDA TOPOLOGY CLASSES!!! """ 99 available_bw_query = (
100 "MATCH (src:switch {{name:'{src_switch}'}}), (dst:switch {{name:'{dst_switch}'}}) WITH src,dst " 101 " MATCH (src)-[i:isl {{ src_port:{src_port}, dst_port: {dst_port}}}]->(dst) WITH src,dst,i " 102 " OPTIONAL MATCH (src)-[fs:flow_segment {{ src_port:{src_port}, dst_port: {dst_port}, ignore_bandwidth: false }}]->(dst) " 103 " WITH sum(fs.bandwidth) AS used_bandwidth, i as i " 104 " SET i.available_bandwidth = i.max_bandwidth - used_bandwidth " 107 'src_switch': src_switch,
108 'src_port': src_port,
109 'dst_switch': dst_switch,
110 'dst_port': dst_port,
112 self.
tx.run(available_bw_query.format(**params))
118 for segment
in affected_segments:
119 neo_repr = segment[
'rel'].__repr__()
123 WHERE a.name = "{src_sw}" AND b.name = "{dst_sw}" 124 CREATE (a)-[r:flow_segment {params}]->(b) 127 src_sw=segment[
'rel'][
'src_switch'],
128 dst_sw=segment[
'rel'][
'dst_switch'],
129 params=neo_repr.split(
'-[:flow_segment ')[1].split(
']->(')[0]
133 MATCH ()-[ rel:flow_segment ]->() 134 WHERE id(rel) = {seg_id} 137 seg_id=remote(segment[
'rel'])._id,
141 src_switch=segment[
'rel'][
'src_switch'],
142 src_port=segment[
'rel'][
'src_port'],
143 dst_switch=segment[
'rel'][
'dst_switch'],
144 dst_port=segment[
'rel'][
'dst_port'])
147 for flow
in affected_flows:
148 neo_repr = flow[
'rel'].__repr__()
152 WHERE a.name = "{src_sw}" AND b.name = "{dst_sw}" 153 CREATE (a)-[ r:flow {params} ]->(b) 156 src_sw=flow[
'rel'][
'src_switch'],
157 dst_sw=flow[
'rel'][
'dst_switch'],
158 params=neo_repr.split(
'-[:flow ')[1].split(
']->(')[0]
162 MATCH ()-[ rel:flow ]->() 163 WHERE id(rel) = {flow_id} 166 flow_id=remote(flow[
'rel'])._id,
172 def _macify_switch_id(dpid):
173 dpid = dpid.lower().replace(
":",
'').replace(
"sw",
'')
178 lambda a:
''.join(a),
184 def _read_replug_ports_map_from_file(old_switch_id, new_swithc_id):
185 file_name =
"{}-to-{}-ports.json".
format(
186 old_switch_id.replace(
':',
''),
187 new_swithc_id.replace(
':',
'')
189 with open(file_name,
'r') as ports_map: 190 ports_map_data = json.load(ports_map) 192 return ports_map_data
194 def start_migration(old_switch_id, new_switch_id, db_connection_config,
195 replug_port_map=None):
197 old_switch_id = _macify_switch_id(old_switch_id)
199 new_switch_id = _macify_switch_id(new_switch_id)
202 if not replug_port_map:
203 replug_port_map = _read_replug_ports_map_from_file(
204 old_switch_id, new_switch_id)
209 affected_segments = kilda_db._find_all_affected_flow_segments(
211 parent_flows = list(set([
212 segment[
'rel'].
get(
'flowid')
213 for segment
in affected_segments
216 affected_flows = kilda_db._find_all_affected_flows(old_switch_id, links=parent_flows)
219 affected_segments = kilda_db._migrate_segments(
220 affected_segments, old_switch_id, new_switch_id, replug_port_map)
222 affected_flows = kilda_db._migrate_flows(
223 affected_flows, old_switch_id, new_switch_id, replug_port_map)
225 kilda_db.apply_migrated_data(affected_segments, affected_flows)
229 """Simple test with semi random data""" 230 db_connection_config = {
231 "db_addr":
"localhost",
238 old_switch_id =
"01:00:00:22:3d:5a:04:87" 239 new_switch_id =
"00:00:00:22:3d:5a:04:87" 240 replug_port_map = {str(i): i
for i
in xrange(100)}
243 old_switch_id=old_switch_id,
244 new_switch_id=new_switch_id,
245 db_connection_config=db_connection_config,
246 replug_port_map=replug_port_map)
248 if __name__ ==
"__main__":
251 parser = argparse.ArgumentParser(description=
'Switch Migration tool')
253 parser.add_argument(
'--old_switch_id', type=str,
254 help=
'Old Switch dpid')
255 parser.add_argument(
'--new_switch_id', type=str,
256 help=
'new Switch dpid')
258 parser.add_argument(
'--test', type=bool,
259 help=
'test', default=
False)
261 parser.add_argument(
'--neo_scheme', type=str,
262 help=
'Neo4j scheme name', default=
'http')
263 parser.add_argument(
'--neo_host', type=str,
264 help=
'Neo4j host name or IP', default=
'locahost')
265 parser.add_argument(
'--neo_port', type=int,
266 help=
'Neo4j port', default=7474)
267 parser.add_argument(
'--neo_secure', type=bool,
268 help=
'Neo4j secure', default=
False)
270 parser.add_argument(
'--neo_user', type=str,
271 help=
'Neo4j user name', default=
'neo4j')
272 parser.add_argument(
'--neo_passwd', type=str,
273 help=
'Neo4j password')
275 args = parser.parse_args()
280 old_switch_id = args.old_switch_id
281 new_switch_id = args.new_switch_id
283 db_connection_config = {
284 "db_addr": args.neo_host,
285 "user": args.neo_user,
286 "passwd": args.neo_passwd,
287 "port": args.neo_port,
288 "secure": args.neo_secure,
289 "scheme": args.neo_scheme
292 old_switch_id=old_switch_id,
293 new_switch_id=new_switch_id,
294 db_connection_config=db_connection_config)
def __init__(self, db_addr, user, passwd, port, secure, scheme)
def apply_migrated_data(self, affected_segments, affected_flows)
def start_migration(old_switch_id, new_switch_id, db_connection_config, replug_port_map=None)
def _get_db_connection(self)
def update_isl_bandwidth(self, src_switch, src_port, dst_switch, dst_port)