+ has_reload = False
+ try:
+ with llfuse.lock:
+ has_reload = "reload" in self.cdir
+ except IOError as e:
+ pass
+
+ if docker_image is None:
+ logger.error("Collection must contain a file 'docker_image' or must specify --image on the command line.")
+ self.stop_docker()
+ return
+
+ if docker_image == self.prev_docker_image and self.cid is not None and has_reload:
+ logger.info("Running container reload command")
+ subprocess.check_call(["docker", "exec", self.cid, "/mnt/reload"])
+ return
+
+ self.stop_docker()
+
+ logger.info("Starting Docker container %s", docker_image)
+ self.cid = subprocess.check_output(["docker", "run",
+ "--detach=true",
+ "--publish=%i:80" % (self.port),
+ "--volume=%s:/mnt:ro" % self.mountdir,
+ docker_image]).strip()
+
+ self.prev_docker_image = docker_image
+ logger.info("Container id %s", self.cid)
+
+ except subprocess.CalledProcessError:
+ self.cid = None
+
+ def wait_for_events(self):
+ if not self.cid:
+ logger.warning("No service running! Will wait for a new collection to appear in the project.")
+ else:
+ logger.info("Waiting for events")
+
+ running = True
+ self.loop = True
+ while running:
+ # Main run loop. Wait on project events, signals, or the
+ # Docker container stopping.
+
+ try:
+ # Poll the queue with a 1 second timeout, if we have no
+ # timeout the Python runtime doesn't have a chance to
+ # process SIGINT or SIGTERM.
+ eq = self.evqueue.get(True, 1)
+ logger.info("%s %s", eq[1], eq[2])
+ self.newcollection = self.collection
+ if eq[1] in ('add', 'update', 'create'):
+ self.newcollection = eq[2]
+ elif eq[1] == 'remove':
+ collections = self.api.collections().list(filters=[["owner_uuid", "=", self.project]],
+ limit=1,
+ order='modified_at desc').execute()['items']
+ self.newcollection = collections[0]['uuid'] if collections else None
+ running = False
+ except Queue.Empty:
+ pass
+
+ if self.cid and not self.check_docker_running():
+ logger.warning("Service has terminated. Will try to restart.")
+ self.cid = None
+ running = False
+
+
+ def run(self):
+ try:
+ while self.loop:
+ self.loop = False
+ self.mount_collection()
+ try:
+ self.run_docker()
+ self.wait_for_events()
+ except (KeyboardInterrupt):
+ logger.info("Got keyboard interrupt")
+ self.ws.close()
+ self.loop = False
+ except Exception as e:
+ logger.exception("Caught fatal exception, shutting down")
+ self.ws.close()
+ self.loop = False
+ finally:
+ self.stop_docker()
+
+ if self.mountdir:
+ logger.info("Unmounting")
+ subprocess.call(["fusermount", "-u", self.mountdir])
+ os.rmdir(self.mountdir)