# Path: chaosmonkey/dal/executor_model.py
# class Executor(db.Model):
#     """
#     Executors are persistent representations of scheduled jobs.
#     This model is shared between the cme and apscheduler.
#     """
# 
#     __tablename__ = 'cme_executors'
# 
#     id = db.Column(db.String(80), primary_key=True)  #: unique identifier
#     next_run_time = db.Column(db.DateTime, index=True)  #: DateTime for the executor to be executed
#     job_state = db.Column(db.LargeBinary, nullable=False)  #: store the full state of the executor (with pickle)
#     plan_id = db.Column(db.Integer, db.ForeignKey('cme_plans.id'))  #: plan id reference
#     executed = db.Column(db.Boolean)  #: if the job was executed
# 
#     def __init__(self, job_id, next_run_time, plan_id, job_state=None):
#         self.id = job_id
#         self.next_run_time = next_run_time
#         self.job_state = job_state
#         self.plan_id = plan_id
#         self.executed = False
# 
#     def to_dict(self):
#         """
#         Return a :meth:`chaosmonkey.api.hal.document` representation for the Executor
# 
#         :return: :meth:`chaosmonkey.dal.executor_model.HalExecutor`
#         """
# 
#         return HalExecutor(data={
#             "id": self.id,
#             "next_run_time": self.next_run_time.strftime('%Y-%m-%dT%H:%M:%s'),
#             "plan_id": self.plan_id,
#             "executed": self.executed
#         }).to_dict()
# 
#     def __repr__(self):
#         return '<Executor %r>' % self.id
# 
# Path: chaosmonkey/api/api_errors.py
# class APIError(Exception):
#     """
#     Represents an API Error
# 
#     :param message: message to be returned to the user
#     :param status_code: response status code (defaults to 400)
#     :param payload: custom payload to give extra info in the response
# 
#     Example:
#             >>> raise APIError("Error detected", 500, {"extra": "extra_info"})
# 
#     """
# 
#     def __init__(self, message, status_code=None, payload=None):
#         Exception.__init__(self)
#         self.message = message
#         self.status_code = status_code or 400
#         self.payload = payload
# 
#     def to_dict(self):
#         """Convert exception to dict"""
#         dict_ = dict(self.payload or ())
#         dict_['msg'] = self.message
#         return dict_
# 
#     def __str__(self):
#         return '[%d] %s' % (self.status_code, self.message)
# 
# Path: chaosmonkey/modules/module_store.py
# class ModuleLookupError(Exception):
#     """
#     Represent a Module lookup error when a module is not found by its ref
#     """
# 
#     def __init__(self, message):
#         Exception.__init__(self)
#         self.message = message
# 
#     def __str__(self):
#         return '%s' % self.message


import logging
from jsonschema import validate, ValidationError
from chaosmonkey.dal.executor_model import Executor
from chaosmonkey.api.api_errors import APIError
from chaosmonkey.modules.module_store import ModuleLookupError
        from chaosmonkey.attacks.executor import execute
    def get_planner_list(self):
        """
        Return a list with all planners loaded in the self._planners_store

        :return: chaosmonkey.planners.planner.Planner list
        """
        planner_list = [self._planners_store.get(planner_ref).to_dict() for planner_ref in self.planners_store.list()]
        return planner_list

    def execute_plan(self, name, planner_config, attack_config):
        """
        Execute a plan with a planner and executor config to create executors based on the configs

        It also validates the planner and executor config against the modules

        :param name:                Plan name
        :param planner_config:      Dict with planner config
        :param attack_config:       Dict with attack config
        """
        try:
            planner_class = self._planners_store.get(planner_config.get("ref"))
            attack_class = self._attacks_store.get(attack_config.get("ref"))
        except ModuleLookupError as e:
            raise APIError("invalid planner %s" % e.message)

        # Validate both executor and planner configs
        try:
            validate(planner_config.get("args"), planner_class.schema)
            validate(attack_config, attack_class.schema)
        except ValidationError as e:

# Path: chaosmonkey/dal/executor_model.py
# class Executor(db.Model):
#     """
#     Executors are persistent representations of scheduled jobs.
#     This model is shared between the cme and apscheduler.
#     """
# 
#     __tablename__ = 'cme_executors'
# 
#     id = db.Column(db.String(80), primary_key=True)  #: unique identifier
#     next_run_time = db.Column(db.DateTime, index=True)  #: DateTime for the executor to be executed
#     job_state = db.Column(db.LargeBinary, nullable=False)  #: store the full state of the executor (with pickle)
#     plan_id = db.Column(db.Integer, db.ForeignKey('cme_plans.id'))  #: plan id reference
#     executed = db.Column(db.Boolean)  #: if the job was executed
# 
#     def __init__(self, job_id, next_run_time, plan_id, job_state=None):
#         self.id = job_id
#         self.next_run_time = next_run_time
#         self.job_state = job_state
#         self.plan_id = plan_id
#         self.executed = False
# 
#     def to_dict(self):
#         """
#         Return a :meth:`chaosmonkey.api.hal.document` representation for the Executor
# 
#         :return: :meth:`chaosmonkey.dal.executor_model.HalExecutor`
#         """
# 
#         return HalExecutor(data={
#             "id": self.id,
#             "next_run_time": self.next_run_time.strftime('%Y-%m-%dT%H:%M:%s'),
#             "plan_id": self.plan_id,
#             "executed": self.executed
#         }).to_dict()
# 
#     def __repr__(self):
#         return '<Executor %r>' % self.id
# 
# Path: chaosmonkey/api/api_errors.py
# class APIError(Exception):
#     """
#     Represents an API Error
# 
#     :param message: message to be returned to the user
#     :param status_code: response status code (defaults to 400)
#     :param payload: custom payload to give extra info in the response
# 
#     Example:
#             >>> raise APIError("Error detected", 500, {"extra": "extra_info"})
# 
#     """
# 
#     def __init__(self, message, status_code=None, payload=None):
#         Exception.__init__(self)
#         self.message = message
#         self.status_code = status_code or 400
#         self.payload = payload
# 
#     def to_dict(self):
#         """Convert exception to dict"""
#         dict_ = dict(self.payload or ())
#         dict_['msg'] = self.message
#         return dict_
# 
#     def __str__(self):
#         return '[%d] %s' % (self.status_code, self.message)
# 
# Path: chaosmonkey/modules/module_store.py
# class ModuleLookupError(Exception):
#     """
#     Represent a Module lookup error when a module is not found by its ref
#     """
# 
#     def __init__(self, message):
#         Exception.__init__(self)
#         self.message = message
# 
#     def __str__(self):
#         return '%s' % self.message


# Path: chaosmonkey/engine/cme_manager.py
import logging
from jsonschema import validate, ValidationError
from chaosmonkey.dal.executor_model import Executor
from chaosmonkey.api.api_errors import APIError
from chaosmonkey.modules.module_store import ModuleLookupError
        from chaosmonkey.attacks.executor import execute

    def get_planner_list(self):
        """
        Return a list with all planners loaded in the self._planners_store

        :return: chaosmonkey.planners.planner.Planner list
        """
        planner_list = [self._planners_store.get(planner_ref).to_dict() for planner_ref in self.planners_store.list()]
        return planner_list

    def execute_plan(self, name, planner_config, attack_config):
        """
        Execute a plan with a planner and executor config to create executors based on the configs

        It also validates the planner and executor config against the modules

        :param name:                Plan name
        :param planner_config:      Dict with planner config
        :param attack_config:       Dict with attack config
        """
        try:
            planner_class = self._planners_store.get(planner_config.get("ref"))
            attack_class = self._attacks_store.get(attack_config.get("ref"))
        except ModuleLookupError as e:
            raise APIError("invalid planner %s" % e.message)

        # Validate both executor and planner configs
        try:
            validate(planner_config.get("args"), planner_class.schema)
            validate(attack_config, attack_class.schema)
        except ValidationError as e:

            raise APIError("invalid payload %s" % e.message)