import redis import json class BuildLogs(object): def __init__(self, redis_host): self._redis = redis.StrictRedis(host=redis_host) @staticmethod def _logs_key(build_id): return 'builds/%s/logs' % build_id @staticmethod def _commands_key(build_id): return 'builds/%s/commands' % build_id def append_log_entry(self, build_id, log_obj): """ Appends the serialized form of log_obj to the end of the log entry list and returns the new length of the list. """ return self._redis.rpush(self._logs_key(build_id), json.dumps(log_obj)) def append_log_message(self, build_id, log_message): """ Wraps the message in an envelope and push it to the end of the log entry list and returns the index at which it was inserted. """ log_obj = { 'message': log_message } return self._redis.rpush(self._logs_key(build_id), json.dumps(log_obj)) - 1 def append_command_message(self, build_id, command_message): """ Wraps the message in an envelope and push it to the end of the log entry list, to the commands list, and returns the new length of the list. """ log_obj = { 'message': command_message, 'is_command': True, } idx = self._redis.rpush(self._logs_key(build_id), json.dumps(log_obj)) - 1 cmd_obj = { 'message': command_message, 'index': idx, } self._redis.rpush(self._commands_key(build_id), json.dumps(cmd_obj)) return idx def get_log_entries(self, build_id, start_index, end_index): """ Returns a tuple of the current length of the list and an iterable of the requested log entries. End index is inclusive. """ llen = self._redis.llen(self._logs_key(build_id)) log_entries = self._redis.lrange(self._logs_key(build_id), start_index, end_index) return (llen, (json.loads(entry) for entry in log_entries)) def get_commands(self, build_id): """ Returns a list of all Dockerfile commands that have passed through the specified build thus far. """ commands = self._redis.lrange(self._commands_key(build_id), 0, -1) return (json.loads(cmd) for cmd in commands) def get_last_command(self, build_id): """ Returns only the last command from the list of commands. """ commands = self._redis.lrange(self._commands_key(build_id), -1, -1) if commands: return json.loads(commands[-1]) else: return None @staticmethod def _status_key(build_id): return 'builds/%s/status' % build_id def set_status(self, build_id, status_obj): """ Sets the status key for this build to json serialized form of the supplied obj. """ self._redis.set(self._status_key(build_id), json.dumps(status_obj)) def get_status(self, build_id): """ Loads the status information for the specified build id. """ fetched = self._redis.get(self._status_key(build_id)) return json.loads(fetched) if fetched else None