Parcourir la source

Remove minion pool tasks executions.

Nashwan Azhari il y a 5 ans
Parent
commit
e1a70c86f3

+ 12 - 44
coriolis/api/v1/minion_pool_actions.py

@@ -4,7 +4,7 @@
 from webob import exc
 
 from coriolis import exception
-from coriolis.api.v1.views import minion_pool_tasks_execution_view
+from coriolis.api.v1.views import minion_pool_view
 from coriolis.api import wsgi as api_wsgi
 from coriolis.policies import minion_pools as minion_pool_policies
 from coriolis.minion_pools import api
@@ -15,63 +15,31 @@ class MinionPoolActionsController(api_wsgi.Controller):
         self.minion_pool_api = api.API()
         super(MinionPoolActionsController, self).__init__()
 
-    @api_wsgi.action('set-up-shared-resources')
-    def _set_up_shared_resources(self, req, id, body):
+    @api_wsgi.action('allocate')
+    def _allocate_pool(self, req, id, body):
         context = req.environ['coriolis.context']
         context.can(
             minion_pool_policies.get_minion_pools_policy_label(
-                "set_up_shared_resources"))
+                "allocate"))
         try:
-            return minion_pool_tasks_execution_view.single(
-                req, self.minion_pool_api.set_up_shared_pool_resources(
+            return minion_pool_view.single(
+                req, self.minion_pool_api.allocate_minion_pool(
                     context, id))
         except exception.NotFound as ex:
             raise exc.HTTPNotFound(explanation=ex.msg)
         except exception.InvalidParameterValue as ex:
             raise exc.HTTPNotFound(explanation=ex.msg)
 
-    @api_wsgi.action('tear-down-shared-resources')
-    def _tear_down_shared_resources(self, req, id, body):
+    @api_wsgi.action('deallocate')
+    def _deallocate_pool(self, req, id, body):
         context = req.environ['coriolis.context']
         context.can(
             minion_pool_policies.get_minion_pools_policy_label(
-                "tear_down_shared_resources"))
-        force = (body["tear-down-shared-resources"] or {}).get(
-            "force", False)
+                "deallocate"))
+        force = (body["deallocate"] or {}).get("force", False)
         try:
-            return minion_pool_tasks_execution_view.single(
-                req, self.minion_pool_api.tear_down_shared_pool_resources(
-                    context, id, force=force))
-        except exception.NotFound as ex:
-            raise exc.HTTPNotFound(explanation=ex.msg)
-        except exception.InvalidParameterValue as ex:
-            raise exc.HTTPNotFound(explanation=ex.msg)
-
-    @api_wsgi.action('allocate-machines')
-    def _allocate_pool_machines(self, req, id, body):
-        context = req.environ['coriolis.context']
-        context.can(
-            minion_pool_policies.get_minion_pools_policy_label(
-                "allocate_machines"))
-        try:
-            return minion_pool_tasks_execution_view.single(
-                req, self.minion_pool_api.allocate_machines(
-                    context, id))
-        except exception.NotFound as ex:
-            raise exc.HTTPNotFound(explanation=ex.msg)
-        except exception.InvalidParameterValue as ex:
-            raise exc.HTTPNotFound(explanation=ex.msg)
-
-    @api_wsgi.action('deallocate-machines')
-    def _deallocate_pool_machines(self, req, id, body):
-        context = req.environ['coriolis.context']
-        context.can(
-            minion_pool_policies.get_minion_pools_policy_label(
-                "deallocate_machines"))
-        force = (body["deallocate-machines"] or {}).get("force", False)
-        try:
-            return minion_pool_tasks_execution_view.single(
-                req, self.minion_pool_api.deallocate_machines(
+            return minion_pool_view.single(
+                req, self.minion_pool_api.deallocate_minion_pool(
                     context, id, force=force))
         except exception.NotFound as ex:
             raise exc.HTTPNotFound(explanation=ex.msg)

+ 0 - 37
coriolis/api/v1/minion_pool_tasks_execution_actions.py

@@ -1,37 +0,0 @@
-# Copyright 2016 Cloudbase Solutions Srl
-# All Rights Reserved.
-
-from webob import exc
-
-from coriolis import exception
-from coriolis.api import wsgi as api_wsgi
-from coriolis.policies \
-    import minion_pool_tasks_executions as pool_execution_policies
-from coriolis.minion_pool_tasks_executions import api
-
-
-class MinionPoolTasksExecutionActionsController(api_wsgi.Controller):
-    def __init__(self):
-        self._minion_pool_tasks_executions_api = api.API()
-        super(MinionPoolTasksExecutionActionsController, self).__init__()
-
-    @api_wsgi.action('cancel')
-    def _cancel(self, req, minion_pool_id, id, body):
-        context = req.environ['coriolis.context']
-        context.can(
-            pool_execution_policies.get_minion_pool_executions_policy_label(
-                'cancel'))
-        try:
-            force = (body["cancel"] or {}).get("force", False)
-
-            self._minion_pool_tasks_executions_api.cancel(
-                context, minion_pool_id, id, force)
-            raise exc.HTTPNoContent()
-        except exception.NotFound as ex:
-            raise exc.HTTPNotFound(explanation=ex.msg)
-        except exception.InvalidParameterValue as ex:
-            raise exc.HTTPNotFound(explanation=ex.msg)
-
-
-def create_resource():
-    return api_wsgi.Resource(MinionPoolTasksExecutionActionsController())

+ 0 - 65
coriolis/api/v1/minion_pool_tasks_executions.py

@@ -1,65 +0,0 @@
-# Copyright 2016 Cloudbase Solutions Srl
-# All Rights Reserved.
-
-from webob import exc
-
-from coriolis.api import wsgi as api_wsgi
-from coriolis.api.v1.views import minion_pool_tasks_execution_view
-from coriolis import exception
-from coriolis.minion_pool_tasks_executions import api
-from coriolis.policies \
-    import minion_pool_tasks_executions as pool_execution_policies
-
-
-class MinionPoolTasksExecutionController(api_wsgi.Controller):
-    def __init__(self):
-        self._pool_tasks_execution_api = api.API()
-        super(MinionPoolTasksExecutionController, self).__init__()
-
-    def show(self, req, minion_pool_id, id):
-        context = req.environ["coriolis.context"]
-        context.can(
-            pool_execution_policies.get_minion_pool_executions_policy_label(
-                "show"))
-        execution = self._pool_tasks_execution_api.get(
-            context, minion_pool_id, id)
-        if not execution:
-            raise exc.HTTPNotFound()
-
-        return minion_pool_tasks_execution_view.single(req, execution)
-
-    def index(self, req, minion_pool_id):
-        context = req.environ["coriolis.context"]
-        context.can(
-            pool_execution_policies.get_minion_pool_executions_policy_label(
-                "list"))
-
-        return minion_pool_tasks_execution_view.collection(
-            req, self._pool_tasks_execution_api.list(
-                context, minion_pool_id, include_tasks=False))
-
-    def detail(self, req, minion_pool_id):
-        context = req.environ["coriolis.context"]
-        context.can(
-            pool_execution_policies.get_minion_pool_executions_policy_label(
-                "show"))
-        return minion_pool_tasks_execution_view.collection(
-            req, self._pool_tasks_execution_api.list(
-                req.environ['coriolis.context'], minion_pool_id,
-                include_tasks=True))
-
-    def delete(self, req, minion_pool_id, id):
-        context = req.environ["coriolis.context"]
-        context.can(
-            pool_execution_policies.get_minion_pool_executions_policy_label(
-                "delete"))
-
-        try:
-            self._pool_tasks_execution_api.delete(context, minion_pool_id, id)
-            raise exc.HTTPNoContent()
-        except exception.NotFound as ex:
-            raise exc.HTTPNotFound(explanation=ex.msg)
-
-
-def create_resource():
-    return api_wsgi.Resource(MinionPoolTasksExecutionController())

+ 0 - 22
coriolis/api/v1/router.py

@@ -18,8 +18,6 @@ from coriolis.api.v1 import migration_actions
 from coriolis.api.v1 import migrations
 from coriolis.api.v1 import minion_pools
 from coriolis.api.v1 import minion_pool_actions
-from coriolis.api.v1 import minion_pool_tasks_executions
-from coriolis.api.v1 import minion_pool_tasks_execution_actions
 from coriolis.api.v1 import provider_schemas
 from coriolis.api.v1 import providers
 from coriolis.api.v1 import regions
@@ -81,26 +79,6 @@ class APIRouter(api.APIRouter):
                        action='action',
                        conditions={'method': 'POST'})
 
-        self.resources['minion_pool_tasks_executions'] = \
-            minion_pool_tasks_executions.create_resource()
-        mapper.resource('minion_pools', 'minion_pools/{minion_pool_id}/executions',
-                        controller=self.resources['minion_pool_tasks_executions'],
-                        collection={'detail': 'GET'},
-                        member={'action': 'POST'})
-
-        minion_pool_tasks_execution_actions_resource = \
-            minion_pool_tasks_execution_actions.create_resource()
-        self.resources['minion_pool_tasks_execution_actions'] = \
-            minion_pool_tasks_execution_actions_resource
-        pool_execution_path = (
-            '/{project_id}/minion_pools/{minion_pool_id}/executions/{id}')
-        mapper.connect('minion_pool_tasks_execution_actions',
-                       pool_execution_path + '/actions',
-                       controller=self.resources[
-                           'minion_pool_tasks_execution_actions'],
-                       action='action',
-                       conditions={'method': 'POST'})
-
         self.resources['endpoint_source_minion_pool_options'] = \
             endpoint_source_minion_pool_options.create_resource()
         mapper.resource('minion_pool_options',

+ 0 - 45
coriolis/api/v1/views/minion_pool_tasks_execution_view.py

@@ -1,45 +0,0 @@
-# Copyright 2016 Cloudbase Solutions Srl
-# All Rights Reserved.
-
-import itertools
-
-from coriolis import constants
-from coriolis import utils
-
-
-def _sort_tasks(tasks, filter_error_only_tasks=True):
-    """ Sorts the given list of dicts representing tasks.
-    Tasks are sorted primarily based on their index.
-    """
-    if filter_error_only_tasks:
-        tasks = [
-            t for t in tasks
-            if t['status'] != (
-                constants.TASK_STATUS_ON_ERROR_ONLY)]
-    return sorted(
-        tasks, key=lambda t: t.get('index', 0))
-
-
-def format_minion_pool_tasks_execution(req, execution, keys=None):
-    def transform(key, value):
-        if keys and key not in keys:
-            return
-        yield (key, value)
-
-    if "tasks" in execution:
-        execution["tasks"] = _sort_tasks(execution["tasks"])
-
-    execution_dict = dict(itertools.chain.from_iterable(
-        transform(k, v) for k, v in execution.items()))
-
-    return execution_dict
-
-
-def single(req, execution):
-    return {"execution": format_minion_pool_tasks_execution(req, execution)}
-
-
-def collection(req, executions):
-    formatted_executions = [
-        format_minion_pool_tasks_execution(req, m) for m in executions]
-    return {'executions': formatted_executions}

+ 2 - 2
coriolis/db/sqlalchemy/migrate_repo/versions/016_adds_minion_vm_pools.py

@@ -109,7 +109,7 @@ def upgrade(migrate_engine):
                           sqlalchemy.ForeignKey('minion_pool.id'),
                           nullable=False),
         sqlalchemy.Column("level", sqlalchemy.String(50), nullable=False),
-        sqlalchemy.Column("message", sqlalchemy.String(1024), nullable=False),
+        sqlalchemy.Column("message", sqlalchemy.Text, nullable=False),
         mysql_engine='InnoDB',
         mysql_charset='utf8'))
 
@@ -126,7 +126,7 @@ def upgrade(migrate_engine):
                           nullable=False),
         sqlalchemy.Column("current_step", sqlalchemy.Integer, nullable=False),
         sqlalchemy.Column("total_steps", sqlalchemy.Integer, nullable=True),
-        sqlalchemy.Column("message", sqlalchemy.String(1024), nullable=True),
+        sqlalchemy.Column("message", sqlalchemy.Text, nullable=True),
         mysql_engine='InnoDB',
         mysql_charset='utf8'))
 

+ 2 - 2
coriolis/db/sqlalchemy/models.py

@@ -53,7 +53,7 @@ class MinionPoolEvent(BASE, models.TimestampMixin, models.SoftDeleteMixin,
                                 sqlalchemy.ForeignKey('minion_pool.id'),
                                 nullable=False)
     level = sqlalchemy.Column(sqlalchemy.String(20), nullable=False)
-    message = sqlalchemy.Column(sqlalchemy.String(1024), nullable=False)
+    message = sqlalchemy.Column(sqlalchemy.Text, nullable=False)
 
     def to_dict(self):
         result = {
@@ -84,7 +84,7 @@ class TaskProgressUpdate(BASE, models.TimestampMixin, models.SoftDeleteMixin,
                                 nullable=False)
     current_step = sqlalchemy.Column(sqlalchemy.Integer, nullable=False)
     total_steps = sqlalchemy.Column(sqlalchemy.Integer, nullable=True)
-    message = sqlalchemy.Column(sqlalchemy.String(1024), nullable=True)
+    message = sqlalchemy.Column(sqlalchemy.Text, nullable=True)
 
     def to_dict(self):
         result = {

+ 93 - 31
coriolis/minion_manager/rpc/server.py

@@ -528,16 +528,16 @@ class MinionManagerServerEndpoint(object):
         setup, and actual minion creation)
         """
         # create task flow:
-        deployment_flow = linear_flow.Flow(
-            minion_manager_tasks.MINION_POOL_DEPLOYMENT_FLOW_NAME_FORMAT % (
+        allocation_flow = linear_flow.Flow(
+            minion_manager_tasks.MINION_POOL_ALLOCATION_FLOW_NAME_FORMAT % (
                 minion_pool.id))
 
         # tansition pool to VALIDATING:
-        deployment_flow.add(minion_manager_tasks.UpdateMinionPoolStatusTask(
+        allocation_flow.add(minion_manager_tasks.UpdateMinionPoolStatusTask(
             minion_pool.id, constants.MINION_POOL_STATUS_VALIDATING_INPUTS))
 
         # add pool options validation task:
-        deployment_flow.add(minion_manager_tasks.ValidateMinionPoolOptionsTask(
+        allocation_flow.add(minion_manager_tasks.ValidateMinionPoolOptionsTask(
             # NOTE: we pass in the ID of the minion pool itself as both
             # the task ID and the instance ID for tasks which are strictly
             # pool-related.
@@ -546,47 +546,48 @@ class MinionManagerServerEndpoint(object):
             minion_pool.platform))
 
         # transition pool to 'DEPLOYING_SHARED_RESOURCES':
-        deployment_flow.add(minion_manager_tasks.UpdateMinionPoolStatusTask(
+        allocation_flow.add(minion_manager_tasks.UpdateMinionPoolStatusTask(
             minion_pool.id,
             constants.MINION_POOL_STATUS_ALLOCATING_SHARED_RESOURCES))
 
         # add pool shared resources deployment task:
-        deployment_flow.add(minion_manager_tasks.DeploySharedPoolResourcesTask(
-            minion_pool.id, minion_pool.id, minion_pool.platform,
-            # NOTE: the shared resource deployment task will always get run
-            # by itself so it is safe to have it override the task_info:
-            provides='task_info'))
+        allocation_flow.add(
+            minion_manager_tasks.AllocateSharedPoolResourcesTask(
+                minion_pool.id, minion_pool.id, minion_pool.platform,
+                # NOTE: the shared resource deployment task will always get
+                # run by itself so it is safe to have it override task_info:
+                provides='task_info'))
 
         # add subflow for deploying all of the minion machines:
         fmt = (
-            minion_manager_tasks.MINION_POOL_CREATE_MINIONS_SUBFLOW_NAME_FORMAT)
+            minion_manager_tasks.MINION_POOL_ALLOCATE_MINIONS_SUBFLOW_NAME_FORMAT)
         machines_flow = unordered_flow.Flow(fmt % minion_pool.id)
         pool_machine_ids = []
         for _ in range(minion_pool.minimum_minions):
             machine_id = str(uuid.uuid4())
             pool_machine_ids.append(machine_id)
             machines_flow.add(
-                minion_manager_tasks.DeployMinionMachineTask(
+                minion_manager_tasks.AllocateMinionMachineTask(
                     minion_pool.id, machine_id, minion_pool.platform))
         # NOTE: bool(flow) == False if the flow has no child flows/tasks:
         if machines_flow:
-            deployment_flow.add(minion_manager_tasks.UpdateMinionPoolStatusTask(
+            allocation_flow.add(minion_manager_tasks.UpdateMinionPoolStatusTask(
                 minion_pool.id,
-                constants.MINION_POOL_STATUS_DEALLOCATING_MACHINES))
+                constants.MINION_POOL_STATUS_ALLOCATING_MACHINES))
             LOG.debug(
                 "The following minion machine IDs will be created for "
                 "pool with ID '%s': %s" % (minion_pool.id, pool_machine_ids))
-            deployment_flow.add(machines_flow)
+            allocation_flow.add(machines_flow)
         else:
             LOG.debug(
                 "No upfront minion machine deployments required for minion "
                 "pool with ID '%s'", minion_pool.id)
 
         # transition pool to ALLOCATED:
-        deployment_flow.add(minion_manager_tasks.UpdateMinionPoolStatusTask(
+        allocation_flow.add(minion_manager_tasks.UpdateMinionPoolStatusTask(
             minion_pool.id, constants.MINION_POOL_STATUS_ALLOCATED))
 
-        return deployment_flow
+        return allocation_flow
 
 
     def create_minion_pool(
@@ -677,7 +678,8 @@ class MinionManagerServerEndpoint(object):
         if minion_pool.status not in acceptable_allocation_statuses:
             raise exception.InvalidMinionPoolState(
                 "Minion machines for pool '%s' cannot be allocated as the pool"
-                " is in '%s' state instead of the expected %s."% (
+                " is in '%s' state instead of the expected %s. Please "
+                "force-deallocate the pool and try again." % (
                     minion_pool_id, minion_pool.status,
                     acceptable_allocation_statuses))
 
@@ -690,26 +692,86 @@ class MinionManagerServerEndpoint(object):
         return self._get_minion_pool(ctxt, minion_pool.id)
 
     def _get_minion_pool_deallocation_flow(self, minion_pool):
-        # TODO
-        pass
+        """ Returns a taskflow.Flow object pertaining to all the tasks
+        required for deallocating a minion pool (machines and shared resources)
+        """
+        # create task flow:
+        deallocation_flow = linear_flow.Flow(
+            minion_manager_tasks.MINION_POOL_DEALLOCATION_FLOW_NAME_FORMAT % (
+                minion_pool.id))
+
+        # add subflow for deallocating all of the minion machines:
+        fmt = (
+            minion_manager_tasks.MINION_POOL_DEALLOCATE_MACHINES_SUBFLOW_NAME_FORMAT)
+        machines_flow = unordered_flow.Flow(fmt % minion_pool.id)
+        for machine in minion_pool.minion_machines:
+            machines_flow.add(
+                minion_manager_tasks.DeallocateMinionMachineTask(
+                    minion_pool.id, machine.id, minion_pool.platform))
+        # NOTE: bool(flow) == False if the flow has no child flows/tasks:
+        if machines_flow:
+            # tansition pool to DEALLOCATING_MACHINES:
+            deallocation_flow.add(minion_manager_tasks.UpdateMinionPoolStatusTask(
+                minion_pool.id,
+                constants.MINION_POOL_STATUS_DEALLOCATING_MACHINES))
+            deallocation_flow.add(machines_flow)
+        else:
+            LOG.debug(
+                "No machines for pool '%s' require deallocating.", minion_pool.id)
+
+        # transition pool to DEALLOCATING_SHARED_RESOURCES:
+        deallocation_flow.add(minion_manager_tasks.UpdateMinionPoolStatusTask(
+            minion_pool.id,
+            constants.MINION_POOL_STATUS_DEALLOCATING_SHARED_RESOURCES))
+
+        # add pool shared resources deletion task:
+        deallocation_flow.add(
+            minion_manager_tasks.DeallocateSharedPoolResourcesTask(
+                minion_pool.id, minion_pool.id, minion_pool.platform))
+
+        # transition pool to DEALLOCATED:
+        deallocation_flow.add(minion_manager_tasks.UpdateMinionPoolStatusTask(
+            minion_pool.id, constants.MINION_POOL_STATUS_DEALLOCATED))
+
+        return deallocation_flow
 
     def _get_pool_deallocation_initial_store(
             self, ctxt, minion_pool, endpoint_dict):
-        # TODO
-        pass
+        # NOTE: considering pools are associated to strictly one endpoint,
+        # we can duplicate the 'origin/destination':
+        origin_dest_info = {
+            "id": endpoint_dict['id'],
+            "connection_info": endpoint_dict['connection_info'],
+            "mapped_regions": endpoint_dict['mapped_regions'],
+            "type": endpoint_dict['type']}
+        initial_store = {
+            "context": ctxt,
+            "origin": origin_dest_info,
+            "destination": origin_dest_info,
+            "task_info": {
+                "pool_identifier": minion_pool.id,
+                "pool_os_type": minion_pool.os_type,
+                "pool_environment_options": minion_pool.environment_options,
+                "pool_shared_resources": minion_pool.shared_resources}}
+        return initial_store
 
     @minion_pool_synchronized
-    def deallocate_minion_pool(self, ctxt, minion_pool_id):
+    def deallocate_minion_pool(self, ctxt, minion_pool_id, force=False):
         LOG.info("Attempting to deallocate Minion Pool '%s'.", minion_pool_id)
         minion_pool = self._get_minion_pool(
             ctxt, minion_pool_id, include_events=False, include_machines=True,
             include_progress_updates=False)
         if minion_pool.status != constants.MINION_POOL_STATUS_ALLOCATED:
-            raise exception.InvalidMinionPoolState(
-                "Minion pool '%s' cannot be deallocated as the pool"
-                " is in '%s' state instead of the expected %s."% (
-                    minion_pool_id, minion_pool.status,
-                    constants.MINION_POOL_STATUS_DEALLOCATED))
+            if not force:
+                raise exception.InvalidMinionPoolState(
+                    "Minion pool '%s' cannot be deallocated as the pool"
+                    " is in '%s' state instead of the expected %s."% (
+                        minion_pool_id, minion_pool.status,
+                        constants.MINION_POOL_STATUS_ALLOCATED))
+            else:
+                LOG.warn(
+                    "Forcibly deallocating minion pool '%s' at user request.",
+                    minion_pool_id)
         self._check_pool_machines_in_use(
             ctxt, minion_pool, raise_if_in_use=True)
         endpoint_dict = self._conductor_client.get_endpoint(
@@ -734,7 +796,8 @@ class MinionManagerServerEndpoint(object):
             include_events=True, include_progress_updates=True):
         minion_pool = db_api.get_minion_pool(
             ctxt, minion_pool_id, include_machines=include_machines,
-            include_events=True, include_progress_updates=True)
+            include_events=include_events,
+            include_progress_updates=include_progress_updates)
         if not minion_pool:
             raise exception.NotFound(
                 "Minion pool with ID '%s' not found." % minion_pool_id)
@@ -1048,6 +1111,7 @@ class MinionManagerServerEndpoint(object):
         minion_pool = self._get_minion_pool(
             ctxt, minion_pool_id, include_machines=True)
         acceptable_deletion_statuses = [
+            constants.MINION_POOL_STATUS_DEALLOCATED,
             constants.MINION_POOL_STATUS_UNINITIALIZED,
             constants.MINION_POOL_STATUS_ERROR]
         if minion_pool.status not in acceptable_deletion_statuses:
@@ -1162,5 +1226,3 @@ class MinionManagerServerEndpoint(object):
     #         execution.type, new_execution_status)
     #     db_api.set_minion_pool_status(
     #         ctxt, execution.action_id, final_pool_status)
-
-

+ 144 - 25
coriolis/minion_manager/rpc/tasks.py

@@ -7,6 +7,7 @@ import copy
 from oslo_log import log as logging
 
 from coriolis import constants
+from coriolis import exception
 from coriolis.db import api as db_api
 from coriolis.db.sqlalchemy import models
 from coriolis.taskflow import base as coriolis_taskflow_base
@@ -14,20 +15,22 @@ from coriolis.taskflow import base as coriolis_taskflow_base
 
 LOG = logging.getLogger(__name__)
 
-MINION_POOL_DEPLOYMENT_FLOW_NAME_FORMAT = "pool-%s-deployment"
+MINION_POOL_ALLOCATION_FLOW_NAME_FORMAT = "pool-%s-allocation"
+MINION_POOL_DEALLOCATION_FLOW_NAME_FORMAT = "pool-%s-deallocation"
 MINION_POOL_VALIDATION_TASK_NAME_FORMAT = "pool-%s-validation"
 MINION_POOL_UPDATE_STATUS_TASK_NAME_FORMAT = "pool-%s-update-status-%s"
-MINION_POOL_SET_UP_SHARED_RESOURCES_TASK_NAME_FORMAT = (
-    "pool-%s-set-up-shared-resources")
-MINION_POOL_TEAR_DOWN_SHARED_RESOURCES_TASK_NAME_FORMAT = (
-    "pool-%s-tear-down-shared-resources")
-MINION_POOL_CREATE_MINIONS_SUBFLOW_NAME_FORMAT = (
-    "pool-%s-machines-deployment")
-MINION_POOL_CREATE_MINION_TASK_NAME_FORMAT = (
-    "pool-%s-machine-%s-deployment")
-MINION_POOL_DELETE_MINION_TASK_NAME_FORMAT = (
-    "pool-%s-machine-%s-deletion")
-
+MINION_POOL_ALLOCATE_SHARED_RESOURCES_TASK_NAME_FORMAT = (
+    "pool-%s-allocate-shared-resources")
+MINION_POOL_DEALLOCATE_SHARED_RESOURCES_TASK_NAME_FORMAT = (
+    "pool-%s-deallocate-shared-resources")
+MINION_POOL_ALLOCATE_MINIONS_SUBFLOW_NAME_FORMAT = (
+    "pool-%s-machines-allocation")
+MINION_POOL_DEALLOCATE_MACHINES_SUBFLOW_NAME_FORMAT = (
+    "pool-%s-machines-deallocation")
+MINION_POOL_ALLOCATE_MACHINE_TASK_NAME_FORMAT = (
+    "pool-%s-machine-%s-allocation")
+MINION_POOL_DEALLOCATE_MACHINE_TASK_NAME_FORMAT = (
+    "pool-%s-machine-%s-deallocation")
 
 
 class UpdateMinionPoolStatusTask(coriolis_taskflow_base.BaseCoriolisTaskflowTask):
@@ -50,6 +53,7 @@ class UpdateMinionPoolStatusTask(coriolis_taskflow_base.BaseCoriolisTaskflowTask
 
     def _add_minion_pool_event(
             self, ctxt, message, level=constants.TASK_EVENT_INFO):
+        LOG.debug("Minion pool '%s' event: %s", self._minion_pool_id, message)
         db_api.add_minion_pool_event(
             ctxt, self._minion_pool_id, level, message)
 
@@ -148,8 +152,19 @@ class BaseMinionManangerTask(coriolis_taskflow_base.BaseRunWorkerTask):
     def _get_task_name(self, minion_pool_id, minion_machine_id):
         raise NotImplementedError("No task name providable")
 
+    def _get_minion_machine(
+            self, ctxt, minion_machine_id,
+            raise_if_not_found=False):
+        machine = db_api.get_minion_machine(ctxt, minion_machine_id)
+        if not machine and raise_if_not_found:
+            raise exception.NotFound(
+                "Could not find minion machine with ID '%s'" % (
+                    minion_machine_id))
+        return machine
+
     def _add_minion_pool_event(
             self, ctxt, message, level=constants.TASK_EVENT_INFO):
+        LOG.debug("Minion pool '%s' event: %s", self._minion_pool_id, message)
         db_api.add_minion_pool_event(
             ctxt, self._minion_pool_id, level, message)
 
@@ -203,7 +218,7 @@ class ValidateMinionPoolOptionsTask(BaseMinionManangerTask):
             context, "Successfully validated minion pool options")
 
 
-class DeploySharedPoolResourcesTask(BaseMinionManangerTask):
+class AllocateSharedPoolResourcesTask(BaseMinionManangerTask):
 
     def __init__(
             self, minion_pool_id, minion_machine_id, minion_pool_type,
@@ -218,29 +233,28 @@ class DeploySharedPoolResourcesTask(BaseMinionManangerTask):
                 constants.TASK_TYPE_SET_UP_DESTINATION_POOL_SHARED_RESOURCES)
             resource_cleanup_task_type = (
                 constants.TASK_TYPE_TEAR_DOWN_DESTINATION_POOL_SHARED_RESOURCES)
-        super(DeploySharedPoolResourcesTask, self).__init__(
+        super(AllocateSharedPoolResourcesTask, self).__init__(
             minion_pool_id, minion_machine_id, resource_deployment_task_type,
             cleanup_task_runner_type=resource_cleanup_task_type)
 
     def _get_task_name(self, minion_pool_id, minion_machine_id):
-        return MINION_POOL_SET_UP_SHARED_RESOURCES_TASK_NAME_FORMAT % (
+        return MINION_POOL_ALLOCATE_SHARED_RESOURCES_TASK_NAME_FORMAT % (
             minion_pool_id)
 
     def execute(self, context, origin, destination, task_info):
         self._add_minion_pool_event(
             context, "Deploying shared pool resources")
-        res = super(DeploySharedPoolResourcesTask, self).execute(
+        res = super(AllocateSharedPoolResourcesTask, self).execute(
             context, origin, destination, task_info)
         pool_shared_resources = res['pool_shared_resources']
         self._add_minion_pool_event(
-            context, "Successfully deployed shared pool resources: %s" % (
-                pool_shared_resources))
+            context, "Successfully deployed shared pool resources")
 
         updated_values = {
             "shared_resources": pool_shared_resources}
         db_api.add_minion_pool_event(
             context, self._minion_pool_id, constants.TASK_EVENT_INFO,
-            "Successfully deployed shared pool resources: %s" % (
+            "Successfully deployed shared pool resources" % (
                 pool_shared_resources))
         db_api.update_minion_pool(
             context, self._minion_pool_id, updated_values)
@@ -252,7 +266,7 @@ class DeploySharedPoolResourcesTask(BaseMinionManangerTask):
         if 'pool_shared_resources' not in task_info:
             task_info['pool_shared_resources'] = {}
 
-        res = super(DeploySharedPoolResourcesTask, self).revert(
+        res = super(AllocateSharedPoolResourcesTask, self).revert(
             context, origin, destination, task_info)
 
         if res and res.get('pool_shared_resources'):
@@ -269,7 +283,53 @@ class DeploySharedPoolResourcesTask(BaseMinionManangerTask):
         return task_info
 
 
-class DeployMinionMachineTask(BaseMinionManangerTask):
+
+class DeallocateSharedPoolResourcesTask(BaseMinionManangerTask):
+
+    def __init__(
+            self, minion_pool_id, minion_machine_id, minion_pool_type,
+            **kwargs):
+
+        resource_deallocation_task = (
+            constants.TASK_TYPE_TEAR_DOWN_SOURCE_POOL_SHARED_RESOURCES)
+        if minion_pool_type != constants.PROVIDER_PLATFORM_SOURCE:
+            resource_deallocation_task = (
+                constants.TASK_TYPE_TEAR_DOWN_DESTINATION_POOL_SHARED_RESOURCES)
+        super(DeallocateSharedPoolResourcesTask, self).__init__(
+            minion_pool_id, minion_machine_id, resource_deallocation_task)
+
+    def _get_task_name(self, minion_pool_id, minion_machine_id):
+        return MINION_POOL_DEALLOCATE_SHARED_RESOURCES_TASK_NAME_FORMAT % (
+            minion_pool_id)
+
+    def execute(self, context, origin, destination, task_info):
+        self._add_minion_pool_event(
+            context, "Deallocating shared pool resources")
+        if 'pool_shared_resources' not in task_info:
+            raise exception.InvalidInput(
+                "[Task '%s'] No 'pool_shared_resources' provided in the "
+                "task_info." % self._task_name)
+        execution_info = {
+            "pool_environment_options": task_info.get(
+                'pool_environment_options', {}),
+            "pool_shared_resources": task_info['pool_shared_resources']}
+        res = super(DeallocateSharedPoolResourcesTask, self).execute(
+            context, origin, destination, execution_info)
+        if res:
+            LOG.warn(
+                "[Task '%s'] Pool '%s' shared resource deallocation task "
+                "returned non-void values: %s" % (
+                    self._task_name, self._minion_pool_id, res))
+        updated_values = {
+            "shared_resources": None}
+        db_api.update_minion_pool(
+            context, self._minion_pool_id, updated_values)
+        self._add_minion_pool_event(
+            context, "Successfully deallocated shared pool resources")
+        return task_info
+
+
+class AllocateMinionMachineTask(BaseMinionManangerTask):
 
     def __init__(
             self, minion_pool_id, minion_machine_id, minion_pool_type,
@@ -283,12 +343,12 @@ class DeployMinionMachineTask(BaseMinionManangerTask):
                 constants.TASK_TYPE_DELETE_SOURCE_MINION_MACHINE)
             resource_cleanup_task_type = (
                 constants.TASK_TYPE_DELETE_DESTINATION_MINION_MACHINE)
-        super(DeployMinionMachineTask, self).__init__(
+        super(AllocateMinionMachineTask, self).__init__(
             minion_pool_id, minion_machine_id, resource_deployment_task_type,
             cleanup_task_runner_type=resource_cleanup_task_type)
 
     def _get_task_name(self, minion_pool_id, minion_machine_id):
-        return MINION_POOL_CREATE_MINION_TASK_NAME_FORMAT % (
+        return MINION_POOL_ALLOCATE_MACHINE_TASK_NAME_FORMAT % (
             minion_pool_id, minion_machine_id)
 
     def execute(self, context, origin, destination, task_info):
@@ -305,9 +365,19 @@ class DeployMinionMachineTask(BaseMinionManangerTask):
             "pool_shared_resources": task_info["pool_shared_resources"],
             "pool_os_type": task_info["pool_os_type"]}
 
-        res = super(DeployMinionMachineTask, self).execute(
+        self._add_minion_pool_event(
+            context,
+            "Allocating minion machine with internal pool ID '%s'" % (
+                self._minion_machine_id))
+
+        res = super(AllocateMinionMachineTask, self).execute(
             context, origin, destination, execution_info)
 
+        self._add_minion_pool_event(
+            context,
+            "Successfully allocated minion machine with internal pool "
+            "ID '%s'" % (self._minion_machine_id))
+
         updated_values = {
             "status": constants.MINION_MACHINE_STATUS_AVAILABLE,
             "connection_info": res['minion_connection_info'],
@@ -336,7 +406,7 @@ class DeployMinionMachineTask(BaseMinionManangerTask):
         cleanup_info = copy.deepcopy(task_info)
         cleanup_info['minion_provider_properties'] = original_result[
             'minion_provider_properties']
-        _ = super(DeployMinionMachineTask, self).revert(
+        _ = super(AllocateMinionMachineTask, self).revert(
             context, origin, destination, cleanup_info)
 
         if db_api.get_minion_machine(context, self._minion_machine_id):
@@ -346,3 +416,52 @@ class DeployMinionMachineTask(BaseMinionManangerTask):
             db_api.delete_minion_machine(context, self._minion_machine_id)
 
         return task_info
+
+
+class DeallocateMinionMachineTask(BaseMinionManangerTask):
+
+    def __init__(
+            self, minion_pool_id, minion_machine_id, minion_pool_type,
+            **kwargs):
+        resource_deletion_task_type = (
+            constants.TASK_TYPE_DELETE_SOURCE_MINION_MACHINE)
+        if minion_pool_type != constants.PROVIDER_PLATFORM_SOURCE:
+            resource_deletion_task_type = (
+                constants.TASK_TYPE_DELETE_DESTINATION_MINION_MACHINE)
+        super(DeallocateMinionMachineTask, self).__init__(
+            minion_pool_id, minion_machine_id, resource_deletion_task_type)
+
+    def _get_task_name(self, minion_pool_id, minion_machine_id):
+        return MINION_POOL_DEALLOCATE_MACHINE_TASK_NAME_FORMAT % (
+            minion_pool_id, minion_machine_id)
+
+    def execute(self, context, origin, destination, task_info):
+        machine = self._get_minion_machine(context, self._minion_machine_id)
+        if not machine:
+            LOG.info(
+                "[Task '%s'] Could not find machine with ID '%s' in the DB. "
+                "Presuming it was already deleted and returning early.",
+                self._task_name, self._minion_machine_id)
+            return task_info
+
+        self._add_minion_pool_event(
+            context,
+            "Deallocating minion machine with internal pool ID '%s'" % (
+                self._minion_machine_id))
+
+        execution_info = {
+            "minion_provider_properties": machine.provider_properties}
+        res = super(DeallocateMinionMachineTask, self).execute(
+            context, origin, destination, execution_info)
+
+        LOG.debug(
+            "[Task '%s'] Deleting minion machine with ID '%s' from the DB",
+            self._task_name, self._minion_machine_id)
+        db_api.delete_minion_machine(context, self._minion_machine_id)
+
+        self._add_minion_pool_event(
+            context,
+            "Successfully deallocated minion machine with internal pool "
+            "ID '%s'" % (self._minion_machine_id))
+
+        return task_info

+ 4 - 13
coriolis/minion_pools/api.py

@@ -31,19 +31,10 @@ class API(object):
     def get_minion_pool(self, ctxt, minion_pool_id):
         return self._rpc_client.get_minion_pool(ctxt, minion_pool_id)
 
-    def set_up_shared_pool_resources(self, ctxt, minion_pool_id):
-        return self._rpc_client.set_up_shared_minion_pool_resources(
+    def allocate_minion_pool(self, ctxt, minion_pool_id):
+        return self._rpc_client.allocate_minion_pool(
             ctxt, minion_pool_id)
 
-    def tear_down_shared_pool_resources(
-            self, ctxt, minion_pool_id, force=False):
-        return self._rpc_client.tear_down_shared_minion_pool_resources(
-            ctxt, minion_pool_id, force=force)
-
-    def allocate_machines(self, ctxt, minion_pool_id):
-        return self._rpc_client.allocate_minion_pool_machines(
-            ctxt, minion_pool_id)
-
-    def deallocate_machines(self, ctxt, minion_pool_id, force=False):
-        return self._rpc_client.deallocate_minion_pool_machines(
+    def deallocate_minion_pool(self, ctxt, minion_pool_id, force=False):
+        return self._rpc_client.deallocate_minion_pool(
             ctxt, minion_pool_id, force=force)

+ 4 - 26
coriolis/policies/minion_pools.py

@@ -73,9 +73,9 @@ MINION_POOLS_DEFAULT_RULES = [
         ]
     ),
     policy.DocumentedRuleDefault(
-        get_minion_pools_policy_label('set_up_shared_resources'),
+        get_minion_pools_policy_label('allocate'),
         MINION_POOLS_DEFAULT_RULE,
-        "Set up shared minion pool resources",
+        "Allocate Minion Pool",
         [
             {
                 "path": "/minion_pools/{minion_pool_id}/actions",
@@ -84,31 +84,9 @@ MINION_POOLS_DEFAULT_RULES = [
         ]
     ),
     policy.DocumentedRuleDefault(
-        get_minion_pools_policy_label('tear_down_shared_resources'),
+        get_minion_pools_policy_label('deallocate'),
         MINION_POOLS_DEFAULT_RULE,
-        "Tear down shared minion pool resources",
-        [
-            {
-                "path": "/minion_pools/{minion_pool_id}/actions",
-                "method": "POST"
-            }
-        ]
-    ),
-    policy.DocumentedRuleDefault(
-        get_minion_pools_policy_label('allocate_machines'),
-        MINION_POOLS_DEFAULT_RULE,
-        "Allocate Minion Pool machines",
-        [
-            {
-                "path": "/minion_pools/{minion_pool_id}/actions",
-                "method": "POST"
-            }
-        ]
-    ),
-    policy.DocumentedRuleDefault(
-        get_minion_pools_policy_label('deallocate_machines'),
-        MINION_POOLS_DEFAULT_RULE,
-        "Deallocate Minion Pool machines",
+        "Deallocate Minion Pool",
         [
             {
                 "path": "/minion_pools/{minion_pool_id}/actions",

+ 7 - 4
coriolis/taskflow/base.py

@@ -37,7 +37,10 @@ class BaseCoriolisTaskflowTask(taskflow_tasks.Task):
         if not flow_failures:
             return "No flow failures provided."
 
-        res = "No flow failures present."
+        if not flow_failures.items():
+            return "No flow failures present."
+
+        res = ""
         for (task_id, task_failure) in flow_failures.items():
             label = "Error message"
             failure_str = task_failure.exception_str
@@ -194,9 +197,9 @@ class BaseRunWorkerTask(BaseCoriolisTaskflowTask):
             return res
         except Exception as ex:
             LOG.debug(
-                "Exception occurred while executing task '%s' (type '%s') on "
-                "the worker service: %s", task_id, task_type,
-                utils.get_exception_details())
+                "[Task %s] Exception occurred while executing task '%s' "
+                "(type '%s') on the worker service: %s", self._task_name,
+                task_id, task_type, utils.get_exception_details())
             raise
 
     def execute(self, context, origin, destination, task_info):