Implement Flavor synchronization in Kingbird.

Flavor Synchronization sync multiple flavors from one region to
multiple target regions.
Only admin can perform flavor-sync.Currently, when a user requests to
sync a flavor kingbird syncs extra specs of the source resource.
Added Test-cases for the same.

Implements:blueprint resource-syncing
Change-Id: Id289cf93bb9c30ea699223e232025285a29042de
This commit is contained in:
Goutham Pratapa 2017-08-11 14:15:35 +05:30
parent 2f6dab7fc1
commit fd6b4cba10
6 changed files with 570 additions and 4 deletions

View File

@ -142,4 +142,64 @@ class NovaClient(base.DriverBase):
except exceptions.ResourceNotFound():
LOG.error('Exception Occurred: Source Flavor %s not available',
res_id)
def get_flavor_access_tenant(self, res_id):
"""Get tenant which has access to the Flavor."""
try:
access_tenants = [access.tenant_id for access in
self.nova_client.
flavor_access.list(flavor=res_id)]
LOG.info("Access to only : %s", access_tenants)
return access_tenants
except exceptions.InternalError():
LOG.error('Exception Occurred couldnot find access tenants.')
pass
def check_and_delete_flavor_in_target_region(self, flavor,
resource_flavor):
"""Check for the flavor and then delete it."""
try:
target_flavor = self.nova_client.flavors.get(flavor.id)
if target_flavor:
resource_flavor.pop("flavorid", None)
flavor_list = self.nova_client.flavors.list(is_public=None)
for target_region_flavor in flavor_list:
if target_region_flavor.name == flavor.name:
self.nova_client.flavors.delete(
target_region_flavor.id)
LOG.info("Deleted Flavor: %s", flavor.name)
break
except Exception:
LOG.error('Exception Occurred: %s not available', flavor.id)
pass
def create_flavor(self, force, flavor, access_tenants=None):
"""Create Flavor in target regions."""
resource_flavor = flavor._info.copy()
resource_flavor.update({'flavorid': resource_flavor['id']})
resource_flavor.pop("links", None)
resource_flavor.pop("OS-FLV-DISABLED:disabled", None)
resource_flavor.pop("OS-FLV-EXT-DATA:ephemeral", None)
resource_flavor.pop("os-flavor-access:is_public", None)
resource_flavor.pop("id", None)
if not resource_flavor['swap']:
resource_flavor.pop("swap", None)
if not flavor.is_public:
resource_flavor.update({'is_public': False})
if force:
self.check_and_delete_flavor_in_target_region(
flavor, resource_flavor)
target_flavor = self.nova_client.flavors.create(**resource_flavor)
target_flavor_properties = flavor.get_keys()
if target_flavor_properties:
try:
target_flavor.set_keys(target_flavor_properties)
except Exception as e:
LOG.error(_("Failed to set flavor property: %s"), e)
if access_tenants:
for tenant in access_tenants:
self.nova_client.flavor_access.add_tenant_access(
target_flavor.id, tenant)
LOG.info('%(flavor)s Access Granted to %(tenant)s'
% {'flavor': target_flavor.name, 'tenant': tenant})
return target_flavor

View File

@ -0,0 +1,118 @@
# Copyright 2017 Ericsson AB.
#
# 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 threading
from oslo_log import log as logging
from kingbird.common import consts
from kingbird.common.endpoint_cache import EndpointCache
from kingbird.common import exceptions
from kingbird.db.sqlalchemy import api as db_api
from kingbird.drivers.openstack.nova_v2 import NovaClient
LOG = logging.getLogger(__name__)
class FlavorSyncManager(object):
"""Manages tasks related to resource management."""
def __init__(self, *args, **kwargs):
super(FlavorSyncManager, self).__init__()
def create_resources_in_region(self, job_id, force, target_regions,
source_flavor, session, context,
access_tenants=None):
"""Create Region specific threads."""
regions_thread = list()
for region in target_regions:
thread = threading.Thread(target=self.create_resources,
args=(job_id, force, region,
source_flavor, session,
context, access_tenants))
regions_thread.append(thread)
thread.start()
for region_thread in regions_thread:
region_thread.join()
def create_resources(self, job_id, force, region, source_flavor,
session, context, access_tenants=None):
"""Create resources using threads."""
target_nova_client = NovaClient(region, session)
try:
target_nova_client.create_flavor(force, source_flavor,
access_tenants)
LOG.info('Flavor %(flavor)s created in %(region)s'
% {'flavor': source_flavor.name, 'region': region})
try:
db_api.resource_sync_update(context, job_id, region,
source_flavor.id,
consts.JOB_SUCCESS)
except exceptions.JobNotFound():
raise
except Exception as exc:
LOG.error('Exception Occurred: %(msg)s in %(region)s'
% {'msg': exc.message, 'region': region})
try:
db_api.resource_sync_update(context, job_id, region,
source_flavor.id,
consts.JOB_FAILURE)
except exceptions.JobNotFound():
raise
pass
def resource_sync(self, context, job_id, payload):
"""Create resources in target regions.
:param context: request context object.
:param job_id: ID of the job which triggered image_sync.
:payload: request payload.
"""
LOG.info("Triggered Flavor Sync.")
flavors_thread = list()
access_tenants = None
target_regions = payload['target']
force = eval(str(payload.get('force', False)))
resource_ids = payload.get('resources')
source_region = payload['source']
session = EndpointCache().get_session_from_token(
context.auth_token, context.project)
# Create Source Region object
source_nova_client = NovaClient(source_region, session)
for flavor in resource_ids:
source_flavor = source_nova_client.get_flavor(flavor)
if not source_flavor.is_public:
access_tenants = source_nova_client.\
get_flavor_access_tenant(flavor)
thread = threading.Thread(target=self.create_resources_in_region,
args=(job_id, force, target_regions,
source_flavor, session,
context, access_tenants))
flavors_thread.append(thread)
thread.start()
for flavor_thread in flavors_thread:
flavor_thread.join()
try:
resource_sync_details = db_api.\
resource_sync_status(context, job_id)
except exceptions.JobNotFound:
raise
result = consts.JOB_SUCCESS
if consts.JOB_FAILURE in resource_sync_details:
result = consts.JOB_FAILURE
try:
db_api.sync_job_update(context, job_id, result)
except exceptions.JobNotFound:
raise

View File

@ -23,6 +23,7 @@ from kingbird.common import context
from kingbird.common import exceptions
from kingbird.common.i18n import _
from kingbird.common import messaging as rpc_messaging
from kingbird.engine.flavor_sync_manager import FlavorSyncManager
from kingbird.engine.image_sync_manager import ImageSyncManager
from kingbird.engine.keypair_sync_manager import KeypairSyncManager
from kingbird.engine.quota_manager import QuotaManager
@ -76,6 +77,7 @@ class EngineService(service.Service):
self.qm = None
self.ksm = None
self.ism = None
self.fsm = None
def init_tgm(self):
self.TG = scheduler.ThreadGroupManager()
@ -89,12 +91,16 @@ class EngineService(service.Service):
def init_ism(self):
self.ism = ImageSyncManager()
def init_fsm(self):
self.fsm = FlavorSyncManager()
def start(self):
self.engine_id = uuidutils.generate_uuid()
self.init_tgm()
self.init_qm()
self.init_ksm()
self.init_ism()
self.init_fsm()
target = oslo_messaging.Target(version=self.rpc_api_version,
server=self.host,
topic=self.topic)
@ -169,6 +175,11 @@ class EngineService(service.Service):
# Image Sync triggered by KB_API.
self.ism.resource_sync(ctxt, job_id, payload)
@request_context
def flavor_sync(self, ctxt, job_id, payload):
# Flavor Sync triggered by KB_API.
self.fsm.resource_sync(ctxt, job_id, payload)
def _stop_rpc_server(self):
# Stop RPC connection to prevent new requests
LOG.debug(_("Attempting to stop engine service..."))

View File

@ -27,7 +27,8 @@ class Server(object):
class Fake_Flavor(object):
def __init__(self, id, ram, cores, disks, name, swap, is_public=True):
def __init__(self, id, ram, cores, disks, name, swap, rxtx_factor,
is_public=True, keys=None):
self.id = id
self.ram = ram
self.vcpus = cores
@ -35,6 +36,28 @@ class Fake_Flavor(object):
self.name = name
self.is_public = is_public
self.swap = swap
self.rxtx_factor = 1.0
self._info = {u'name': self.name,
u'links': [
{u'href': u'http://www.flavor.com/v2.1/flavors/2',
u'rel': u'self'},
{u'href': u'http://www.fake_flavor.com/flavors/2',
u'rel': u'bookmark'}],
u'ram': self.ram, u'OS-FLV-DISABLED:disabled': False,
u'vcpus': self.vcpus, u'swap': self.swap,
u'rxtx_factor': 1.0, u'disk': self.disk,
u'os-flavor-access:is_public': self.is_public,
u'OS-FLV-EXT-DATA:ephemeral': 0, u'id': self.id}
self.keys = keys
def get_keys(self):
return self.keys
class Access(object):
def __init__(self, tenant_id):
self.tenant_id = tenant_id
s1 = Server(1, {'mkey': 'mvalue'})
s2 = Server(1, {'mkey': 'mvalue', 'm2key': 'm2value'})
@ -120,8 +143,8 @@ class TestNovaClient(base.KingbirdTestCase):
def test_get_keypairs(self, mock_novaclient):
nv_client = nova_v2.NovaClient('fake_region', self.session,
DISABLED_QUOTAS)
nv_client.get_keypairs(FAKE_RESOURCE_ID)
mock_novaclient.Client().keypairs.get.return_value = 'key1'
nv_client.get_keypairs(FAKE_RESOURCE_ID)
mock_novaclient.Client().keypairs.get.\
assert_called_once_with(FAKE_RESOURCE_ID)
@ -151,9 +174,134 @@ class TestNovaClient(base.KingbirdTestCase):
@mock.patch.object(nova_v2, 'client')
def test_get_flavor(self, mock_novaclient):
"""Test get_flavor method of nova."""
nv_client = nova_v2.NovaClient('fake_region', self.session,
DISABLED_QUOTAS)
fake_flavor = Fake_Flavor('fake_id', 512, 2, 30, 'fake_flavor', 1)
nv_client.get_flavor(fake_flavor.id)
nv_client.get_flavor('fake_id')
mock_novaclient.Client().flavors.get.\
assert_called_once_with('fake_id')
@mock.patch.object(nova_v2, 'client')
def test_get_flavor_access_tenants(self, mock_novaclient):
nv_client = nova_v2.NovaClient('fake_region', self.session,
DISABLED_QUOTAS)
nv_client.get_flavor_access_tenant('fake_flavor')
mock_novaclient.Client().flavor_access.list.\
assert_called_once_with(flavor='fake_flavor')
@mock.patch.object(nova_v2, 'client')
def test_check_and_delete_flavor(self, mock_novaclient):
nv_client = nova_v2.NovaClient('fake_region', self.session,
DISABLED_QUOTAS)
fake_flavor = Fake_Flavor('fake_id', 512, 2, 30, 'fake_flavor', 1,
1.0)
mock_novaclient.Client().flavors.list.return_value = [fake_flavor]
nv_client.check_and_delete_flavor_in_target_region(fake_flavor,
fake_flavor._info)
mock_novaclient.Client().flavors.get.\
assert_called_once_with(fake_flavor.id)
mock_novaclient.Client().flavors.list.\
assert_called_once_with(is_public=None)
mock_novaclient.Client().flavors.delete.\
assert_called_once_with(fake_flavor.id)
@mock.patch.object(nova_v2, 'client')
def test_check_and_delete_target_flavor(self, mock_novaclient):
nv_client = nova_v2.NovaClient('fake_region', self.session,
DISABLED_QUOTAS)
fake_flavor = Fake_Flavor('fake_id', 512, 2, 30, 'fake_flavor', 1,
1.0)
mock_novaclient.Client().flavors.get.return_value = None
mock_novaclient.Client().flavors.list.return_value = []
nv_client.check_and_delete_flavor_in_target_region(fake_flavor,
fake_flavor._info)
@mock.patch.object(nova_v2, 'client')
def test_create_flavor_force_true_no_access_tenants(self,
mock_novaclient):
nv_client = nova_v2.NovaClient('fake_region', self.session,
DISABLED_QUOTAS)
fake_flavor = Fake_Flavor('fake_id', 512, 2, 30, 'fake_flavor', 1,
1.0)
nv_client.create_flavor(True, fake_flavor)
mock_novaclient.Client().flavors.create.\
assert_called_once_with(
disk=fake_flavor.disk, name=fake_flavor.name,
ram=fake_flavor.ram, rxtx_factor=fake_flavor.rxtx_factor,
swap=fake_flavor.swap, vcpus=fake_flavor.vcpus)
fake_resource_dict = fake_flavor._info.copy()
fake_resource_dict.update({'flavorid': fake_flavor.id})
fake_resource_dict.pop("links", None)
fake_resource_dict.pop("OS-FLV-DISABLED:disabled", None)
fake_resource_dict.pop("OS-FLV-EXT-DATA:ephemeral", None)
fake_resource_dict.pop("os-flavor-access:is_public", None)
fake_resource_dict.pop("id", None)
mock_novaclient.Client().flavors.get.\
assert_called_once_with(fake_flavor.id)
mock_novaclient.Client().flavors.list.\
assert_called_once_with(is_public=None)
@mock.patch.object(nova_v2, 'client')
def test_create_flavor_force_false_no_access_tenants(self,
mock_novaclient):
nv_client = nova_v2.NovaClient('fake_region', self.session,
DISABLED_QUOTAS)
fake_flavor = Fake_Flavor('fake_id', 512, 2, 30, 'fake_flavor', 1,
1.0)
nv_client.create_flavor(False, fake_flavor)
mock_novaclient.Client().flavors.create.\
assert_called_once_with(
flavorid=fake_flavor.id, disk=fake_flavor.disk,
name=fake_flavor.name, ram=fake_flavor.ram,
rxtx_factor=fake_flavor.rxtx_factor,
swap=fake_flavor.swap, vcpus=fake_flavor.vcpus)
mock_novaclient.Client().flavors.assert_not_called
mock_novaclient.Client().flavors.assert_not_called
@mock.patch.object(nova_v2, 'client')
def test_create_flavor_force_true_with_access_tenants(self,
mock_novaclient):
nv_client = nova_v2.NovaClient('fake_region', self.session,
DISABLED_QUOTAS)
fake_flavor = Fake_Flavor('fake_id', 512, 2, 30, 'fake_flavor', 1,
1.0)
access_tenants = ['fake_tenant_1', 'fake_tenant_2']
nv_client.create_flavor(True, fake_flavor, access_tenants)
mock_novaclient.Client().flavors.create.\
assert_called_once_with(
disk=fake_flavor.disk, name=fake_flavor.name,
ram=fake_flavor.ram, rxtx_factor=fake_flavor.rxtx_factor,
swap=fake_flavor.swap, vcpus=fake_flavor.vcpus)
fake_resource_dict = fake_flavor._info.copy()
fake_resource_dict.update({'flavorid': fake_flavor.id})
fake_resource_dict.pop("links", None)
fake_resource_dict.pop("OS-FLV-DISABLED:disabled", None)
fake_resource_dict.pop("OS-FLV-EXT-DATA:ephemeral", None)
fake_resource_dict.pop("os-flavor-access:is_public", None)
fake_resource_dict.pop("id", None)
mock_novaclient.Client().flavors.get.\
assert_called_once_with(fake_flavor.id)
mock_novaclient.Client().flavors.list.\
assert_called_once_with(is_public=None)
self.assertEqual(mock_novaclient.Client().flavor_access.
add_tenant_access.call_count, 2)
@mock.patch.object(nova_v2, 'client')
def test_create_flavor_force_false_with_access_tenants(self,
mock_novaclient):
nv_client = nova_v2.NovaClient('fake_region', self.session,
DISABLED_QUOTAS)
fake_flavor = Fake_Flavor('fake_id', 512, 2, 30, 'fake_flavor', 1,
1.0)
access_tenants = ['fake_tenant_1', 'fake_tenant_2']
nv_client.create_flavor(False, fake_flavor, access_tenants)
mock_novaclient.Client().flavors.create.\
assert_called_once_with(
flavorid=fake_flavor.id, disk=fake_flavor.disk,
name=fake_flavor.name, ram=fake_flavor.ram,
rxtx_factor=fake_flavor.rxtx_factor,
swap=fake_flavor.swap, vcpus=fake_flavor.vcpus)
mock_novaclient.Client().flavors.assert_not_called
mock_novaclient.Client().flavors.assert_not_called
self.assertEqual(mock_novaclient.Client().flavor_access.
add_tenant_access.call_count, 2)

View File

@ -0,0 +1,216 @@
# Copyright 2017 Ericsson AB.
#
# 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 mock
from kingbird.engine import flavor_sync_manager
from kingbird.tests import base
from kingbird.tests import utils
DEFAULT_FORCE = False
SOURCE_FLAVOR = 'fake_key1'
FAKE_USER_ID = 'user123'
FAKE_TARGET_REGION = 'fake_target_region'
FAKE_SOURCE_REGION = 'fake_source_region'
FAKE_RESOURCE_ID = 'fake_id'
FAKE_JOB_ID = utils.UUID1
JOB_RESULT = "SUCCESS"
FAKE_TENANTS = ['fake_tenant_1', 'fake_tenant_2']
class FakeFlavor(object):
def __init__(self, id, ram, cores, disks, name, swap, rxtx_factor,
is_public=True):
self.id = id
self.ram = ram
self.vcpus = cores
self.disk = disks
self.name = name
self.is_public = is_public
self.swap = swap
self.rxtx_factor = 1.0
class TestFlavorSyncManager(base.KingbirdTestCase):
def setUp(self):
super(TestFlavorSyncManager, self).setUp()
self.ctxt = utils.dummy_context()
@mock.patch.object(flavor_sync_manager, 'NovaClient')
@mock.patch.object(flavor_sync_manager, 'EndpointCache')
@mock.patch.object(flavor_sync_manager.FlavorSyncManager,
'create_resources')
@mock.patch.object(flavor_sync_manager, 'db_api')
def test_flavor_sync_force_false_no_access_tenants(
self, mock_db_api, mock_create_resource, mock_endpoint_cache,
mock_nova):
access_tenants = None
fake_flavor = FakeFlavor('fake_id', 512, 2, 30, 'fake_flavor', 1,
1.0)
payload = dict()
payload['target'] = [FAKE_TARGET_REGION]
payload['force'] = DEFAULT_FORCE
payload['source'] = FAKE_SOURCE_REGION
payload['resources'] = [fake_flavor]
mock_endpoint_cache().get_session_from_token.\
return_value = 'fake_session'
mock_nova().get_flavor.return_value = fake_flavor
mock_db_api().resource_sync_status.return_value = [JOB_RESULT]
fsm = flavor_sync_manager.FlavorSyncManager()
fsm.resource_sync(self.ctxt, FAKE_JOB_ID, payload)
mock_create_resource.assert_called_once_with(
FAKE_JOB_ID, payload['force'], payload['target'][0], fake_flavor,
'fake_session', self.ctxt, access_tenants)
mock_nova().get_flavor_access_tenant.assert_not_called
mock_db_api.resource_sync_status.\
assert_called_once_with(self.ctxt, FAKE_JOB_ID)
mock_db_api.sync_job_update.\
assert_called_once_with(self.ctxt, FAKE_JOB_ID, JOB_RESULT)
@mock.patch.object(flavor_sync_manager, 'NovaClient')
@mock.patch.object(flavor_sync_manager, 'EndpointCache')
@mock.patch.object(flavor_sync_manager.FlavorSyncManager,
'create_resources')
@mock.patch.object(flavor_sync_manager, 'db_api')
def test_flavor_sync_force_true_no_access_tenants(
self, mock_db_api, mock_create_resource, mock_endpoint_cache,
mock_nova):
access_tenants = None
fake_flavor = FakeFlavor('fake_id', 512, 2, 30, 'fake_flavor', 1,
1.0)
payload = dict()
payload['target'] = [FAKE_TARGET_REGION]
payload['force'] = True
payload['source'] = FAKE_SOURCE_REGION
payload['resources'] = [fake_flavor]
mock_endpoint_cache().get_session_from_token.\
return_value = 'fake_session'
mock_nova().get_flavor.return_value = fake_flavor
mock_db_api().resource_sync_status.return_value = [JOB_RESULT]
fsm = flavor_sync_manager.FlavorSyncManager()
fsm.resource_sync(self.ctxt, FAKE_JOB_ID, payload)
mock_create_resource.assert_called_once_with(
FAKE_JOB_ID, payload['force'], payload['target'][0], fake_flavor,
'fake_session', self.ctxt, access_tenants)
mock_nova().get_flavor_access_tenant.assert_not_called
mock_db_api.resource_sync_status.\
assert_called_once_with(self.ctxt, FAKE_JOB_ID)
mock_db_api.sync_job_update.\
assert_called_once_with(self.ctxt, FAKE_JOB_ID, JOB_RESULT)
@mock.patch.object(flavor_sync_manager, 'NovaClient')
@mock.patch.object(flavor_sync_manager, 'EndpointCache')
@mock.patch.object(flavor_sync_manager.FlavorSyncManager,
'create_resources')
@mock.patch.object(flavor_sync_manager, 'db_api')
def test_flavor_sync_force_false_with_access_tenants(
self, mock_db_api, mock_create_resource, mock_endpoint_cache,
mock_nova):
access_tenants = FAKE_TENANTS
fake_flavor = FakeFlavor('fake_id', 512, 2, 30, 'fake_flavor', 1,
1.0, False)
payload = dict()
payload['target'] = [FAKE_TARGET_REGION]
payload['force'] = DEFAULT_FORCE
payload['source'] = FAKE_SOURCE_REGION
payload['resources'] = [fake_flavor]
mock_nova().get_flavor_access_tenant.return_value = access_tenants
mock_endpoint_cache().get_session_from_token.\
return_value = 'fake_session'
mock_nova().get_flavor.return_value = fake_flavor
mock_db_api().resource_sync_status.return_value = [JOB_RESULT]
fsm = flavor_sync_manager.FlavorSyncManager()
fsm.resource_sync(self.ctxt, FAKE_JOB_ID, payload)
mock_create_resource.assert_called_once_with(
FAKE_JOB_ID, payload['force'], payload['target'][0], fake_flavor,
'fake_session', self.ctxt, access_tenants)
mock_nova().get_flavor_access_tenant.\
assert_called_once_with(fake_flavor)
mock_db_api.resource_sync_status.\
assert_called_once_with(self.ctxt, FAKE_JOB_ID)
mock_db_api.sync_job_update.\
assert_called_once_with(self.ctxt, FAKE_JOB_ID, JOB_RESULT)
@mock.patch.object(flavor_sync_manager, 'NovaClient')
@mock.patch.object(flavor_sync_manager, 'EndpointCache')
@mock.patch.object(flavor_sync_manager.FlavorSyncManager,
'create_resources')
@mock.patch.object(flavor_sync_manager, 'db_api')
def test_flavor_sync_force_true_with_access_tenants(
self, mock_db_api, mock_create_resource, mock_endpoint_cache,
mock_nova):
access_tenants = FAKE_TENANTS
fake_flavor = FakeFlavor('fake_id', 512, 2, 30, 'fake_flavor', 1,
1.0, False)
payload = dict()
payload['target'] = [FAKE_TARGET_REGION]
payload['force'] = True
payload['source'] = FAKE_SOURCE_REGION
payload['resources'] = [fake_flavor]
mock_nova().get_flavor_access_tenant.return_value = access_tenants
mock_endpoint_cache().get_session_from_token.\
return_value = 'fake_session'
mock_nova().get_flavor.return_value = fake_flavor
mock_db_api().resource_sync_status.return_value = [JOB_RESULT]
fsm = flavor_sync_manager.FlavorSyncManager()
fsm.resource_sync(self.ctxt, FAKE_JOB_ID, payload)
mock_create_resource.assert_called_once_with(
FAKE_JOB_ID, payload['force'], payload['target'][0], fake_flavor,
'fake_session', self.ctxt, access_tenants)
mock_nova().get_flavor_access_tenant.\
assert_called_once_with(fake_flavor)
mock_db_api.resource_sync_status.\
assert_called_once_with(self.ctxt, FAKE_JOB_ID)
mock_db_api.sync_job_update.\
assert_called_once_with(self.ctxt, FAKE_JOB_ID, JOB_RESULT)
@mock.patch.object(flavor_sync_manager.FlavorSyncManager,
'create_resources')
def test_create_resources_in_region(self, mock_create_resource):
access_tenants = None
fake_flavor = FakeFlavor('fake_id', 512, 2, 30, 'fake_flavor', 1,
1.0, False)
payload = dict()
payload['target'] = [FAKE_TARGET_REGION]
payload['force'] = True
payload['source'] = FAKE_SOURCE_REGION
payload['resources'] = [fake_flavor]
fsm = flavor_sync_manager.FlavorSyncManager()
fsm.create_resources_in_region(FAKE_JOB_ID, payload['force'],
payload['target'], fake_flavor,
'fake_session', self.ctxt,
access_tenants)
mock_create_resource.assert_called_once_with(
FAKE_JOB_ID, payload['force'], payload['target'][0], fake_flavor,
'fake_session', self.ctxt, access_tenants)
@mock.patch.object(flavor_sync_manager, 'NovaClient')
@mock.patch.object(flavor_sync_manager, 'db_api')
def test_create_resources(self, mock_db_api, mock_nova):
access_tenants = None
fake_flavor = FakeFlavor('fake_id', 512, 2, 30, 'fake_flavor', 1,
1.0, False)
payload = dict()
payload['target'] = [FAKE_TARGET_REGION]
payload['force'] = True
payload['source'] = FAKE_SOURCE_REGION
payload['resources'] = [fake_flavor]
fsm = flavor_sync_manager.FlavorSyncManager()
fsm.create_resources(FAKE_JOB_ID, payload['force'],
payload['target'][0], fake_flavor,
'fake_session', self.ctxt, access_tenants)
mock_nova().create_flavor.assert_called_once_with(
payload['force'], fake_flavor, access_tenants)
mock_db_api.resource_sync_update.assert_called_once_with(
self.ctxt, FAKE_JOB_ID, payload['target'][0], fake_flavor.id,
JOB_RESULT)

View File

@ -58,6 +58,11 @@ class TestEngineService(base.KingbirdTestCase):
self.service_obj.init_ksm()
self.assertIsNotNone(self.service_obj.ksm)
@mock.patch.object(service, 'FlavorSyncManager')
def test_init_fsm(self, mock_flavor_sync_manager):
self.service_obj.init_fsm()
self.assertIsNotNone(self.service_obj.fsm)
@mock.patch.object(service, 'ImageSyncManager')
def test_init_ism(self, mock_image_sync_manager):
self.service_obj.init_ism()
@ -131,3 +136,11 @@ class TestEngineService(base.KingbirdTestCase):
self.service_obj.image_sync(self.context, self.job_id, self.payload)
mock_image_sync_manager().resource_sync.\
assert_called_once_with(self.context, self.job_id, self.payload)
@mock.patch.object(service, 'FlavorSyncManager')
def test_flavor_sync(self, mock_flavor_sync_manager):
self.service_obj.init_tgm()
self.service_obj.init_fsm()
self.service_obj.flavor_sync(self.context, self.job_id, self.payload)
mock_flavor_sync_manager().resource_sync.\
assert_called_once_with(self.context, self.job_id, self.payload)