19 from topologylistener
import db
20 from topologylistener
import exc
21 from topologylistener
import flow_utils
22 from topologylistener
import model
23 from topologylistener
import link_props_utils
25 logger = logging.getLogger(__name__)
29 q = textwrap.dedent(
""" 30 MATCH (src:switch {name: $src_switch}) 31 MATCH (dst:switch {name: $dst_switch}) 32 MERGE (src) - [target:isl { 33 src_switch: $src_switch, 35 dst_switch: $dst_switch, 39 target.status=$status, target.actual=$status, 41 target.time_create=$timestamp, 42 target.time_modify=$timestamp 43 ON MATCH SET target.time_modify=$timestamp""")
45 for isl
in sorted(links):
46 for target
in (isl, isl.reversed()):
47 p = _make_match(target)
48 p[
'status'] =
'inactive' 49 p[
'timestamp'] = str(timestamp)
51 logger.info(
'Ensure ISL %s exists', target)
52 db.log_query(
'create ISL', q, p)
58 q = textwrap.dedent(
""" 60 (:switch {name: $src_switch}) 63 src_switch: $src_switch, 65 dst_switch: $dst_switch, 69 (:switch {name: $dst_switch}) 72 db.log_query(
'ISL fetch', q, p)
76 target = db.fetch_one(cursor)[
'target']
84 q = textwrap.dedent(
""" 85 MATCH (src:switch)-[target:isl]->(:switch) 86 WHERE src.name=$src_switch AND target.src_port=$src_port 89 'src_switch': endpoint.dpid,
90 'src_port': endpoint.port}
96 q = textwrap.dedent(
""" 97 MATCH (sw:switch {name: $src_switch}) 98 - [target:isl {src_switch: $src_switch}] -> () 100 p = {
'src_switch': dpid}
101 cursor = tx.run(q, p)
102 return (x[
'target']
for x
in cursor)
106 logger.debug(
"Touch ISL %s", isl)
109 mtime = model.TimeProperty.now()
110 props = {
'time_modify': str(mtime)}
115 logger.info(
'Check ISL %s for conflicts', isl)
119 keep_dbid = {db.neo_id(x)
for x
in involved}
124 _lock_affected_switches(tx, involved)
126 for link
in involved:
127 link_dbid = db.neo_id(link)
128 if link_dbid
in keep_dbid:
131 link_isl = model.InterSwitchLink.new_from_db(link)
133 logger.error(
'Detected ISL %s conflict with %s. Please contact dev team', link_isl, isl)
137 logger.debug(
"Skip conflict ISL %s deactivation due to its current status - %s", link_isl, link[
'actual'])
141 logging.info(
"Deactivate all ISL to/from %s", dpid)
144 _lock_affected_switches(tx, involved, dpid)
146 for db_link
in involved:
148 db_link[
'src_switch'], db_link[
'src_port'])
151 logging.debug(
"Found ISL: %s", isl)
158 logging.debug(
'Locate all ISL starts on %s', endpoint)
161 _lock_affected_switches(tx, involved, endpoint.dpid)
164 for link
in involved:
165 isl = model.InterSwitchLink.new_from_db(link)
166 logger.info(
'Deactivate ISL %s', isl)
168 status =
'moved' if is_moved
else 'inactive' 178 logging.info(
"Sync status both sides of ISL %s to each other", isl)
180 q = textwrap.dedent(
""" 182 (:switch {name: $src_switch}) 185 src_switch: $src_switch, 187 dst_switch: $dst_switch, 191 (:switch {name: $dst_switch}) 193 (:switch {name: $peer_src_switch}) 196 src_switch: $peer_src_switch, 197 src_port: $peer_src_port, 198 dst_switch: $peer_dst_switch, 199 dst_port: $peer_dst_port 202 (:switch {name: $peer_dst_switch}) 204 WITH self, peer, CASE 205 WHEN self.actual = $status_up AND peer.actual = $status_up 207 WHEN self.actual = $status_moved OR peer.actual = $status_moved 212 SET self.status=isl_status 213 SET peer.status=isl_status""")
215 'status_up':
'active',
216 'status_moved':
'moved',
217 'status_down':
'inactive'}
218 p.update(_make_match(isl))
219 p.update({
'peer_' + k: v
for k, v
in _make_match(isl.reversed()).items()})
221 expected_update_properties_count = 2
224 mtime = model.TimeProperty.now()
226 q +=
'\nSET self.time_modify=$mtime, peer.time_modify=$mtime' 227 p[
'mtime'] = str(mtime)
228 expected_update_properties_count = 4
230 db.log_query(
'ISL update status', q, p)
231 cursor = tx.run(q, p)
234 stats = cursor.stats()
235 if stats[
'properties_set'] != expected_update_properties_count:
237 'Failed to sync ISL\'s %s records statuses. Looks like it is ' 238 'unidirectional.', isl)
242 db_isl =
fetch(tx, isl)
243 values = [db_isl[
'time_create'], db_isl[
'time_modify']]
244 for idx, item
in enumerate(values):
247 values[idx] = model.TimeProperty.new_from_db(item)
248 return model.LifeCycleFields(*values)
252 q = textwrap.dedent(
""" 253 MATCH (:switch) - [target:isl] -> () 254 WHERE id(target) = $id 255 SET target.actual = $status""")
273 db_record =
fetch(tx, isl)
274 value = db_record[
'cost']
275 if value
is not None:
276 value = model.convert_integer(value)
281 link_props = model.LinkProps.new_from_isl(isl)
282 link_props.props[
'cost'] = cost
284 origin = link_props_utils.set_props_and_propagate_to_isl(
287 origin =
set_props(tx, isl, {
'cost': cost})
289 original_cost = origin.get(
'cost')
290 if original_cost != cost:
292 'ISL %s cost have been changed from %s to %s',
293 isl, original_cost, cost)
297 target =
fetch(tx, isl)
298 origin, update = db.locate_changes(target, props)
300 q = textwrap.dedent(
""" 301 MATCH (:switch)-[target:isl]->(:switch) 302 WHERE id(target)=$target_id 303 """) + db.format_set_fields(
304 db.escape_fields(update), field_prefix=
'target.')
306 logger.debug(
'Push ISL properties: %r', update)
307 tx.run(q, {
'target_id': db.neo_id(target)})
314 'ISL drop %s props request: %s', isl,
', '.join(repr(x)
for x
in props))
316 remove = [
'target.{}'.
format(db.escape(x))
for x
in props]
322 q = textwrap.dedent(
""" 324 (:switch {name: $src_switch}) 327 src_switch: $src_switch, 329 dst_switch: $dst_switch, 333 (:switch {name: $dst_switch})""") +
'\nREMOVE '.join(remove)
334 db.log_query(
'ISL drop props', q, p)
335 stats = tx.run(q, p).stats()
336 return stats[
'contains_updates']
339 def _lock_affected_switches(tx, db_links, *extra):
340 affected_switches = set(extra)
341 for link
in db_links:
342 affected_switches.add(link[
'src_switch'])
343 affected_switches.add(link[
'dst_switch'])
345 flow_utils.precreate_switches(tx, *affected_switches)
348 def _make_match(isl):
350 'src_switch': isl.source.dpid,
351 'src_port': isl.source.port,
352 'dst_switch': isl.dest.dpid,
353 'dst_port': isl.dest.port}
357 return status ==
'active' def set_active_field(tx, neo_id, status)
def set_cost(tx, isl, cost)
def update_status(tx, isl, mtime=True)
def fetch_by_datapath(tx, dpid)
def set_props(tx, isl, props)
def fetch_by_endpoint(tx, endpoint)
def switch_unplug(tx, dpid, mtime=True)
def del_props(tx, isl, props)
def is_active_status(status)
def touch(tx, isl, mtime=None)
def disable_by_endpoint(tx, endpoint, is_moved=False, mtime=True)
def increase_cost(tx, isl, amount, limit)
def resolve_conflicts(tx, isl)
def get_life_cycle_fields(tx, isl)
def create_if_missing(tx, timestamp, links)