Merge "Check if host belongs to a segment"

This commit is contained in:
Zuul 2020-06-03 00:51:43 +00:00 committed by Gerrit Code Review
commit b02657e6b3
15 changed files with 291 additions and 153 deletions

View File

@ -8,6 +8,22 @@
"name": "fake-mini",
"on_maintenance": false,
"control_attributes": "TEST",
"failover_segment": {
"masakari_object.name": "FailoverSegment",
"masakari_object.data": {
"uuid": "89597691-bebd-4860-a93e-1b6e9de34b9e",
"deleted": false,
"created_at": "2018-11-27T09:26:30Z",
"recovery_method": "auto",
"updated_at": "2018-11-27T09:54:50Z",
"name": "test",
"service_type": "compute",
"deleted_at": null,
"id": 877, "description": null
},
"masakari_object.version": "1.0",
"masakari_object.namespace": "masakari"
},
"fault": null,
"type": "COMPUTE",
"failover_segment_id": "89597691-bebd-4860-a93e-1b6e9de34b9e"

View File

@ -23,6 +23,7 @@ from webob import exc
from masakari.api.openstack import common
from masakari.api.openstack import extensions
from masakari.api.openstack.ha.schemas import hosts as schema
from masakari.api.openstack.ha.views import hosts as views_hosts
from masakari.api.openstack import wsgi
from masakari.api import validation
from masakari import exception
@ -94,7 +95,8 @@ class HostsController(wsgi.Controller):
except exception.FailoverSegmentNotFound as ex:
raise exc.HTTPNotFound(explanation=ex.format_message())
return {'hosts': hosts}
builder = views_hosts.get_view_builder(req)
return builder.build_hosts(hosts)
@wsgi.response(http.CREATED)
@extensions.expected_errors((http.BAD_REQUEST, http.FORBIDDEN,
@ -114,7 +116,8 @@ class HostsController(wsgi.Controller):
except exception.HostExists as e:
raise exc.HTTPConflict(explanation=e.format_message())
return {'host': host}
builder = views_hosts.get_view_builder(req)
return {'host': builder.build_host(host)}
@extensions.expected_errors((http.FORBIDDEN, http.NOT_FOUND))
def show(self, req, segment_id, id):
@ -127,7 +130,9 @@ class HostsController(wsgi.Controller):
raise exc.HTTPNotFound(explanation=e.format_message())
except exception.FailoverSegmentNotFound as e:
raise exc.HTTPNotFound(explanation=e.format_message())
return {'host': host}
builder = views_hosts.get_view_builder(req)
return {'host': builder.build_host(host)}
@extensions.expected_errors((http.BAD_REQUEST, http.FORBIDDEN,
http.NOT_FOUND, http.CONFLICT))
@ -148,7 +153,8 @@ class HostsController(wsgi.Controller):
except (exception.HostExists, exception.Conflict) as e:
raise exc.HTTPConflict(explanation=e.format_message())
return {'host': host}
builder = views_hosts.get_view_builder(req)
return {'host': builder.build_host(host)}
@wsgi.response(http.NO_CONTENT)
@extensions.expected_errors((http.FORBIDDEN, http.NOT_FOUND,

View File

@ -0,0 +1,57 @@
# Copyright (c) 2020 NTT Data
# All Rights Reserved.
#
# 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 masakari.api.openstack import common
def get_view_builder(req):
base_url = req.application_url
return ViewBuilder(base_url)
class ViewBuilder(common.ViewBuilder):
def __init__(self, base_url):
""":param base_url: url of the root wsgi application."""
self.prefix = self._update_masakari_link_prefix(base_url)
self.base_url = base_url
def _host_details(self, host):
return {
'id': host.id,
'uuid': host.uuid,
'name': host.name,
'failover_segment_id': host.failover_segment.uuid,
'failover_segment': host.failover_segment,
'type': host.type,
'reserved': host.reserved,
'control_attributes': host.control_attributes,
'on_maintenance': host.on_maintenance,
'created_at': host.created_at,
'updated_at': host.updated_at,
'deleted_at': host.deleted_at,
'deleted': host.deleted
}
def build_host(self, host):
get_host_response = self._host_details(host)
return get_host_response
def build_hosts(self, hosts):
host_objs = []
for host in hosts:
get_host_response = self._host_details(host)
host_objs.append(get_host_response)
return dict(hosts=host_objs)

View File

@ -216,7 +216,7 @@ class MasakariManager(manager.Manager):
fields.FailoverSegmentRecoveryMethod.AUTO):
reserved_host_object_list = objects.HostList.get_all(
context, filters={
'failover_segment_id': host_obj.failover_segment_id,
'failover_segment_id': host_obj.failover_segment.uuid,
'reserved': True,
'on_maintenance': False
})

View File

@ -155,12 +155,13 @@ class HostAPI(object):
def get_host(self, context, segment_uuid, host_uuid):
"""Get a host by id"""
objects.FailoverSegment.get_by_uuid(context, segment_uuid)
if uuidutils.is_uuid_like(host_uuid):
LOG.debug("Fetching host by "
"UUID", host_uuid=host_uuid)
host = objects.Host.get_by_uuid(context, host_uuid)
host = objects.Host.get_by_uuid(
context, host_uuid, segment_uuid=segment_uuid)
else:
LOG.debug("Failed to fetch host by uuid %s", host_uuid)
raise exception.HostNotFound(id=host_uuid)
@ -189,7 +190,7 @@ class HostAPI(object):
# Populate host object for create
host.name = host_data.get('name')
host.failover_segment_id = segment.uuid
host.failover_segment = segment
host.type = host_data.get('type')
host.control_attributes = host_data.get('control_attributes')
host.on_maintenance = strutils.bool_from_string(
@ -213,11 +214,11 @@ class HostAPI(object):
def update_host(self, context, segment_uuid, id, host_data):
"""Update the host"""
segment = objects.FailoverSegment.get_by_uuid(context, segment_uuid)
host = objects.Host.get_by_uuid(context, id)
host = objects.Host.get_by_uuid(
context, id, segment_uuid=segment_uuid)
if is_failover_segment_under_recovery(segment):
if is_failover_segment_under_recovery(host.failover_segment):
msg = _("Host %s can't be updated as "
"it is in-use to process notifications.") % host.uuid
LOG.error(msg)
@ -248,9 +249,8 @@ class HostAPI(object):
def delete_host(self, context, segment_uuid, id):
"""Delete the host"""
segment = objects.FailoverSegment.get_by_uuid(context, segment_uuid)
host = objects.Host.get_by_uuid(context, id, segment_uuid=segment_uuid)
if is_failover_segment_under_recovery(segment):
if is_failover_segment_under_recovery(host.failover_segment):
msg = _("Host %s can't be deleted as "
"it is in-use to process notifications.") % host.uuid
LOG.error(msg)

View File

@ -66,7 +66,6 @@ class HostApiPayloadBase(base.NotificationPayloadBase):
'id': ('host', 'id'),
'uuid': ('host', 'uuid'),
'name': ('host', 'name'),
'failover_segment_id': ('host', 'failover_segment_id'),
'failover_segment': ('host', 'failover_segment'),
'type': ('host', 'type'),
'reserved': ('host', 'reserved'),
@ -74,12 +73,12 @@ class HostApiPayloadBase(base.NotificationPayloadBase):
'on_maintenance': ('host', 'on_maintenance'),
}
# Version 1.0: Initial version
VERSION = '1.0'
# Version 1.1: Removed 'failover_segment_id' parameter
VERSION = '1.1'
fields = {
'id': fields.IntegerField(),
'uuid': fields.UUIDField(),
'name': fields.StringField(),
'failover_segment_id': fields.UUIDField(),
'failover_segment': fields.ObjectField('FailoverSegment'),
'type': fields.StringField(),
'reserved': fields.BooleanField(),

View File

@ -15,6 +15,7 @@
from oslo_log import log as logging
from oslo_utils import uuidutils
from oslo_utils import versionutils
from masakari.api import utils as api_utils
from masakari import db
@ -32,13 +33,14 @@ class Host(base.MasakariPersistentObject, base.MasakariObject,
# Version 1.0: Initial version
# Version 1.1: Added 'segment_uuid' parameter to 'get_by_uuid' method
VERSION = '1.1'
# Version 1.2: Removed 'failover_segment_id' parameter which can be
# retrieved from failover_segment object
VERSION = '1.2'
fields = {
'id': fields.IntegerField(),
'uuid': fields.UUIDField(),
'name': fields.StringField(),
'failover_segment_id': fields.UUIDField(),
'failover_segment': fields.ObjectField('FailoverSegment'),
'type': fields.StringField(),
'reserved': fields.BooleanField(),
@ -46,6 +48,12 @@ class Host(base.MasakariPersistentObject, base.MasakariObject,
'on_maintenance': fields.BooleanField(),
}
def obj_make_compatible(self, primitive, target_version):
super(Host, self).obj_make_compatible(primitive, target_version)
target_version = versionutils.convert_version_to_tuple(target_version)
if target_version >= (1, 2) and 'failover_segment_id' in primitive:
del primitive['failover_segment_id']
@staticmethod
def _from_db_object(context, host, db_host):
@ -53,7 +61,7 @@ class Host(base.MasakariPersistentObject, base.MasakariObject,
db_value = db_host.get(key)
if key == "failover_segment":
db_value = objects.FailoverSegment._from_db_object(
host._context, objects.FailoverSegment(), db_value)
context, objects.FailoverSegment(), db_value)
setattr(host, key, db_value)
@ -88,10 +96,13 @@ class Host(base.MasakariPersistentObject, base.MasakariObject,
LOG.debug('Generated uuid %(uuid)s for host',
dict(uuid=updates['uuid']))
if 'failover_segment' in updates:
if 'failover_segment' not in updates:
raise exception.ObjectActionError(action='create',
reason='failover segment '
'assigned')
'not assigned')
segment = updates.pop('failover_segment')
updates['failover_segment_id'] = segment.uuid
api_utils.notify_about_host_api(self._context, self,
action=fields.EventNotificationAction.HOST_CREATE,

View File

@ -142,7 +142,7 @@ class TestHosts(base.BaseFunctionalTest):
reserved='True')
result = self.admin_conn.ha.get_host(host.uuid,
host.failover_segment_id)
self.segment.uuid)
# Confirm host update
self.assertEqual(True, result.on_maintenance)
self.assertEqual(True, result.reserved)
@ -165,5 +165,5 @@ class TestHosts(base.BaseFunctionalTest):
name=self.hypervisors[1]['name'])
result = self.admin_conn.ha.get_host(host.uuid,
host.failover_segment_id)
self.segment.uuid)
self.assertEqual(result.name, updated_host.name)

View File

@ -30,6 +30,7 @@ from masakari.objects import host as host_obj
from masakari.objects import segment as segment_obj
from masakari import test
from masakari.tests.unit.api.openstack import fakes
from masakari.tests.unit import fakes as fakes_data
from masakari.tests import uuidsentinel
@ -42,33 +43,6 @@ def _make_hosts_list(hosts_list):
_make_host_obj(a) for a in hosts_list])
HOST_LIST = [
{"name": "host_1", "id": "1", "reserved": False,
"on_maintenance": False, "type": "fake",
"control_attributes": "fake-control_attributes",
"uuid": uuidsentinel.fake_host_1,
"failover_segment_id": uuidsentinel.fake_segment1},
{"name": "host_2", "id": "2", "reserved": False,
"on_maintenance": False, "type": "fake",
"control_attributes": "fake-control_attributes",
"uuid": uuidsentinel.fake_host_2,
"failover_segment_id": uuidsentinel.fake_segment1}
]
HOST_LIST = _make_hosts_list(HOST_LIST)
HOST = {
"name": "host_1", "id": "1", "reserved": False,
"on_maintenance": False, "type": "fake",
"control_attributes": "fake-control_attributes",
"uuid": uuidsentinel.fake_host_1,
"failover_segment_id": uuidsentinel.fake_segment1
}
HOST = _make_host_obj(HOST)
@ddt.ddt
class HostTestCase(test.TestCase):
"""Test Case for host api."""
@ -85,6 +59,25 @@ class HostTestCase(test.TestCase):
def setUp(self):
super(HostTestCase, self).setUp()
self._set_up()
self.failover_segment = fakes_data.create_fake_failover_segment(
name="segment1", id=1, description="failover_segment for compute",
service_type="COMPUTE", recovery_method="auto",
uuid=uuidsentinel.fake_segment
)
self.host = fakes_data.create_fake_host(
name="host_1", id=1, reserved=False, on_maintenance=False,
type="fake", control_attributes="fake-control_attributes",
uuid=uuidsentinel.fake_host_1,
failover_segment=self.failover_segment
)
self.host_2 = fakes_data.create_fake_host(
name="host_2", id=2, reserved=False, on_maintenance=False,
type="fake", control_attributes="fake-control_attributes",
uuid=uuidsentinel.fake_host_2,
failover_segment=self.failover_segment
)
self.host_list = [self.host, self.host_2]
self.host_list_obj = _make_hosts_list(self.host_list)
@property
def app(self):
@ -98,18 +91,20 @@ class HostTestCase(test.TestCase):
@mock.patch.object(ha_api.HostAPI, 'get_all')
def test_index(self, mock_get_all, mock_segment):
mock_segment.return_value = mock.Mock()
mock_get_all.return_value = HOST_LIST
mock_get_all.return_value = self.host_list
result = self.controller.index(self.req, uuidsentinel.fake_segment1)
result = result['hosts']
self._assert_host_data(HOST_LIST, _make_hosts_list(result))
self._assert_host_data(self.host_list_obj, _make_hosts_list(result))
@mock.patch.object(segment_obj.FailoverSegment, 'get_by_uuid')
@mock.patch.object(ha_api.HostAPI, 'get_all')
def test_index_valid_on_maintenance(self, mock_get_all, mock_segment):
host_list = [{"name": "host_1", "id": "1", "on_maintenance": True},
{"name": "host_2", "id": "2", "on_maintenance": True}]
mock_get_all.return_value = host_list
mock_segment.return_value = mock.Mock()
self.host_list[0]['on_maintenance'] = True
self.host_list[1]['on_maintenance'] = True
mock_get_all.return_value = self.host_list
for parameter in ['1', 't', 'true', 'on', 'y', 'yes']:
req = fakes.HTTPRequest.blank(
'/v1/segments/%s/hosts?on_maintenance=''%s' % (
@ -117,13 +112,12 @@ class HostTestCase(test.TestCase):
use_admin_context=True)
result = self.controller.index(req, uuidsentinel.fake_segment1)
self.assertIn('hosts', result)
self.assertEqual(len(host_list), len(result['hosts']))
for host in result['hosts']:
self.assertTrue(host['on_maintenance'])
host_list = [{"name": "host_1", "id": "1", "on_maintenance": False},
{"name": "host_2", "id": "2", "on_maintenance": False}]
mock_get_all.return_value = host_list
self.host_list[0]['on_maintenance'] = False
self.host_list[1]['on_maintenance'] = False
mock_get_all.return_value = self.host_list
for parameter in ['0', 'f', 'false', 'off', 'n', 'no']:
req = fakes.HTTPRequest.blank(
'/v1/segments/%s/hosts?on_maintenance=''%s' % (
@ -131,7 +125,6 @@ class HostTestCase(test.TestCase):
use_admin_context=True)
result = self.controller.index(req, uuidsentinel.fake_segment1)
self.assertIn('hosts', result)
self.assertEqual(len(host_list), len(result['hosts']))
for host in result['hosts']:
self.assertFalse(host['on_maintenance'])
@ -148,9 +141,9 @@ class HostTestCase(test.TestCase):
@mock.patch.object(segment_obj.FailoverSegment, 'get_by_uuid')
@mock.patch.object(ha_api.HostAPI, 'get_all')
def test_index_valid_reserved(self, mock_get_all, mock_segment):
host_list = [{"name": "host_1", "id": "1", "reserved": True},
{"name": "host_2", "id": "2", "reserved": True}]
mock_get_all.return_value = host_list
self.host_list[0]['reserved'] = True
self.host_list[1]['reserved'] = True
mock_get_all.return_value = self.host_list
for parameter in ['1', 't', 'true', 'on', 'y', 'yes']:
req = fakes.HTTPRequest.blank(
'/v1/segments/%s/hosts?reserved=''%s' % (
@ -158,13 +151,12 @@ class HostTestCase(test.TestCase):
), use_admin_context=True)
result = self.controller.index(req, uuidsentinel.fake_segment1)
self.assertIn('hosts', result)
self.assertEqual(len(host_list), len(result['hosts']))
for host in result['hosts']:
self.assertTrue(host['reserved'])
host_list = [{"name": "host_1", "id": "1", "reserved": False},
{"name": "host_2", "id": "2", "reserved": False}]
mock_get_all.return_value = host_list
self.host_list[0]['reserved'] = False
self.host_list[1]['reserved'] = False
mock_get_all.return_value = self.host_list
for parameter in ['0', 'f', 'false', 'off', 'n', 'no']:
req = fakes.HTTPRequest.blank(
'/v1/segments/%s/hosts?reserved=''%s' % (
@ -172,7 +164,6 @@ class HostTestCase(test.TestCase):
use_admin_context=True)
result = self.controller.index(req, uuidsentinel.fake_segment1)
self.assertIn('hosts', result)
self.assertEqual(len(host_list), len(result['hosts']))
for host in result['hosts']:
self.assertFalse(host['reserved'])
@ -232,7 +223,7 @@ class HostTestCase(test.TestCase):
@mock.patch.object(ha_api.HostAPI, 'create_host')
def test_create(self, mock_create):
mock_create.return_value = HOST
mock_create.return_value = self.host
body = {
"host": {
"name": "host-1", "type": "fake",
@ -244,7 +235,7 @@ class HostTestCase(test.TestCase):
result = self.controller.create(self.req,
uuidsentinel.fake_segment1, body=body)
result = result['host']
self._assert_host_data(HOST, _make_host_obj(result))
self._assert_host_data(self.host, _make_host_obj(result))
@mock.patch('masakari.rpc.get_client')
@mock.patch.object(ha_api.HostAPI, 'create_host')
@ -354,12 +345,12 @@ class HostTestCase(test.TestCase):
@mock.patch.object(ha_api.HostAPI, 'get_host')
def test_show(self, mock_get_host):
mock_get_host.return_value = HOST
mock_get_host.return_value = self.host
result = self.controller.show(self.req, uuidsentinel.fake_segment1,
uuidsentinel.fake_host_1)
result = result['host']
self._assert_host_data(HOST, _make_host_obj(result))
self._assert_host_data(self.host, _make_host_obj(result))
@mock.patch.object(ha_api.HostAPI, 'get_host')
def test_show_with_non_existing_id(self, mock_get_host):
@ -369,6 +360,16 @@ class HostTestCase(test.TestCase):
self.controller.show, self.req,
uuidsentinel.fake_segment1, "2")
@mock.patch.object(ha_api.HostAPI, 'get_host')
def test_show_non_assigned_failover_segment(self, mock_get_host):
mock_get_host.side_effect = exception.HostNotFoundUnderFailoverSegment(
host_uuid=uuidsentinel.fake_host_3,
segment_uuid=uuidsentinel.fake_segment1)
self.assertRaises(exc.HTTPNotFound, self.controller.show,
self.req, uuidsentinel.fake_segment1,
uuidsentinel.fake_host_3)
@ddt.data(
{"body": {
"host": {
@ -382,14 +383,14 @@ class HostTestCase(test.TestCase):
@ddt.unpack
@mock.patch.object(ha_api.HostAPI, 'update_host')
def test_update(self, mock_update_host, body):
mock_update_host.return_value = HOST
mock_update_host.return_value = self.host
result = self.controller.update(self.req, uuidsentinel.fake_segment1,
uuidsentinel.fake_host_1,
body=body)
result = result['host']
self._assert_host_data(HOST, _make_host_obj(result))
self._assert_host_data(self.host, _make_host_obj(result))
@ddt.data(
# no updates
@ -435,6 +436,17 @@ class HostTestCase(test.TestCase):
self.req, uuidsentinel.fake_segment1,
uuidsentinel.fake_host_1, body=test_data)
@mock.patch.object(ha_api.HostAPI, 'update_host')
def test_update_non_assigned_failover_segment(self, mock_update_host):
test_data = {"host": {"name": "host-1"}}
mock_update_host.side_effect = \
exception.HostNotFoundUnderFailoverSegment(
host_uuid=uuidsentinel.fake_host_3,
segment_uuid=uuidsentinel.fake_segment1)
self.assertRaises(exc.HTTPNotFound, self.controller.update,
self.req, uuidsentinel.fake_segment1,
uuidsentinel.fake_host_3, body=test_data)
@mock.patch.object(ha_api.HostAPI, 'delete_host')
def test_delete_host(self, mock_delete):

View File

@ -332,6 +332,7 @@ class HostsTestCase(test.TestCase, ModelsObjectComparatorMixin):
# create one more reserved_host which is not on maintenance
temp_host = self._get_fake_values()
temp_host['on_maintenance'] = False
temp_host['failover_segment_id'] = uuidsentinel.failover_segment_id
self._create_host(temp_host)
ignored_keys = ['deleted', 'created_at', 'updated_at', 'deleted_at',

View File

@ -396,8 +396,7 @@ class EngineManagerUnitTestCase(test.NoDBTestCase):
mock_format.return_value = mock.ANY
fake_host = fakes.create_fake_host()
fake_host.failover_segment = fakes.create_fake_failover_segment(
recovery_method='reserved_host')
fake_host.failover_segment.recovery_method = 'reserved_host'
mock_host_obj.return_value = fake_host
notification = self._get_compute_host_type_notification()
@ -440,8 +439,7 @@ class EngineManagerUnitTestCase(test.NoDBTestCase):
mock_host_update, mock_host_save, mock_host_obj,
mock_notification_get):
fake_host = fakes.create_fake_host()
fake_host.failover_segment = fakes.create_fake_failover_segment(
recovery_method='reserved_host')
fake_host.failover_segment.recovery_method = 'reserved_host'
reserved_host_object_list = [fake_host]
mock_get_all.return_value = reserved_host_object_list
mock_host_obj.return_value = fake_host
@ -495,8 +493,7 @@ class EngineManagerUnitTestCase(test.NoDBTestCase):
mock_host_update, mock_host_save, mock_host_obj,
mock_notification_get):
fake_host = fakes.create_fake_host(reserved=True)
fake_host.failover_segment = fakes.create_fake_failover_segment(
recovery_method='reserved_host')
fake_host.failover_segment.recovery_method = 'reserved_host'
reserved_host_object_list = [fake_host]
mock_get_all.return_value = reserved_host_object_list
mock_host_obj.return_value = fake_host

View File

@ -12,15 +12,31 @@
# License for the specific language governing permissions and limitations
# under the License.
import datetime
import iso8601
from oslo_utils import timeutils
from oslo_utils import uuidutils
from masakari import objects
from masakari.objects import segment as segment_obj
from masakari.tests import uuidsentinel
NOW = timeutils.utcnow().replace(microsecond=0)
def _make_segment_obj(segment_dict):
return segment_obj.FailoverSegment(**segment_dict)
FAILOVER_SEGMENT = {"name": "segment1", "id": "1",
"service_type": "COMPUTE", "recovery_method": "auto",
"uuid": uuidsentinel.fake_segment1,
"description": "failover_segment for compute"}
FAILOVER_SEGMENT = _make_segment_obj(FAILOVER_SEGMENT)
class FakeNovaClient(object):
class Server(object):
def __init__(self, id=None, uuid=None, host=None, vm_state=None,
@ -170,15 +186,19 @@ def create_fake_notification(type="VM", id=1, payload=None,
notification_uuid=notification_uuid)
def create_fake_host(name='fake_host', id=1, reserved=False,
on_maintenance=False, type='SSH',
control_attributes='fake',
uuid=uuidsentinel.fake_host,
failover_segment_id=uuidsentinel.fake_segment):
return objects.Host(
name=name, id=id, reserved=reserved, on_maintenance=on_maintenance,
type=type, control_attributes=control_attributes, uuid=uuid,
failover_segment_id=failover_segment_id)
def create_fake_host(**updates):
host = {
'name': 'fake_host', 'id': 1, 'reserved': False,
'on_maintenance': False, 'type': 'SSH',
'control_attributes': 'fake', 'uuid': uuidsentinel.fake_host,
'failover_segment': FAILOVER_SEGMENT,
'created_at': datetime.datetime(
2019, 8, 8, 0, 0, 0, tzinfo=iso8601.UTC),
'updated_at': None, 'deleted_at': None, 'deleted': False
}
if updates:
host.update(updates)
return objects.Host(**host)
def create_fake_failover_segment(name='fake_segment', id=1, description=None,

View File

@ -298,8 +298,7 @@ class HostAPITestCase(test.NoDBTestCase):
self.host = fakes_data.create_fake_host(
name="host_1", id=1, reserved=False, on_maintenance=False,
type="fake", control_attributes="fake-control_attributes",
uuid=uuidsentinel.fake_host_1,
failover_segment_id=uuidsentinel.fake_segment1
uuid=uuidsentinel.fake_host_1
)
self.exception_in_use = exception.HostInUse(
uuid=self.host.uuid)
@ -315,8 +314,7 @@ class HostAPITestCase(test.NoDBTestCase):
fake_host = fakes_data.create_fake_host(
name="host_2", id=2, reserved=False, on_maintenance=False,
type="fake", control_attributes="fake-control_attributes",
uuid=uuidsentinel.fake_host_2,
failover_segment_id=uuidsentinel.fake_segment1
uuid=uuidsentinel.fake_host_2
)
fake_host_list = [self.host, fake_host]
mock_get_all.return_value = fake_host_list
@ -461,7 +459,7 @@ class HostAPITestCase(test.NoDBTestCase):
'control_attributes': 'fake-control_attributes',
'on_maintenance': False,
'uuid': uuidsentinel.fake_uuid,
'failover_segment_id': uuidsentinel.fake_segment,
'failover_segment_id': self.failover_segment.uuid,
'type': 'fake-type'
}
mock_host_create.create = mock.Mock()
@ -505,11 +503,9 @@ class HostAPITestCase(test.NoDBTestCase):
@mock.patch.object(nova_obj.API, 'hypervisor_search')
@mock.patch.object(host_obj.Host, 'save')
@mock.patch.object(host_obj.Host, 'get_by_uuid')
@mock.patch.object(segment_obj.FailoverSegment, 'get_by_uuid')
def test_update(self, mock_segment_get, mock_get,
mock_update, mock_hypervisor_search, mock_host_obj,
mock_is_under_recovery):
mock_segment_get.return_value = self.failover_segment
def test_update(
self, mock_get, mock_update, mock_hypervisor_search,
mock_host_obj, mock_is_under_recovery):
host_data = {"name": "host_1"}
mock_get.return_value = self.host
mock_host_obj.return_value = self.host
@ -525,11 +521,8 @@ class HostAPITestCase(test.NoDBTestCase):
'is_under_recovery')
@mock.patch.object(nova_obj.API, 'hypervisor_search')
@mock.patch.object(host_obj.Host, 'get_by_uuid')
@mock.patch.object(segment_obj.FailoverSegment, 'get_by_uuid')
def test_update_with_non_existing_host(self, mock_segment_get, mock_get,
mock_hypervisor_search,
mock_is_under_recovery):
mock_segment_get.return_value = self.failover_segment
def test_update_with_non_existing_host(
self, mock_get, mock_hypervisor_search, mock_is_under_recovery):
host_data = {"name": "host-2"}
mock_get.return_value = self.host
mock_hypervisor_search.side_effect = (
@ -547,12 +540,9 @@ class HostAPITestCase(test.NoDBTestCase):
@mock.patch.object(host_obj.Host, 'save')
@mock.patch.object(api_utils, 'notify_about_host_api')
@mock.patch.object(host_obj.Host, 'get_by_uuid')
@mock.patch.object(segment_obj.FailoverSegment, 'get_by_uuid')
def test_host_update_exception(self, mock_segment_get, mock_get,
mock_notify_about_host_api,
mock_host_obj, mock_hypervisor_search,
mock_is_under_recovery):
mock_segment_get.return_value = self.failover_segment
def test_host_update_exception(
self, mock_get, mock_notify_about_host_api, mock_host_obj,
mock_hypervisor_search, mock_is_under_recovery):
host_data = {"name": "host_1"}
mock_get.return_value = self.host
e = exception.InvalidInput(reason="TEST")
@ -579,10 +569,9 @@ class HostAPITestCase(test.NoDBTestCase):
'is_under_recovery')
@mock.patch.object(host_obj, 'Host')
@mock.patch.object(host_obj.Host, 'get_by_uuid')
@mock.patch.object(segment_obj.FailoverSegment, 'get_by_uuid')
def test_update_host_under_recovery(self, mock_segment_get, mock_get,
mock_host_obj, mock_is_under_recovery, mock_HostInUse):
mock_segment_get.return_value = self.failover_segment
def test_update_host_under_recovery(
self, mock_get, mock_host_obj, mock_is_under_recovery,
mock_HostInUse):
host_data = {"name": "host_1"}
mock_get.return_value = self.host
mock_host_obj.return_value = self.host
@ -596,13 +585,14 @@ class HostAPITestCase(test.NoDBTestCase):
@mock.patch.object(api_utils, 'notify_about_host_api')
@mock.patch.object(segment_obj.FailoverSegment,
'is_under_recovery')
@mock.patch('masakari.objects.base.MasakariObject'
'.masakari_obj_get_changes')
@mock.patch.object(host_obj.Host, '_from_db_object')
@mock.patch.object(host_obj.Host, 'get_by_uuid')
@mock.patch('masakari.db.host_update')
@mock.patch.object(segment_obj.FailoverSegment, 'get_by_uuid')
def test_update_convert_boolean_attributes(
self, mock_segment, mock_host_update, mock_host_object,
mock__from_db_object, mock_is_under_recovery,
self, mock_host_update, mock_host_object, mock__from_db_object,
mock_masakari_obj_get_changes, mock_is_under_recovery,
mock_notify_about_host_api):
host_data = {
"reserved": 'Off',
@ -612,22 +602,23 @@ class HostAPITestCase(test.NoDBTestCase):
expected_data = {
'name': 'host_1', 'uuid': uuidsentinel.fake_host_1,
'on_maintenance': True,
'failover_segment_id': uuidsentinel.fake_segment1,
'failover_segment': self.failover_segment,
'reserved': False, 'type': 'fake',
'control_attributes': 'fake-control_attributes'
}
mock_segment.return_value = self.failover_segment
mock_masakari_obj_get_changes.return_value = host_data
mock_host_object.return_value = self.host
self.host._context = self.context
mock_is_under_recovery.return_value = False
result = self.host_api.update_host(self.context,
uuidsentinel.fake_segment1,
uuidsentinel.fake_segment,
uuidsentinel.fake_host_1,
host_data)
mock_host_update.assert_called_with(self.context,
uuidsentinel.fake_host_1,
expected_data)
host_data)
mock_host_update.return_value = expected_data
action = fields.EventNotificationAction.HOST_UPDATE
phase_start = fields.EventNotificationPhase.START
phase_end = fields.EventNotificationPhase.END
@ -642,10 +633,8 @@ class HostAPITestCase(test.NoDBTestCase):
'is_under_recovery')
@mock.patch.object(host_obj.Host, 'destroy')
@mock.patch.object(host_obj.Host, 'get_by_uuid')
@mock.patch.object(segment_obj.FailoverSegment, 'get_by_uuid')
def test_delete_host(self, mock_segment_get, mock_get,
mock_segment_destroy, mock_is_under_recovery):
mock_segment_get.return_value = self.failover_segment
def test_delete_host(
self, mock_get, mock_segment_destroy, mock_is_under_recovery):
mock_get.return_value = self.host
mock_is_under_recovery.return_value = False
@ -659,11 +648,9 @@ class HostAPITestCase(test.NoDBTestCase):
@mock.patch.object(host_obj.Host, 'destroy')
@mock.patch.object(api_utils, 'notify_about_host_api')
@mock.patch.object(host_obj.Host, 'get_by_uuid')
@mock.patch.object(segment_obj.FailoverSegment, 'get_by_uuid')
def test_host_delete_exception(self, mock_segment_get, mock_get,
mock_notify_about_host_api,
mock_host_destroy, mock_is_under_recovery):
mock_segment_get.return_value = self.failover_segment
def test_host_delete_exception(
self, mock_get, mock_notify_about_host_api, mock_host_destroy,
mock_is_under_recovery):
mock_get.return_value = self.host
mock_is_under_recovery.return_value = False
e = exception.InvalidInput(reason="TEST")
@ -689,10 +676,9 @@ class HostAPITestCase(test.NoDBTestCase):
'is_under_recovery')
@mock.patch.object(host_obj, 'Host')
@mock.patch.object(host_obj.Host, 'get_by_uuid')
@mock.patch.object(segment_obj.FailoverSegment, 'get_by_uuid')
def test_delete_host_under_recovery(self, mock_segment_get, mock_get,
mock_host_obj, mock_is_under_recovery, mock_HostInUse):
mock_segment_get.return_value = self.failover_segment
def test_delete_host_under_recovery(
self, mock_get, mock_host_obj, mock_is_under_recovery,
mock_HostInUse):
mock_get.return_value = self.host
mock_is_under_recovery.return_value = True
mock_HostInUse.return_value = self.exception_in_use
@ -712,11 +698,15 @@ class NotificationAPITestCase(test.NoDBTestCase):
self.req = fakes.HTTPRequest.blank('/v1/notifications',
use_admin_context=True)
self.context = self.req.environ['masakari.context']
self.failover_segment = fakes_data.create_fake_failover_segment(
name="segment1", id=1, description="something",
service_type="COMPUTE", recovery_method="auto",
uuid=uuidsentinel.fake_segment
)
self.host = fakes_data.create_fake_host(
name="host_1", id=1, reserved=False, on_maintenance=False,
type="fake", control_attributes="fake-control_attributes",
uuid=uuidsentinel.fake_host_1,
failover_segment_id=uuidsentinel.fake_segment1
uuid=uuidsentinel.fake_host_1
)
self.notification = fakes_data.create_fake_notification(
type="VM", id=1, payload={

View File

@ -23,7 +23,7 @@ from masakari import db
from masakari import exception
from masakari.objects import fields
from masakari.objects import host
from masakari.objects import segment
from masakari.tests.unit import fakes as fakes_data
from masakari.tests.unit.objects import test_objects
from masakari.tests import uuidsentinel
@ -56,8 +56,7 @@ def _fake_host(**kwargs):
'on_maintenance': False,
'control_attributes': 'fake_control_attributes',
'type': 'SSH',
'failover_segment': fake_segment_dict,
'failover_segment_id': uuidsentinel.fake_segment,
'failover_segment': fake_segment_dict
}
fake_host.update(kwargs)
return fake_host
@ -107,9 +106,15 @@ class TestHostObject(test_objects._LocalTest):
def _host_create_attributes(self):
failover_segment = fakes_data.create_fake_failover_segment(
name="fake_segment", id=123, description="fakefake",
service_type="COMPUTE", recovery_method="auto",
uuid=uuidsentinel.fake_segment
)
host_obj = host.Host(context=self.context)
host_obj.name = 'foo-host'
host_obj.failover_segment_id = uuidsentinel.fake_segment
host_obj.failover_segment = failover_segment
host_obj.type = 'fake-type'
host_obj.reserved = False
host_obj.on_maintenance = False
@ -225,24 +230,30 @@ class TestHostObject(test_objects._LocalTest):
self.context, limit=5, marker=host_name)
@mock.patch.object(api_utils, 'notify_about_host_api')
@mock.patch('masakari.objects.base.MasakariObject'
'.masakari_obj_get_changes')
@mock.patch.object(db, 'host_update')
def test_save(self, mock_host_update, mock_notify_about_host_api):
def test_save(
self, mock_host_update, mock_masakari_obj_get_changes,
mock_notify_about_host_api):
mock_host_update.return_value = fake_host
host_data = {
'name': 'foo-host',
"uuid": uuidsentinel.fake_host,
'id': 123
}
mock_masakari_obj_get_changes.return_value = host_data
host_obj = self._host_create_attributes()
host_obj.id = 123
host_obj.save()
self._compare_segment_and_host_data(host_obj)
(mock_host_update.
assert_called_once_with(self.context, uuidsentinel.fake_host,
{'control_attributes': u'fake_attributes',
'type': u'fake-type',
'failover_segment_id':
uuidsentinel.fake_segment,
'name': u'foo-host',
'uuid': uuidsentinel.fake_host,
'reserved': False, 'on_maintenance': False
{'name': 'foo-host',
'uuid': uuidsentinel.fake_host
}))
action = fields.EventNotificationAction.HOST_UPDATE
phase_start = fields.EventNotificationPhase.START
@ -260,8 +271,6 @@ class TestHostObject(test_objects._LocalTest):
mock_host_update.return_value = fake_host
host_obj = self._host_create_attributes()
host_obj.failover_segment = (segment.
FailoverSegment(context=self.context))
host_obj.id = 123
self.assertRaises(exception.ObjectActionError, host_obj.save)
@ -304,3 +313,23 @@ class TestHostObject(test_objects._LocalTest):
mock.call(self.context, host_object, action=action,
phase=phase_start)]
mock_notify_about_host_api.assert_has_calls(notify_calls)
def _host_create_attributes2(self):
failover_segment = fakes_data.create_fake_failover_segment(
name="fake_segment", id=123, description="fakefake",
service_type="COMPUTE", recovery_method="auto",
uuid=uuidsentinel.fake_segment
)
host_obj = self._host_create_attributes()
host_obj.failover_segment_id = failover_segment.uuid
return host_obj
def test_obj_make_compatible(self):
host_obj = self._host_create_attributes2()
primitive = host_obj.obj_to_primitive()
self.assertIn('failover_segment', primitive['masakari_object.data'])
self.assertNotIn(
'failover_segment_id', primitive['masakari_object.data'])

View File

@ -655,7 +655,7 @@ class TestRegistry(test.NoDBTestCase):
object_data = {
'FailoverSegment': '1.0-5e8b8bc8840b35439b5f2b621482d15d',
'FailoverSegmentList': '1.0-dfc5c6f5704d24dcaa37b0bbb03cbe60',
'Host': '1.1-3fc4d548fa220c76906426095e5971fc',
'Host': '1.2-f05735b156b687bc916d46b551bc45e3',
'HostList': '1.0-25ebe1b17fbd9f114fae8b6a10d198c0',
'Notification': '1.1-91e3a051078e35300e325a3e2ae5fde5',
'NotificationProgressDetails': '1.0-fc611ac932b719fbc154dbe34bb8edee',
@ -664,8 +664,8 @@ object_data = {
'ExceptionNotification': '1.0-1187e93f564c5cca692db76a66cda2a6',
'ExceptionPayload': '1.0-96f178a12691e3ef0d8e3188fc481b90',
'HostApiNotification': '1.0-1187e93f564c5cca692db76a66cda2a6',
'HostApiPayload': '1.0-ca9035d81cec6697f12dd4cac4c8f027',
'HostApiPayloadBase': '1.0-211379087a876212df6194b011207339',
'HostApiPayload': '1.0-20603e23a06477975b860459ba684d34',
'HostApiPayloadBase': '1.1-e02e80de08d0b584ee7a0a0320bfd029',
'NotificationApiPayload': '1.0-c050869a1f4aed23e7645bd4d1830ecd',
'NotificationApiPayloadBase': '1.0-cda8d53a77e64f83e3782fc9c4d499bb',
'NotificationApiNotification': '1.0-1187e93f564c5cca692db76a66cda2a6',