Initial connect up retry task submit and re-enqueue

This CR adds the remaining pieces need to allow worker task processing
to add tasks needing retries to the order retry tasks table, and then
to have the periodic task service pick these retry tasks up and enqueue
them for retries. With this initial CR no attempt is made to protect
against concurrency between the existing worker RPC process and the
separate periodic retry scheduler process. A subsequent CR will add
concurrency protection. This CR does allow the retry behavior to be
demonstrated locally as follows: 1) run the 'barbican.sh start', then
2) run the new barbican-worker-retry-scheduler.py script, then 3)
POST to the orders resource a 'certificate' type order, and finally
poll this new order until it becomes ACTIVE. The simple certificate
plugin will call for a retry for the status check method after the
initial certificate request is made. The retry processing will
eventually call the plugins status check method, which then produces
a fake certificate.

Change-Id: Idee08abcd3bf2920039f91a7f5b6125eacd1f785
This commit is contained in:
jfwood 2015-03-24 01:07:27 -05:00
parent edb3c6d7b1
commit eb4b711679
16 changed files with 854 additions and 242 deletions

View File

@ -21,6 +21,9 @@ from barbican.plugin.interface import certificate_manager as cert
LOG = utils.getLogger(__name__)
MSEC_UNTIL_CHECK_STATUS = 5000
class SimpleCertificatePlugin(cert.CertificatePluginBase):
"""Simple/default certificate plugin."""
@ -49,7 +52,9 @@ class SimpleCertificatePlugin(cert.CertificatePluginBase):
:rtype: :class:`ResultDTO`
"""
LOG.info(u._LI('Invoking issue_certificate_request()'))
return cert.ResultDTO(cert.CertificateStatus.WAITING_FOR_CA)
return cert.ResultDTO(
cert.CertificateStatus.WAITING_FOR_CA,
retry_msec=MSEC_UNTIL_CHECK_STATUS)
def modify_certificate_request(self, order_id, order_meta, plugin_meta,
barbican_meta_dto):
@ -103,7 +108,7 @@ class SimpleCertificatePlugin(cert.CertificatePluginBase):
:rtype: :class:`ResultDTO`
"""
LOG.info(u._LI('Invoking check_certificate_status()'))
return cert.ResultDTO(cert.CertificateStatus.WAITING_FOR_CA)
return cert.ResultDTO(cert.CertificateStatus.CERTIFICATE_GENERATED)
def supports(self, certificate_spec):
"""Indicates whether the plugin supports the certificate type.

View File

@ -51,6 +51,12 @@ class TaskClient(object):
project_id=project_id,
updated_meta=updated_meta)
def check_certificate_status(self, order_id, project_id):
"""Check the status of a certificate order."""
self._cast('check_certificate_status',
order_id=order_id,
project_id=project_id)
def _cast(self, name, **kwargs):
"""Asynchronous call handler. Barbican probably only needs casts.

View File

@ -16,10 +16,14 @@
"""
Retry/scheduler classes and logic.
"""
import datetime
import random
from oslo_config import cfg
from barbican.common import utils
from barbican import i18n as u
from barbican.model import models
from barbican.model import repositories
from barbican.openstack.common import periodic_task
from barbican.openstack.common import service
@ -32,10 +36,10 @@ retry_opt_group = cfg.OptGroup(name='retry_scheduler',
retry_opts = [
cfg.FloatOpt(
'task_retry_tg_initial_delay', default=10.0,
'initial_delay_seconds', default=10.0,
help=u._('Seconds (float) to wait before starting retry scheduler')),
cfg.FloatOpt(
'task_retry_tg_periodic_interval_max', default=10.0,
'periodic_interval_max_seconds', default=10.0,
help=u._('Seconds (float) to wait between periodic schedule events')),
]
@ -44,6 +48,15 @@ CONF.register_group(retry_opt_group)
CONF.register_opts(retry_opts, group=retry_opt_group)
def _compute_next_periodic_interval():
periodic_interval = (
CONF.retry_scheduler.periodic_interval_max_seconds
)
# Return +- 20% of interval.
return random.uniform(0.8 * periodic_interval, 1.2 * periodic_interval)
class PeriodicServer(service.Service):
"""Server to process retry and scheduled tasks.
@ -64,13 +77,15 @@ class PeriodicServer(service.Service):
# Start the task retry periodic scheduler process up.
periodic_interval = (
CONF.retry_scheduler.task_retry_tg_periodic_interval_max
CONF.retry_scheduler.periodic_interval_max_seconds
)
self.tg.add_dynamic_timer(
self._check_retry_tasks,
initial_delay=CONF.retry_scheduler.task_retry_tg_initial_delay,
initial_delay=CONF.retry_scheduler.initial_delay_seconds,
periodic_interval_max=periodic_interval)
self.order_retry_repo = repositories.get_order_retry_tasks_repository()
def start(self):
LOG.info("Starting the PeriodicServer")
super(PeriodicServer, self).start()
@ -81,9 +96,68 @@ class PeriodicServer(service.Service):
@periodic_task.periodic_task
def _check_retry_tasks(self):
"""Periodically check to see if tasks need to be scheduled."""
LOG.debug("Processing scheduled retry tasks")
"""Periodically check to see if tasks need to be scheduled.
# Return the next delay before this method is invoked again
# TODO(john-wood-w) A future CR will fill in the blanks here.
return 60.0
:return: Return the number of seconds to wait before invoking this
method again.
"""
LOG.info(u._LI("Processing scheduled retry tasks:"))
# Retrieve tasks to retry.
entities, _, _, total = self.order_retry_repo.get_by_create_date(
only_at_or_before_this_date=datetime.datetime.utcnow(),
suppress_exception=True)
# Create RPC tasks for each retry task found.
if total > 0:
for task in entities:
self._enqueue_task(task)
# Return the next delay before this method is invoked again.
check_again_in_seconds = _compute_next_periodic_interval()
LOG.info(
u._LI("Done processing '%(total)s' tasks, will check again in "
"'%(next)s' seconds."),
{
'total': total,
'next': check_again_in_seconds
}
)
return check_again_in_seconds
def _enqueue_task(self, task):
retry_task_name = 'N/A'
retry_args = 'N/A'
retry_kwargs = 'N/A'
try:
# Invoke queue client to place retried RPC task on queue.
retry_task_name = task.retry_task
retry_args = task.retry_args
retry_kwargs = task.retry_kwargs
retry_method = getattr(self.queue, retry_task_name)
retry_method(*retry_args, **retry_kwargs)
# Remove the retry record from the queue.
task.status = models.States.ACTIVE
self.order_retry_repo.delete_entity_by_id(task.id, None)
repositories.commit()
LOG.debug(
"(Enqueued method '{0}' with args '{1}' and "
"kwargs '{2}')".format(
retry_task_name, retry_args, retry_kwargs))
except Exception:
LOG.exception(
u._LE(
"Problem enqueuing method '%(name)s' with args '%(args)s' "
"and kwargs '%(kwargs)s'."),
{
'name': retry_task_name,
'args': retry_args,
'kwargs': retry_kwargs
}
)
repositories.rollback()
finally:
repositories.clear()

View File

@ -134,7 +134,7 @@ def monitored(fn): # pragma: no cover
def schedule_order_retry_tasks(
invoked_task, retry_result, order_id, *args, **kwargs):
invoked_task, retry_result, context, *args, **kwargs):
"""Schedules an Order-related task for retry.
:param invoked_task: The RPC method that was just invoked.
@ -142,6 +142,7 @@ def schedule_order_retry_tasks(
processing (such as retrying this or another task) is
required, otherwise None indicates no such follow-on
processing is required.
:param context: Queue context, not used.
:param order_id: ID of the Order entity the task to retry is for.
:param args: List of arguments passed in to the just-invoked task.
:param kwargs: Dict of arguments passed in to the just-invoked task.
@ -150,6 +151,7 @@ def schedule_order_retry_tasks(
"""
retry_rpc_method = None
order_id = kwargs.get('order_id')
if not retry_result or not order_id:
pass
@ -166,7 +168,7 @@ def schedule_order_retry_tasks(
LOG.debug(
'Scheduling RPC method for retry: {0}'.format(retry_rpc_method))
date_to_retry_at = datetime.datetime.now() + datetime.timedelta(
date_to_retry_at = datetime.datetime.utcnow() + datetime.timedelta(
milliseconds=retry_result.retry_msec)
retry_model = models.OrderRetryTask()
@ -221,6 +223,19 @@ class Tasks(object):
return resources.UpdateOrder().process(
order_id, project_id, updated_meta)
@monitored
@transactional
@retryable_order
def check_certificate_status(self, context, order_id, project_id):
"""Check the status of a certificate order."""
LOG.info(
u._LI("Processing check certificate status on order: order ID is "
"'%s'"),
order_id
)
return resources.CheckCertificateStatusOrder().process(
order_id, project_id)
class TaskServer(Tasks, service.Service):
"""Server to process asynchronous tasking from Barbican API nodes.

View File

@ -23,6 +23,7 @@ from barbican.model import models
from barbican.model import repositories as repos
from barbican.plugin.interface import certificate_manager as cert
from barbican.plugin import resources as plugin
from barbican.tasks import common
LOG = utils.getLogger(__name__)
@ -64,128 +65,154 @@ ORDER_STATUS_CA_UNAVAIL_FOR_CHECK = models.OrderStatus(
)
def issue_certificate_request(order_model, project_model):
def issue_certificate_request(order_model, project_model, result_follow_on):
"""Create the initial order with CA.
Note that this method may be called more than once if retries are
required. Barbican metadata is used to store intermediate information,
including selected plugins by name, to support such retries.
:param: order_model - order associated with this cert request
:param: project_model - project associated with this request
:param: result_follow_on - A :class:`FollowOnProcessingStatusDTO` instance
instantiated by the client that this function may optionally update
with information on how to process this task into the future.
:returns: container_model - container with the relevant cert if
the request has been completed. None otherwise
"""
container_model = None
plugin_meta = _get_plugin_meta(order_model)
barbican_meta_dto = cert.BarbicanMetaDTO()
barbican_meta = _get_barbican_meta(order_model)
# TODO(john-wood-w) We need to de-conflict barbican_meta (stored with order
# and not shown to plugins) with barbican_meta_dto (shared with plugins).
# As a minimum we should change the name of the DTO to something like
# 'extended_meta_dto' or some such.
barbican_meta_for_plugins_dto = cert.BarbicanMetaDTO()
# refresh the CA table. This is mostly a no-op unless the entries
# for a plugin are expired.
cert.CertificatePluginManager().refresh_ca_table()
# Locate the required certificate plugin.
cert_plugin_name = barbican_meta.get('plugin_name')
if cert_plugin_name:
cert_plugin = cert.CertificatePluginManager().get_plugin_by_name(
cert_plugin_name)
else:
ca_id = _get_ca_id(order_model.meta, project_model.id)
if ca_id:
barbican_meta_dto.plugin_ca_id = ca_id
barbican_meta_for_plugins_dto.plugin_ca_id = ca_id
cert_plugin = cert.CertificatePluginManager().get_plugin_by_ca_id(
ca_id)
else:
cert_plugin = cert.CertificatePluginManager().get_plugin(
order_model.meta)
barbican_meta['plugin_name'] = utils.generate_fullname_for(cert_plugin)
# Generate CSR if needed.
request_type = order_model.meta.get(cert.REQUEST_TYPE)
if request_type == cert.CertificateRequestType.STORED_KEY_REQUEST:
csr = order_model.order_barbican_metadata.get('generated_csr')
csr = barbican_meta.get('generated_csr')
if csr is None:
csr = _generate_csr(order_model)
order_model.order_barbican_metadata['generated_csr'] = csr
order_model.save()
barbican_meta_dto.generated_csr = csr
barbican_meta['generated_csr'] = csr
barbican_meta_for_plugins_dto.generated_csr = csr
result = cert_plugin.issue_certificate_request(order_model.id,
order_model.meta,
plugin_meta,
barbican_meta_dto)
result = cert_plugin.issue_certificate_request(
order_model.id, order_model.meta,
plugin_meta, barbican_meta_for_plugins_dto)
# Save plugin order plugin state
# Save plugin and barbican metadata for this order.
_save_plugin_metadata(order_model, plugin_meta)
_save_barbican_metadata(order_model, barbican_meta)
# Handle result
if cert.CertificateStatus.WAITING_FOR_CA == result.status:
# TODO(alee-3): Add code to set sub status of "waiting for CA"
_update_order_status(ORDER_STATUS_REQUEST_PENDING)
_schedule_check_cert_request(cert_plugin, order_model, plugin_meta,
result, project_model, cert.RETRY_MSEC)
_update_result_follow_on(
result_follow_on,
order_status=ORDER_STATUS_REQUEST_PENDING,
retry_task=common.RetryTasks.INVOKE_CERT_STATUS_CHECK_TASK,
retry_msec=result.retry_msec)
elif cert.CertificateStatus.CERTIFICATE_GENERATED == result.status:
_update_order_status(ORDER_STATUS_CERT_GENERATED)
_update_result_follow_on(
result_follow_on,
order_status=ORDER_STATUS_CERT_GENERATED)
container_model = _save_secrets(result, project_model)
elif cert.CertificateStatus.CLIENT_DATA_ISSUE_SEEN == result.status:
_update_order_status(ORDER_STATUS_DATA_INVALID)
raise cert.CertificateStatusClientDataIssue(result.status_message)
elif cert.CertificateStatus.CA_UNAVAILABLE_FOR_REQUEST == result.status:
# TODO(alee-3): set retry counter and error out if retries are exceeded
_update_order_status(ORDER_STATUS_CA_UNAVAIL_FOR_ISSUE)
_schedule_issue_cert_request(cert_plugin, order_model, plugin_meta,
result, project_model,
cert.ERROR_RETRY_MSEC)
_update_result_follow_on(
result_follow_on,
order_status=ORDER_STATUS_CA_UNAVAIL_FOR_ISSUE,
retry_task=common.RetryTasks.INVOKE_SAME_TASK,
retry_msec=cert.ERROR_RETRY_MSEC)
_notify_ca_unavailable(order_model, result)
elif cert.CertificateStatus.INVALID_OPERATION == result.status:
_update_order_status(ORDER_STATUS_INVALID_OPERATION)
raise cert.CertificateStatusInvalidOperation(result.status_message)
else:
_update_order_status(ORDER_STATUS_INTERNAL_ERROR)
raise cert.CertificateStatusNotSupported(result.status)
return container_model
def check_certificate_request(order_model, project_model, plugin_name):
def check_certificate_request(order_model, project_model, result_follow_on):
"""Check the status of a certificate request with the CA.
Note that this method may be called more than once if retries are
required. Barbican metadata is used to store intermediate information,
including selected plugins by name, to support such retries.
:param: order_model - order associated with this cert request
:param: project_model - project associated with this request
:param: plugin_name - plugin the issued the certificate request
:param: result_follow_on - A :class:`FollowOnProcessingStatusDTO` instance
instantiated by the client that this function may optionally update
with information on how to process this task into the future.
:returns: container_model - container with the relevant cert if the
request has been completed. None otherwise.
"""
container_model = None
plugin_meta = _get_plugin_meta(order_model)
barbican_meta_dto = cert.BarbicanMetaDTO()
barbican_meta = _get_barbican_meta(order_model)
# TODO(john-wood-w) See note above about DTO's name.
barbican_meta_for_plugins_dto = cert.BarbicanMetaDTO()
cert_plugin = cert.CertificatePluginManager().get_plugin_by_name(
plugin_name)
barbican_meta.get('plugin_name'))
result = cert_plugin.check_certificate_request(order_model.id,
order_model.meta,
plugin_meta,
barbican_meta_dto)
result = cert_plugin.check_certificate_status(
order_model.id, order_model.meta,
plugin_meta, barbican_meta_for_plugins_dto)
# Save plugin order plugin state
_save_plugin_metadata(order_model, plugin_meta)
# Handle result
if cert.CertificateStatus.WAITING_FOR_CA == result.status:
_update_order_status(ORDER_STATUS_REQUEST_PENDING)
_schedule_check_cert_request(cert_plugin, order_model, plugin_meta,
result, project_model,
cert.RETRY_MSEC)
_update_result_follow_on(
result_follow_on,
order_status=ORDER_STATUS_REQUEST_PENDING,
retry_task=common.RetryTasks.INVOKE_CERT_STATUS_CHECK_TASK,
retry_msec=result.retry_msec)
elif cert.CertificateStatus.CERTIFICATE_GENERATED == result.status:
_update_order_status(ORDER_STATUS_CERT_GENERATED)
_update_result_follow_on(
result_follow_on,
order_status=ORDER_STATUS_CERT_GENERATED)
container_model = _save_secrets(result, project_model)
elif cert.CertificateStatus.CLIENT_DATA_ISSUE_SEEN == result.status:
_update_order_status(cert.ORDER_STATUS_DATA_INVALID)
raise cert.CertificateStatusClientDataIssue(result.status_message)
elif cert.CertificateStatus.CA_UNAVAILABLE_FOR_REQUEST == result.status:
# TODO(alee-3): decide what to do about retries here
_update_order_status(ORDER_STATUS_CA_UNAVAIL_FOR_CHECK)
_schedule_check_cert_request(cert_plugin, order_model, plugin_meta,
result, project_model,
cert.ERROR_RETRY_MSEC)
_update_result_follow_on(
result_follow_on,
order_status=ORDER_STATUS_CA_UNAVAIL_FOR_CHECK,
retry_task=common.RetryTasks.INVOKE_SAME_TASK,
retry_msec=cert.ERROR_RETRY_MSEC)
_notify_ca_unavailable(order_model, result)
elif cert.CertificateStatus.INVALID_OPERATION == result.status:
_update_order_status(ORDER_STATUS_INVALID_OPERATION)
raise cert.CertificateStatusInvalidOperation(result.status_message)
else:
_update_order_status(ORDER_STATUS_INTERNAL_ERROR)
raise cert.CertificateStatusNotSupported(result.status)
return container_model
@ -216,57 +243,17 @@ def _get_ca_id(order_meta, project_id):
return None
def _schedule_cert_retry_task(cert_result_dto, cert_plugin, order_model,
plugin_meta,
retry_method=None,
retry_object=None,
retry_time=None,
retry_args=None):
if cert_result_dto.retry_msec > 0:
retry_time = cert_result_dto.retry_msec
if cert_result_dto.retry_method:
retry_method = cert_result_dto.retry_method
retry_object = utils.generate_fullname_for(cert_plugin)
retry_args = [order_model.id, order_model.meta, plugin_meta]
_schedule_retry_task(retry_object, retry_method, retry_time, retry_args)
def _schedule_issue_cert_request(cert_plugin, order_model, plugin_meta,
cert_result_dto, project_model, retry_time):
retry_args = [order_model,
project_model]
_schedule_cert_retry_task(
cert_result_dto, cert_plugin, order_model, plugin_meta,
retry_method="issue_certificate_request",
retry_object="barbican.tasks.certificate_resources",
retry_time=retry_time,
retry_args=retry_args)
def _schedule_check_cert_request(cert_plugin, order_model, plugin_meta,
cert_result_dto, project_model, retry_time):
retry_args = [order_model,
project_model,
utils.generate_fullname_for(cert_plugin)]
_schedule_cert_retry_task(
cert_result_dto, cert_plugin, order_model, plugin_meta,
retry_method="check_certificate_request",
retry_object="barbican.tasks.certificate_resources",
retry_time=retry_time,
retry_args=retry_args)
def _update_order_status(order_status):
# TODO(alee-3): add code to set order substatus, substatus message
# and save the order. most likely this call methods defined in Order.
pass
def _schedule_retry_task(retry_object, retry_method, retry_time, args):
# TODO(alee-3): Implement this method - here or elsewhere .
pass
def _update_result_follow_on(
result_follow_on,
order_status=None,
retry_task=common.RetryTasks.NO_ACTION_REQUIRED,
retry_msec=common.RETRY_MSEC_DEFAULT):
if order_status:
result_follow_on.status = order_status.id
result_follow_on.status_message = order_status.message
result_follow_on.retry_task = retry_task
if retry_msec and retry_msec >= 0:
result_follow_on.retry_msec = retry_msec
def _get_plugin_meta(order_model):
@ -277,6 +264,14 @@ def _get_plugin_meta(order_model):
return {}
def _get_barbican_meta(order_model):
if order_model:
order_barbican_meta_repo = repos.get_order_barbican_meta_repository()
return order_barbican_meta_repo.get_metadata_for_order(order_model.id)
else:
return {}
def _generate_csr(order_model):
"""Generate a CSR from the public key.
@ -355,6 +350,16 @@ def _save_plugin_metadata(order_model, plugin_meta):
order_plugin_meta_repo.save(plugin_meta, order_model)
def _save_barbican_metadata(order_model, barbican_meta):
"""Add barbican metadata to an order."""
if not isinstance(barbican_meta, dict):
barbican_meta = {}
order_barbican_meta_repo = repos.get_order_barbican_meta_repository()
order_barbican_meta_repo.save(barbican_meta, order_model)
def _save_secrets(result, project_model):
cert_secret_model, transport_key_model = plugin.store_secret(
unencrypted_raw=result.certificate,

View File

@ -27,6 +27,7 @@ from barbican.model import models
from barbican.model import repositories as rep
from barbican.plugin import resources as plugin
from barbican.tasks import certificate_resources as cert
from barbican.tasks import common
LOG = utils.getLogger(__name__)
@ -221,7 +222,7 @@ class BeginTypeOrder(BaseTask):
return self.helper.retrieve_entity(*args, **kwargs)
def handle_processing(self, order, *args, **kwargs):
self.handle_order(order)
return self.handle_order(order)
def handle_order(self, order):
"""Handle secret creation using meta info.
@ -234,7 +235,12 @@ class BeginTypeOrder(BaseTask):
if type is certificate
TBD
:param order: Order to process.
:return: None if no follow on processing is needed for this task,
otherwise a :class:`FollowOnProcessingStatusDTO` instance
with information on how to process this task into the future.
"""
result_follow_on = common.FollowOnProcessingStatusDTO()
order_info = order.to_dict_fields()
order_type = order_info.get('type')
meta_info = order_info.get('meta')
@ -263,7 +269,8 @@ class BeginTypeOrder(BaseTask):
LOG.debug("...done creating asymmetric order's secret.")
elif order_type == models.OrderType.CERTIFICATE:
# Request a certificate
new_container = cert.issue_certificate_request(order, project)
new_container = cert.issue_certificate_request(
order, project, result_follow_on)
if new_container:
order.container_id = new_container.id
LOG.debug("...done requesting a certificate.")
@ -272,6 +279,8 @@ class BeginTypeOrder(BaseTask):
u._('Order type "{order_type}" not implemented.').format(
order_type=order_type))
return result_follow_on
def handle_error(self, order, status, message, exception,
*args, **kwargs):
self.helper.handle_error(
@ -326,3 +335,60 @@ class UpdateOrder(BaseTask):
def handle_success(self, order, result, *args, **kwargs):
self.helper.handle_success(
order, result, *args, **kwargs)
class CheckCertificateStatusOrder(BaseTask):
"""Handles checking the status of a certificate order."""
def get_name(self):
return u._('Check Certificate Order Status')
def __init__(self):
LOG.debug('Creating CheckCertificateStatusOrder task processor')
self.project_repo = rep.get_project_repository()
self.helper = _OrderTaskHelper()
def retrieve_entity(self, *args, **kwargs):
return self.helper.retrieve_entity(*args, **kwargs)
def handle_processing(self, order, *args, **kwargs):
return self.handle_order(order)
def handle_order(self, order):
"""Handle checking the status of a certificate order.
:param order: Order to process.
:return: None if no follow on processing is needed for this task,
otherwise a :class:`FollowOnProcessingStatusDTO` instance
with information on how to process this task into the future.
"""
result_follow_on = common.FollowOnProcessingStatusDTO()
order_info = order.to_dict_fields()
order_type = order_info.get('type')
# Retrieve the project.
project = self.project_repo.get(order.project_id)
if order_type != models.OrderType.CERTIFICATE:
raise NotImplementedError(
u._('Order type "{order_type}" not supported.').format(
order_type=order_type))
# Request a certificate
new_container = cert.check_certificate_request(
order, project, result_follow_on)
if new_container:
order.container_id = new_container.id
LOG.debug("...done checking status of a certificate order.")
return result_follow_on
def handle_error(self, order, status, message, exception,
*args, **kwargs):
self.helper.handle_error(
order, status, message, exception, *args, **kwargs)
def handle_success(self, order, result, *args, **kwargs):
self.helper.handle_success(
order, result, *args, **kwargs)

View File

@ -53,7 +53,10 @@ def create_project(external_id="my keystone id", session=None):
return project
def create_order(project, session=None):
def create_order(project=None, session=None):
if not project:
project = create_project(session=session)
order = models.Order()
order.project_id = project.id
order_repo = repositories.get_order_repository()

View File

@ -28,7 +28,7 @@ class WhenTestingOrderRetryTaskRepository(database_utils.RepositoryTestCase):
def setUp(self):
super(WhenTestingOrderRetryTaskRepository, self).setUp()
self.date_time_now = datetime.datetime.now()
self.date_time_now = datetime.datetime.utcnow()
self.test_args = ['test', 'args']
self.test_kwargs = {'test': 1, 'kwargs': 2}
@ -79,7 +79,7 @@ class WhenTestingOrderRetryTaskRepository(database_utils.RepositoryTestCase):
# Now, a retrieve by the current time should return our entry.
entities, offset, limit, total = self.repo.get_by_create_date(
only_at_or_before_this_date=datetime.datetime.now(),
only_at_or_before_this_date=datetime.datetime.utcnow(),
session=session,
suppress_exception=True
)

View File

@ -31,7 +31,8 @@ class WhenTestingSimpleCertificateManagerPlugin(testtools.TestCase):
def test_check_certificate_status(self):
result = self.plugin.check_certificate_status(None, None, None, None)
self.assertEqual(cm.CertificateStatus.WAITING_FOR_CA, result.status)
self.assertEqual(
cm.CertificateStatus.CERTIFICATE_GENERATED, result.status)
def test_modify_certificate_request(self):
result = self.plugin.modify_certificate_request(None, None, None, None)

View File

@ -25,17 +25,27 @@ class WhenUsingAsyncTaskClient(utils.BaseTestCase):
def setUp(self):
super(WhenUsingAsyncTaskClient, self).setUp()
# Mock out the queue get_client() call:
self.mock_client = mock.MagicMock()
self.mock_client.cast.return_value = None
queue.get_client = mock.MagicMock(return_value=self.mock_client)
get_client_config = {
'return_value': self.mock_client
}
self.get_client_patcher = mock.patch(
'barbican.queue.get_client',
**get_client_config
)
self.get_client_patcher.start()
self.client = client.TaskClient()
def tearDown(self):
super(WhenUsingAsyncTaskClient, self).tearDown()
self.get_client_patcher.stop()
def test_should_process_type_order(self):
self.client.process_type_order(order_id=self.order_id,
project_id=self.external_project_id)
queue.get_client.assert_called_with()
self.mock_client.cast.assert_called_with(
{}, 'process_type_order', order_id=self.order_id,
project_id=self.external_project_id)
@ -45,11 +55,18 @@ class WhenUsingAsyncTaskClient(utils.BaseTestCase):
self.client.update_order(order_id=self.order_id,
project_id=self.external_project_id,
updated_meta=updated_meta)
queue.get_client.assert_called_with()
self.mock_client.cast.assert_called_with(
{}, 'update_order', order_id=self.order_id,
project_id=self.external_project_id, updated_meta=updated_meta)
def test_should_check_certificate_order(self):
self.client.check_certificate_status(
order_id=self.order_id,
project_id=self.external_project_id)
self.mock_client.cast.assert_called_with(
{}, 'check_certificate_status',
order_id=self.order_id, project_id=self.external_project_id)
class WhenCreatingDirectTaskClient(utils.BaseTestCase):
"""Test using the synchronous task client (i.e. standalone mode)."""

View File

@ -11,13 +11,17 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import datetime
import time
import eventlet
import mock
import oslotest.base as oslotest
from barbican.model import models
from barbican.model import repositories
from barbican.queue import retry_scheduler
from barbican.tests import database_utils
# Oslo messaging RPC server uses eventlet.
eventlet.monkey_patch()
@ -27,7 +31,7 @@ INITIAL_DELAY_SECONDS = 5.0
NEXT_RETRY_SECONDS = 5.0
class WhenRunningPeriodicServerRetryLogic(oslotest.BaseTestCase):
class WhenRunningPeriodicServerRetryLogic(database_utils.RepositoryTestCase):
"""Tests the retry logic invoked by the periodic task retry server.
These tests are only concerned with the logic of the invoked periodic
@ -40,27 +44,96 @@ class WhenRunningPeriodicServerRetryLogic(oslotest.BaseTestCase):
super(WhenRunningPeriodicServerRetryLogic, self).setUp()
retry_scheduler.CONF.set_override(
"task_retry_tg_initial_delay",
"initial_delay_seconds",
2 * INITIAL_DELAY_SECONDS,
group='retry_scheduler')
self.database_patcher = _DatabasePatcherHelper()
self.database_patcher.start()
retry_scheduler.CONF.set_override(
"periodic_interval_max_seconds",
NEXT_RETRY_SECONDS,
group='retry_scheduler')
self.queue_client = mock.MagicMock()
self.periodic_server = retry_scheduler.PeriodicServer(
queue_resource=None)
queue_resource=self.queue_client)
def tearDown(self):
super(WhenRunningPeriodicServerRetryLogic, self).tearDown()
self.periodic_server.stop()
self.database_patcher.stop()
def test_should_perform_retry_processing(self):
next_interval = self.periodic_server._check_retry_tasks()
def test_should_perform_retry_processing_no_tasks(self):
interval = self.periodic_server._check_retry_tasks()
# TODO(john-wood-w) Will be updated by future CR with actual retry
# logic unit tests.
self.assertEqual(60, next_interval)
self.assertEqual(
True,
NEXT_RETRY_SECONDS * .8 <= interval < NEXT_RETRY_SECONDS * 1.2)
def test_should_perform_retry_processing_one_task(self):
# Add one retry task.
args, kwargs, retry_repo = self._create_retry_task()
# Retrieve this entity.
entities, _, _, total = retry_repo.get_by_create_date()
self.assertEqual(1, total)
time.sleep(1)
interval = self.periodic_server._check_retry_tasks()
# Attempt to retrieve this entity, should have been deleted above.
entities, _, _, total = retry_repo.get_by_create_date(
suppress_exception=True)
self.assertEqual(0, total)
self.assertEqual(
True,
NEXT_RETRY_SECONDS * .8 <= interval < NEXT_RETRY_SECONDS * 1.2)
self.queue_client.test_task.assert_called_once_with(
*args, **kwargs
)
@mock.patch('barbican.model.repositories.commit')
def test_should_fail_and_force_a_rollback(self, mock_commit):
mock_commit.side_effect = Exception()
# Add one retry task.
args, kwargs, retry_repo = self._create_retry_task()
# Retrieve this entity.
entities, _, _, total = retry_repo.get_by_create_date()
self.assertEqual(1, total)
time.sleep(1)
self.periodic_server._check_retry_tasks()
# Attempt to retrieve this entity, should not have been deleted above.
entities, _, _, total = retry_repo.get_by_create_date(
suppress_exception=True)
self.assertEqual(1, total)
def _create_retry_task(self):
# Add one retry task:
task = 'test_task'
args = ('foo', 'bar')
kwargs = {'k_foo': 1, 'k_bar': 2}
order = database_utils.create_order()
retry = models.OrderRetryTask()
retry.order_id = order.id
retry.retry_at = datetime.datetime.utcnow()
retry.retry_task = task
retry.retry_args = args
retry.retry_kwargs = kwargs
retry_repo = repositories.get_order_retry_tasks_repository()
retry_repo.create_from(retry)
database_utils.get_session().commit()
return args, kwargs, retry_repo
class WhenRunningPeriodicServer(oslotest.BaseTestCase):
@ -76,7 +149,7 @@ class WhenRunningPeriodicServer(oslotest.BaseTestCase):
super(WhenRunningPeriodicServer, self).setUp()
retry_scheduler.CONF.set_override(
"task_retry_tg_initial_delay",
"initial_delay_seconds",
INITIAL_DELAY_SECONDS,
group='retry_scheduler')

View File

@ -189,9 +189,11 @@ class WhenCallingScheduleOrderRetryTasks(database_utils.RepositoryTestCase):
self.result = common.FollowOnProcessingStatusDTO()
self.args = ['args-foo', 'args-bar']
self.kwargs = {'foo': 1, 'bar': 2}
self.date_to_retry_at = datetime.datetime.now() + datetime.timedelta(
self.kwargs = {'order_id': self.order.id, 'foo': 1, 'bar': 2}
self.date_to_retry_at = (
datetime.datetime.utcnow() + datetime.timedelta(
milliseconds=self.result.retry_msec)
)
def test_should_not_schedule_task_due_to_no_result(self):
retry_rpc_method = server.schedule_order_retry_tasks(None, None, None)
@ -213,7 +215,7 @@ class WhenCallingScheduleOrderRetryTasks(database_utils.RepositoryTestCase):
retry_rpc_method = server.schedule_order_retry_tasks(
self.test_should_schedule_invoking_task_for_retry,
self.result,
self.order.id,
None, # Not used.
*self.args,
**self.kwargs)
database_utils.get_session().commit() # Flush to the database.
@ -232,7 +234,7 @@ class WhenCallingScheduleOrderRetryTasks(database_utils.RepositoryTestCase):
retry_rpc_method = server.schedule_order_retry_tasks(
None, # Should be ignored for non-self retries.
self.result,
self.order.id,
None, # Not used.
*self.args,
**self.kwargs)
database_utils.get_session().commit() # Flush to the database.
@ -262,11 +264,11 @@ class WhenCallingScheduleOrderRetryTasks(database_utils.RepositoryTestCase):
self.assertEqual(True, delta_seconds <= 2)
class WhenUsingBeginTypeOrderTask(utils.BaseTestCase):
"""Test using the Tasks class for 'type order' task."""
class WhenCallingTasksMethod(utils.BaseTestCase):
"""Test calling methods on the Tasks class."""
def setUp(self):
super(WhenUsingBeginTypeOrderTask, self).setUp()
super(WhenCallingTasksMethod, self).setUp()
# Mock the 'am I a server process?' flag used by the decorator around
# all task methods. Since this test class focuses on testing task
@ -284,7 +286,7 @@ class WhenUsingBeginTypeOrderTask(utils.BaseTestCase):
self.tasks = server.Tasks()
def tearDown(self):
super(WhenUsingBeginTypeOrderTask, self).tearDown()
super(WhenCallingTasksMethod, self).tearDown()
self.is_server_side_patcher.stop()
@mock.patch('barbican.tasks.resources.BeginTypeOrder')
@ -308,6 +310,16 @@ class WhenUsingBeginTypeOrderTask(utils.BaseTestCase):
self.order_id, self.external_project_id, updated_meta
)
@mock.patch('barbican.tasks.resources.CheckCertificateStatusOrder')
def test_should_check_certificate_order(self, mock_check_cert_order):
mock_check_cert_order.return_value.process.return_value = None
self.tasks.check_certificate_status(
None, self.order_id, self.external_project_id)
mock_check_cert_order.return_value.process.assert_called_with(
self.order_id, self.external_project_id
)
@mock.patch('barbican.tasks.resources.BeginTypeOrder')
def test_process_order_catch_exception(self, mock_begin_order):
"""Test that BeginTypeOrder's process() handles all exceptions."""

View File

@ -22,6 +22,7 @@ from barbican.common import hrefs
from barbican.model import models
from barbican.plugin.interface import certificate_manager as cert_man
from barbican.tasks import certificate_resources as cert_res
from barbican.tasks import common
from barbican.tests import utils
@ -35,6 +36,10 @@ class WhenPerformingPrivateOperations(utils.BaseTestCase,
self.setup_order_plugin_meta_repository_mock(
self.order_plugin_meta_repo)
self.order_barbican_meta_repo = mock.MagicMock()
self.setup_order_barbican_meta_repository_mock(
self.order_barbican_meta_repo)
def test_get_plugin_meta(self):
class Value(object):
def __init__(self, value):
@ -80,6 +85,21 @@ class WhenPerformingPrivateOperations(utils.BaseTestCase,
self.order_plugin_meta_repo.save.assert_called_once_with(
{}, test_order_model)
def test_get_barbican_meta_with_empty_dict(self):
result = cert_res._get_barbican_meta(None)
self._assert_dict_equal({}, result)
def test_save_barbican_w_null_meta(self):
test_order_model = 'My order model'
# Test None for plugin meta data.
cert_res._save_barbican_metadata(
test_order_model, None)
self.order_barbican_meta_repo.save.assert_called_once_with(
{}, test_order_model)
def _assert_dict_equal(self, expected, test):
self.assertIsInstance(expected, dict)
self.assertIsInstance(test, dict)
@ -94,12 +114,12 @@ class WhenPerformingPrivateOperations(utils.BaseTestCase,
'between the expected and test dicts')
class WhenIssuingCertificateRequests(utils.BaseTestCase,
class BaseCertificateRequestsTestCase(utils.BaseTestCase,
utils.MockModelRepositoryMixin):
"""Tests the 'issue_certificate_request()' function."""
"""Tests the 'xxxx_certificate_request()' functions."""
def setUp(self):
super(WhenIssuingCertificateRequests, self).setUp()
super(BaseCertificateRequestsTestCase, self).setUp()
self.project_id = "56789"
self.order_id = "12345"
self.barbican_meta_dto = mock.MagicMock()
@ -109,9 +129,11 @@ class WhenIssuingCertificateRequests(utils.BaseTestCase,
self.result = cert_man.ResultDTO(
cert_man.CertificateStatus.WAITING_FOR_CA
)
self.result_follow_on = common.FollowOnProcessingStatusDTO()
self.cert_plugin = mock.MagicMock()
self.cert_plugin.issue_certificate_request.return_value = self.result
self.cert_plugin.check_certificate_status.return_value = self.result
self.order_model = mock.MagicMock()
self.order_model.id = self.order_id
@ -124,6 +146,8 @@ class WhenIssuingCertificateRequests(utils.BaseTestCase,
self._config_cert_event_plugin()
self._config_save_meta_plugin()
self._config_get_meta_plugin()
self._config_save_barbican_meta_plugin()
self._config_get_barbican_meta_plugin()
self._config_barbican_meta_dto()
self.private_key_secret_id = "private_key_secret_id"
@ -168,11 +192,161 @@ class WhenIssuingCertificateRequests(utils.BaseTestCase,
"https://localhost/containers/" + self.container_id,
"subject_name": "cn=host.example.com,ou=dev,ou=us,o=example.com"
}
self.order_model.order_barbican_metadata = {}
# Set up mocked repos
self.container_repo = mock.MagicMock()
self.secret_repo = mock.MagicMock()
# Set up mocked repositories
self.setup_container_repository_mock(self.container_repo)
self.setup_container_secret_repository_mock()
self.setup_order_plugin_meta_repository_mock()
self.setup_project_secret_repository_mock()
self.setup_secret_repository_mock(self.secret_repo)
def tearDown(self):
super(BaseCertificateRequestsTestCase, self).tearDown()
self.cert_plugin_patcher.stop()
self.save_plugin_meta_patcher.stop()
self.get_plugin_meta_patcher.stop()
self.cert_event_plugin_patcher.stop()
self.barbican_meta_dto_patcher.stop()
self.save_barbican_barbican_meta_patcher.stop()
self.get_barbican_plugin_meta_patcher.stop()
def _test_should_return_waiting_for_ca(self, method_to_test):
self.result.status = cert_man.CertificateStatus.WAITING_FOR_CA
method_to_test(
self.order_model, self.project_model, self.result_follow_on)
self.assertEqual(
common.RetryTasks.INVOKE_CERT_STATUS_CHECK_TASK,
self.result_follow_on.retry_task)
self.assertEqual(
cert_res.ORDER_STATUS_REQUEST_PENDING.id,
self.result_follow_on.status)
self.assertEqual(
cert_res.ORDER_STATUS_REQUEST_PENDING.message,
self.result_follow_on.status_message)
def _test_should_return_certificate_generated(self, method_to_test):
self.result.status = cert_man.CertificateStatus.CERTIFICATE_GENERATED
method_to_test(
self.order_model, self.project_model, self.result_follow_on)
self.assertEqual(
common.RetryTasks.NO_ACTION_REQUIRED,
self.result_follow_on.retry_task)
self.assertEqual(
cert_res.ORDER_STATUS_CERT_GENERATED.id,
self.result_follow_on.status)
self.assertEqual(
cert_res.ORDER_STATUS_CERT_GENERATED.message,
self.result_follow_on.status_message)
def _test_should_raise_client_data_issue_seen(self, method_to_test):
self.result.status = cert_man.CertificateStatus.CLIENT_DATA_ISSUE_SEEN
self.assertRaises(
cert_man.CertificateStatusClientDataIssue,
method_to_test,
self.order_model,
self.project_model,
self.result_follow_on
)
def _test_should_raise_status_not_supported(self, method_to_test):
self.result.status = "Legend of Link"
self.assertRaises(
cert_man.CertificateStatusNotSupported,
method_to_test,
self.order_model,
self.project_model,
self.result_follow_on
)
def _config_cert_plugin(self):
"""Mock the certificate plugin manager."""
cert_plugin_config = {
'return_value.get_plugin.return_value': self.cert_plugin,
'return_value.get_plugin_by_name.return_value': self.cert_plugin,
'return_value.get_plugin_by_ca_id.return_value': self.cert_plugin
}
self.cert_plugin_patcher = mock.patch(
'barbican.plugin.interface.certificate_manager'
'.CertificatePluginManager',
**cert_plugin_config
)
self.cert_plugin_patcher.start()
def _config_cert_event_plugin(self):
"""Mock the certificate event plugin manager."""
self.cert_event_plugin_patcher = mock.patch(
'barbican.plugin.interface.certificate_manager'
'.EVENT_PLUGIN_MANAGER'
)
self.cert_event_plugin_patcher.start()
def _config_save_meta_plugin(self):
"""Mock the save plugin meta function."""
self.save_plugin_meta_patcher = mock.patch(
'barbican.tasks.certificate_resources._save_plugin_metadata'
)
self.mock_save_plugin = self.save_plugin_meta_patcher.start()
def _config_get_meta_plugin(self):
"""Mock the get plugin meta function."""
get_plugin_config = {'return_value': self.plugin_meta}
self.get_plugin_meta_patcher = mock.patch(
'barbican.tasks.certificate_resources._get_plugin_meta',
**get_plugin_config
)
self.get_plugin_meta_patcher.start()
def _config_save_barbican_meta_plugin(self):
"""Mock the save barbican plugin meta function."""
self.save_barbican_barbican_meta_patcher = mock.patch(
'barbican.tasks.certificate_resources._save_barbican_metadata'
)
self.mock_barbican_save_plugin = (
self.save_barbican_barbican_meta_patcher.start()
)
def _config_get_barbican_meta_plugin(self):
"""Mock the get barbican plugin meta function."""
get_barbican_plugin_config = {'return_value': self.barbican_meta}
self.get_barbican_plugin_meta_patcher = mock.patch(
'barbican.tasks.certificate_resources._get_barbican_meta',
**get_barbican_plugin_config
)
self.get_barbican_plugin_meta_patcher.start()
def _config_barbican_meta_dto(self):
"""Mock the BarbicanMetaDTO."""
get_plugin_config = {'return_value': self.barbican_meta_dto}
self.barbican_meta_dto_patcher = mock.patch(
'barbican.plugin.interface.certificate_manager'
'.BarbicanMetaDTO',
**get_plugin_config
)
self.barbican_meta_dto_patcher.start()
class WhenIssuingCertificateRequests(BaseCertificateRequestsTestCase):
"""Tests the 'issue_certificate_request()' function."""
def setUp(self):
super(WhenIssuingCertificateRequests, self).setUp()
self.private_key_secret_id = "private_key_secret_id"
self.public_key_secret_id = "public_key_secret_id"
self.passphrase_secret_id = "passphrase_secret_id"
self.private_key_value = None
self.public_key_value = "my public key"
self.passphrase_value = "my passphrase"
self.ca_repo = mock.MagicMock()
self.preferred_ca_repo = mock.MagicMock()
@ -184,12 +358,6 @@ class WhenIssuingCertificateRequests(utils.BaseTestCase,
self.project_id,
"ca_id")
# Set up mocked repositories
self.setup_container_repository_mock(self.container_repo)
self.setup_container_secret_repository_mock()
self.setup_order_plugin_meta_repository_mock()
self.setup_project_secret_repository_mock()
self.setup_secret_repository_mock(self.secret_repo)
self.setup_ca_repository_mock(self.ca_repo)
self.setup_preferred_ca_repository_mock(self.preferred_ca_repo)
@ -205,37 +373,33 @@ class WhenIssuingCertificateRequests(utils.BaseTestCase,
def tearDown(self):
super(WhenIssuingCertificateRequests, self).tearDown()
self.cert_plugin_patcher.stop()
self.save_plugin_meta_patcher.stop()
self.get_plugin_meta_patcher.stop()
self.cert_event_plugin_patcher.stop()
self.barbican_meta_dto_patcher.stop()
def test_should_return_waiting_for_ca(self):
self.result.status = cert_man.CertificateStatus.WAITING_FOR_CA
self._test_should_return_waiting_for_ca(
cert_res.issue_certificate_request)
cert_res.issue_certificate_request(self.order_model,
self.project_model)
self._verify_issue_certificate_plugins_called()
def test_should_return_waiting_for_ca_as_retry(self):
# For a retry, the plugin-name to look up would have already been
# saved into the barbican metadata for the order, so just make sure
# we can retrieve it.
self.barbican_meta.update({'plugin_name': 'foo-plugin'})
self._test_should_return_waiting_for_ca(
cert_res.issue_certificate_request)
self._verify_issue_certificate_plugins_called()
def test_should_return_certificate_generated(self):
self.result.status = cert_man.CertificateStatus.CERTIFICATE_GENERATED
cert_res.issue_certificate_request(self.order_model,
self.project_model)
self._test_should_return_certificate_generated(
cert_res.issue_certificate_request)
self._verify_issue_certificate_plugins_called()
def test_should_raise_client_data_issue_seen(self):
self.result.status = cert_man.CertificateStatus.CLIENT_DATA_ISSUE_SEEN
self.assertRaises(
cert_man.CertificateStatusClientDataIssue,
cert_res.issue_certificate_request,
self.order_model,
self.project_model
)
self._test_should_raise_client_data_issue_seen(
cert_res.issue_certificate_request)
def _do_pyopenssl_stored_key_request(self):
self.container = models.Container(
@ -254,13 +418,14 @@ class WhenIssuingCertificateRequests(utils.BaseTestCase,
self.result.status = cert_man.CertificateStatus.WAITING_FOR_CA
cert_res.issue_certificate_request(self.order_model,
self.project_model)
self.project_model,
self.result_follow_on)
def test_should_return_for_pyopenssl_stored_key(self):
self._do_pyopenssl_stored_key_request()
self._verify_issue_certificate_plugins_called()
self.assertIsNotNone(
self.order_model.order_barbican_metadata['generated_csr'])
self.order_model.order_barbican_metadata.get('generated_csr'))
# TODO(alee-3) Add tests to validate the request based on the validator
# code that dave-mccowan is adding.
@ -306,7 +471,8 @@ class WhenIssuingCertificateRequests(utils.BaseTestCase,
self.result.status = cert_man.CertificateStatus.WAITING_FOR_CA
cert_res.issue_certificate_request(self.order_model,
self.project_model)
self.project_model,
self.result_follow_on)
self._verify_issue_certificate_plugins_called()
self.assertIsNotNone(
@ -332,7 +498,8 @@ class WhenIssuingCertificateRequests(utils.BaseTestCase,
self.result.status = cert_man.CertificateStatus.WAITING_FOR_CA
cert_res.issue_certificate_request(self.order_model,
self.project_model)
self.project_model,
self.result_follow_on)
self._verify_issue_certificate_plugins_called()
self.assertIsNotNone(
@ -357,7 +524,8 @@ class WhenIssuingCertificateRequests(utils.BaseTestCase,
self.result.status = cert_man.CertificateStatus.WAITING_FOR_CA
cert_res.issue_certificate_request(self.order_model,
self.project_model)
self.project_model,
self.result_follow_on)
self._verify_issue_certificate_plugins_called()
self.assertIsNotNone(
@ -384,7 +552,8 @@ class WhenIssuingCertificateRequests(utils.BaseTestCase,
self.assertRaises(excep.StoredKeyContainerNotFound,
cert_res.issue_certificate_request,
self.order_model,
self.project_model)
self.project_model,
self.result_follow_on)
def test_should_raise_for_pycrypto_stored_key_no_private_key(self):
self.container = models.Container(
@ -404,7 +573,8 @@ class WhenIssuingCertificateRequests(utils.BaseTestCase,
self.assertRaises(excep.StoredKeyPrivateKeyNotFound,
cert_res.issue_certificate_request,
self.order_model,
self.project_model)
self.project_model,
self.result_follow_on)
def test_should_return_for_pyopenssl_stored_key_with_extensions(self):
self.container = models.Container(
@ -425,7 +595,8 @@ class WhenIssuingCertificateRequests(utils.BaseTestCase,
self.result.status = cert_man.CertificateStatus.WAITING_FOR_CA
cert_res.issue_certificate_request(self.order_model,
self.project_model)
self.project_model,
self.result_follow_on)
self._verify_issue_certificate_plugins_called()
self.assertIsNotNone(
@ -442,7 +613,8 @@ class WhenIssuingCertificateRequests(utils.BaseTestCase,
cert_man.CertificateStatusInvalidOperation,
cert_res.issue_certificate_request,
self.order_model,
self.project_model
self.project_model,
self.result_follow_on
)
def test_should_return_ca_unavailable_for_request(self):
@ -455,7 +627,8 @@ class WhenIssuingCertificateRequests(utils.BaseTestCase,
order_ref = hrefs.convert_order_to_href(self.order_id)
cert_res.issue_certificate_request(self.order_model,
self.project_model)
self.project_model,
self.result_follow_on)
self._verify_issue_certificate_plugins_called()
@ -466,16 +639,19 @@ class WhenIssuingCertificateRequests(utils.BaseTestCase,
status_msg,
retry_msec
)
self.assertEqual(
common.RetryTasks.INVOKE_SAME_TASK,
self.result_follow_on.retry_task)
self.assertEqual(
cert_res.ORDER_STATUS_CA_UNAVAIL_FOR_ISSUE.id,
self.result_follow_on.status)
self.assertEqual(
cert_res.ORDER_STATUS_CA_UNAVAIL_FOR_ISSUE.message,
self.result_follow_on.status_message)
def test_should_raise_status_not_supported(self):
self.result.status = "Legend of Link"
self.assertRaises(
cert_man.CertificateStatusNotSupported,
cert_res.issue_certificate_request,
self.order_model,
self.project_model
)
self._test_should_raise_status_not_supported(
cert_res.issue_certificate_request)
def _verify_issue_certificate_plugins_called(self):
self.cert_plugin.issue_certificate_request.assert_called_once_with(
@ -490,49 +666,82 @@ class WhenIssuingCertificateRequests(utils.BaseTestCase,
self.plugin_meta
)
def _config_cert_plugin(self):
"""Mock the certificate plugin manager."""
cert_plugin_config = {
'return_value.get_plugin.return_value': self.cert_plugin,
'return_value.get_plugin_by_ca_id.return_value': self.cert_plugin
}
self.cert_plugin_patcher = mock.patch(
'barbican.plugin.interface.certificate_manager'
'.CertificatePluginManager',
**cert_plugin_config
self.mock_barbican_save_plugin.assert_called_once_with(
self.order_model,
self.barbican_meta
)
self.cert_plugin_patcher.start()
def _config_cert_event_plugin(self):
"""Mock the certificate event plugin manager."""
self.cert_event_plugin_patcher = mock.patch(
'barbican.plugin.interface.certificate_manager'
'.EVENT_PLUGIN_MANAGER'
)
self.cert_event_plugin_patcher.start()
def _config_save_meta_plugin(self):
"""Mock the save plugin meta function."""
self.save_plugin_meta_patcher = mock.patch(
'barbican.tasks.certificate_resources._save_plugin_metadata'
)
self.mock_save_plugin = self.save_plugin_meta_patcher.start()
class WhenCheckingCertificateRequests(BaseCertificateRequestsTestCase):
"""Tests the 'check_certificate_request()' function."""
def _config_get_meta_plugin(self):
"""Mock the get plugin meta function."""
get_plugin_config = {'return_value': self.plugin_meta}
self.get_plugin_meta_patcher = mock.patch(
'barbican.tasks.certificate_resources._get_plugin_meta',
**get_plugin_config
)
self.get_plugin_meta_patcher.start()
def setUp(self):
super(WhenCheckingCertificateRequests, self).setUp()
def _config_barbican_meta_dto(self):
"""Mock the BarbicanMetaDTO."""
get_plugin_config = {'return_value': self.barbican_meta_dto}
self.barbican_meta_dto_patcher = mock.patch(
'barbican.plugin.interface.certificate_manager'
'.BarbicanMetaDTO',
**get_plugin_config
def tearDown(self):
super(WhenCheckingCertificateRequests, self).tearDown()
def test_should_return_waiting_for_ca(self):
self._test_should_return_waiting_for_ca(
cert_res.check_certificate_request)
self._verify_check_certificate_plugins_called()
def test_should_return_certificate_generated(self):
self._test_should_return_certificate_generated(
cert_res.check_certificate_request)
self._verify_check_certificate_plugins_called()
def test_should_raise_client_data_issue_seen(self):
self._test_should_raise_client_data_issue_seen(
cert_res.check_certificate_request)
def test_should_raise_status_not_supported(self):
self._test_should_raise_status_not_supported(
cert_res.check_certificate_request)
def test_should_return_ca_unavailable_for_request(self):
retry_msec = 123
status_msg = 'Test status'
self.result.status = (
cert_man.CertificateStatus.CA_UNAVAILABLE_FOR_REQUEST)
self.result.retry_msec = retry_msec
self.result.status_message = status_msg
order_ref = hrefs.convert_order_to_href(self.order_id)
cert_res.check_certificate_request(self.order_model,
self.project_model,
self.result_follow_on)
self._verify_check_certificate_plugins_called()
epm = self.cert_event_plugin_patcher.target.EVENT_PLUGIN_MANAGER
epm.notify_ca_is_unavailable.assert_called_once_with(
self.project_id,
order_ref,
status_msg,
retry_msec
)
self.assertEqual(
common.RetryTasks.INVOKE_SAME_TASK,
self.result_follow_on.retry_task)
self.assertEqual(
cert_res.ORDER_STATUS_CA_UNAVAIL_FOR_CHECK.id,
self.result_follow_on.status)
self.assertEqual(
cert_res.ORDER_STATUS_CA_UNAVAIL_FOR_CHECK.message,
self.result_follow_on.status_message)
def _verify_check_certificate_plugins_called(self):
self.cert_plugin.check_certificate_status.assert_called_once_with(
self.order_id,
self.order_meta,
self.plugin_meta,
self.barbican_meta_dto
)
self.mock_save_plugin.assert_called_once_with(
self.order_model,
self.plugin_meta
)
self.barbican_meta_dto_patcher.start()

View File

@ -14,6 +14,7 @@
# limitations under the License.
import mock
import six
from barbican import i18n as u
from barbican.model import models
@ -169,6 +170,7 @@ class WhenBeginningKeyTypeOrder(BaseOrderTestCase):
@mock.patch('barbican.plugin.resources.generate_secret')
def test_should_process_key_order(self, mock_generate_secret):
mock_generate_secret.return_value = self.secret
self.resource.process(self.order.id, self.external_project_id)
self.order_repo.get.assert_called_once_with(
@ -253,6 +255,57 @@ class WhenBeginningKeyTypeOrder(BaseOrderTestCase):
)
class WhenBeginningCertificateTypeOrder(BaseOrderTestCase):
def setUp(self):
super(WhenBeginningCertificateTypeOrder, self).setUp()
self.order.type = models.OrderType.CERTIFICATE
self.resource = resources.BeginTypeOrder()
@mock.patch(
'barbican.tasks.certificate_resources.issue_certificate_request')
def test_should_process_order_no_container(
self, mock_issue_cert_request):
mock_issue_cert_request.return_value = None
self.resource.process(self.order.id, self.external_project_id)
self.order_repo.get.assert_called_once_with(
entity_id=self.order.id,
external_project_id=self.external_project_id)
self.assertEqual(self.order.status, models.States.ACTIVE)
mock_issue_cert_request.assert_called_once_with(
self.order,
self.project,
mock.ANY
)
self.assertIsNone(self.order.container_id)
@mock.patch(
'barbican.tasks.certificate_resources.issue_certificate_request')
def test_should_process_order_with_container(
self, mock_issue_cert_request):
mock_issue_cert_request.return_value = self.container
self.resource.process(self.order.id, self.external_project_id)
self.order_repo.get.assert_called_once_with(
entity_id=self.order.id,
external_project_id=self.external_project_id)
self.assertEqual(self.order.status, models.States.ACTIVE)
mock_issue_cert_request.assert_called_once_with(
self.order,
self.project,
mock.ANY
)
self.assertEqual(self.container.id, self.order.container_id)
class WhenUpdatingOrder(BaseOrderTestCase):
def setUp(self):
@ -398,3 +451,73 @@ class WhenBeginningAsymmetricTypeOrder(BaseOrderTestCase):
self.order.id,
self.external_project_id,
)
class WhenCheckingCertificateStatus(BaseOrderTestCase):
def setUp(self):
super(WhenCheckingCertificateStatus, self).setUp()
self.order.type = models.OrderType.CERTIFICATE
self.resource = resources.CheckCertificateStatusOrder()
@mock.patch(
'barbican.tasks.certificate_resources.check_certificate_request')
def test_should_process_order_no_container(
self, mock_check_cert_request):
mock_check_cert_request.return_value = None
self.resource.process(self.order.id, self.external_project_id)
self.order_repo.get.assert_called_once_with(
entity_id=self.order.id,
external_project_id=self.external_project_id)
self.assertEqual(self.order.status, models.States.ACTIVE)
mock_check_cert_request.assert_called_once_with(
self.order,
self.project,
mock.ANY
)
self.assertIsNone(self.order.container_id)
@mock.patch(
'barbican.tasks.certificate_resources.check_certificate_request')
def test_should_process_order_with_container(
self, mock_check_cert_request):
mock_check_cert_request.return_value = self.container
self.resource.process(self.order.id, self.external_project_id)
self.order_repo.get.assert_called_once_with(
entity_id=self.order.id,
external_project_id=self.external_project_id)
self.assertEqual(self.order.status, models.States.ACTIVE)
mock_check_cert_request.assert_called_once_with(
self.order,
self.project,
mock.ANY
)
self.assertEqual(self.container.id, self.order.container_id)
def test_should_fail_with_bogus_order_type(self):
self.order.type = 'bogus-type'
self.assertRaises(
NotImplementedError,
self.resource.process,
self.order.id,
self.external_project_id,
)
# Order state should be set to ERROR.
self.assertEqual(models.States.ERROR, self.order.status)
self.assertEqual(
six.u('Check Certificate Order Status failure seen - '
'please contact site administrator.'),
self.order.error_reason)
self.assertEqual(500, self.order.error_status_code)

View File

@ -156,10 +156,10 @@ server_name = 'barbican.queue'
[retry_scheduler]
# Seconds (float) to wait between starting retry scheduler
task_retry_tg_initial_delay = 10.0
initial_delay_seconds = 10.0
# Seconds (float) to wait between starting retry scheduler
task_retry_tg_periodic_interval_max = 10.0
periodic_interval_max_seconds = 10.0
# ================= Keystone Notification Options - Application ===============

View File

@ -21,11 +21,14 @@ class OrderModel(BaseModel):
def __init__(self, type=None, name=None, status=None, secret_ref=None,
expiration=None, updated=None, created=None, meta=None,
payload_content_type=None, order_ref=None, container_ref=None,
error_status_code=None, error_reason=None):
error_status_code=None, error_reason=None,
sub_status=None, sub_status_message=None):
super(OrderModel, self).__init__()
self.type = type
self.name = name
self.status = status
self.sub_status = sub_status
self.sub_status_message = sub_status_message
self.secret_ref = secret_ref
self.expiration = expiration
self.updated = updated