openrvdas.server.server_api
API for interacting with data store. Implementations should subclass.
1#!/usr/bin/env python3 2""" 3API for interacting with data store. Implementations should subclass. 4""" 5import logging 6import sys 7 8 9################################################################################ 10class ServerAPI: 11 """Abstract base class defining an API through which a LoggerServer 12 can interact with a data store. 13 14 Parameters below have the following semantics: 15 ``` 16 configuration - dict definition of a OpenRVDAS configuration 17 mode - dict name of mode, and logger_config_names associated with that mode 18 default_mode - name of mode to use at startup or when returning to a default state 19 20 logger_config_name - string name of a logger configuration, unique within configration 21 logger_config - dict definition of a logger configuration 22 23 logger_id - string name of logger, unique within cruise 24 logger - dict definition of logger, including list of names of 25 valid configs and optional host restriction 26 27 logger_configs - dict of {logger_config_name:logger_config,...} 28 ``` 29 For the purposes of documentation below, assume a sample 30 cruise_config as follows: 31 ``` 32 { 33 "loggers": { 34 "knud": { 35 "host": "knud.pi", 36 "configs": ["off", "knud->net", "knud->file/net/db"] 37 }, 38 "gyr1": { 39 "configs": ["off", "gyr1->net", "gyr1->file/net/db"] 40 }, 41 "modes": { 42 "off": {"knud": "off", "gyr1": "off"}, 43 "port": {"knud": "off", "gyr1": "gyr1->net"}, 44 "underway": { "knud": "knud->file/net/db", 45 "gyr1": "gyr1->file/net/db" 46 } 47 }, 48 "default_mode": "off", 49 "configs": { 50 "off": {}, 51 "knud->net": { config_spec }, 52 "knud->file/net/db": { config_spec }, 53 "gyr1->net": { config_spec }, 54 "gyr1->file/net/dbnet": { config_spec } 55 } 56 } 57 ``` 58 """ 59 60 ############################ 61 def __init__(self): 62 # Called when we update which configs are active. 63 self.update_callbacks = [] 64 65 # Called when the set of configs changes. 66 self.load_callbacks = [] 67 68 # Called, obviously, when 'quit' is signalled. 69 self.quit_callbacks = [] 70 71 ############################# 72 # API methods below are used in querying/modifying the API for the 73 # record of the running state of loggers. 74 ############################# 75 # def get_cruises(self): 76 # """Return list of cruise id's. Returns, e.g. 77 # > api.get_cruises() 78 # ["NBP1700", "NBP1701"] 79 # """ 80 # raise NotImplementedError('get_cruises must be implemented by subclass') 81 82 ############################# 83 def get_configuration(self): 84 """Get OpenRVDAS configuration from the data store. 85 """ 86 raise NotImplementedError('get_configuration must be implemented by subclass') 87 88 ############################# 89 def get_modes(self): 90 """Get the list of modes from the data store. 91 > api.get_modes() 92 ["off", "port", "underway"] 93 """ 94 raise NotImplementedError('get_modes must be implemented by subclass') 95 96 ############################# 97 def get_active_mode(self): 98 """Get the currently active mode from the data store. 99 > api.get_active_mode() 100 "port" 101 """ 102 raise NotImplementedError('get_active_mode must be implemented by subclass') 103 104 ############################# 105 def get_default_mode(self): 106 """Get the default mode from the data store. 107 > api.get_default_mode() 108 "off" 109 """ 110 raise NotImplementedError('get_default_mode must be implemented by subclass') 111 112 ############################# 113 def get_loggers(self): 114 """Get the dict of {logger_id:logger_spec,...} from the data store. 115 > api.get_loggers() 116 { 117 "knud": {"host": "knud.pi", "configs":...}, 118 "gyr1": {"configs":...} 119 } 120 """ 121 raise NotImplementedError('get_loggers must be implemented by subclass') 122 123 ############################# 124 def get_logger(self, logger_id): 125 """Retrieve the logger spec for the specified logger id. 126 > api.get_logger('knud') 127 {"name": "knud->net", "host_id": "knud.pi", "configs":...} 128 """ 129 raise NotImplementedError('get_logger must be implemented by subclass') 130 131 ############################# 132 def get_logger_config(self, config_name): 133 """Retrieve the logger config associated with the specified name. 134 > api.get_logger_config('knud->net') 135 { "readers": [...], "transforms": [...], "writers": [...] } 136 """ 137 raise NotImplementedError('get_logger_config must be implemented by subclass') 138 139 ############################# 140 def get_logger_configs(self, mode=None): 141 """Retrieve the configs associated with a mode from the data store. 142 If mode is omitted, retrieve configs associated with the active mode. 143 > api.get_logger_configs() 144 {"knud": { config_spec }, 145 "gyr1": { config_spec } 146 } 147 """ 148 raise NotImplementedError('get_logger_configs must be implemented by subclass') 149 150 ############################# 151 def get_logger_config_name(self, logger_id, mode=None): 152 """Retrieve the name of the logger config associated with the 153 specified logger in the specified mode. If mode is omitted, 154 retrieve config name associated with the active mode. 155 > api.get_logger_config_name('knud') 156 knud->net 157 """ 158 raise NotImplementedError( 159 'get_logger_config_name must be implemented by subclass') 160 161 ############################# 162 def get_logger_config_names(self, logger_id): 163 """Retrieve list of logger config names for the specified logger. 164 > api.get_logger_config_names('knud') 165 ["off", "knud->net", "knud->net/file", "knud->net/file/db"] 166 """ 167 raise NotImplementedError( 168 'get_logger_config_names must be implemented by subclass') 169 170 ############################ 171 # Methods for manipulating the desired state via API to indicate 172 # current mode and which loggers should be in which configs. 173 # 174 # These are triggered from the user/API/web interface 175 ############################ 176 def set_active_mode(self, mode): 177 """Set the active mode for OpenRVDAS. 178 > api.set_active_mode(port') 179 """ 180 raise NotImplementedError('set_active_mode must be implemented by subclass') 181 182 ############################# 183 def set_active_logger_config(self, logger, config_name): 184 """Set the active logger config for the specified logger to 185 the specific logger_config name. 186 > api.set_active_logger_config('knud', 'knud->file/net/db') 187 """ 188 raise NotImplementedError( 189 'set_active_logger_config must be implemented by subclass') 190 191 ############################# 192 193 def quit(self): 194 """Execute any callbacks that were registered to run on quit.""" 195 for (callback, kwargs) in self.quit_callbacks: 196 logging.debug('Executing quit callback: %s', callback) 197 callback(**kwargs) 198 199 ############################# 200 # API method to register a callback. When the data store changes, 201 # methods that are registered via on_update() will be called so they 202 # can fetch updated results. 203 ############################# 204 def on_update(self, callback, kwargs=None): 205 """Register a method to be called when current configs change.""" 206 if kwargs is None: 207 kwargs = {} 208 self.update_callbacks.append((callback, kwargs)) 209 210 ############################# 211 def signal_update(self): 212 """Call the registered methods when current configs change.""" 213 for (callback, kwargs) in self.update_callbacks: 214 logging.debug('Executing update callback: %s', callback) 215 callback(**kwargs) 216 217 ############################# 218 # API method to register a callback. When the data store changes, 219 # methods that are registered via on_update() will be called so they 220 # can fetch updated results. 221 ############################# 222 def on_load(self, callback, kwargs=None): 223 """Register a method to be called when new configs have been loaded.""" 224 if kwargs is None: 225 kwargs = {} 226 self.load_callbacks.append((callback, kwargs)) 227 228 ############################# 229 def signal_load(self): 230 """Call the registered methods when new configs have been loaded.""" 231 for (callback, kwargs) in self.load_callbacks: 232 logging.debug('Executing load callback: %s', callback) 233 callback(**kwargs) 234 235 ############################# 236 # API method to register a callback. When the data store changes, 237 # methods that are registered via on_update() will be called so they 238 # can fetch updated results. 239 ############################# 240 def on_quit(self, callback, kwargs=None): 241 """Register a method to be called when quit is signaled changes.""" 242 if kwargs is None: 243 kwargs = {} 244 self.quit_callbacks.append((callback, kwargs)) 245 246 ############################ 247 # Methods for getting logger status data from API 248 ############################ 249 def get_status(self, since_timestamp=None): 250 """Retrieve a dict of the most-recent status report from each 251 logger. If since_timestamp is specified, retrieve all status reports 252 since that time.""" 253 raise NotImplementedError('get_status must be implemented by subclass') 254 255 ############################ 256 # Methods for storing/retrieving messages from servers/loggers/etc. 257 ############################ 258 # Logging levels corresponding to logging module levels 259 CRITICAL = logging.CRITICAL 260 ERROR = logging.ERROR 261 WARNING = logging.WARNING 262 INFO = logging.INFO 263 DEBUG = logging.DEBUG 264 265 ############################ 266 def message_log(self, source, user, log_level, message): 267 """Timestamp and store the passed message.""" 268 raise NotImplementedError('message_log must be implemented by subclass') 269 270 ############################ 271 def get_message_log(self, source=None, user=None, log_level=sys.maxsize, 272 since_timestamp=None): 273 """Retrieve log messages from source at or above log_level since 274 timestamp. If source is omitted, retrieve from all sources. If 275 log_level is omitted, retrieve at all levels. If since_timestamp is 276 omitted, only retrieve most recent message. 277 """ 278 raise NotImplementedError('get_message_log must be implemented by subclass') 279 280 ############################# 281 """Methods below are used to load/create/modify the data store's model 282 of a cruise.""" 283 ############################# 284 285 def load_configuration(self, configuration): 286 """Load a complete cruise configuration to the data store. 287 > api.load_configuration({ configuration }) 288 """ 289 raise NotImplementedError('load_configuration must be implemented by subclass') 290 291 ############################# 292 # def add_cruise(self, cruise_id, start=None, end=None): 293 # """Add a new cruise_id to the data store. Use methods below to build 294 # it out. 295 # > api.add_cruise('NBP1702', '2017-02-02', '2017-03-01') 296 # """ 297 # raise NotImplementedError('add_cruise must be implemented by subclass') 298 299 ############################# 300 def delete_configuration(self): 301 """Remove the specified cruise from the data store. 302 > api.delete_configuration() 303 """ 304 raise NotImplementedError('delete_configuration must be implemented by subclass') 305 306 ############################# 307 def add_mode(self, mode): 308 """Add a new mode to the OpenRVDAS configuration. 309 > api.add_mode('underway') 310 """ 311 raise NotImplementedError('add_mode must be implemented by subclass') 312 313 ############################# 314 def delete_mode(self, mode): 315 """Delete the named mode (and all its configs) from the 316 data store. If the deleted mode is the active mode, set 317 the active mode to the default mode. 318 > api.delete_mode('underway') 319 """ 320 raise NotImplementedError('delete_mode must be implemented by subclass') 321 322 ############################# 323 def add_logger(self, logger_id, logger_config): 324 """Add a new logger to the data store. 325 326 logger_config - a dict defining: 327 host - optional restriction on which host logger must run 328 configs - list of logger_config names 329 > api.add_logger(gyr2', { 'host_id': <host_id>, 'configs': [....] }) 330 """ 331 raise NotImplementedError('add_logger must be implemented by subclass') 332 333 ############################# 334 def delete_logger(self, logger_id): 335 """Remove a logger and all its associated logger_configs from the data store. 336 > api.delete_logger(gyr2') 337 """ 338 raise NotImplementedError('delete_logger must be implemented by subclass') 339 340 ############################# 341 def add_logger_config(self, logger_config_name, logger_config_spec): 342 """Add a new logger config to the data store. 343 > api.add_logger_config('gyr2->net/file/db', { logger_config_spec }) 344 """ 345 raise NotImplementedError('add_config must be implemented by subclass') 346 347 ############################# 348 def add_logger_config_to_logger(self, config, logger_id): 349 """Associate a config with a logger. 350 > api.add_logger_config_to_logger('gyr2->net/file/db', 'gyr2') 351 """ 352 raise NotImplementedError('add_logger_config_to_logger must be implemented by subclass') 353 354 ############################# 355 def add_logger_config_to_mode(self, config, logger_id, mode): 356 """Associate a config with a logger and mode. 357 > api.add_logger_config_to_mode('gyr2->net/file/db', 'gyr2', 'underway') 358 """ 359 raise NotImplementedError('add_logger_config_to_mode must be implemented by subclass') 360 361 ############################# 362 def delete_logger_config(self, config_id): 363 """Delete specified config from data store (and by extension, 364 from the mode and logger with which it is associated. 365 > api.delete_logger_config('gyr2->net/file/db') 366 """ 367 raise NotImplementedError('delete_logger_config must be implemented by subclass')
11class ServerAPI: 12 """Abstract base class defining an API through which a LoggerServer 13 can interact with a data store. 14 15 Parameters below have the following semantics: 16 ``` 17 configuration - dict definition of a OpenRVDAS configuration 18 mode - dict name of mode, and logger_config_names associated with that mode 19 default_mode - name of mode to use at startup or when returning to a default state 20 21 logger_config_name - string name of a logger configuration, unique within configration 22 logger_config - dict definition of a logger configuration 23 24 logger_id - string name of logger, unique within cruise 25 logger - dict definition of logger, including list of names of 26 valid configs and optional host restriction 27 28 logger_configs - dict of {logger_config_name:logger_config,...} 29 ``` 30 For the purposes of documentation below, assume a sample 31 cruise_config as follows: 32 ``` 33 { 34 "loggers": { 35 "knud": { 36 "host": "knud.pi", 37 "configs": ["off", "knud->net", "knud->file/net/db"] 38 }, 39 "gyr1": { 40 "configs": ["off", "gyr1->net", "gyr1->file/net/db"] 41 }, 42 "modes": { 43 "off": {"knud": "off", "gyr1": "off"}, 44 "port": {"knud": "off", "gyr1": "gyr1->net"}, 45 "underway": { "knud": "knud->file/net/db", 46 "gyr1": "gyr1->file/net/db" 47 } 48 }, 49 "default_mode": "off", 50 "configs": { 51 "off": {}, 52 "knud->net": { config_spec }, 53 "knud->file/net/db": { config_spec }, 54 "gyr1->net": { config_spec }, 55 "gyr1->file/net/dbnet": { config_spec } 56 } 57 } 58 ``` 59 """ 60 61 ############################ 62 def __init__(self): 63 # Called when we update which configs are active. 64 self.update_callbacks = [] 65 66 # Called when the set of configs changes. 67 self.load_callbacks = [] 68 69 # Called, obviously, when 'quit' is signalled. 70 self.quit_callbacks = [] 71 72 ############################# 73 # API methods below are used in querying/modifying the API for the 74 # record of the running state of loggers. 75 ############################# 76 # def get_cruises(self): 77 # """Return list of cruise id's. Returns, e.g. 78 # > api.get_cruises() 79 # ["NBP1700", "NBP1701"] 80 # """ 81 # raise NotImplementedError('get_cruises must be implemented by subclass') 82 83 ############################# 84 def get_configuration(self): 85 """Get OpenRVDAS configuration from the data store. 86 """ 87 raise NotImplementedError('get_configuration must be implemented by subclass') 88 89 ############################# 90 def get_modes(self): 91 """Get the list of modes from the data store. 92 > api.get_modes() 93 ["off", "port", "underway"] 94 """ 95 raise NotImplementedError('get_modes must be implemented by subclass') 96 97 ############################# 98 def get_active_mode(self): 99 """Get the currently active mode from the data store. 100 > api.get_active_mode() 101 "port" 102 """ 103 raise NotImplementedError('get_active_mode must be implemented by subclass') 104 105 ############################# 106 def get_default_mode(self): 107 """Get the default mode from the data store. 108 > api.get_default_mode() 109 "off" 110 """ 111 raise NotImplementedError('get_default_mode must be implemented by subclass') 112 113 ############################# 114 def get_loggers(self): 115 """Get the dict of {logger_id:logger_spec,...} from the data store. 116 > api.get_loggers() 117 { 118 "knud": {"host": "knud.pi", "configs":...}, 119 "gyr1": {"configs":...} 120 } 121 """ 122 raise NotImplementedError('get_loggers must be implemented by subclass') 123 124 ############################# 125 def get_logger(self, logger_id): 126 """Retrieve the logger spec for the specified logger id. 127 > api.get_logger('knud') 128 {"name": "knud->net", "host_id": "knud.pi", "configs":...} 129 """ 130 raise NotImplementedError('get_logger must be implemented by subclass') 131 132 ############################# 133 def get_logger_config(self, config_name): 134 """Retrieve the logger config associated with the specified name. 135 > api.get_logger_config('knud->net') 136 { "readers": [...], "transforms": [...], "writers": [...] } 137 """ 138 raise NotImplementedError('get_logger_config must be implemented by subclass') 139 140 ############################# 141 def get_logger_configs(self, mode=None): 142 """Retrieve the configs associated with a mode from the data store. 143 If mode is omitted, retrieve configs associated with the active mode. 144 > api.get_logger_configs() 145 {"knud": { config_spec }, 146 "gyr1": { config_spec } 147 } 148 """ 149 raise NotImplementedError('get_logger_configs must be implemented by subclass') 150 151 ############################# 152 def get_logger_config_name(self, logger_id, mode=None): 153 """Retrieve the name of the logger config associated with the 154 specified logger in the specified mode. If mode is omitted, 155 retrieve config name associated with the active mode. 156 > api.get_logger_config_name('knud') 157 knud->net 158 """ 159 raise NotImplementedError( 160 'get_logger_config_name must be implemented by subclass') 161 162 ############################# 163 def get_logger_config_names(self, logger_id): 164 """Retrieve list of logger config names for the specified logger. 165 > api.get_logger_config_names('knud') 166 ["off", "knud->net", "knud->net/file", "knud->net/file/db"] 167 """ 168 raise NotImplementedError( 169 'get_logger_config_names must be implemented by subclass') 170 171 ############################ 172 # Methods for manipulating the desired state via API to indicate 173 # current mode and which loggers should be in which configs. 174 # 175 # These are triggered from the user/API/web interface 176 ############################ 177 def set_active_mode(self, mode): 178 """Set the active mode for OpenRVDAS. 179 > api.set_active_mode(port') 180 """ 181 raise NotImplementedError('set_active_mode must be implemented by subclass') 182 183 ############################# 184 def set_active_logger_config(self, logger, config_name): 185 """Set the active logger config for the specified logger to 186 the specific logger_config name. 187 > api.set_active_logger_config('knud', 'knud->file/net/db') 188 """ 189 raise NotImplementedError( 190 'set_active_logger_config must be implemented by subclass') 191 192 ############################# 193 194 def quit(self): 195 """Execute any callbacks that were registered to run on quit.""" 196 for (callback, kwargs) in self.quit_callbacks: 197 logging.debug('Executing quit callback: %s', callback) 198 callback(**kwargs) 199 200 ############################# 201 # API method to register a callback. When the data store changes, 202 # methods that are registered via on_update() will be called so they 203 # can fetch updated results. 204 ############################# 205 def on_update(self, callback, kwargs=None): 206 """Register a method to be called when current configs change.""" 207 if kwargs is None: 208 kwargs = {} 209 self.update_callbacks.append((callback, kwargs)) 210 211 ############################# 212 def signal_update(self): 213 """Call the registered methods when current configs change.""" 214 for (callback, kwargs) in self.update_callbacks: 215 logging.debug('Executing update callback: %s', callback) 216 callback(**kwargs) 217 218 ############################# 219 # API method to register a callback. When the data store changes, 220 # methods that are registered via on_update() will be called so they 221 # can fetch updated results. 222 ############################# 223 def on_load(self, callback, kwargs=None): 224 """Register a method to be called when new configs have been loaded.""" 225 if kwargs is None: 226 kwargs = {} 227 self.load_callbacks.append((callback, kwargs)) 228 229 ############################# 230 def signal_load(self): 231 """Call the registered methods when new configs have been loaded.""" 232 for (callback, kwargs) in self.load_callbacks: 233 logging.debug('Executing load callback: %s', callback) 234 callback(**kwargs) 235 236 ############################# 237 # API method to register a callback. When the data store changes, 238 # methods that are registered via on_update() will be called so they 239 # can fetch updated results. 240 ############################# 241 def on_quit(self, callback, kwargs=None): 242 """Register a method to be called when quit is signaled changes.""" 243 if kwargs is None: 244 kwargs = {} 245 self.quit_callbacks.append((callback, kwargs)) 246 247 ############################ 248 # Methods for getting logger status data from API 249 ############################ 250 def get_status(self, since_timestamp=None): 251 """Retrieve a dict of the most-recent status report from each 252 logger. If since_timestamp is specified, retrieve all status reports 253 since that time.""" 254 raise NotImplementedError('get_status must be implemented by subclass') 255 256 ############################ 257 # Methods for storing/retrieving messages from servers/loggers/etc. 258 ############################ 259 # Logging levels corresponding to logging module levels 260 CRITICAL = logging.CRITICAL 261 ERROR = logging.ERROR 262 WARNING = logging.WARNING 263 INFO = logging.INFO 264 DEBUG = logging.DEBUG 265 266 ############################ 267 def message_log(self, source, user, log_level, message): 268 """Timestamp and store the passed message.""" 269 raise NotImplementedError('message_log must be implemented by subclass') 270 271 ############################ 272 def get_message_log(self, source=None, user=None, log_level=sys.maxsize, 273 since_timestamp=None): 274 """Retrieve log messages from source at or above log_level since 275 timestamp. If source is omitted, retrieve from all sources. If 276 log_level is omitted, retrieve at all levels. If since_timestamp is 277 omitted, only retrieve most recent message. 278 """ 279 raise NotImplementedError('get_message_log must be implemented by subclass') 280 281 ############################# 282 """Methods below are used to load/create/modify the data store's model 283 of a cruise.""" 284 ############################# 285 286 def load_configuration(self, configuration): 287 """Load a complete cruise configuration to the data store. 288 > api.load_configuration({ configuration }) 289 """ 290 raise NotImplementedError('load_configuration must be implemented by subclass') 291 292 ############################# 293 # def add_cruise(self, cruise_id, start=None, end=None): 294 # """Add a new cruise_id to the data store. Use methods below to build 295 # it out. 296 # > api.add_cruise('NBP1702', '2017-02-02', '2017-03-01') 297 # """ 298 # raise NotImplementedError('add_cruise must be implemented by subclass') 299 300 ############################# 301 def delete_configuration(self): 302 """Remove the specified cruise from the data store. 303 > api.delete_configuration() 304 """ 305 raise NotImplementedError('delete_configuration must be implemented by subclass') 306 307 ############################# 308 def add_mode(self, mode): 309 """Add a new mode to the OpenRVDAS configuration. 310 > api.add_mode('underway') 311 """ 312 raise NotImplementedError('add_mode must be implemented by subclass') 313 314 ############################# 315 def delete_mode(self, mode): 316 """Delete the named mode (and all its configs) from the 317 data store. If the deleted mode is the active mode, set 318 the active mode to the default mode. 319 > api.delete_mode('underway') 320 """ 321 raise NotImplementedError('delete_mode must be implemented by subclass') 322 323 ############################# 324 def add_logger(self, logger_id, logger_config): 325 """Add a new logger to the data store. 326 327 logger_config - a dict defining: 328 host - optional restriction on which host logger must run 329 configs - list of logger_config names 330 > api.add_logger(gyr2', { 'host_id': <host_id>, 'configs': [....] }) 331 """ 332 raise NotImplementedError('add_logger must be implemented by subclass') 333 334 ############################# 335 def delete_logger(self, logger_id): 336 """Remove a logger and all its associated logger_configs from the data store. 337 > api.delete_logger(gyr2') 338 """ 339 raise NotImplementedError('delete_logger must be implemented by subclass') 340 341 ############################# 342 def add_logger_config(self, logger_config_name, logger_config_spec): 343 """Add a new logger config to the data store. 344 > api.add_logger_config('gyr2->net/file/db', { logger_config_spec }) 345 """ 346 raise NotImplementedError('add_config must be implemented by subclass') 347 348 ############################# 349 def add_logger_config_to_logger(self, config, logger_id): 350 """Associate a config with a logger. 351 > api.add_logger_config_to_logger('gyr2->net/file/db', 'gyr2') 352 """ 353 raise NotImplementedError('add_logger_config_to_logger must be implemented by subclass') 354 355 ############################# 356 def add_logger_config_to_mode(self, config, logger_id, mode): 357 """Associate a config with a logger and mode. 358 > api.add_logger_config_to_mode('gyr2->net/file/db', 'gyr2', 'underway') 359 """ 360 raise NotImplementedError('add_logger_config_to_mode must be implemented by subclass') 361 362 ############################# 363 def delete_logger_config(self, config_id): 364 """Delete specified config from data store (and by extension, 365 from the mode and logger with which it is associated. 366 > api.delete_logger_config('gyr2->net/file/db') 367 """ 368 raise NotImplementedError('delete_logger_config must be implemented by subclass')
Abstract base class defining an API through which a LoggerServer can interact with a data store.
Parameters below have the following semantics:
configuration - dict definition of a OpenRVDAS configuration
mode - dict name of mode, and logger_config_names associated with that mode
default_mode - name of mode to use at startup or when returning to a default state
logger_config_name - string name of a logger configuration, unique within configration
logger_config - dict definition of a logger configuration
logger_id - string name of logger, unique within cruise
logger - dict definition of logger, including list of names of
valid configs and optional host restriction
logger_configs - dict of {logger_config_name:logger_config,...}
For the purposes of documentation below, assume a sample cruise_config as follows:
{
"loggers": {
"knud": {
"host": "knud.pi",
"configs": ["off", "knud->net", "knud->file/net/db"]
},
"gyr1": {
"configs": ["off", "gyr1->net", "gyr1->file/net/db"]
},
"modes": {
"off": {"knud": "off", "gyr1": "off"},
"port": {"knud": "off", "gyr1": "gyr1->net"},
"underway": { "knud": "knud->file/net/db",
"gyr1": "gyr1->file/net/db"
}
},
"default_mode": "off",
"configs": {
"off": {},
"knud->net": { config_spec },
"knud->file/net/db": { config_spec },
"gyr1->net": { config_spec },
"gyr1->file/net/dbnet": { config_spec }
}
}
84 def get_configuration(self): 85 """Get OpenRVDAS configuration from the data store. 86 """ 87 raise NotImplementedError('get_configuration must be implemented by subclass')
Get OpenRVDAS configuration from the data store.
90 def get_modes(self): 91 """Get the list of modes from the data store. 92 > api.get_modes() 93 ["off", "port", "underway"] 94 """ 95 raise NotImplementedError('get_modes must be implemented by subclass')
Get the list of modes from the data store.
api.get_modes() ["off", "port", "underway"]
98 def get_active_mode(self): 99 """Get the currently active mode from the data store. 100 > api.get_active_mode() 101 "port" 102 """ 103 raise NotImplementedError('get_active_mode must be implemented by subclass')
Get the currently active mode from the data store.
api.get_active_mode() "port"
106 def get_default_mode(self): 107 """Get the default mode from the data store. 108 > api.get_default_mode() 109 "off" 110 """ 111 raise NotImplementedError('get_default_mode must be implemented by subclass')
Get the default mode from the data store.
api.get_default_mode() "off"
114 def get_loggers(self): 115 """Get the dict of {logger_id:logger_spec,...} from the data store. 116 > api.get_loggers() 117 { 118 "knud": {"host": "knud.pi", "configs":...}, 119 "gyr1": {"configs":...} 120 } 121 """ 122 raise NotImplementedError('get_loggers must be implemented by subclass')
Get the dict of {logger_id:logger_spec,...} from the data store.
api.get_loggers() { "knud": {"host": "knud.pi", "configs":...}, "gyr1": {"configs":...} }
125 def get_logger(self, logger_id): 126 """Retrieve the logger spec for the specified logger id. 127 > api.get_logger('knud') 128 {"name": "knud->net", "host_id": "knud.pi", "configs":...} 129 """ 130 raise NotImplementedError('get_logger must be implemented by subclass')
Retrieve the logger spec for the specified logger id.
api.get_logger('knud') {"name": "knud->net", "host_id": "knud.pi", "configs":...}
133 def get_logger_config(self, config_name): 134 """Retrieve the logger config associated with the specified name. 135 > api.get_logger_config('knud->net') 136 { "readers": [...], "transforms": [...], "writers": [...] } 137 """ 138 raise NotImplementedError('get_logger_config must be implemented by subclass')
Retrieve the logger config associated with the specified name.
api.get_logger_config('knud->net') { "readers": [...], "transforms": [...], "writers": [...] }
141 def get_logger_configs(self, mode=None): 142 """Retrieve the configs associated with a mode from the data store. 143 If mode is omitted, retrieve configs associated with the active mode. 144 > api.get_logger_configs() 145 {"knud": { config_spec }, 146 "gyr1": { config_spec } 147 } 148 """ 149 raise NotImplementedError('get_logger_configs must be implemented by subclass')
Retrieve the configs associated with a mode from the data store. If mode is omitted, retrieve configs associated with the active mode.
api.get_logger_configs() {"knud": { config_spec }, "gyr1": { config_spec } }
152 def get_logger_config_name(self, logger_id, mode=None): 153 """Retrieve the name of the logger config associated with the 154 specified logger in the specified mode. If mode is omitted, 155 retrieve config name associated with the active mode. 156 > api.get_logger_config_name('knud') 157 knud->net 158 """ 159 raise NotImplementedError( 160 'get_logger_config_name must be implemented by subclass')
Retrieve the name of the logger config associated with the specified logger in the specified mode. If mode is omitted, retrieve config name associated with the active mode.
api.get_logger_config_name('knud') knud->net
163 def get_logger_config_names(self, logger_id): 164 """Retrieve list of logger config names for the specified logger. 165 > api.get_logger_config_names('knud') 166 ["off", "knud->net", "knud->net/file", "knud->net/file/db"] 167 """ 168 raise NotImplementedError( 169 'get_logger_config_names must be implemented by subclass')
Retrieve list of logger config names for the specified logger.
api.get_logger_config_names('knud') ["off", "knud->net", "knud->net/file", "knud->net/file/db"]
177 def set_active_mode(self, mode): 178 """Set the active mode for OpenRVDAS. 179 > api.set_active_mode(port') 180 """ 181 raise NotImplementedError('set_active_mode must be implemented by subclass')
Set the active mode for OpenRVDAS.
api.set_active_mode(port')
184 def set_active_logger_config(self, logger, config_name): 185 """Set the active logger config for the specified logger to 186 the specific logger_config name. 187 > api.set_active_logger_config('knud', 'knud->file/net/db') 188 """ 189 raise NotImplementedError( 190 'set_active_logger_config must be implemented by subclass')
Set the active logger config for the specified logger to the specific logger_config name.
api.set_active_logger_config('knud', 'knud->file/net/db')
194 def quit(self): 195 """Execute any callbacks that were registered to run on quit.""" 196 for (callback, kwargs) in self.quit_callbacks: 197 logging.debug('Executing quit callback: %s', callback) 198 callback(**kwargs)
Execute any callbacks that were registered to run on quit.
205 def on_update(self, callback, kwargs=None): 206 """Register a method to be called when current configs change.""" 207 if kwargs is None: 208 kwargs = {} 209 self.update_callbacks.append((callback, kwargs))
Register a method to be called when current configs change.
212 def signal_update(self): 213 """Call the registered methods when current configs change.""" 214 for (callback, kwargs) in self.update_callbacks: 215 logging.debug('Executing update callback: %s', callback) 216 callback(**kwargs)
Call the registered methods when current configs change.
223 def on_load(self, callback, kwargs=None): 224 """Register a method to be called when new configs have been loaded.""" 225 if kwargs is None: 226 kwargs = {} 227 self.load_callbacks.append((callback, kwargs))
Register a method to be called when new configs have been loaded.
230 def signal_load(self): 231 """Call the registered methods when new configs have been loaded.""" 232 for (callback, kwargs) in self.load_callbacks: 233 logging.debug('Executing load callback: %s', callback) 234 callback(**kwargs)
Call the registered methods when new configs have been loaded.
241 def on_quit(self, callback, kwargs=None): 242 """Register a method to be called when quit is signaled changes.""" 243 if kwargs is None: 244 kwargs = {} 245 self.quit_callbacks.append((callback, kwargs))
Register a method to be called when quit is signaled changes.
250 def get_status(self, since_timestamp=None): 251 """Retrieve a dict of the most-recent status report from each 252 logger. If since_timestamp is specified, retrieve all status reports 253 since that time.""" 254 raise NotImplementedError('get_status must be implemented by subclass')
Retrieve a dict of the most-recent status report from each logger. If since_timestamp is specified, retrieve all status reports since that time.
267 def message_log(self, source, user, log_level, message): 268 """Timestamp and store the passed message.""" 269 raise NotImplementedError('message_log must be implemented by subclass')
Timestamp and store the passed message.
272 def get_message_log(self, source=None, user=None, log_level=sys.maxsize, 273 since_timestamp=None): 274 """Retrieve log messages from source at or above log_level since 275 timestamp. If source is omitted, retrieve from all sources. If 276 log_level is omitted, retrieve at all levels. If since_timestamp is 277 omitted, only retrieve most recent message. 278 """ 279 raise NotImplementedError('get_message_log must be implemented by subclass')
Retrieve log messages from source at or above log_level since timestamp. If source is omitted, retrieve from all sources. If log_level is omitted, retrieve at all levels. If since_timestamp is omitted, only retrieve most recent message.
286 def load_configuration(self, configuration): 287 """Load a complete cruise configuration to the data store. 288 > api.load_configuration({ configuration }) 289 """ 290 raise NotImplementedError('load_configuration must be implemented by subclass')
Load a complete cruise configuration to the data store.
api.load_configuration({ configuration })
301 def delete_configuration(self): 302 """Remove the specified cruise from the data store. 303 > api.delete_configuration() 304 """ 305 raise NotImplementedError('delete_configuration must be implemented by subclass')
Remove the specified cruise from the data store.
api.delete_configuration()
308 def add_mode(self, mode): 309 """Add a new mode to the OpenRVDAS configuration. 310 > api.add_mode('underway') 311 """ 312 raise NotImplementedError('add_mode must be implemented by subclass')
Add a new mode to the OpenRVDAS configuration.
api.add_mode('underway')
315 def delete_mode(self, mode): 316 """Delete the named mode (and all its configs) from the 317 data store. If the deleted mode is the active mode, set 318 the active mode to the default mode. 319 > api.delete_mode('underway') 320 """ 321 raise NotImplementedError('delete_mode must be implemented by subclass')
Delete the named mode (and all its configs) from the data store. If the deleted mode is the active mode, set the active mode to the default mode.
api.delete_mode('underway')
324 def add_logger(self, logger_id, logger_config): 325 """Add a new logger to the data store. 326 327 logger_config - a dict defining: 328 host - optional restriction on which host logger must run 329 configs - list of logger_config names 330 > api.add_logger(gyr2', { 'host_id': <host_id>, 'configs': [....] }) 331 """ 332 raise NotImplementedError('add_logger must be implemented by subclass')
Add a new logger to the data store.
logger_config - a dict defining: host - optional restriction on which host logger must run configs - list of logger_config names
api.add_logger(gyr2', { 'host_id':
, 'configs': [....] })
335 def delete_logger(self, logger_id): 336 """Remove a logger and all its associated logger_configs from the data store. 337 > api.delete_logger(gyr2') 338 """ 339 raise NotImplementedError('delete_logger must be implemented by subclass')
Remove a logger and all its associated logger_configs from the data store.
api.delete_logger(gyr2')
342 def add_logger_config(self, logger_config_name, logger_config_spec): 343 """Add a new logger config to the data store. 344 > api.add_logger_config('gyr2->net/file/db', { logger_config_spec }) 345 """ 346 raise NotImplementedError('add_config must be implemented by subclass')
Add a new logger config to the data store.
api.add_logger_config('gyr2->net/file/db', { logger_config_spec })
349 def add_logger_config_to_logger(self, config, logger_id): 350 """Associate a config with a logger. 351 > api.add_logger_config_to_logger('gyr2->net/file/db', 'gyr2') 352 """ 353 raise NotImplementedError('add_logger_config_to_logger must be implemented by subclass')
Associate a config with a logger.
api.add_logger_config_to_logger('gyr2->net/file/db', 'gyr2')
356 def add_logger_config_to_mode(self, config, logger_id, mode): 357 """Associate a config with a logger and mode. 358 > api.add_logger_config_to_mode('gyr2->net/file/db', 'gyr2', 'underway') 359 """ 360 raise NotImplementedError('add_logger_config_to_mode must be implemented by subclass')
Associate a config with a logger and mode.
api.add_logger_config_to_mode('gyr2->net/file/db', 'gyr2', 'underway')
363 def delete_logger_config(self, config_id): 364 """Delete specified config from data store (and by extension, 365 from the mode and logger with which it is associated. 366 > api.delete_logger_config('gyr2->net/file/db') 367 """ 368 raise NotImplementedError('delete_logger_config must be implemented by subclass')
Delete specified config from data store (and by extension, from the mode and logger with which it is associated.
api.delete_logger_config('gyr2->net/file/db')