Merge "Skip resize actions in pre_condition phase"

This commit is contained in:
Zuul
2026-02-26 11:02:56 +00:00
committed by Gerrit Code Review
4 changed files with 78 additions and 3 deletions

View File

@@ -23,3 +23,16 @@ parameter type required description
``flavor`` string yes ID or Name of Flavor (Nova accepts
either ID or Name)
======================== ====== ======== ===================================
Skipping conditions
--------------------
Resize actions will be automatically skipped in the pre_condition phase in
the following case:
- The server does not exist
On other condition the action will be FAILED in the pre_condition check:
- Destination flavor does not exist

View File

@@ -0,0 +1,15 @@
---
features:
- |
Added a pre-condition check to the resize action to prevent executing
it when required criteria are not met. In following condition,
the action status will be set to SKIPPED:
- Instance is not found
On other condition the action will be FAILED in the pre_condition
check:
- Destination flavor does not exist
This improves safety and correctness of migrations.

View File

@@ -18,7 +18,9 @@
from oslo_log import log
from watcher._i18n import _
from watcher.applier.actions import base
from watcher.common import exception
from watcher.common import nova_helper
LOG = log.getLogger(__name__)
@@ -97,9 +99,27 @@ class Resize(base.BaseAction):
LOG.warning("revert not supported")
def pre_condition(self):
# TODO(jed): check if the instance exists / check if the instance is on
# the source_node
pass
"""Check resize preconditions
Skipping conditions:
- Instance does not exist
Failing conditions:
- Flavor does not exist
"""
nova = nova_helper.NovaHelper(osc=self.osc)
# Check that the instance exists
try:
nova.find_instance(self.instance_uuid)
except exception.ComputeResourceNotFound:
raise exception.ActionSkipped(
_("Instance %s not found") % self.instance_uuid)
try:
nova.get_flavor_id(self.flavor)
except exception.ComputeResourceNotFound:
raise exception.ActionExecutionFailure(
_("Flavor %s not found") % self.flavor)
def post_condition(self):
# TODO(jed): check extra parameters (network response, etc.)

View File

@@ -18,6 +18,7 @@ from unittest import mock
from watcher.applier.actions import base as baction
from watcher.applier.actions import resize
from watcher.common import clients
from watcher.common import exception
from watcher.common import nova_helper
from watcher.tests.unit import base
@@ -89,3 +90,29 @@ class TestResize(base.TestCase):
self.action.execute()
self.r_helper.resize_instance.assert_called_once_with(
instance_id=self.INSTANCE_UUID, flavor='x1')
def test_pre_condition_success(self):
"""Test pre_condition succeeds when instance and flavor exist"""
self.r_helper.find_instance.return_value = self.INSTANCE_UUID
self.r_helper.get_flavor_id.return_value = '123'
self.action.pre_condition()
def test_pre_condition_instance_not_found(self):
"""Test pre_condition fails when instance doesn't exist"""
err = exception.ComputeResourceNotFound()
self.r_helper.find_instance.side_effect = err
self.assertRaisesRegex(
exception.ActionSkipped,
f"Instance {self.INSTANCE_UUID} not found",
self.action.pre_condition)
def test_pre_condition_flavor_not_found(self):
"""Test pre_condition fails when flavor doesn't exist"""
err = exception.ComputeResourceNotFound()
self.r_helper.get_flavor_id.side_effect = err
self.assertRaisesRegex(
exception.ActionExecutionFailure,
"Flavor x1 not found",
self.action.pre_condition)