#!/usr/bin/python
-# Copyright (c) 2009, 2010, 2011, 2012 Nicira Networks
+# Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
import argparse
import os
-import signal
import sys
import time
from ovs.db import types
import ovs.daemon
import ovs.db.idl
+import ovs.unixctl
+import ovs.unixctl.server
-root_prefix = '' # Prefix for absolute file names, for testing.
vlog = ovs.vlog.Vlog("ovs-xapi-sync")
session = None
-force_run = False
+flush_cache = False
+exiting = False
+
+
+def unixctl_exit(conn, unused_argv, unused_aux):
+ global exiting
+ exiting = True
+ conn.reply(None)
+
+
+def unixctl_flush_cache(conn, unused_argv, unused_aux):
+ global flush_cache
+ flush_cache = True
+ conn.reply(None)
# Set up a session to interact with XAPI.
" XAPI session could not be initialized" % br_name)
return None
- for n in session.xenapi.network.get_all():
- rec = session.xenapi.network.get_record(n)
- if rec['bridge'] == br_name:
- return rec
+ recs = session.xenapi.network.get_all_records_where('field "bridge"="%s"' % br_name)
+ if len(recs) > 0:
+ return recs.values()[0]
return None
def set_external_id(row, key, value):
+ row.verify("external_ids")
external_ids = row.external_ids
if set_or_delete(external_ids, key, value):
row.external_ids = external_ids
if fail_mode not in ['standalone', 'secure']:
fail_mode = 'standalone'
+ row.verify("fail_mode")
if row.fail_mode != fail_mode:
row.fail_mode = fail_mode
dib = rec['other_config'].get('vswitch-disable-in-band')
+ row.verify("other_config")
other_config = row.other_config
if dib and dib not in ['true', 'false']:
vlog.warn('"%s" isn\'t a valid setting for '
row.other_config = other_config
-def update_bridge_id(row):
- id_ = get_bridge_id(row.name, row.external_ids.get("xs-network-uuids"))
- if not id_:
- return
-
- set_external_id(row, "bridge-id", id_.split(";")[0])
-
-
-def keep_table_columns(schema, table_name, columns):
- table = schema.tables.get(table_name)
- if not table:
- raise error.Error("schema has no %s table" % table_name)
-
- new_columns = {}
- for column_name in columns:
- column = table.columns.get(column_name)
- if not column:
- raise error.Error("%s table schema lacks %s column"
- % (table_name, column_name))
- new_columns[column_name] = column
- table.columns = new_columns
- return table
-
-
-def prune_schema(schema):
- new_tables = {}
- new_tables["Bridge"] = keep_table_columns(
- schema, "Bridge", ("name", "external_ids", "other_config",
- "fail_mode"))
- new_tables["Interface"] = keep_table_columns(
- schema, "Interface", ("name", "external_ids"))
- schema.tables = new_tables
-
-
-def handler(signum, _):
- global force_run
- if (signum == signal.SIGHUP):
- force_run = True
-
-
def main():
- global force_run
+ global flush_cache
parser = argparse.ArgumentParser()
parser.add_argument("database", metavar="DATABASE",
help="A socket on which ovsdb-server is listening.")
- parser.add_argument("--root-prefix", metavar="DIR",
+ parser.add_argument("--root-prefix", metavar="DIR", default='',
help="Use DIR as alternate root directory"
" (for testing).")
ovs.vlog.handle_args(args)
ovs.daemon.handle_args(args)
- global root_prefix
- if args.root_prefix:
- root_prefix = args.root_prefix
-
remote = args.database
- schema_file = "%s/vswitch.ovsschema" % ovs.dirs.PKGDATADIR
- schema = ovs.db.schema.DbSchema.from_json(ovs.json.from_file(schema_file))
- prune_schema(schema)
- idl = ovs.db.idl.Idl(remote, schema)
+ schema_helper = ovs.db.idl.SchemaHelper()
+ schema_helper.register_columns("Bridge", ["name", "external_ids",
+ "other_config", "fail_mode"])
+ schema_helper.register_columns("Interface", ["name", "external_ids"])
+ idl = ovs.db.idl.Idl(remote, schema_helper)
ovs.daemon.daemonize()
+ ovs.unixctl.command_register("exit", "", 0, 0, unixctl_exit, None)
+ ovs.unixctl.command_register("flush-cache", "", 0, 0, unixctl_flush_cache,
+ None)
+ error, unixctl_server = ovs.unixctl.server.UnixctlServer.create(None)
+ if error:
+ ovs.util.ovs_fatal(error, "could not create unixctl server", vlog)
+
# This daemon is usually started before XAPI, but to complete our
# tasks, we need it. Wait here until it's up.
- cookie_file = root_prefix + "/var/run/xapi_init_complete.cookie"
+ cookie_file = args.root_prefix + "/var/run/xapi_init_complete.cookie"
while not os.path.exists(cookie_file):
time.sleep(1)
- signal.signal(signal.SIGHUP, handler)
-
- bridges = {} # Map from bridge name to xs_network_uuids
+ bridges = {} # Map from bridge name to nicira-bridge-id
iface_ids = {} # Map from xs-vif-uuid to iface-id
vm_ids = {} # Map from xs-vm-uuid to vm-id
+ seqno = idl.change_seqno # Sequence number when we last processed the db
while True:
- if not force_run and not idl.run():
+ unixctl_server.run()
+ if exiting:
+ break;
+
+ idl.run()
+ if not flush_cache and seqno == idl.change_seqno:
poller = ovs.poller.Poller()
+ unixctl_server.wait(poller)
idl.wait(poller)
poller.block()
continue
- if force_run:
- vlog.info("Forced to re-run as the result of a SIGHUP")
+ if flush_cache:
+ vlog.info("Flushing cache as the result of unixctl.")
bridges = {}
iface_ids = {}
vm_ids = {}
- force_run = False
+ flush_cache = False
+ seqno = idl.change_seqno
txn = ovs.db.idl.Transaction(idl)
new_bridges = {}
for row in idl.tables["Bridge"].rows.itervalues():
- old_xnu = bridges.get(row.name)
- new_xnu = row.external_ids.get("xs-network-uuids", "")
- if old_xnu is None:
+ if row.name in bridges:
+ nbd = bridges[row.name]
+ else:
# New bridge.
update_fail_mode(row)
update_in_band_mgmt(row)
+ nbd = get_bridge_id(row.name)
+
+ bridge_id = nbd
+ if bridge_id is None:
+ bridge_id = row.external_ids.get("xs-network-uuids")
- update_bridge_id(row)
- new_bridges[row.name] = new_xnu
+ if bridge_id is not None:
+ set_external_id(row, "bridge-id", bridge_id.split(";")[0])
+
+ new_bridges[row.name] = nbd
bridges = new_bridges
iface_by_name = {}
iface_ids = new_iface_ids
vm_ids = new_vm_ids
+ txn.add_comment("ovs-xapi-sync: Updating records from XAPI")
txn.commit_block()
+ unixctl_server.close()
+ idl.close()
+
if __name__ == '__main__':
try: