Merge "extend-node-status"

This commit is contained in:
Zuul
2017-11-29 13:35:54 +00:00
committed by Gerrit Code Review
14 changed files with 58 additions and 23 deletions

View File

@@ -36,15 +36,20 @@ class ChangeNovaServiceState(base.BaseAction):
schema = Schema({
'resource_id': str,
'state': str,
'disabled_reason': str,
})
The `resource_id` references a nova-compute service name (list of available
nova-compute services is returned by this command: ``nova service-list
--binary nova-compute``).
The `state` value should either be `ONLINE` or `OFFLINE`.
The `disabled_reason` references the reason why Watcher disables this
nova-compute service. The value should be with `watcher_` prefix, such as
`watcher_disabled`, `watcher_maintaining`.
"""
STATE = 'state'
REASON = 'disabled_reason'
@property
def schema(self):
@@ -61,6 +66,10 @@ class ChangeNovaServiceState(base.BaseAction):
element.ServiceState.OFFLINE.value,
element.ServiceState.ENABLED.value,
element.ServiceState.DISABLED.value]
},
'disabled_reason': {
'type': 'string',
"minlength": 1
}
},
'required': ['resource_id', 'state'],
@@ -75,6 +84,10 @@ class ChangeNovaServiceState(base.BaseAction):
def state(self):
return self.input_parameters.get(self.STATE)
@property
def reason(self):
return self.input_parameters.get(self.REASON)
def execute(self):
target_state = None
if self.state == element.ServiceState.DISABLED.value:
@@ -100,7 +113,7 @@ class ChangeNovaServiceState(base.BaseAction):
if state is True:
return nova.enable_service_nova_compute(self.host)
else:
return nova.disable_service_nova_compute(self.host)
return nova.disable_service_nova_compute(self.host, self.reason)
def pre_condition(self):
pass

View File

@@ -545,9 +545,10 @@ class NovaHelper(object):
else:
return False
def disable_service_nova_compute(self, hostname):
if self.nova.services.disable(host=hostname,
binary='nova-compute'). \
def disable_service_nova_compute(self, hostname, reason=None):
if self.nova.services.disable_log_reason(host=hostname,
binary='nova-compute',
reason=reason). \
status == 'disabled':
return True
else:

View File

@@ -248,7 +248,8 @@ class ModelBuilder(object):
"disk_capacity": node.local_gb,
"vcpus": node.vcpus,
"state": node.state,
"status": node.status}
"status": node.status,
"disabled_reason": compute_service.disabled_reason}
compute_node = element.ComputeNode(**node_attributes)
# compute_node = self._build_node("physical", "compute", "hypervisor",

View File

@@ -36,8 +36,8 @@ class ComputeNode(compute_resource.ComputeResource):
"id": wfields.StringField(),
"hostname": wfields.StringField(),
"status": wfields.StringField(default=ServiceState.ENABLED.value),
"disabled_reason": wfields.StringField(nullable=True),
"state": wfields.StringField(default=ServiceState.ONLINE.value),
"memory": wfields.NonNegativeIntegerField(),
"disk": wfields.IntegerField(),
"disk_capacity": wfields.NonNegativeIntegerField(),

View File

@@ -122,11 +122,15 @@ class NovaNotification(base.NotificationEndpoint):
node_status = (
element.ServiceState.DISABLED.value
if node_data['disabled'] else element.ServiceState.ENABLED.value)
disabled_reason = (
node_data['disabled_reason']
if node_data['disabled'] else None)
node.update({
'hostname': node_data['host'],
'state': node_state,
'status': node_status,
'disabled_reason': disabled_reason,
})
def create_compute_node(self, node_hostname):

View File

@@ -324,6 +324,8 @@ class UnclassifiedStrategy(BaseStrategy):
@six.add_metaclass(abc.ABCMeta)
class ServerConsolidationBaseStrategy(BaseStrategy):
REASON_FOR_DISABLE = 'watcher_disabled'
@classmethod
def get_goal_name(cls):
return "server_consolidation"

View File

@@ -415,8 +415,9 @@ class BasicConsolidation(base.ServerConsolidationBaseStrategy):
return self.calculate_weight(instance, total_cores_used, 0, 0)
def add_change_service_state(self, resource_id, state):
parameters = {'state': state}
def add_action_disable_node(self, resource_id):
parameters = {'state': element.ServiceState.DISABLED.value,
'disabled_reason': self.REASON_FOR_DISABLE}
self.solution.add_action(action_type=self.CHANGE_NOVA_SERVICE_STATE,
resource_id=resource_id,
input_parameters=parameters)
@@ -472,9 +473,7 @@ class BasicConsolidation(base.ServerConsolidationBaseStrategy):
mig_destination_node.uuid)
if len(self.compute_model.get_node_instances(mig_source_node)) == 0:
self.add_change_service_state(mig_source_node.
uuid,
element.ServiceState.DISABLED.value)
self.add_action_disable_node(mig_source_node.uuid)
self.number_of_released_nodes += 1
def calculate_num_migrations(self, sorted_instances, node_to_release,

View File

@@ -228,7 +228,8 @@ class VMWorkloadConsolidation(base.ServerConsolidationBaseStrategy):
:param node: node object
:return: None
"""
params = {'state': element.ServiceState.DISABLED.value}
params = {'state': element.ServiceState.DISABLED.value,
'disabled_reason': self.REASON_FOR_DISABLE}
self.solution.add_action(
action_type=self.CHANGE_NOVA_SERVICE_STATE,
resource_id=node.uuid,

View File

@@ -110,18 +110,22 @@ class TestChangeNovaServiceState(base.TestCase):
def test_execute_change_service_state_with_disable_target(self):
self.action.input_parameters["state"] = (
element.ServiceState.DISABLED.value)
self.action.input_parameters["disabled_reason"] = (
"watcher_disabled")
self.action.execute()
self.m_helper_cls.assert_called_once_with(osc=self.m_osc)
self.m_helper.disable_service_nova_compute.assert_called_once_with(
"compute-1")
"compute-1", "watcher_disabled")
def test_revert_change_service_state_with_enable_target(self):
self.action.input_parameters["disabled_reason"] = (
"watcher_disabled")
self.action.revert()
self.m_helper_cls.assert_called_once_with(osc=self.m_osc)
self.m_helper.disable_service_nova_compute.assert_called_once_with(
"compute-1")
"compute-1", "watcher_disabled")
def test_revert_change_service_state_with_disable_target(self):
self.action.input_parameters["state"] = (

View File

@@ -349,13 +349,13 @@ class TestNovaHelper(base.TestCase):
mock_neutron, mock_nova):
nova_util = nova_helper.NovaHelper()
nova_services = nova_util.nova.services
nova_services.disable.return_value = mock.MagicMock(
nova_services.disable_log_reason.return_value = mock.MagicMock(
status='enabled')
result = nova_util.disable_service_nova_compute('nanjing')
self.assertFalse(result)
nova_services.disable.return_value = mock.MagicMock(
nova_services.disable_log_reason.return_value = mock.MagicMock(
status='disabled')
result = nova_util.disable_service_nova_compute('nanjing')

View File

@@ -36,7 +36,13 @@ class TestNovaClusterDataModelCollector(base.TestCase):
m_nova_helper = mock.Mock(name="nova_helper")
m_nova_helper_cls.return_value = m_nova_helper
m_nova_helper.get_service.return_value = mock.Mock(
host="test_hostname")
id=1355,
host='test_hostname',
binary='nova-compute',
status='enabled',
state='up',
disabled_reason='',
)
fake_compute_node = mock.Mock(
id=1337,

View File

@@ -10,7 +10,7 @@
<ComputeNode hostname="hostname_2" uuid="Node_2" id="2" state="up" human_id="" status="enabled" vcpus="16" disk="250" disk_capacity="250" memory="64">
<Instance human_id="" state="active" uuid="INSTANCE_4" vcpus="2" disk="20" disk_capacity="20" memory="2" metadata='{"optimize": true,"top": "floor", "nested": {"x": "y"}}'/>
</ComputeNode>
<ComputeNode hostname="hostname_3" uuid="Node_3" id="3" state="up" human_id="" status="disabled" vcpus="16" disk="250" disk_capacity="250" memory="64">
<ComputeNode hostname="hostname_3" uuid="Node_3" id="3" state="up" human_id="" status="disabled" disabled_reason='watcher_disabled' vcpus="16" disk="250" disk_capacity="250" memory="64">
<Instance human_id="" state="active" uuid="INSTANCE_5" vcpus="2" disk="20" disk_capacity="20" memory="2" metadata='{"optimize": true,"top": "floor", "nested": {"x": "y"}}'/>
</ComputeNode>
</ModelRoot>

View File

@@ -10,7 +10,7 @@
"last_seen_up": "2012-10-29T13:42:05Z",
"binary": "nova-compute",
"topic": "compute",
"disabled_reason": null,
"disabled_reason": "watcher_disabled",
"report_count": 1,
"forced_down": true,
"version": 15

View File

@@ -197,8 +197,10 @@ class TestVMWorkloadConsolidation(base.TestCase):
n = model.get_node_by_uuid('Node_0')
self.strategy.add_action_disable_node(n)
expected = [{'action_type': 'change_nova_service_state',
'input_parameters': {'state': 'disabled',
'resource_id': 'Node_0'}}]
'input_parameters': {
'state': 'disabled',
'disabled_reason': 'watcher_disabled',
'resource_id': 'Node_0'}}]
self.assertEqual(expected, self.strategy.solution.actions)
def test_disable_unused_nodes(self):
@@ -217,8 +219,10 @@ class TestVMWorkloadConsolidation(base.TestCase):
self.strategy.disable_unused_nodes()
expected = {'action_type': 'change_nova_service_state',
'input_parameters': {'state': 'disabled',
'resource_id': 'Node_0'}}
'input_parameters': {
'state': 'disabled',
'disabled_reason': 'watcher_disabled',
'resource_id': 'Node_0'}}
self.assertEqual(2, len(self.strategy.solution.actions))
self.assertEqual(expected, self.strategy.solution.actions[1])