Code refactoring - Watcher Decision Engine package

This patchset is there to change the code structure.
The objective is to flatten the project file tree by merging
'api/' and 'framework/' into a single package. This also contains
some tidy ups in package naming (like using only singular nouns).

This should only affect file/folder names and their subsequent
import paths wherever they were used.

Change-Id: Ie903ba20ca5cf03b0b42efa60131d1b919b0c2c9
This commit is contained in:
Vincent Françoise
2015-11-26 11:54:32 +01:00
parent 6e81a31bd8
commit eb3870a4b3
100 changed files with 124 additions and 158 deletions

View File

@@ -0,0 +1,37 @@
# -*- encoding: utf-8 -*-
# Copyright (c) 2015 b<>com
#
# Authors: Jean-Emile DARTOIS <jean-emile.dartois@b-com.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import abc
import six
@six.add_metaclass(abc.ABCMeta)
class Planner(object):
@abc.abstractmethod
def schedule(self, context, audit_uuid, solution):
"""The planner receives a solution to schedule
:param solution: the solution given by the strategy to
:param audit_uuid: the audit uuid
:return: ActionPlan ordered sequence of change requests
such that all security, dependency,
and performance requirements are met.
"""
# example: directed acyclic graph
raise NotImplementedError(
"Should have implemented this") # pragma:no cover

View File

@@ -0,0 +1,180 @@
# -*- encoding: utf-8 -*-
# Copyright (c) 2015 b<>com
#
# Authors: Jean-Emile DARTOIS <jean-emile.dartois@b-com.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from oslo_log import log
from enum import Enum
from watcher.common.exception import MetaActionNotFound
from watcher.common import utils
from watcher.decision_engine.planner.base import Planner
from watcher import objects
from watcher.decision_engine.meta_action.hypervisor_state import \
ChangeHypervisorState
from watcher.decision_engine.meta_action.migrate import Migrate
from watcher.decision_engine.meta_action.nop import Nop
from watcher.decision_engine.meta_action.power_state import ChangePowerState
from watcher.objects.action import Status as AStatus
from watcher.objects.action_plan import Status as APStatus
LOG = log.getLogger(__name__)
# TODO(jed) The default planner is a very simple planner
# https://wiki.openstack.org/wiki/NovaOrchestration/WorkflowEngines
class Primitives(Enum):
LIVE_MIGRATE = 'MIGRATE'
COLD_MIGRATE = 'MIGRATE'
POWER_STATE = 'POWERSTATE'
HYPERVISOR_STATE = 'HYPERVISOR_STATE'
NOP = 'NOP'
priority_primitives = {
Primitives.HYPERVISOR_STATE.value: 0,
Primitives.LIVE_MIGRATE.value: 1,
Primitives.COLD_MIGRATE.value: 2,
Primitives.POWER_STATE.value: 3
}
class DefaultPlanner(Planner):
def create_action(self, action_plan_id, action_type, applies_to=None,
src=None,
dst=None,
parameter=None,
description=None):
uuid = utils.generate_uuid()
action = {
'uuid': uuid,
'action_plan_id': int(action_plan_id),
'action_type': action_type,
'applies_to': applies_to,
'src': src,
'dst': dst,
'parameter': parameter,
'description': description,
'state': AStatus.PENDING,
'alarm': None,
'next': None,
}
return action
def schedule(self, context, audit_id, solution):
LOG.debug('Create an action plan for the audit uuid')
action_plan = self._create_action_plan(context, audit_id)
actions = list(solution.meta_actions)
to_schedule = []
for action in actions:
if isinstance(action, Migrate):
# TODO(jed) type
primitive = self.create_action(action_plan.id,
Primitives.LIVE_MIGRATE.value,
action.get_vm().uuid,
action.get_source_hypervisor().
uuid,
action.get_dest_hypervisor().
uuid,
description="{0}".format(
action)
)
elif isinstance(action, ChangePowerState):
primitive = self.create_action(action_plan_id=action_plan.id,
action_type=Primitives.
POWER_STATE.value,
applies_to=action.target.uuid,
parameter=action.
powerstate.
value,
description="{0}".format(
action))
elif isinstance(action, ChangeHypervisorState):
primitive = self.create_action(action_plan_id=action_plan.id,
action_type=Primitives.
HYPERVISOR_STATE.value,
applies_to=action.target.uuid,
parameter=action.state.
value,
description="{0}".format(
action))
elif isinstance(action, Nop):
primitive = self.create_action(action_plan_id=action_plan.id,
action_type=Primitives.
NOP.value,
description="{0}".format(
action))
else:
raise MetaActionNotFound()
priority = priority_primitives[primitive['action_type']]
to_schedule.append((priority, primitive))
# scheduling
scheduled = sorted(to_schedule, reverse=False, key=lambda x: (x[0]))
if len(scheduled) == 0:
LOG.warning("The ActionPlan is empty")
action_plan.first_action_id = None
action_plan.save()
else:
parent_action = self._create_action(context,
scheduled[0][1],
None)
scheduled.pop(0)
action_plan.first_action_id = parent_action.id
action_plan.save()
for s_action in scheduled:
action = self._create_action(context, s_action[1],
parent_action)
parent_action = action
return action_plan
def _create_action_plan(self, context, audit_id):
action_plan_dict = {
'uuid': utils.generate_uuid(),
'audit_id': audit_id,
'first_action_id': None,
'state': APStatus.RECOMMENDED
}
new_action_plan = objects.ActionPlan(context, **action_plan_dict)
new_action_plan.create(context)
new_action_plan.save()
return new_action_plan
def _create_action(self, context, _action, parent_action):
action_description = str(_action)
LOG.debug("Create a action for the following resquest : %s"
% action_description)
new_action = objects.Action(context, **_action)
new_action.create(context)
new_action.save()
if parent_action:
parent_action.next = new_action.id
parent_action.save()
return new_action