| OLD | NEW |
| 1 # Copyright (c) 2015 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2015 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import collections | 5 import collections |
| 6 import glob | 6 import glob |
| 7 import json | 7 import json |
| 8 import logging | 8 import logging |
| 9 import os.path | 9 import os.path |
| 10 import time | 10 import time |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 """Polls a directory for .json files describing services to be run. | 26 """Polls a directory for .json files describing services to be run. |
| 27 | 27 |
| 28 Tries to keep the running services in sync with the config files - services | 28 Tries to keep the running services in sync with the config files - services |
| 29 are started immediately when valid configs are added, restarted when their | 29 are started immediately when valid configs are added, restarted when their |
| 30 configs change (adding or removing args for example), and stopped when the | 30 configs change (adding or removing args for example), and stopped when the |
| 31 configs are deleted. | 31 configs are deleted. |
| 32 """ | 32 """ |
| 33 | 33 |
| 34 def __init__(self, config_directory, config_poll_interval, | 34 def __init__(self, config_directory, config_poll_interval, |
| 35 service_poll_interval, state_directory, root_directory, | 35 service_poll_interval, state_directory, root_directory, |
| 36 cloudtail_path, |
| 36 sleep_fn=time.sleep): | 37 sleep_fn=time.sleep): |
| 37 """ | 38 """ |
| 38 Args: | 39 Args: |
| 39 config_directory: Directory containing .json config files to monitor. | 40 config_directory: Directory containing .json config files to monitor. |
| 40 config_poll_interval: How often (in seconds) to poll config_directory | 41 config_poll_interval: How often (in seconds) to poll config_directory |
| 41 for changes. | 42 for changes. |
| 42 service_poll_interval: How often (in seconds) to restart failed services. | 43 service_poll_interval: How often (in seconds) to restart failed services. |
| 43 state_directory: A file will be created in this directory (with the same | 44 state_directory: A file will be created in this directory (with the same |
| 44 name as the service) when it is running containing its PID and | 45 name as the service) when it is running containing its PID and |
| 45 starttime. | 46 starttime. |
| 47 cloudtail_path: Path to the cloudtail binary to use for logging, or None |
| 48 if logging is disabled. |
| 46 """ | 49 """ |
| 47 | 50 |
| 48 self._config_glob = os.path.join(config_directory, '*.json') | 51 self._config_glob = os.path.join(config_directory, '*.json') |
| 49 self._config_poll_interval = config_poll_interval | 52 self._config_poll_interval = config_poll_interval |
| 50 self._service_poll_interval = service_poll_interval | 53 self._service_poll_interval = service_poll_interval |
| 51 self._state_directory = state_directory | 54 self._state_directory = state_directory |
| 55 self._cloudtail_path = cloudtail_path |
| 52 | 56 |
| 53 self._metadata = {} # Filename -> _Metadata | 57 self._metadata = {} # Filename -> _Metadata |
| 54 self._services = {} # Service name -> Filename | 58 self._services = {} # Service name -> Filename |
| 55 self._stop = False | 59 self._stop = False |
| 56 | 60 |
| 57 self._sleep_fn = sleep_fn | 61 self._sleep_fn = sleep_fn |
| 58 | 62 |
| 59 self._own_service = service.OwnService(state_directory, root_directory) | 63 self._own_service = service.OwnService(state_directory, root_directory) |
| 60 | 64 |
| 61 def run(self): | 65 def run(self): |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 126 if config['name'] in self._services: | 130 if config['name'] in self._services: |
| 127 LOGGER.error('Duplicate service name "%s" (defined in %s and %s)' % ( | 131 LOGGER.error('Duplicate service name "%s" (defined in %s and %s)' % ( |
| 128 config['name'], self._services[config['name']], filename)) | 132 config['name'], self._services[config['name']], filename)) |
| 129 return | 133 return |
| 130 | 134 |
| 131 LOGGER.info('Adding new service config for %s', config['name']) | 135 LOGGER.info('Adding new service config for %s', config['name']) |
| 132 | 136 |
| 133 thread = service_thread.ServiceThread( | 137 thread = service_thread.ServiceThread( |
| 134 self._service_poll_interval, | 138 self._service_poll_interval, |
| 135 self._state_directory, | 139 self._state_directory, |
| 136 config) | 140 config, |
| 141 self._cloudtail_path) |
| 137 thread.start() | 142 thread.start() |
| 138 thread.start_service() | 143 thread.start_service() |
| 139 self._metadata[filename] = _Metadata(mtime, config, thread) | 144 self._metadata[filename] = _Metadata(mtime, config, thread) |
| 140 self._services[config['name']] = filename | 145 self._services[config['name']] = filename |
| 141 | 146 |
| 142 def _config_changed(self, filename, metadata, new_mtime): | 147 def _config_changed(self, filename, metadata, new_mtime): |
| 143 if metadata.config is not None: | 148 if metadata.config is not None: |
| 144 del self._services[metadata.config['name']] | 149 del self._services[metadata.config['name']] |
| 145 | 150 |
| 146 metadata.config = self._load_config(filename) | 151 metadata.config = self._load_config(filename) |
| (...skipping 11 matching lines...) Expand all Loading... |
| 158 if metadata.thread is not None: | 163 if metadata.thread is not None: |
| 159 metadata.thread.stop_service() | 164 metadata.thread.stop_service() |
| 160 return | 165 return |
| 161 | 166 |
| 162 LOGGER.info('Updating service config for %s', metadata.config['name']) | 167 LOGGER.info('Updating service config for %s', metadata.config['name']) |
| 163 | 168 |
| 164 if metadata.thread is None: | 169 if metadata.thread is None: |
| 165 metadata.thread = service_thread.ServiceThread( | 170 metadata.thread = service_thread.ServiceThread( |
| 166 self._service_poll_interval, | 171 self._service_poll_interval, |
| 167 self._state_directory, | 172 self._state_directory, |
| 168 metadata.config) | 173 metadata.config, |
| 174 self._cloudtail_path) |
| 169 metadata.thread.start() | 175 metadata.thread.start() |
| 170 metadata.thread.start_service() | 176 metadata.thread.start_service() |
| 171 else: | 177 else: |
| 172 metadata.thread.restart_with_new_config(metadata.config) | 178 metadata.thread.restart_with_new_config(metadata.config) |
| 173 | 179 |
| 174 self._services[metadata.config['name']] = filename | 180 self._services[metadata.config['name']] = filename |
| 175 | 181 |
| 176 def _config_removed(self, metadata): | 182 def _config_removed(self, metadata): |
| 177 LOGGER.info('Removing service config for %s', metadata.config['name']) | 183 LOGGER.info('Removing service config for %s', metadata.config['name']) |
| 178 | 184 |
| 179 del self._services[metadata.config['name']] | 185 del self._services[metadata.config['name']] |
| 180 | 186 |
| 181 metadata.config = None | 187 metadata.config = None |
| 182 metadata.mtime = None | 188 metadata.mtime = None |
| 183 metadata.thread.stop_service() | 189 metadata.thread.stop_service() |
| OLD | NEW |