# Path: lava_dispatcher/log.py
# class YAMLLogger(logging.Logger):
#     def __init__(self, name):
#         super(YAMLLogger, self).__init__(name)
#         self.handler = None
# 
#     def addZMQHandler(self, logging_url, master_cert, slave_cert, job_id, ipv6):
#         self.handler = ZMQPushHandler(logging_url, master_cert,
#                                       slave_cert, job_id, ipv6)
#         self.addHandler(self.handler)
#         return self.handler
# 
#     def close(self, linger=-1):
#         if self.handler is not None:
#             self.handler.close(linger)
#             self.removeHandler(self.handler)
#             self.handler = None
# 
#     def log_message(self, level, level_name, message, *args, **kwargs):  # pylint: disable=unused-argument
#         # Build the dictionnary
#         data = {'dt': datetime.datetime.utcnow().isoformat(),
#                 'lvl': level_name}
# 
#         if isinstance(message, str) and args:
#             data['msg'] = message % args
#         else:
#             data['msg'] = message
# 
#         # Set width to a really large value in order to always get one line.
#         # But keep this reasonable because the logs will be loaded by CLoader
#         # that is limited to around 10**7 chars
#         data_str = yaml.dump(data, default_flow_style=True,
#                              default_style='"',
#                              width=10 ** 6,
#                              Dumper=yaml.CDumper)[:-1]
#         # Test the limit and skip if the line is too long
#         if len(data_str) >= 10 ** 6:
#             if isinstance(message, str):
#                 data['msg'] = "<line way too long ...>"
#             else:
#                 data['msg'] = {"skip": "line way too long ..."}
#             data_str = yaml.dump(data, default_flow_style=True,
#                                  default_style='"',
#                                  width=10 ** 6,
#                                  Dumper=yaml.CDumper)[:-1]
#         self._log(level, data_str, ())
# 
#     def exception(self, exc, *args, **kwargs):
#         self.log_message(logging.ERROR, 'exception', exc, *args, **kwargs)
# 
#     def error(self, message, *args, **kwargs):
#         self.log_message(logging.ERROR, 'error', message, *args, **kwargs)
# 
#     def warning(self, message, *args, **kwargs):
#         self.log_message(logging.WARNING, 'warning', message, *args, **kwargs)
# 
#     def info(self, message, *args, **kwargs):
#         self.log_message(logging.INFO, 'info', message, *args, **kwargs)
# 
#     def debug(self, message, *args, **kwargs):
#         self.log_message(logging.DEBUG, 'debug', message, *args, **kwargs)
# 
#     def input(self, message, *args, **kwargs):
#         self.log_message(logging.INFO, 'input', message, *args, **kwargs)
# 
#     def target(self, message, *args, **kwargs):
#         self.log_message(logging.INFO, 'target', message, *args, **kwargs)
# 
#     def feedback(self, message, *args, **kwargs):
#         self.log_message(logging.INFO, 'feedback', message, *args, **kwargs)
# 
#     def results(self, results, *args, **kwargs):
#         if 'extra' in results and 'level' not in results:
#             raise Exception("'level' is mandatory when 'extra' is used")
#         self.log_message(logging.INFO, 'results', results, *args, **kwargs)
# 
# Path: lava_dispatcher/utils/constants.py
# ACTION_TIMEOUT = 30
# 
# OVERRIDE_CLAMP_DURATION = 300
# 
# Path: lava_dispatcher/utils/strings.py
# def seconds_to_str(time):
#     hours, remainder = divmod(int(round(time)), 3600)
#     minutes, seconds = divmod(remainder, 60)
#     return "%02d:%02d:%02d" % (hours, minutes, seconds)


import logging
import sys
import copy
import time
import types
import signal
import datetime
import traceback
import subprocess
from functools import reduce  # pylint: disable=redefined-builtin
from collections import OrderedDict
from contextlib import contextmanager
from nose.tools import nottest
from lava_dispatcher.log import YAMLLogger
from lava_dispatcher.utils.constants import (
    ACTION_TIMEOUT,
    OVERRIDE_CLAMP_DURATION
)
from lava_dispatcher.utils.strings import seconds_to_str
        :param label: Arbitrary label used by many actions to sub-divide similar keys with distinct
            values. Can be set to the same as the action.
        :param key: The lookup key for the requested value within the data defined by
            data[namespace][action][label]
        :param value: The value to set into the namespace data, can be an object.
        :param parameters: Pass parameters when calling get_namespace_data from populate() as the parameters
            will not have been set in the action at that point.
        """
        params = parameters if parameters else self.parameters
        namespace = params['namespace']
        if not label or not key:
            raise LAVABug("Invalid call to set_namespace_data: %s" % action)
        self.data.setdefault(namespace, {})  # pylint: disable=no-member
        self.data[namespace].setdefault(action, {})
        self.data[namespace][action].setdefault(label, {})
        self.data[namespace][action][label][key] = value

    def wait(self, connection, max_end_time=None):
        if not connection:
            return
        if not connection.connected:
            self.logger.debug("Already disconnected")
            return
        if not max_end_time:
            max_end_time = self.timeout.duration + self.timeout.start
        remaining = max_end_time - time.time()
        # FIXME: connection.prompt_str needs to be always a list
        # bootloader_prompt is one which does not get set that way
        # also need functionality to clear the list at times.
        self.logger.debug("%s: Wait for prompt %s (timeout %s)",

# Path: lava_dispatcher/log.py
# class YAMLLogger(logging.Logger):
#     def __init__(self, name):
#         super(YAMLLogger, self).__init__(name)
#         self.handler = None
# 
#     def addZMQHandler(self, logging_url, master_cert, slave_cert, job_id, ipv6):
#         self.handler = ZMQPushHandler(logging_url, master_cert,
#                                       slave_cert, job_id, ipv6)
#         self.addHandler(self.handler)
#         return self.handler
# 
#     def close(self, linger=-1):
#         if self.handler is not None:
#             self.handler.close(linger)
#             self.removeHandler(self.handler)
#             self.handler = None
# 
#     def log_message(self, level, level_name, message, *args, **kwargs):  # pylint: disable=unused-argument
#         # Build the dictionnary
#         data = {'dt': datetime.datetime.utcnow().isoformat(),
#                 'lvl': level_name}
# 
#         if isinstance(message, str) and args:
#             data['msg'] = message % args
#         else:
#             data['msg'] = message
# 
#         # Set width to a really large value in order to always get one line.
#         # But keep this reasonable because the logs will be loaded by CLoader
#         # that is limited to around 10**7 chars
#         data_str = yaml.dump(data, default_flow_style=True,
#                              default_style='"',
#                              width=10 ** 6,
#                              Dumper=yaml.CDumper)[:-1]
#         # Test the limit and skip if the line is too long
#         if len(data_str) >= 10 ** 6:
#             if isinstance(message, str):
#                 data['msg'] = "<line way too long ...>"
#             else:
#                 data['msg'] = {"skip": "line way too long ..."}
#             data_str = yaml.dump(data, default_flow_style=True,
#                                  default_style='"',
#                                  width=10 ** 6,
#                                  Dumper=yaml.CDumper)[:-1]
#         self._log(level, data_str, ())
# 
#     def exception(self, exc, *args, **kwargs):
#         self.log_message(logging.ERROR, 'exception', exc, *args, **kwargs)
# 
#     def error(self, message, *args, **kwargs):
#         self.log_message(logging.ERROR, 'error', message, *args, **kwargs)
# 
#     def warning(self, message, *args, **kwargs):
#         self.log_message(logging.WARNING, 'warning', message, *args, **kwargs)
# 
#     def info(self, message, *args, **kwargs):
#         self.log_message(logging.INFO, 'info', message, *args, **kwargs)
# 
#     def debug(self, message, *args, **kwargs):
#         self.log_message(logging.DEBUG, 'debug', message, *args, **kwargs)
# 
#     def input(self, message, *args, **kwargs):
#         self.log_message(logging.INFO, 'input', message, *args, **kwargs)
# 
#     def target(self, message, *args, **kwargs):
#         self.log_message(logging.INFO, 'target', message, *args, **kwargs)
# 
#     def feedback(self, message, *args, **kwargs):
#         self.log_message(logging.INFO, 'feedback', message, *args, **kwargs)
# 
#     def results(self, results, *args, **kwargs):
#         if 'extra' in results and 'level' not in results:
#             raise Exception("'level' is mandatory when 'extra' is used")
#         self.log_message(logging.INFO, 'results', results, *args, **kwargs)
# 
# Path: lava_dispatcher/utils/constants.py
# ACTION_TIMEOUT = 30
# 
# OVERRIDE_CLAMP_DURATION = 300
# 
# Path: lava_dispatcher/utils/strings.py
# def seconds_to_str(time):
#     hours, remainder = divmod(int(round(time)), 3600)
#     minutes, seconds = divmod(remainder, 60)
#     return "%02d:%02d:%02d" % (hours, minutes, seconds)


# Path: lava_dispatcher/action.py
import logging
import sys
import copy
import time
import types
import signal
import datetime
import traceback
import subprocess
from functools import reduce  # pylint: disable=redefined-builtin
from collections import OrderedDict
from contextlib import contextmanager
from nose.tools import nottest
from lava_dispatcher.log import YAMLLogger
from lava_dispatcher.utils.constants import (
    ACTION_TIMEOUT,
    OVERRIDE_CLAMP_DURATION
)
from lava_dispatcher.utils.strings import seconds_to_str

        :param label: Arbitrary label used by many actions to sub-divide similar keys with distinct
            values. Can be set to the same as the action.
        :param key: The lookup key for the requested value within the data defined by
            data[namespace][action][label]
        :param value: The value to set into the namespace data, can be an object.
        :param parameters: Pass parameters when calling get_namespace_data from populate() as the parameters
            will not have been set in the action at that point.
        """
        params = parameters if parameters else self.parameters
        namespace = params['namespace']
        if not label or not key:
            raise LAVABug("Invalid call to set_namespace_data: %s" % action)
        self.data.setdefault(namespace, {})  # pylint: disable=no-member
        self.data[namespace].setdefault(action, {})
        self.data[namespace][action].setdefault(label, {})
        self.data[namespace][action][label][key] = value

    def wait(self, connection, max_end_time=None):
        if not connection:
            return
        if not connection.connected:
            self.logger.debug("Already disconnected")
            return
        if not max_end_time:
            max_end_time = self.timeout.duration + self.timeout.start
        remaining = max_end_time - time.time()
        # FIXME: connection.prompt_str needs to be always a list
        # bootloader_prompt is one which does not get set that way
        # also need functionality to clear the list at times.
        self.logger.debug("%s: Wait for prompt %s (timeout %s)",

                          self.name, connection.prompt_str, seconds_to_str(remaining))