def __init__(self, felix_sck): # Wrap the socket with our protocol reader/writer objects. self._msg_reader = MessageReader(felix_sck) self._msg_writer = MessageWriter(felix_sck) # Global stop event used to signal to all threads to stop. self._stop_event = Event() # Threads to own the connection from/to Felix. The resync thread # is responsible for doing resyncs and merging updates from the # watcher thread (which it manages). self._reader_thread = Thread(target=self._read_from_socket, name="reader-thread") self._reader_thread.daemon = True self._resync_thread = Thread(target=self._resync_and_merge, name="resync-thread") self._resync_thread.daemon = True self._watcher_thread = None # Created on demand self._watcher_stop_event = None self._watcher_start_index = None # High-water mark cache. Owned by resync thread. self._hwms = HighWaterTracker() self._first_resync = True self._resync_http_pool = None self._cluster_id = None # Resync thread stats. self._snap_keys_processed = RateStat("snapshot keys processed") self._event_keys_processed = RateStat("event keys processed") self._felix_updates_sent = RateStat("felix updates sent") self._resync_stats = [ self._snap_keys_processed, self._event_keys_processed, self._felix_updates_sent, ] self._last_resync_stat_log_time = monotonic_time() # Set by the reader thread once the init message has been received # from Felix. self._init_received = Event() # Initial config, received in the init message. self._etcd_base_url = None self._etcd_other_urls = [] # Lock for the etcd url fields: this is the only lock, and no thread # ever recursively acquires it, so it cannot deadlock. Must be locked # to access the _etcd_base_url and _etcd_other_urls fields (after they # are initialized). self._etcd_url_lock = Lock() self._hostname = None # Set by the reader thread once the logging config has been received # from Felix. Triggers the first resync. self._config_received = Event() # Flag to request a resync. Set by the reader thread, polled by the # resync and merge thread. self._resync_requested = False
def _start_driver(self): """ Starts the driver subprocess, connects to it over the socket and sends it the init message. Stores the Popen object in self._driver_process for future access. :return: the connected socket to the driver. """ _log.info("Creating server socket.") try: os.unlink("/run/felix-driver.sck") except OSError: _log.debug("Failed to delete driver socket, assuming it " "didn't exist.") update_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) update_socket.bind("/run/felix-driver.sck") update_socket.listen(1) self._driver_process = subprocess.Popen([ sys.executable, "-m", "calico.etcddriver", "/run/felix-driver.sck" ]) _log.info("Started etcd driver with PID %s", self._driver_process.pid) update_conn, _ = update_socket.accept() _log.info("Accepted connection on socket") # No longer need the server socket, remove it. try: os.unlink("/run/felix-driver.sck") except OSError: # Unexpected but carry on... _log.exception("Failed to unlink socket") else: _log.info("Unlinked server socket") # Wrap the socket in reader/writer objects that simplify using the # protocol. reader = MessageReader(update_conn) writer = MessageWriter(update_conn) # Give the driver its config. writer.send_message( MSG_TYPE_INIT, { MSG_KEY_ETCD_URLS: [ self._config.ETCD_SCHEME + "://" + addr for addr in self._config.ETCD_ADDRS ], MSG_KEY_HOSTNAME: self._config.HOSTNAME, MSG_KEY_KEY_FILE: self._config.ETCD_KEY_FILE, MSG_KEY_CERT_FILE: self._config.ETCD_CERT_FILE, MSG_KEY_CA_FILE: self._config.ETCD_CA_FILE }) return reader, writer
def _start_driver(self): """ Starts the driver subprocess, connects to it over the socket and sends it the init message. Stores the Popen object in self._driver_process for future access. :return: the connected socket to the driver. """ _log.info("Creating server socket.") if os.path.exists("/run"): # Linux FHS version 3.0+ location for runtime sockets etc. sck_filename = "/run/felix-driver.sck" else: # Older Linux versions use /var/run. sck_filename = "/var/run/felix-driver.sck" try: os.unlink(sck_filename) except OSError: _log.debug("Failed to delete driver socket, assuming it " "didn't exist.") update_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) update_socket.bind(sck_filename) update_socket.listen(1) if getattr(sys, "frozen", False): # We're running under pyinstaller, where we share our executable # with the etcd driver. Re-run this executable with the "driver" # argument to invoke the etcd driver. cmd = [sys.argv[0], "driver"] else: # Not running under pyinstaller, execute the etcd driver directly. cmd = [sys.executable, "-m", "calico.etcddriver"] # etcd driver takes the felix socket name as argument. cmd += [sck_filename] _log.info("etcd-driver command line: %s", cmd) self._driver_process = subprocess.Popen(cmd) _log.info("Started etcd driver with PID %s", self._driver_process.pid) with gevent.Timeout(10): update_conn, _ = update_socket.accept() _log.info("Accepted connection on socket") # No longer need the server socket, remove it. try: os.unlink(sck_filename) except OSError: # Unexpected but carry on... _log.exception("Failed to unlink socket") else: _log.info("Unlinked server socket") # Wrap the socket in reader/writer objects that simplify using the # protocol. reader = MessageReader(update_conn) writer = MessageWriter(update_conn) # Give the driver its config. writer.send_message( MSG_TYPE_INIT, { MSG_KEY_ETCD_URLS: [ self._config.ETCD_SCHEME + "://" + addr for addr in self._config.ETCD_ADDRS ], MSG_KEY_HOSTNAME: self._config.HOSTNAME, MSG_KEY_KEY_FILE: self._config.ETCD_KEY_FILE, MSG_KEY_CERT_FILE: self._config.ETCD_CERT_FILE, MSG_KEY_CA_FILE: self._config.ETCD_CA_FILE, }) return reader, writer
def setUp(self): self.sck = StubWriterSocket() self.writer = MessageWriter(self.sck) self.unpacker = msgpack.Unpacker()