Exemplo n.º 1
0
 def __init__(self, executor=MultiprocessedExecutor):
     """Initializes a Controller object.
     
     Args:
         executor (cls, optional): The executor to use in the controller. Defaults to MultiprocessedExecutor
     """
     self.uid = 'controller'
     self.playbook_store = PlaybookStore()
     self.scheduler = Scheduler()
     self.executor = executor()
Exemplo n.º 2
0
 def setUp(self):
     self.store = PlaybookStore()
     self.loader = MockPlaybookLoader()
Exemplo n.º 3
0
class TestPlaybookStore(TestCase):

    def setUp(self):
        self.store = PlaybookStore()
        self.loader = MockPlaybookLoader()

    def assertStoreKeysEqual(self, keys):
        self.assertSetEqual(set(self.store.playbooks.keys()), set(keys))

    def assertPlaybookHasWorkflowName(self, playbook_name, workflow_name):
        self.assertTrue(self.store.playbooks[playbook_name].has_workflow_name(workflow_name))

    def assertPlaybookWorkflowNamesEqual(self, playbook_name, workflows):
        self.assertSetEqual(set(self.store.playbooks[playbook_name].get_all_workflow_names()), set(workflows))

    def test_init(self):
        self.assertDictEqual(self.store.playbooks, {})

    def test_load_workflow_not_found(self):
        self.assertIsNone(self.store.load_workflow('test1', 'invalid', loader=self.loader))

    def test_load_workflow_playbook_not_in_store_empty_store(self):
        self.store.load_workflow('play1', 'work1', loader=self.loader)
        self.assertIn('play1', self.store.playbooks)
        self.assertPlaybookWorkflowNamesEqual('play1', {'work1'})

    def test_load_workflow_playbook_not_in_store(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.store.load_workflow('play2', 'work3', loader=self.loader)
        self.assertIn('play2', self.store.playbooks)
        self.assertPlaybookWorkflowNamesEqual('play2', {'work3'})

    def test_load_workflow_playbook_in_storage_new_workflows(self):
        copied_playbook = deepcopy(self.loader.playbook1)
        copied_playbook.remove_workflow_by_name('work1')
        self.store.playbooks['play1'] = copied_playbook
        self.store.load_workflow('play1', 'work1', loader=self.loader)
        self.assertIn('play1', self.store.playbooks)
        self.assertPlaybookWorkflowNamesEqual('play1', {'work1', 'work2'})

    def test_load_workflow_playbook_in_storage_workflow_in_storage(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.store.load_workflow('play1', 'work1', loader=self.loader)
        self.assertIn('play1', self.store.playbooks)
        self.assertPlaybookWorkflowNamesEqual('play1', {'work1', 'work2'})

    def test_load_playbook_not_found_none_in_store(self):
        self.store.load_playbook('invalid', loader=self.loader)
        self.assertDictEqual(self.store.playbooks, {})

    def test_load_playbook_not_found_some_in_store(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.store.load_playbook('invalid', loader=self.loader)
        self.assertStoreKeysEqual({'play1'})

    def test_load_playbook_not_in_store(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.store.load_playbook('play2', loader=self.loader)
        self.assertStoreKeysEqual({'play1', 'play2'})

    def test_load_playbook_already_in_store(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.store.load_playbook('play1', loader=self.loader)
        self.assertStoreKeysEqual({'play1'})
        self.assertPlaybookWorkflowNamesEqual('play1', {'work1', 'work2'})

    def test_add_playbook_no_playbooks(self):
        self.store.add_playbook(self.loader.playbook1)
        self.assertStoreKeysEqual({'play1'})
        self.assertEqual(self.store.playbooks['play1'], self.loader.playbook1)

    def test_add_playbook_some_playbooks(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.store.add_playbook(self.loader.playbook2)
        self.assertStoreKeysEqual({'play1', 'play2'})
        self.assertEqual(self.store.playbooks['play2'], self.loader.playbook2)

    def test_add_playbook_same_playbook(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.store.add_playbook(self.loader.playbook1)
        self.assertStoreKeysEqual({'play1'})
        self.assertEqual(self.store.playbooks['play1'], self.loader.playbook1)

    def test_add_workflow_no_playbooks(self):
        workflow = Workflow('work1')
        self.store.add_workflow('play1', workflow)
        self.assertStoreKeysEqual({'play1'})
        self.assertListEqual(list(self.store.playbooks['play1'].workflows.values()), [workflow])

    def test_add_workflow_playbook_in_store(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        workflow = Workflow('work3')
        self.store.add_workflow('play1', workflow)
        self.assertStoreKeysEqual({'play1'})
        self.assertPlaybookHasWorkflowName('play1', 'work3')

    def test_add_workflow_playbook_not_in_store(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        workflow = Workflow('work3')
        self.store.add_workflow('play2', workflow)
        self.assertSetEqual(set(self.store.playbooks.keys()), {'play1', 'play2'})
        self.assertListEqual(list(self.store.playbooks['play2'].workflows.values()), [workflow])

    def test_load_playbooks(self):
        self.store.load_playbooks('resource', loader=self.loader)
        self.assertStoreKeysEqual({'play1', 'play2'})

    def test_create_workflow(self):
        self.store.create_workflow('play1', 'work1')
        self.assertStoreKeysEqual({'play1'})
        self.assertPlaybookHasWorkflowName('play1', 'work1')

    def test_create_workflow_playbook_exists(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.store.create_workflow('play1', 'work3')
        self.assertStoreKeysEqual({'play1'})
        self.assertPlaybookWorkflowNamesEqual('play1', {'work1', 'work2', 'work3'})

    def test_create_workflow_playbook_workflow_exist(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        original_uid = self.store.playbooks['play1'].get_workflow_by_name('work1').uid
        self.store.create_workflow('play1', 'work1')
        self.assertNotEqual(self.store.playbooks['play1'].get_workflow_by_name('work1').uid, original_uid)

    def test_create_playbook_empty_store_no_workflows(self):
        self.store.create_playbook('play1')
        self.assertStoreKeysEqual({'play1'})
        self.assertListEqual(list(self.store.playbooks['play1'].workflows.values()), [])

    def test_create_playbook_empty_store_with_workflows(self):
        workflow = Workflow('work1')
        self.store.create_playbook('play1', [workflow])
        self.assertStoreKeysEqual({'play1'})
        self.assertListEqual(list(self.store.playbooks['play1'].workflows.values()), [workflow])

    def test_create_playbook_nonempty_store_no_workflows(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.store.create_playbook('play2')
        self.assertStoreKeysEqual({'play1', 'play2'})
        self.assertListEqual(list(self.store.playbooks['play2'].workflows.values()), [])

    def test_create_playbook_nonempty_store_with_workflows(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        workflow = Workflow('work1')
        self.store.create_playbook('play2', [workflow])
        self.assertStoreKeysEqual({'play1', 'play2'})
        self.assertListEqual(list(self.store.playbooks['play2'].workflows.values()), [workflow])

    def test_create_playbook_playbook_already_exists(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        workflow = Workflow('work3')
        self.store.create_playbook('play1', workflows=[workflow])
        self.assertStoreKeysEqual({'play1'})
        self.assertPlaybookWorkflowNamesEqual('play1', {'work3'})

    def test_remove_workflow(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.assertTrue(self.store.remove_workflow('play1', 'work1'))
        self.assertStoreKeysEqual({'play1'})
        self.assertPlaybookWorkflowNamesEqual('play1', {'work2'})

    def test_remove_workflow_workflow_not_found(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.assertFalse(self.store.remove_workflow('play1', 'invalid'))
        self.assertStoreKeysEqual({'play1'})
        self.assertPlaybookWorkflowNamesEqual('play1', {'work1', 'work2'})

    def test_remove_workflow_playbook_not_found(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.assertFalse(self.store.remove_workflow('invalid', 'work1'))
        self.assertStoreKeysEqual({'play1'})
        self.assertPlaybookWorkflowNamesEqual('play1', {'work1', 'work2'})

    def test_remove_workflow_empty_store(self):
        self.assertFalse(self.store.remove_workflow('play1', 'work1'))
        self.assertStoreKeysEqual(set())

    def test_remove_playbook_empty_store(self):
        self.assertFalse(self.store.remove_playbook('play1'))
        self.assertStoreKeysEqual(set())

    def test_remove_playbook_playbook_not_found(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.assertFalse(self.store.remove_playbook('invalid'))
        self.assertStoreKeysEqual({'play1'})

    def test_remove_playbook(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.assertTrue(self.store.remove_playbook('play1'))
        self.assertStoreKeysEqual(set())

    def test_get_all_workflows_with_representations_empty_store(self):
        self.assertListEqual(self.store.get_all_workflows(full_representations=True), [])

    def test_get_all_workflows_with_limited_representations_empty_store(self):
        self.assertListEqual(self.store.get_all_workflows(), [])

    def test_get_all_workflows_with_representations(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.assertListEqual(self.store.get_all_workflows(full_representations=True), [self.loader.playbook1.read()])

    def test_get_all_workflows_with_limited_representations(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        expected = [{'name': 'play1', 'workflows': [{'name': workflow.name, 'uid': workflow.uid}
                                                   for workflow in self.loader.playbook1.workflows.values()]}]
        self.assertListEqual(self.store.get_all_workflows(), expected)

    def test_get_all_workflows_with_representation_custom_reader(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.assertListEqual(self.store.get_all_workflows(full_representations=True, reader=MockElementReader),
                             [id(self.loader.playbook1)])

    def test_get_all_playbooks_empty_store(self):
        self.assertListEqual(self.store.get_all_playbooks(), [])

    def test_get_all_playbooks(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.store.playbooks['play2'] = self.loader.playbook2
        self.assertSetEqual(set(self.store.get_all_playbooks()), {'play1', 'play2'})

    def test_is_workflow_registered(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.assertTrue(self.store.is_workflow_registered('play1', 'work1'))

    def test_is_workflow_registered_empty_store(self):
        self.assertFalse(self.store.is_workflow_registered('play1', 'work1'))

    def test_is_workflow_registered_invalid_playbook(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.assertFalse(self.store.is_workflow_registered('invalid', 'work1'))

    def test_is_workflow_registered_invalid_workflow(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.assertFalse(self.store.is_workflow_registered('play1', 'invalid'))

    def test_is_playbook_registered_empty_store(self):
        self.assertFalse(self.store.is_playbook_registered('play1'))

    def test_is_playbook_registered(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.assertTrue(self.store.is_playbook_registered('play1'))

    def test_is_playbook_registered_invalid_playbook(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.assertFalse(self.store.is_playbook_registered('invalid'))

    def test_update_workflow_name_empty_store(self):
        self.store.update_workflow_name('old_playbook', 'old_workflow', 'new_playbook', 'new_workflow')
        self.assertStoreKeysEqual(set())

    def test_update_workflow_name_invalid_playbook(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.store.update_workflow_name('invalid', 'work1', 'new_playbook', 'new_workflow')
        self.assertStoreKeysEqual({'play1'})
        self.assertPlaybookWorkflowNamesEqual('play1', {'work1', 'work2'})

    def test_update_workflow_name_invalid_workflow(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.store.update_workflow_name('play1', 'invalid', 'new_playbook', 'new_workflow')
        self.assertStoreKeysEqual({'play1'})
        self.assertPlaybookWorkflowNamesEqual('play1', {'work1', 'work2'})

    def test_update_workflow_name_same_playbook_same_workflow(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.store.update_workflow_name('play1', 'work1', 'play1', 'work1')
        self.assertStoreKeysEqual({'play1'})
        self.assertPlaybookWorkflowNamesEqual('play1', {'work1', 'work2'})

    def test_update_workflow_name_same_playbook(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.store.update_workflow_name('play1', 'work1', 'play1', 'renamed')
        self.assertStoreKeysEqual({'play1'})
        self.assertPlaybookWorkflowNamesEqual('play1', {'renamed', 'work2'})

    def test_update_workflow_name_new_playbook(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.store.update_workflow_name('play1', 'work1', 'play2', 'renamed')
        self.assertStoreKeysEqual({'play1', 'play2'})
        self.assertPlaybookWorkflowNamesEqual('play1', {'work2'})
        self.assertPlaybookWorkflowNamesEqual('play2', {'renamed'})

    def test_update_playbook_name_empty_store(self):
        self.store.update_playbook_name('old_playbook', 'new_playbook')
        self.assertStoreKeysEqual(set())

    def test_update_playbook_name_invalid_playbook(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.store.update_playbook_name('invalid', 'renamed')
        self.assertStoreKeysEqual({'play1'})

    def test_update_playbook_name(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.store.update_playbook_name('play1', 'renamed')
        self.assertStoreKeysEqual({'renamed'})
        self.assertEqual(self.store.playbooks['renamed'], self.loader.playbook1)

    def test_get_workflow_empty_store(self):
        self.assertIsNone(self.store.get_workflow('play1', 'work1'))

    def test_get_workflow_invalid_playbook(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.assertIsNone(self.store.get_workflow('invalid', 'work1'))

    def test_get_workflow_invalid_workflow(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.assertIsNone(self.store.get_workflow('play1', 'invalid'))

    def test_get_workflow(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        workflow = self.loader.playbook1.get_workflow_by_name('work1')
        self.assertEqual(self.store.get_workflow('play1', 'work1'), workflow)

    def test_get_playbook_empty_store(self):
        self.assertIsNone(self.store.get_playbook('play1'))

    def test_get_playbook_invalid_playbook(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.assertIsNone(self.store.get_playbook('invalid'))

    def test_get_playbook(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.store.playbooks['play2'] = self.loader.playbook2
        self.assertEqual(self.store.get_playbook('play1'), self.loader.playbook1)

    def test_get_all_workflows_by_playbook_empty_store(self):
        self.assertListEqual(self.store.get_all_workflows_by_playbook('play1'), [])

    def test_get_all_workflows_by_playbook_invalid_playbook(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.assertListEqual(self.store.get_all_workflows_by_playbook('invalid'), [])

    def test_get_all_workflows_by_playbook(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.store.playbooks['play2'] = self.loader.playbook2
        self.assertSetEqual(set(self.store.get_all_workflows_by_playbook('play2')), {'work1', 'work3'})

    def test_playbook_representation_empty_store(self):
        self.assertIsNone(self.store.get_playbook_representation('play1'))

    def test_playbook_representation_invalid_playbook(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.store.playbooks['play2'] = self.loader.playbook2
        self.assertIsNone(self.store.get_playbook_representation('invalid'))

    def test_playbook_representation(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.store.playbooks['play2'] = self.loader.playbook2
        self.assertDictEqual(self.store.get_playbook_representation('play1'), self.loader.playbook1.read())

    def test_playbook_representation_custom_reader(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.store.playbooks['play2'] = self.loader.playbook2
        self.assertEqual(id(self.loader.playbook1), self.loader.playbook1.read(reader=MockElementReader))

    def test_copy_workflow_empty_store(self):
        self.store.copy_workflow('old_playbook', 'new_playbook', 'old_workflow', 'new_workflow')
        self.assertStoreKeysEqual(set())

    def test_copy_workflow_invalid_playbook(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.store.playbooks['play2'] = self.loader.playbook2
        self.store.copy_workflow('invalid', 'play1', 'old_workflow', 'new_workflow')
        self.assertStoreKeysEqual({'play1', 'play2'})
        self.assertPlaybookWorkflowNamesEqual('play1', {'work1', 'work2'})

    def test_copy_workflow_invalid_workflow(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.store.playbooks['play2'] = self.loader.playbook2
        self.store.copy_workflow('play1', 'play3', 'invalid', 'new_workflow')
        self.assertStoreKeysEqual({'play1', 'play2'})
        self.assertPlaybookWorkflowNamesEqual('play1', {'work1', 'work2'})

    def test_copy_workflow_same_playbook_same_workflow(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.store.playbooks['play2'] = self.loader.playbook2
        self.store.copy_workflow('play1', 'play1', 'work1', 'work1')
        self.assertStoreKeysEqual({'play1', 'play2'})
        self.assertPlaybookWorkflowNamesEqual('play1', {'work1', 'work2'})

    def test_copy_workflow_same_playbook(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.store.playbooks['play2'] = self.loader.playbook2
        self.store.copy_workflow('play1', 'play1', 'work1', 'new_work')
        self.assertStoreKeysEqual({'play1', 'play2'})
        self.assertPlaybookWorkflowNamesEqual('play1', {'work1', 'work2', 'new_work'})

    def test_copy_workflow_new_playbook_new_playbook_does_not_exist(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.store.playbooks['play2'] = self.loader.playbook2
        self.store.copy_workflow('play1', 'play3', 'work1', 'new_work')
        self.assertStoreKeysEqual({'play1', 'play2', 'play3'})
        self.assertPlaybookWorkflowNamesEqual('play1', {'work1', 'work2'})
        self.assertPlaybookWorkflowNamesEqual('play3', {'new_work'})

    def test_copy_workflow_new_playbook_new_playbook_already_exists(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.store.playbooks['play2'] = self.loader.playbook2
        self.store.copy_workflow('play1', 'play2', 'work1', 'new_work')
        self.assertStoreKeysEqual({'play1', 'play2'})
        self.assertPlaybookWorkflowNamesEqual('play1', {'work1', 'work2'})
        self.assertPlaybookWorkflowNamesEqual('play2', {'work1', 'work3', 'new_work'})

    def test_copy_playbook_empty_store(self):
        self.store.copy_playbook('old_playbook', 'new_playbook')
        self.assertStoreKeysEqual(set())

    def test_copy_playbook_invalid_playbook(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.store.playbooks['play2'] = self.loader.playbook2
        self.store.copy_playbook('invalid', 'new_playbook')
        self.assertStoreKeysEqual({'play1', 'play2'})

    def test_copy_playbook(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.store.playbooks['play2'] = self.loader.playbook2
        original_uid = self.loader.playbook1.uid
        self.store.copy_playbook('play1', 'play3')
        self.assertStoreKeysEqual({'play1', 'play2', 'play3'})
        self.assertPlaybookWorkflowNamesEqual('play3', {'work1', 'work2'})
        self.assertNotEqual(self.store.playbooks['play3'].uid, original_uid)

    def test_copy_playbook_new_playbook_already_exists(self):
        self.store.playbooks['play1'] = self.loader.playbook1
        self.store.playbooks['play2'] = self.loader.playbook2
        original_uid = self.loader.playbook1.uid
        self.store.copy_playbook('play1', 'play2')
        self.assertStoreKeysEqual({'play1', 'play2'})
        self.assertPlaybookWorkflowNamesEqual('play2', {'work1', 'work2'})
        self.assertNotEqual(self.store.playbooks['play2'].uid, original_uid)
Exemplo n.º 4
0
class Controller(object):
    def __init__(self, executor=MultiprocessedExecutor):
        """Initializes a Controller object.
        
        Args:
            executor (cls, optional): The executor to use in the controller. Defaults to MultiprocessedExecutor
        """
        self.uid = 'controller'
        self.playbook_store = PlaybookStore()
        self.scheduler = Scheduler()
        self.executor = executor()

    def initialize_threading(self, worker_environment_setup=None):
        """Initializes threading in the executor
        """
        self.executor.initialize_threading(
            worker_environment_setup=worker_environment_setup)

    def shutdown_pool(self, num_workflows=0):
        """Shuts down the executor

        Args:
            num_workflows (int, optional): Number of workflows to wait to complete before shutting down. Defaults to 0,
                meaning that it will immediately shutdown the pool upon receiving this command.
        """
        self.executor.shutdown_pool(num_workflows=num_workflows)

    def pause_workflow(self, execution_uid):
        """Pauses a workflow.

        Args:
            execution_uid (str): The execution UID of the workflow to pause
        """
        self.executor.pause_workflow(execution_uid)

    def resume_workflow(self, workflow_execution_uid):
        """Resumes a workflow that has been paused.

        Args:
            workflow_execution_uid (str): The randomly-generated hexadecimal key that was returned from
                pause_workflow(). This is needed to resume a workflow for security purposes.

        Returns:
            (bool) True if successful, False otherwise.
        """
        return self.executor.resume_workflow(workflow_execution_uid)

    def load_workflow(self, resource, workflow_name):
        """Loads a workflow from a file.

        Args:
            resource (str): Path to the workflow.
            workflow_name (str): Name of the workflow to load.

        Returns:
            True on success, False otherwise.
        """
        return self.playbook_store.load_workflow(resource, workflow_name)

    def load_playbook(self, resource):
        """Loads playbook from a file.

        Args:
            resource (str): Path to the workflow.
        """
        return self.playbook_store.load_playbook(resource)

    def load_playbooks(self, resource_collection=None):
        """Loads all playbooks from a directory.

        Args:
            resource_collection (str, optional): Path to the directory to load from. Defaults to the
                configuration workflows_path.
        """
        return self.playbook_store.load_playbooks(resource_collection)

    def schedule_workflows(self, task_id, workflow_uids, trigger):
        """Schedules workflows to be run by the scheduler

        Args:
            task_id (str|int): Id of the task to run
            workflow_uids (list[str]): UIDs of the workflows to schedule
            trigger: The type of scheduler trigger to use
        """
        playbook_workflows = self.playbook_store.get_workflows_by_uid(
            workflow_uids)
        schedule_workflows = []
        for playbook_name, workflows in playbook_workflows.items():
            for workflow in workflows:
                schedule_workflows.append(
                    (playbook_name, workflow.name, workflow.uid))
        self.scheduler.schedule_workflows(task_id, self.execute_workflow,
                                          schedule_workflows, trigger)

    def create_workflow(self, playbook_name, workflow_name):
        """Creates a workflow from a workflow template.
        
        Args:
            playbook_name (str): The name of the new playbook. 
            workflow_name (str): The name of the new workflow.

        Returns:
            True on success, False if otherwise.
        """
        return self.playbook_store.create_workflow(playbook_name,
                                                   workflow_name)

    def create_playbook(self, playbook_name, workflows=None):
        """Creates a playbook from a playbook template.

        Args:
            playbook_name (str): The name of the new playbook.
            workflows (list[Workflow], optional): An optional list of Workflows to be associated with this
                Playbook. Defaults to None.
        """
        return self.playbook_store.create_playbook(playbook_name, workflows)

    def remove_workflow(self, playbook_name, workflow_name):
        """Removes a workflow.
        
        Args:
            playbook_name (str): Playbook name under which the workflow is located.
            workflow_name (str): The name of the workflow to remove.
            
        Returns:
            True on success, False otherwise.
        """
        self.playbook_store.remove_workflow(playbook_name, workflow_name)

    def remove_playbook(self, playbook_name):
        """Removes a playbook and all workflows within it.
        
        Args:
            playbook_name (str): The name of the playbook to remove.
            
        Returns:
            True on success, False otherwise.
        """
        self.playbook_store.remove_playbook(playbook_name)

    def get_all_workflows(self, full_representation=False, reader=None):
        """Gets all of the currently loaded workflows.

        Args:
            full_representation (bool, optional): A boolean specifying whether or not to include the JSON representation
                of all the workflows, or just their names. Defaults to False.
            reader (cls): The reader to specify how to display the Workflows. Defaults to None, which will show
                basic JSON representation of the Workflows.
        
        Returns:
            A dict with key being the playbook, mapping to a list of workflow names for each playbook.
        """
        return self.playbook_store.get_all_workflows(full_representation,
                                                     reader=reader)

    def get_all_playbooks(self):
        """Gets a list of all playbooks.
        
        Returns:
            A list containing all currently loaded playbook names.
        """
        return self.playbook_store.get_all_playbooks()

    def is_workflow_registered(self, playbook_name, workflow_name):
        """Checks whether or not a workflow is currently registered in the system.
        
        Args:
            playbook_name (str): Playbook name under which the workflow is located.
            workflow_name (str): The name of the workflow.
            
        Returns:
            True if the workflow is registered, false otherwise.
        """
        return self.playbook_store.is_workflow_registered(
            playbook_name, workflow_name)

    def is_playbook_registered(self, playbook_name):
        """Checks whether or not a playbook is currently registered in the system.
        
        Args:
            playbook_name (str): The name of the playbook.
            
        Returns:
            True if the playbook is registered, false otherwise.
        """
        return self.playbook_store.is_playbook_registered(playbook_name)

    def update_workflow_name(self, old_playbook, old_workflow, new_playbook,
                             new_workflow):
        """Update the name of a workflow.
        
        Args:
            old_playbook (str): Name of the current playbook.
            old_workflow (str): Name of the current workflow.
            new_playbook (str): The new name of the playbook.
            new_workflow (str): The new name of the workflow.
        """
        self.playbook_store.update_workflow_name(old_playbook, old_workflow,
                                                 new_playbook, new_workflow)

    def update_playbook_name(self, old_playbook, new_playbook):
        """Update the name of a playbook.
        
        Args:
            old_playbook (str): Name of the current playbook.
            new_playbook (str): The new name of the playbook.
        """
        self.playbook_store.update_playbook_name(old_playbook, new_playbook)

    def execute_workflow(self,
                         playbook_name,
                         workflow_name,
                         start=None,
                         start_input=None):
        """Executes a workflow.

        Args:
            playbook_name (str): Playbook name under which the workflow is located.
            workflow_name (str): Workflow to execute.
            start (str, optional): The name of the first, or starting step. Defaults to None.
            start_input (dict, optional): The input to the starting step of the workflow. Defaults to None.

        Returns:
            The execution UID if successful, None otherwise.
        """
        if self.playbook_store.is_workflow_registered(playbook_name,
                                                      workflow_name):
            workflow = self.playbook_store.get_workflow(
                playbook_name, workflow_name)
            return self.executor.execute_workflow(workflow, start, start_input)
        else:
            logger.error(
                'Attempted to execute playbook which does not exist in controller'
            )
            return None, 'Attempted to execute playbook which does not exist in controller'

    def get_waiting_workflows(self):
        return self.executor.get_waiting_workflows()

    def get_workflow(self, playbook_name, workflow_name):
        """Get a workflow object.
        
        Args:
            playbook_name (str): Playbook name under which the workflow is located.
            workflow_name (str): The name of the workflow.
            
        Returns:
            The workflow object if found, else None.
        """
        return self.playbook_store.get_workflow(playbook_name, workflow_name)

    def get_all_workflows_by_playbook(self, playbook_name):
        """Get a list of all workflow objects in a playbook.
        
        Args:
            playbook_name: The name of the playbook.
            
        Returns:
            A list of all workflow objects in a playbook.
        """
        return self.playbook_store.get_all_workflows_by_playbook(playbook_name)

    def get_playbook_representation(self, playbook_name, reader=None):
        """Returns the JSON representation of a playbook.

        Args:
            playbook_name: The name of the playbook.
            reader (cls, optional): An optional different way to represent the Playbook. Defaults to None,
                meaning that it will show basic JSON representation.

        Returns:
            The JSON representation of the playbook if the playbook has any workflows under it, else None.
        """
        return self.playbook_store.get_playbook_representation(playbook_name,
                                                               reader=reader)

    def copy_workflow(self, old_playbook_name, new_playbook_name,
                      old_workflow_name, new_workflow_name):
        """Duplicates a workflow into its current playbook, or a different playbook.
        
        Args:
            old_playbook_name (str): Playbook name under which the workflow is located.
            new_playbook_name (str): The new playbook name for the duplicated workflow.
            old_workflow_name (str): The name of the workflow to be copied.
            new_workflow_name (str): The new name of the duplicated workflow.
        """
        self.playbook_store.copy_workflow(old_playbook_name, new_playbook_name,
                                          old_workflow_name, new_workflow_name)

    def copy_playbook(self, old_playbook_name, new_playbook_name):
        """Copies a playbook.
        
        Args:
            old_playbook_name (str): The name of the playbook to be copied.
            new_playbook_name (str): The new name of the duplicated playbook.
        """
        self.playbook_store.copy_playbook(old_playbook_name, new_playbook_name)

    def send_data_to_trigger(self, data_in, workflow_uids, inputs=None):
        """Tries to match the data in against the conditionals of all the triggers registered in the database.

        Args:
            data_in (dict): Data to be used to match against the triggers for a Step awaiting data.
            workflow_uids (list[str]): A list of workflow execution UIDs to send this data to.
            inputs (dict, optional): An optional dict of inputs to update for a Step awaiting data for a trigger.
                Defaults to {}.

        Returns:
            Dictionary of {"status": <status string>}
        """
        inputs = inputs if inputs is not None else {}
        if workflow_uids is not None:
            self.executor.send_data_to_trigger(data_in, workflow_uids, inputs)

    def get_workflow_status(self, execution_uid):
        """Gets the status of an executing workflow

        Args:
            execution_uid (str): Execution UID of the executing workflow

        Returns:
            (int) Status code of the executing workflow
        """
        return self.executor.get_workflow_status(execution_uid)