Enhancing Sync template feature.

The sync template feature in kingbird is to sync multiple
resource types to multiple regions.We can sync the same
resource_type more than once and in any order.
Added test-cases and tempest test-cases for the same.
Closes-Bug: #1748172

Change-Id: I01fd628ef8ed34363facc21c39e66908c4f383ac
This commit is contained in:
mounikasreeram 2018-02-08 17:32:28 +05:30
parent fad12485f7
commit 679da316cb
18 changed files with 251 additions and 258 deletions

View File

@ -56,11 +56,13 @@ class ResourceSyncController(object):
def _entries_to_database(self, context, target_regions, source_region,
resources, resource_type, result):
"""Manage the entries to database for both Keypair and image."""
"""Manage the entries to database"""
# Insert into the child table
job_ids = list()
for region in target_regions:
for resource in resources:
job_id = uuidutils.generate_uuid()
job_ids.append(job_id)
try:
db_api.resource_sync_create(context, result,
region, source_region,
@ -68,6 +70,7 @@ class ResourceSyncController(object):
job_id)
except exceptions.JobNotFound:
pecan.abort(404, _('Job not found'))
return job_ids
@index.when(method='GET', template='json')
def get(self, project, action=None):
@ -154,10 +157,10 @@ class ResourceSyncController(object):
if not source_keypair:
db_api._delete_failure_sync_job(context, result.job_id)
pecan.abort(404)
self._entries_to_database(context, target_regions,
source, source_resources,
resource_type, result)
return self._keypair_sync(force, context, result)
jobs = self._entries_to_database(context, target_regions,
source, source_resources,
resource_type, result)
return self._keypair_sync(force, context, result, jobs)
elif resource_type == consts.IMAGE:
for source in source_regions:
@ -169,10 +172,10 @@ class ResourceSyncController(object):
if image != source_image:
db_api._delete_failure_sync_job(context, result.job_id)
pecan.abort(404)
self._entries_to_database(context, target_regions,
source, source_resources,
resource_type, result)
return self._image_sync(force, context, result)
jobs = self._entries_to_database(context, target_regions,
source, source_resources,
resource_type, result)
return self._image_sync(force, context, result, jobs)
elif resource_type == consts.FLAVOR:
if not context.is_admin:
@ -186,10 +189,10 @@ class ResourceSyncController(object):
if not source_flavor:
db_api._delete_failure_sync_job(context, result.job_id)
pecan.abort(404)
self._entries_to_database(context, target_regions,
source, source_resources,
resource_type, result)
return self._flavor_sync(force, context, result)
jobs = self._entries_to_database(context, target_regions,
source, source_resources,
resource_type, result)
return self._flavor_sync(force, context, result, jobs)
else:
pecan.abort(400, _('Bad resource_type'))
@ -221,44 +224,45 @@ class ResourceSyncController(object):
else:
pecan.abort(400, _('Bad request'))
def _keypair_sync(self, force, context, result):
def _keypair_sync(self, force, context, result, jobs):
"""Make an rpc call to kb-engine.
:param job_id: ID of the job to update values in database based on
the job_id.
:param payload: payload object.
:param force: Mention force as "True" to sync the same resource
again otherwise False
:param context: context of the request.
:param result: Result object to return an output.
:param jobs: List of resource_sync_id's for job_id.
"""
self.rpc_client.keypair_sync_for_user(context, result.job_id, force)
self.rpc_client.keypair_sync_for_user(context, result.job_id,
force, jobs)
return {'job_status': {'id': result.job_id,
'status': result.sync_status,
'created_at': result.created_at}}
def _image_sync(self, force, context, result):
def _image_sync(self, force, context, result, jobs):
"""Make an rpc call to engine.
:param job_id: ID of the job to update values in database based on
the job_id.
:param payload: payload object.
:param force: Mention force as "True" to sync the same resource
again otherwise False
:param context: context of the request.
:param result: Result object to return an output.
:param jobs: List of resource_sync_id's for job_id.
"""
self.rpc_client.image_sync(context, result.job_id, force)
self.rpc_client.image_sync(context, result.job_id, force, jobs)
return {'job_status': {'id': result.job_id,
'status': result.sync_status,
'created_at': result.created_at}}
def _flavor_sync(self, force, context, result):
def _flavor_sync(self, force, context, result, jobs):
"""Make an rpc call to engine.
:param job_id: ID of the job to update values in database based on
the job_id.
:param payload: payload object.
:param force: Mention force as "True" to sync the same resource
again otherwise False
:param context: context of the request.
:param result: Result object to return an output.
:param jobs: List of resource_sync_id's for job_id.
"""
self.rpc_client.flavor_sync(context, result.job_id, force)
self.rpc_client.flavor_sync(context, result.job_id, force, jobs)
return {'job_status': {'id': result.job_id,
'status': result.sync_status,
'created_at': result.created_at}}

View File

@ -124,7 +124,3 @@ class InvalidInputError(KingbirdException):
class ResourceNotFound(NotFound):
message = _("Resource not available")
class DuplicateJobEntry(KingbirdException):
message = _("Job name is already present")

View File

@ -515,16 +515,16 @@ def resource_sync_status(context, job_id):
@require_context
def resource_sync_list(context, job_id, resource_type=None):
def resource_sync_list(context, job_id, resource_sync_id=None):
parent_row = model_query(context, models.SyncJob).\
filter_by(job_id=job_id, user_id=context.user,
project_id=context.project).first()
if not parent_row:
raise exception.JobNotFound()
if resource_type:
if resource_sync_id:
rows = model_query(context, models.ResourceSync).\
filter_by(job_id=parent_row.job_id,
resource_type=resource_type).all()
resource_sync_id=resource_sync_id).all()
else:
rows = model_query(context, models.ResourceSync).\
filter_by(job_id=parent_row.job_id).all()

View File

@ -57,54 +57,59 @@ class FlavorSyncManager(object):
raise
pass
def resource_sync(self, context, job_id, force):
def resource_sync(self, context, job_id, force, jobs):
"""Create resources in target regions.
Flavor with same name is created in target_regions.If a user
wants to syncs the same resource then nova throws 409 error
because the name is already used. In order to avoid that we
use --force and there by creates resource without fail.
:param context: request context object.
:param job_id: ID of the job which triggered image_sync.
:payload: request payload.
:force: True/False option to sync the same resource again.
:jobs: List of resource_sync_id's for param job_id.
"""
LOG.info("Triggered Flavor Sync.")
flavors_thread = list()
access_tenants = None
session = EndpointCache().get_session_from_token(
context.auth_token, context.project)
# Create Source Region object
try:
resource_jobs = db_api.resource_sync_list(context, job_id,
consts.FLAVOR)
except exceptions.JobNotFound():
raise
source_regions = [i["source_region"] for i in resource_jobs]
unique_source = list(set(source_regions))
for source_object in unique_source:
source_nova_client = NovaClient(source_object, session)
for resource_job in resource_jobs:
source_flavor = source_nova_client.\
get_flavor(resource_job["resource"])
if not source_flavor.is_public:
access_tenants = source_nova_client.\
get_flavor_access_tenant(resource_job["resource"])
thread = threading.Thread(
target=self.create_resources_in_region,
args=(resource_job["id"], force,
resource_job["target_region"],
source_flavor, session, context, access_tenants))
flavors_thread.append(thread)
thread.start()
for flavor_thread in flavors_thread:
flavor_thread.join()
for job in jobs:
try:
resource_job = db_api.resource_sync_list(context, job_id,
job)
resource_job = resource_job.pop()
except exceptions.JobNotFound():
raise
# Create Source Region object
source_nova_client = NovaClient(
resource_job["source_region"], session)
source_flavor = source_nova_client.get_flavor(
resource_job["resource"])
if not source_flavor.is_public:
access_tenants = source_nova_client.\
get_flavor_access_tenant(resource_job["resource"])
thread = threading.Thread(
target=self.create_resources_in_region,
args=(resource_job["id"], force,
resource_job["target_region"],
source_flavor, session, context, access_tenants))
flavors_thread.append(thread)
thread.start()
for flavor_thread in flavors_thread:
flavor_thread.join()
# Update Result in DATABASE.
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
# Update Result in DATABASE.
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

@ -152,7 +152,7 @@ class ImageSyncManager(object):
% {'msg': exc.message, 'region': region})
return False
def resource_sync(self, context, job_id, force):
def resource_sync(self, context, job_id, force, jobs):
"""Create resources in target regions.
Image with same id is created in target_regions and therefore
@ -163,39 +163,38 @@ class ImageSyncManager(object):
:param context: request context object.
:param job_id: ID of the job which triggered image_sync.
:payload: request payload.
:force: True/False option to sync the same resource again.
:jobs: List of resource_sync_id's for param job_id.
"""
LOG.info('Triggered image sync.')
images_thread = list()
try:
resource_jobs = db_api.resource_sync_list(context, job_id,
consts.IMAGE)
except exceptions.JobNotFound():
raise
source_regions = [i["source_region"] for i in resource_jobs]
unique_source = list(set(source_regions))
for source_object in unique_source:
for resource_job in resource_jobs:
thread = threading.Thread(
target=self.create_resources_in_region,
args=(resource_job["id"], resource_job["target_region"],
source_object, context, resource_job["resource"],
force))
images_thread.append(thread)
thread.start()
for image_thread in images_thread:
image_thread.join()
for job in jobs:
try:
resource_job = db_api.resource_sync_list(context, job_id,
job)
resource_job = resource_job.pop()
except exceptions.JobNotFound():
raise
thread = threading.Thread(
target=self.create_resources_in_region,
args=(resource_job["id"], resource_job["target_region"],
resource_job["source_region"], context,
resource_job["resource"], force))
images_thread.append(thread)
thread.start()
for image_thread in images_thread:
image_thread.join()
# Update Result in DATABASE.
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
# Update Result in DATABASE.
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

@ -55,49 +55,54 @@ class KeypairSyncManager(object):
raise
pass
def resource_sync(self, context, job_id, force):
def resource_sync(self, context, job_id, force, jobs):
"""Create resources in target regions.
Keypair with same name is created in target_regions.If a user
wants to syncs the same resource then nova throws 409 error
because the name is already used. In order to avoid that we
use --force and there by creates resource without fail.
:param context: request context object.
:param job_id: ID of the job which triggered image_sync.
:payload: request payload.
:force: True/False option to sync the same resource again.
:jobs: List of resource_sync_id's for param job_id.
"""
LOG.info("Triggered Keypair Sync.")
keypairs_thread = list()
session = EndpointCache().get_session_from_token(
context.auth_token, context.project)
try:
resource_jobs = db_api.resource_sync_list(context, job_id,
consts.KEYPAIR)
except exceptions.JobNotFound():
raise
source_regions = [i["source_region"] for i in resource_jobs]
unique_source = list(set(source_regions))
for source_object in unique_source:
source_nova_client = NovaClient(source_object, session)
for resource_job in resource_jobs:
source_keypair = source_nova_client.\
get_keypairs(resource_job["resource"])
thread = threading.Thread(
target=self.create_resources_in_region,
args=(resource_job["id"], force,
resource_job["target_region"],
source_keypair, session, context,))
keypairs_thread.append(thread)
thread.start()
for keypair_thread in keypairs_thread:
keypair_thread.join()
for job in jobs:
try:
resource_job = db_api.resource_sync_list(context, job_id,
job)
resource_job = resource_job.pop()
except exceptions.JobNotFound():
raise
# Create Source Region object
source_nova_client = NovaClient(
resource_job["source_region"], session)
source_keypair = source_nova_client.get_keypairs(
resource_job["resource"])
thread = threading.Thread(target=self.create_resources_in_region,
args=(resource_job["id"], force,
resource_job["target_region"],
source_keypair, session, context))
keypairs_thread.append(thread)
thread.start()
for keypair_thread in keypairs_thread:
keypair_thread.join()
# Update Result in DATABASE.
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
# Update Result in DATABASE.
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

@ -166,19 +166,19 @@ class EngineService(service.Service):
self.qm.quota_sync_for_project(project_id)
@request_context
def keypair_sync_for_user(self, ctxt, job_id, force):
def keypair_sync_for_user(self, ctxt, job_id, force, jobs):
# Keypair Sync for a user, will be triggered by KB-API
self.ksm.resource_sync(ctxt, job_id, force)
self.ksm.resource_sync(ctxt, job_id, force, jobs)
@request_context
def image_sync(self, ctxt, job_id, force):
def image_sync(self, ctxt, job_id, force, jobs):
# Image Sync triggered by KB_API.
self.ism.resource_sync(ctxt, job_id, force)
self.ism.resource_sync(ctxt, job_id, force, jobs)
@request_context
def flavor_sync(self, ctxt, job_id, force):
def flavor_sync(self, ctxt, job_id, force, jobs):
# Flavor Sync triggered by KB_API.
self.fsm.resource_sync(ctxt, job_id, force)
self.fsm.resource_sync(ctxt, job_id, force, jobs)
def _stop_rpc_server(self):
# Stop RPC connection to prevent new requests

View File

@ -69,18 +69,20 @@ class EngineClient(object):
return self.cast(ctxt, self.make_msg('quota_sync_for_project',
project_id=project_id))
def keypair_sync_for_user(self, ctxt, job_id, force):
def keypair_sync_for_user(self, ctxt, job_id, force, jobs):
return self.cast(
ctxt,
self.make_msg('keypair_sync_for_user', job_id=job_id,
force=force))
force=force, jobs=jobs))
def image_sync(self, ctxt, job_id, force):
def image_sync(self, ctxt, job_id, force, jobs):
return self.cast(
ctxt,
self.make_msg('image_sync', job_id=job_id, force=force))
self.make_msg('image_sync', job_id=job_id, force=force,
jobs=jobs))
def flavor_sync(self, ctxt, job_id, force):
def flavor_sync(self, ctxt, job_id, force, jobs):
return self.cast(
ctxt,
self.make_msg('flavor_sync', job_id=job_id, force=force))
self.make_msg('flavor_sync', job_id=job_id, force=force,
jobs=jobs))

View File

@ -107,13 +107,7 @@ class BaseKingbirdClass(object):
result['images'] = images
return result
def _check_job_status(self):
# Wait until the status of the job is not "IN_PROGRESS"
job_list_resp = self.get_sync_job_list()
status = job_list_resp.get('job_set')[0].get('sync_status')
return status != consts.JOB_PROGRESS
def _check_template_job_status(self, job_id):
def _check_job_status(self, job_id):
# Wait until the status of the each resource job is not "IN_PROGRESS"
job_list_resp = self.get_sync_job_detail(job_id)
for i in range(len(job_list_resp['job_set'])):

View File

@ -43,7 +43,7 @@ class KingbirdFlavorSyncTest(base.BaseKBFlavorsTest,
# Flavors created should be available in the response list
job_details = self._flavor_sync_job_create(FORCE, admin_session)
utils.wait_until_true(
lambda: self._check_job_status(),
lambda: self._check_job_status(job_details['job_id']),
exception=RuntimeError("Timed out waiting for job %s " %
job_details['job_id']))
# Check for resources in target_regions
@ -71,7 +71,7 @@ class KingbirdFlavorSyncTest(base.BaseKBFlavorsTest,
admin_session = True
job_details = self._flavor_sync_job_create(FORCE, admin_session)
utils.wait_until_true(
lambda: self._check_job_status(),
lambda: self._check_job_status(job_details['job_id']),
exception=RuntimeError("Timed out waiting for job %s " %
job_details['job_id']))
job_list_resp = self.get_sync_job_list()
@ -88,7 +88,7 @@ class KingbirdFlavorSyncTest(base.BaseKBFlavorsTest,
admin_session = True
job_details = self._flavor_sync_job_create(FORCE, admin_session)
utils.wait_until_true(
lambda: self._check_job_status(),
lambda: self._check_job_status(job_details['job_id']),
exception=RuntimeError("Timed out waiting for job %s " %
job_details['job_id']))
job_list_resp = self.get_sync_job_detail(job_details['job_id'])
@ -116,7 +116,7 @@ class KingbirdFlavorSyncTest(base.BaseKBFlavorsTest,
status = active_job.get('job_set')[0].get('sync_status')
self.assertEqual(status, consts.JOB_PROGRESS)
utils.wait_until_true(
lambda: self._check_job_status(),
lambda: self._check_job_status(job_details['job_id']),
exception=RuntimeError("Timed out waiting for job %s " %
job_details['job_id']))
# Clean_up the database entries
@ -136,7 +136,7 @@ class KingbirdFlavorSyncTest(base.BaseKBFlavorsTest,
# Actual result when we try and delete an active_job
# Clean_up the database entries
utils.wait_until_true(
lambda: self._check_job_status(),
lambda: self._check_job_status(job_details['job_id']),
exception=RuntimeError("Timed out waiting for job %s " %
job_details['job_id']))
# Clean_up the database entries
@ -151,7 +151,7 @@ class KingbirdFlavorSyncTest(base.BaseKBFlavorsTest,
job_details = self._flavor_sync_job_create(FORCE, admin_session)
# Clean_up the database entries
utils.wait_until_true(
lambda: self._check_job_status(),
lambda: self._check_job_status(job_details['job_id']),
exception=RuntimeError("Timed out waiting for job %s " %
job_details['job_id']))
self.delete_db_entries(job_details['job_id'])
@ -168,14 +168,14 @@ class KingbirdFlavorSyncTest(base.BaseKBFlavorsTest,
job_details_1 = self._flavor_sync_job_create(FORCE, admin_session)
job_id_1 = job_details_1['job_id']
utils.wait_until_true(
lambda: self._check_job_status(),
lambda: self._check_job_status(job_id_1),
exception=RuntimeError("Timed out waiting for job %s " % job_id_1))
self.delete_db_entries(job_id_1)
job_details_2 = self._flavor_sync_job_create(FORCE, admin_session,
job_details_1['flavors'])
job_id_2 = job_details_2['job_id']
utils.wait_until_true(
lambda: self._check_job_status(),
lambda: self._check_job_status(job_id_2),
exception=RuntimeError("Timed out waiting for job %s " % job_id_2))
# Clean_up the database entries
self.delete_db_entries(job_id_2)
@ -190,7 +190,7 @@ class KingbirdFlavorSyncTest(base.BaseKBFlavorsTest,
admin_session)
job_id_1 = job_details_1['job_id']
utils.wait_until_true(
lambda: self._check_job_status(),
lambda: self._check_job_status(job_id_1),
exception=RuntimeError("Timed out waiting for job %s " % job_id_1))
self.delete_db_entries(job_id_1)
job_details_2 = self._flavor_sync_job_create(DEFAULT_FORCE,
@ -198,7 +198,7 @@ class KingbirdFlavorSyncTest(base.BaseKBFlavorsTest,
job_details_1['flavors'])
job_id_2 = job_details_2['job_id']
utils.wait_until_true(
lambda: self._check_job_status(),
lambda: self._check_job_status(job_id_2),
exception=RuntimeError("Timed out waiting for job %s " % job_id_2))
job_list_resp = self.get_sync_job_detail(job_id_2)
# This job fail because resoruce is already created.

View File

@ -46,7 +46,7 @@ class KingbirdImageSyncTest(base.BaseKBImageTest, base.BaseKingbirdClass):
}
job_details = self._image_sync_job_create(FORCE, **create_params)
utils.wait_until_true(
lambda: self._check_job_status(),
lambda: self._check_job_status(job_details['job_id']),
exception=RuntimeError("Timed out waiting for job %s " %
job_details['job_id']))
# Check for resources in target_regions.
@ -67,7 +67,7 @@ class KingbirdImageSyncTest(base.BaseKBImageTest, base.BaseKingbirdClass):
}
job_details = self._image_sync_job_create(FORCE, **create_params)
utils.wait_until_true(
lambda: self._check_job_status(),
lambda: self._check_job_status(job_details['job_id']),
exception=RuntimeError("Timed out waiting for job %s " %
job_details['job_id']))
# Check for resources in target_regions.
@ -89,7 +89,7 @@ class KingbirdImageSyncTest(base.BaseKBImageTest, base.BaseKingbirdClass):
job_details = self._image_sync_job_create(DEFAULT_FORCE,
**create_params)
utils.wait_until_true(
lambda: self._check_job_status(),
lambda: self._check_job_status(job_details['job_id']),
exception=RuntimeError("Timed out waiting for job %s " %
job_details['job_id']))
# Check for resources in target_regions.
@ -109,7 +109,7 @@ class KingbirdImageSyncTest(base.BaseKBImageTest, base.BaseKingbirdClass):
job_details = self._image_sync_job_create(DEFAULT_FORCE,
**create_params)
utils.wait_until_true(
lambda: self._check_job_status(),
lambda: self._check_job_status(job_details['job_id']),
exception=RuntimeError("Timed out waiting for job %s " %
job_details['job_id']))
# Check for resources in target_regions.
@ -132,7 +132,7 @@ class KingbirdImageSyncTest(base.BaseKBImageTest, base.BaseKingbirdClass):
job_details = self._image_sync_job_create(DEFAULT_FORCE,
**create_params)
utils.wait_until_true(
lambda: self._check_job_status(),
lambda: self._check_job_status(job_details['job_id']),
exception=RuntimeError("Timed out waiting for job %s " %
job_details['job_id']))
job_list_resp = self.get_sync_job_detail(job_details['job_id'])
@ -164,7 +164,7 @@ class KingbirdImageSyncTest(base.BaseKBImageTest, base.BaseKingbirdClass):
status = active_job.get('job_set')[0].get('sync_status')
self.assertEqual(status, consts.JOB_PROGRESS)
utils.wait_until_true(
lambda: self._check_job_status(),
lambda: self._check_job_status(job_details['job_id']),
exception=RuntimeError("Timed out waiting for job %s " %
job_details['job_id']))
# Check for resources in target_regions.
@ -190,7 +190,7 @@ class KingbirdImageSyncTest(base.BaseKBImageTest, base.BaseKingbirdClass):
# Actual result when we try and delete an active_job
# Clean_up the database entries
utils.wait_until_true(
lambda: self._check_job_status(),
lambda: self._check_job_status(job_details['job_id']),
exception=RuntimeError("Timed out waiting for job %s " %
job_details['job_id']))
# Check for resources in target_regions.
@ -210,7 +210,7 @@ class KingbirdImageSyncTest(base.BaseKBImageTest, base.BaseKingbirdClass):
job_details = self._image_sync_job_create(DEFAULT_FORCE,
**create_params)
utils.wait_until_true(
lambda: self._check_job_status(),
lambda: self._check_job_status(job_details['job_id']),
exception=RuntimeError("Timed out waiting for job %s " %
job_details['job_id']))
# Clean_up the database entries
@ -247,7 +247,7 @@ class KingbirdImageSyncTest(base.BaseKBImageTest, base.BaseKingbirdClass):
job_details = self._sync_ami_image(DEFAULT_FORCE, ami_image['id'])
# Clean_up the database entries
utils.wait_until_true(
lambda: self._check_job_status(),
lambda: self._check_job_status(job_details['job_id']),
exception=RuntimeError("Timed out waiting for job %s " %
job_details['job_id']))
# Check for resources in target_regions.

View File

@ -35,7 +35,7 @@ class KingbirdKeyPairSyncTest(base.BaseKBKeypairTest,
# Create 2 keypairs:
job_details = self._keypair_sync_job_create(FORCE)
utils.wait_until_true(
lambda: self._check_job_status(),
lambda: self._check_job_status(job_details['job_id']),
exception=RuntimeError("Timed out waiting for job %s " %
job_details['job_id']))
# Check for resources in target_regions
@ -51,7 +51,7 @@ class KingbirdKeyPairSyncTest(base.BaseKBKeypairTest,
def test_get_kingbird_sync_list(self):
job_details = self._keypair_sync_job_create(FORCE)
utils.wait_until_true(
lambda: self._check_job_status(),
lambda: self._check_job_status(job_details['job_id']),
exception=RuntimeError("Timed out waiting for job %s " %
job_details['job_id']))
job_list_resp = self.get_sync_job_list()
@ -67,7 +67,7 @@ class KingbirdKeyPairSyncTest(base.BaseKBKeypairTest,
def test_get_sync_job_details(self):
job_details = self._keypair_sync_job_create(FORCE)
utils.wait_until_true(
lambda: self._check_job_status(),
lambda: self._check_job_status(job_details['job_id']),
exception=RuntimeError("Timed out waiting for job %s " %
job_details['job_id']))
job_list_resp = self.get_sync_job_detail(job_details['job_id'])
@ -94,7 +94,7 @@ class KingbirdKeyPairSyncTest(base.BaseKBKeypairTest,
status = active_job.get('job_set')[0].get('sync_status')
self.assertEqual(status, consts.JOB_PROGRESS)
utils.wait_until_true(
lambda: self._check_job_status(),
lambda: self._check_job_status(job_details['job_id']),
exception=RuntimeError("Timed out waiting for job %s " %
job_details['job_id']))
# Clean_up the database entries
@ -113,7 +113,7 @@ class KingbirdKeyPairSyncTest(base.BaseKBKeypairTest,
# Actual result when we try and delete an active_job
# Clean_up the database entries
utils.wait_until_true(
lambda: self._check_job_status(),
lambda: self._check_job_status(job_details['job_id']),
exception=RuntimeError("Timed out waiting for job %s " %
job_details['job_id']))
# Clean_up the database entries
@ -127,7 +127,7 @@ class KingbirdKeyPairSyncTest(base.BaseKBKeypairTest,
job_details = self._keypair_sync_job_create(FORCE)
# Clean_up the database entries
utils.wait_until_true(
lambda: self._check_job_status(),
lambda: self._check_job_status(job_details['job_id']),
exception=RuntimeError("Timed out waiting for job %s " %
job_details['job_id']))
self.delete_db_entries(job_details['job_id'])
@ -143,14 +143,14 @@ class KingbirdKeyPairSyncTest(base.BaseKBKeypairTest,
job_details_1 = self._keypair_sync_job_create(FORCE)
job_id_1 = job_details_1['job_id']
utils.wait_until_true(
lambda: self._check_job_status(),
lambda: self._check_job_status(job_id_1),
exception=RuntimeError("Timed out waiting for job %s " % job_id_1))
self.delete_db_entries(job_id_1)
job_details_2 = self._keypair_sync_job_create(
FORCE, job_details_1['keys'])
job_id_2 = job_details_2['job_id']
utils.wait_until_true(
lambda: self._check_job_status(),
lambda: self._check_job_status(job_id_2),
exception=RuntimeError("Timed out waiting for job %s " % job_id_2))
# Clean_up the database entries
self.delete_db_entries(job_id_2)
@ -163,14 +163,14 @@ class KingbirdKeyPairSyncTest(base.BaseKBKeypairTest,
job_details_1 = self._keypair_sync_job_create(DEFAULT_FORCE)
job_id_1 = job_details_1['job_id']
utils.wait_until_true(
lambda: self._check_job_status(),
lambda: self._check_job_status(job_id_1),
exception=RuntimeError("Timed out waiting for job %s " % job_id_1))
self.delete_db_entries(job_id_1)
job_details_2 = self._keypair_sync_job_create(DEFAULT_FORCE,
job_details_1['keys'])
job_id_2 = job_details_2['job_id']
utils.wait_until_true(
lambda: self._check_job_status(),
lambda: self._check_job_status(job_id_2),
exception=RuntimeError("Timed out waiting for job %s " % job_id_2))
job_list_resp = self.get_sync_job_detail(job_id_2)
# This job fail because resoruce is already created.

View File

@ -46,7 +46,7 @@ class KingbirdTemplateSyncTest(base.BaseKBKeypairTest,
job_details = self.template_sync_job_create_non_admin(
keypairs, images, FORCE)
utils.wait_until_true(
lambda: self._check_template_job_status(job_details['job_id']),
lambda: self._check_job_status(job_details['job_id']),
exception=RuntimeError("Timed out waiting for job %s " %
job_details['job_id']))
# Check for resources in target_regions
@ -75,7 +75,7 @@ class KingbirdTemplateSyncTest(base.BaseKBKeypairTest,
flavors = self._create_flavor(admin_session)
job_details = self.template_sync_job_create_admin(flavors[0], FORCE)
utils.wait_until_true(
lambda: self._check_template_job_status(job_details['job_id']),
lambda: self._check_job_status(job_details['job_id']),
exception=RuntimeError("Timed out waiting for job %s " %
job_details['job_id']))
# Check for resources in target_regions
@ -101,7 +101,7 @@ class KingbirdTemplateSyncTest(base.BaseKBKeypairTest,
job_details = self.template_sync_job_create_non_admin(
keypairs, images, DEFAULT_FORCE)
utils.wait_until_true(
lambda: self._check_template_job_status(job_details['job_id']),
lambda: self._check_job_status(job_details['job_id']),
exception=RuntimeError("Timed out waiting for job %s " %
job_details['job_id']))
job_list_resp = self.get_sync_job_list()
@ -130,7 +130,7 @@ class KingbirdTemplateSyncTest(base.BaseKBKeypairTest,
job_details = self.template_sync_job_create_non_admin(
keypairs, images, DEFAULT_FORCE)
utils.wait_until_true(
lambda: self._check_template_job_status(job_details['job_id']),
lambda: self._check_job_status(job_details['job_id']),
exception=RuntimeError("Timed out waiting for job %s " %
job_details['job_id']))
job_list_resp = self.get_sync_job_detail(job_details['job_id'])
@ -160,34 +160,6 @@ class KingbirdTemplateSyncTest(base.BaseKBKeypairTest,
keypairs, job_details['keypair_targets'],
self.keypair_client.user_id)
@decorators.idempotent_id('f5701f6a-183b-41fe-b0ab-e0ddef3fbd89')
def test_get_active_jobs(self):
# Keypairs and images can be created by non-admin
kwargs = {
"container_format": CONF.image.container_formats[3],
"disk_format": CONF.image.disk_formats[6],
"visibility": 'private'
}
keypairs = self._create_keypairs()
images = self._create_images(**kwargs)
job_details = self.template_sync_job_create_non_admin(
keypairs, images, FORCE)
active_job = self.get_sync_job_list(consts.JOB_ACTIVE)
status = active_job.get('job_set')[0].get('sync_status')
self.assertEqual(status, consts.JOB_PROGRESS)
utils.wait_until_true(
lambda: self._check_template_job_status(job_details['job_id']),
exception=RuntimeError("Timed out waiting for job %s " %
job_details['job_id']))
# Clean_up the database entries
self._check_images_delete_target_region(
job_details['admin'], job_details['image_targets'],
images, FORCE, **kwargs)
self.delete_db_entries(job_details['job_id'])
self._keypair_cleanup_resources(
keypairs, job_details['keypair_targets'],
self.keypair_client.user_id)
@decorators.idempotent_id('adf565b1-c076-4273-b7d2-305cc144d0e2')
def test_delete_already_deleted_job(self):
# Keypairs and images can be created by non-admin
@ -201,7 +173,7 @@ class KingbirdTemplateSyncTest(base.BaseKBKeypairTest,
job_details = self.template_sync_job_create_non_admin(
keypairs, images, FORCE)
utils.wait_until_true(
lambda: self._check_template_job_status(job_details['job_id']),
lambda: self._check_job_status(job_details['job_id']),
exception=RuntimeError("Timed out waiting for job %s " %
job_details['job_id']))
# Clean_up the database entries

View File

@ -113,7 +113,7 @@ class DBAPIResourceSyncTest(base.KingbirdTestCase):
resource_sync_create = self.resource_sync_create(
self.ctx, job=job, region='Fake_region',
source_region='Fake_region2', resource='fake_key',
resource_type='keypair', job_id=job.job_id)
resource_type='keypair', job_id=UUID2)
self.assertIsNotNone(resource_sync_create)
self.assertEqual(consts.JOB_PROGRESS, resource_sync_create.sync_status)
@ -122,7 +122,7 @@ class DBAPIResourceSyncTest(base.KingbirdTestCase):
resource_sync_create = self.resource_sync_create(
self.ctx, job=job, region='Fake_region',
source_region='Fake_region2', resource='fake_key',
resource_type='keypair', job_id=job.job_id)
resource_type='keypair', job_id=UUID2)
self.assertIsNotNone(resource_sync_create)
status = db_api.resource_sync_status(self.ctx, job.job_id)
self.assertEqual(consts.JOB_PROGRESS, status[0])
@ -132,14 +132,14 @@ class DBAPIResourceSyncTest(base.KingbirdTestCase):
resource_sync_create = self.resource_sync_create(
self.ctx, job=job, region='Fake_region',
source_region='Fake_region2', resource='fake_key',
resource_type='keypair', job_id=job.job_id)
resource_type='keypair', job_id=UUID2)
self.assertIsNotNone(resource_sync_create)
self.assertEqual(consts.JOB_PROGRESS,
resource_sync_create.sync_status)
db_api.resource_sync_update(
self.ctx, job.job_id, consts.JOB_SUCCESS)
self.ctx, UUID2, consts.JOB_SUCCESS)
updated_job = db_api.resource_sync_list(self.ctx, job.job_id,
resource_type='keypair')
resource_sync_id=UUID2)
self.assertEqual(consts.JOB_SUCCESS, updated_job[0].get('sync_status'))
self.assertEqual(consts.JOB_SUCCESS, updated_job[0].get('sync_status'))
@ -149,7 +149,7 @@ class DBAPIResourceSyncTest(base.KingbirdTestCase):
resource_sync_create = self.resource_sync_create(
self.ctx, job=job, region='Fake_region',
source_region='Fake_region2', resource='fake_key',
resource_type='keypair', job_id=job.job_id)
resource_type='keypair', job_id=UUID2)
self.assertIsNotNone(resource_sync_create)
self.assertEqual(job.job_id, resource_sync_create.job_id)
@ -160,7 +160,7 @@ class DBAPIResourceSyncTest(base.KingbirdTestCase):
self.resource_sync_create(
self.ctx, job=job, region='Fake_region',
source_region='Fake_region2', resource='fake_key',
resource_type='keypair', job_id=job.job_id)
resource_type='keypair', job_id=UUID2)
db_api.sync_job_delete(self.ctx, job_id)
updated_job = db_api.sync_job_list(self.ctx)
self.assertEqual(0, len(updated_job))
@ -170,12 +170,12 @@ class DBAPIResourceSyncTest(base.KingbirdTestCase):
self.resource_sync_create(
self.ctx, job=job, region='Fake_region',
source_region='Fake_region2', resource='fake_key',
resource_type='keypair', job_id=job.job_id)
resource_type='keypair', job_id=UUID2)
self.assertRaises(oslo_db.exception.DBDuplicateEntry,
self.resource_sync_create, self.ctx, job=job,
region='Fake_region', source_region='Fake_region2',
resource='fake_key', resource_type='keypair',
job_id=job.job_id)
job_id=UUID2)
def test_delete_failure_sync_job(self):
job = self.sync_job_create(self.ctx, job_id=UUID1)

View File

@ -13,7 +13,6 @@
# under the License.
import mock
from kingbird.common import consts
from kingbird.engine import flavor_sync_manager
from kingbird.tests import base
from kingbird.tests import utils
@ -23,8 +22,8 @@ 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
FAKE_RESOURCE_SYNC_ID = utils.UUID2
JOB_RESULT = "SUCCESS"
FAKE_TENANTS = ['fake_tenant_1', 'fake_tenant_2']
@ -68,13 +67,15 @@ class TestFlavorSyncManager(base.KingbirdTestCase):
mock_nova().get_flavor.return_value = fake_flavor
mock_db_api.resource_sync_list.return_value = [resource_job]
fsm = flavor_sync_manager.FlavorSyncManager()
fsm.resource_sync(self.ctxt, FAKE_JOB_ID, DEFAULT_FORCE)
fsm.resource_sync(self.ctxt, FAKE_JOB_ID, DEFAULT_FORCE,
[FAKE_RESOURCE_SYNC_ID])
mock_create_resource.assert_called_once_with(
FAKE_JOB_ID, DEFAULT_FORCE, resource_job['target_region'],
fake_flavor, 'fake_session', self.ctxt, access_tenants)
mock_nova().get_flavor_access_tenant.assert_not_called
mock_db_api.resource_sync_list.\
assert_called_once_with(self.ctxt, FAKE_JOB_ID, consts.FLAVOR)
assert_called_once_with(self.ctxt, FAKE_JOB_ID,
FAKE_RESOURCE_SYNC_ID)
mock_db_api.resource_sync_status.\
assert_called_once_with(self.ctxt, FAKE_JOB_ID)
mock_db_api.sync_job_update.\
@ -101,7 +102,8 @@ class TestFlavorSyncManager(base.KingbirdTestCase):
mock_nova().get_flavor.return_value = fake_flavor
mock_db_api.resource_sync_list.return_value = [resource_job]
fsm = flavor_sync_manager.FlavorSyncManager()
fsm.resource_sync(self.ctxt, FAKE_JOB_ID, True)
fsm.resource_sync(self.ctxt, FAKE_JOB_ID, True,
[FAKE_RESOURCE_SYNC_ID])
mock_create_resource.assert_called_once_with(
FAKE_JOB_ID, True, resource_job['target_region'], fake_flavor,
'fake_session', self.ctxt, access_tenants)
@ -134,7 +136,8 @@ class TestFlavorSyncManager(base.KingbirdTestCase):
mock_db_api.resource_sync_list.return_value = [resource_job]
mock_db_api().resource_sync_status.return_value = [JOB_RESULT]
fsm = flavor_sync_manager.FlavorSyncManager()
fsm.resource_sync(self.ctxt, FAKE_JOB_ID, DEFAULT_FORCE)
fsm.resource_sync(self.ctxt, FAKE_JOB_ID, DEFAULT_FORCE,
[FAKE_RESOURCE_SYNC_ID])
mock_create_resource.assert_called_once_with(
FAKE_JOB_ID, DEFAULT_FORCE, resource_job['target_region'],
fake_flavor, 'fake_session', self.ctxt, access_tenants)
@ -168,7 +171,8 @@ class TestFlavorSyncManager(base.KingbirdTestCase):
mock_db_api.resource_sync_list.return_value = [resource_job]
mock_db_api().resource_sync_status.return_value = [JOB_RESULT]
fsm = flavor_sync_manager.FlavorSyncManager()
fsm.resource_sync(self.ctxt, FAKE_JOB_ID, True)
fsm.resource_sync(self.ctxt, FAKE_JOB_ID, True,
[FAKE_RESOURCE_SYNC_ID])
mock_create_resource.assert_called_once_with(
FAKE_JOB_ID, True, resource_job['target_region'], fake_flavor,
'fake_session', self.ctxt, access_tenants)

View File

@ -22,11 +22,11 @@ DEFAULT_FORCE = False
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
FAKE_KERNEL_ID = utils.UUID2
FAKE_RAMDISK_ID = utils.UUID3
FAKE_ID = utils.UUID4
FAKE_RESOURCE_SYNC_ID = utils.UUID5
FAKE_RESULT = 'SUCCESS'
FAKE_RESULT_FAIL = 'FAILURE'
FAKE_RESOURCE = 'fake_image'
@ -121,7 +121,8 @@ class TestImageSyncManager(base.KingbirdTestCase):
mock_glance_adapter.check_dependent_images.\
return_value = expected_resources
ism = image_sync_manager.ImageSyncManager()
ism.resource_sync(self.ctxt, FAKE_JOB_ID, DEFAULT_FORCE)
ism.resource_sync(self.ctxt, FAKE_JOB_ID, DEFAULT_FORCE,
[FAKE_RESOURCE_SYNC_ID])
mock_glance_adapter.check_dependent_images.\
assert_called_once_with(self.ctxt, FAKE_SOURCE_REGION,
fake_ami_image.id)
@ -152,7 +153,8 @@ class TestImageSyncManager(base.KingbirdTestCase):
mock_glance_adapter.check_dependent_images.\
return_value = expected_resources
ism = image_sync_manager.ImageSyncManager()
ism.resource_sync(self.ctxt, FAKE_JOB_ID, DEFAULT_FORCE)
ism.resource_sync(self.ctxt, FAKE_JOB_ID, DEFAULT_FORCE,
[FAKE_RESOURCE_SYNC_ID])
self.assertEqual(mock_glance_client().get_image_data.call_count, 1)
self.assertEqual(mock_glance_client().create_image.call_count, 1)
self.assertEqual(mock_glance_upload.call_count, 1)
@ -180,7 +182,8 @@ class TestImageSyncManager(base.KingbirdTestCase):
mock_glance_adapter.check_dependent_images.\
return_value = expected_resources
ism = image_sync_manager.ImageSyncManager()
ism.resource_sync(self.ctxt, FAKE_JOB_ID, DEFAULT_FORCE)
ism.resource_sync(self.ctxt, FAKE_JOB_ID, DEFAULT_FORCE,
[FAKE_RESOURCE_SYNC_ID])
mock_glance_adapter.check_dependent_images.\
assert_called_once_with(self.ctxt, FAKE_SOURCE_REGION,
fake_aki_image.id)
@ -211,7 +214,8 @@ class TestImageSyncManager(base.KingbirdTestCase):
mock_glance_adapter.check_dependent_images.\
return_value = expected_resources
ism = image_sync_manager.ImageSyncManager()
ism.resource_sync(self.ctxt, FAKE_JOB_ID, DEFAULT_FORCE)
ism.resource_sync(self.ctxt, FAKE_JOB_ID, DEFAULT_FORCE,
[FAKE_RESOURCE_SYNC_ID])
mock_glance_adapter.check_dependent_images.\
assert_called_once_with(self.ctxt, FAKE_SOURCE_REGION,
fake_ari_image.id)

View File

@ -13,7 +13,6 @@
# under the License.
import mock
from kingbird.common import consts
from kingbird.engine import keypair_sync_manager
from kingbird.tests import base
from kingbird.tests import utils
@ -23,8 +22,8 @@ SOURCE_KEYPAIR = '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
FAKE_RESOURCE_SYNC_ID = utils.UUID2
class FakeKeypair(object):
@ -54,9 +53,10 @@ class TestKeypairSyncManager(base.KingbirdTestCase):
mock_db_api.resource_sync_list.return_value = [resource_job]
mock_nova().get_keypairs.return_value = fake_key
ksm = keypair_sync_manager.KeypairSyncManager()
ksm.resource_sync(self.ctxt, FAKE_JOB_ID, DEFAULT_FORCE)
ksm.resource_sync(self.ctxt, FAKE_JOB_ID, DEFAULT_FORCE,
[FAKE_RESOURCE_SYNC_ID])
mock_db_api.resource_sync_list.assert_called_once_with(
self.ctxt, FAKE_JOB_ID, consts.KEYPAIR)
self.ctxt, FAKE_JOB_ID, FAKE_RESOURCE_SYNC_ID)
mock_nova().get_keypairs.assert_called_once_with(
resource_job['resource'])
@ -76,9 +76,10 @@ class TestKeypairSyncManager(base.KingbirdTestCase):
mock_db_api.resource_sync_list.return_value = [resource_job]
mock_nova().get_keypairs.return_value = fake_key
ksm = keypair_sync_manager.KeypairSyncManager()
ksm.resource_sync(self.ctxt, FAKE_JOB_ID, True)
ksm.resource_sync(self.ctxt, FAKE_JOB_ID, True,
[FAKE_RESOURCE_SYNC_ID])
mock_db_api.resource_sync_list.assert_called_once_with(
self.ctxt, FAKE_JOB_ID, consts.KEYPAIR)
self.ctxt, FAKE_JOB_ID, FAKE_RESOURCE_SYNC_ID)
mock_nova().get_keypairs.assert_called_once_with(
resource_job['resource'])

View File

@ -21,6 +21,7 @@ from oslo_config import cfg
CONF = cfg.CONF
FAKE_USER = utils.UUID1
FAKE_JOB = utils.UUID2
FAKE_RESOURCE_JOB = utils.UUID3
class TestEngineService(base.KingbirdTestCase):
@ -36,6 +37,7 @@ class TestEngineService(base.KingbirdTestCase):
self.force = False
self.user_id = FAKE_USER
self.job_id = FAKE_JOB
self.resource_sync_id = FAKE_RESOURCE_JOB
def test_init(self):
self.assertEqual(self.service_obj.host, 'localhost')
@ -126,22 +128,27 @@ class TestEngineService(base.KingbirdTestCase):
self.service_obj.init_tgm()
self.service_obj.init_ksm()
self.service_obj.keypair_sync_for_user(
self.context, self.job_id, self.force)
self.context, self.job_id, self.force, [self.resource_sync_id])
mock_keypair_sync_manager().resource_sync.\
assert_called_once_with(self.context, self.job_id, self.force)
assert_called_once_with(self.context, self.job_id, self.force,
[self.resource_sync_id])
@mock.patch.object(service, 'ImageSyncManager')
def test_image_sync(self, mock_image_sync_manager):
self.service_obj.init_tgm()
self.service_obj.init_ism()
self.service_obj.image_sync(self.context, self.job_id, self.force)
self.service_obj.image_sync(self.context, self.job_id, self.force,
[self.resource_sync_id])
mock_image_sync_manager().resource_sync.\
assert_called_once_with(self.context, self.job_id, self.force)
assert_called_once_with(self.context, self.job_id, self.force,
[self.resource_sync_id])
@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.force)
self.service_obj.flavor_sync(self.context, self.job_id, self.force,
[self.resource_sync_id])
mock_flavor_sync_manager().resource_sync.\
assert_called_once_with(self.context, self.job_id, self.force)
assert_called_once_with(self.context, self.job_id, self.force,
[self.resource_sync_id])