Implements base classes for storage controllers

This patch follows (or should follow) the specs written in the v1
specification: https://wiki.openstack.org/wiki/Marconi/specs/api/v1

This patch deletes driver_base.py and adds base.py in marconi/storage
package.

Note: Most of this implementations will be tested in further patches
since there's no good way to test these base classes.

Implements blueprint storage-base

Change-Id: Iefa6374635fcf9dd9fc60417d8ed5c306bbc619a
This commit is contained in:
Flaper Fesp 2013-03-05 18:52:43 +01:00
parent 1778a07fb9
commit 665ae50599
6 changed files with 432 additions and 19 deletions

View File

@ -1,3 +1,7 @@
"""Marconi Storage Drivers"""
from marconi.storage.driver_base import DriverBase # NOQA
from marconi.storage.base import ClaimBase # NOQA
from marconi.storage.base import DriverBase # NOQA
from marconi.storage.base import MessageBase # NOQA
from marconi.storage.base import QueueBase # NOQA
from marconi.storage import exceptions # NOQA

307
marconi/storage/base.py Normal file
View File

@ -0,0 +1,307 @@
# Copyright (c) 2013 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Implements the DriverBase abstract class for Marconi storage drivers."""
import abc
# Seconds
MIN_TTL = 60
# Seconds (14 days)
MAX_TTL = 1209600
class DriverBase:
__metaclass__ = abc.ABCMeta
@abc.abstractproperty
def queue_controller(self):
"""
Returns storage's queues controller
"""
pass
@abc.abstractproperty
def message_controller(self):
"""
Returns storage's messages controller
"""
pass
@abc.abstractproperty
def claim_controller(self):
"""
Returns storage's claims controller
"""
pass
class ControllerBase(object):
"""
Top level class for controllers.
:param driver: Instance of the driver
instantiating this controller.
"""
def __init__(self, driver):
self.driver = driver
class QueueBase(ControllerBase):
"""
This class is responsible of managing
queues which means handling their CRUD
operations, monitoring and interactions.
Storages' implementations of this class
should be capable of handling high work
loads and huge number of queues.
"""
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def list(self, tenant=None):
"""
Base method for listing queues.
:param tenant: Tenant id
:returns: List of queues
"""
pass
@abc.abstractmethod
def get(self, name, tenant=None):
"""
Base method for queue retrieval.
:param name: The queue name
:param tenant: Tenant id
:returns: Dictionary containing queue metadata
:raises: DoesNotExist
"""
pass
@abc.abstractmethod
def create(self, name, tenant=None, ttl=MIN_TTL, **metadata):
"""
Base method for queue creation.
:param name: The queue name
:param tenant: Tenant id
:param ttl: Number of seconds the server
will keep messages for this queue.
:param metadata: Arbitrary metadata
"""
pass
@abc.abstractmethod
def update(self, name, tenant=None, **metadata):
"""
Base method for queue update.
:param name: The queue name
:param tenant: Tenant id
:param metadata: Extra parameters defining
the new metadata for this queue.
"""
pass
@abc.abstractmethod
def delete(self, name, tenant=None):
"""
Base method for queue deletion.
:param name: The queue name
:param tenant: Tenant id
"""
pass
@abc.abstractmethod
def stats(self, name, tenant=None):
"""
Base method for queue stats.
:param name: The queue name
:param tenant: Tenant id
:returns: Dictionary with the
queue stats
"""
pass
@abc.abstractmethod
def actions(self, name, tenant=None, marker=None, limit=10):
"""
Base method for queue actions.
:param name: Queue name
:param tenant: Tenant id
:param marker: Tail identifier
:param limit: (Default 10) Max number
of messages to retrieve.
"""
pass
class MessageBase(ControllerBase):
"""
This class is responsible for managing
messages CRUD.
"""
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def get(self, queue, tenant=None, message_id=None,
marker=None, echo=False, client_uuid=None):
"""
Base message get method
This method is responsible for querying messages
and should be capable of retrieving a single
message based on message_id or multiple messages
based on the other parameters being passed.
:param queue: Name of the queue to get the
message from.
:param tenant: Tenant id
:param message: Message ID
:param marker: Tail identifier
:param echo: (Default False) Boolean expressing whether
or not this client should receive its own messages.
:param client_uuid: Client's unique identifier. This param
is required when echo=False.
:returns: List of messages
:raises: DoesNotExist
"""
pass
@abc.abstractmethod
def post(self, queue, messages, tenant=None):
"""
Base message post method
Implementations of this method should guarantee
and preserve the order, in the returned list, of
incoming messages.
:param queue: Name of the queue to post message to.
:param messages: Messages to post to queue,
it can be a list of 1 or more elements.
:param tenant: Tenant id
:returns: List of message ids
"""
pass
@abc.abstractmethod
def delete(self, queue, message_id, tenant=None, claim=None):
"""
Base message delete method
:param queue: Name of the queue to post
message to.
:param message_id: Message to be deleted
:param tenant: Tenant id
:param claim: Claim this message
belongs to. When specified, claim must
be valid and message_id must belong to
it.
"""
pass
class ClaimBase(ControllerBase):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def get(self, queue, claim_id, tenant=None):
"""
Base claim get method
:param queue: Name of the queue this
claim belongs to.
:param claim_id: The claim id
:param tenant: Tenant id
:returns: Dictionary containing claim's
metadata and claimed messages.
:raises: DoesNotExist
"""
pass
@abc.abstractmethod
def create(self, queue, tenant=None, ttl=MIN_TTL, limit=10):
"""
Base claim create method
:param queue: Name of the queue this
claim belongs to.
:param tenant: Tenant id
:param ttl: Number of seconds the server
will keep this claim in this queue.
:param limit: (Default 10) Max number
of messages to claim.
:returns: Dictionary containing claim's
metadata and claimed messages.
"""
pass
@abc.abstractmethod
def update(self, queue, claim_id, tenant=None, **metadata):
"""
Base claim update method
:param queue: Name of the queue this
claim belongs to.
:param claim_id: Claim to be updated
:param tenant: Tenant id
:param metadata: Claim's parameters
to be updated.
"""
pass
@abc.abstractmethod
def delete(self, queue, claim_id, tenant=None):
"""
Base claim delete method
:param queue: Name of the queue this
claim belongs to.
:param claim_id: Claim to be deleted
:param tenant: Tenant id
"""
pass
@abc.abstractmethod
def stats(self, queue, claim_id, tenant=None):
"""
Base method for claim stats.
:param queue: Name of the queue this
claim belongs to.
:param claim_id: Claim to be deleted
:param tenant: Tenant id
:returns: Dictionary with the
queue stats
"""
pass

View File

@ -1,4 +1,4 @@
# Copyright (c) 2013 Rackspace, Inc.
# Copyright (c) 2013 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -13,20 +13,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import abc
class DriverBase:
__metaclass__ = abc.ABCMeta
@abc.abstractproperty
def queue_controller(self):
pass
@abc.abstractproperty
def message_controller(self):
pass
@abc.abstractproperty
def claim_controller(self):
pass
class DoesNotExist(Exception):
pass

View File

@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import marconi.storage as storage
from marconi import storage
class Driver(storage.DriverBase):

View File

View File

@ -0,0 +1,116 @@
# Copyright (c) 2013 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from marconi import storage
from marconi.tests.util import suite
class ControllerBaseTest(suite.TestSuite):
driver_class = None
controller_class = None
controller_base_class = None
def setUp(self):
super(ControllerBaseTest, self).setUp()
if not self.driver_class:
self.skipTest("No driver class specified")
if not isinstance(self.controller_class, self.controller_base_class):
self.skipTest("%s is not an instance of %s. Tests not supported" %
(self.controller_class, self.controller_base_class))
self.driver = self.driver_class()
self.controller = self.controller_class(self.driver)
class QueueControllerTest(ControllerBaseTest):
"""
Queue Controller base tests
"""
controller_base_class = storage.QueueBase
def test_queue_lifecycle(self):
# Test Queue Creation
self.controller.create("test", ttl=10,
topic="test_queue")
# Test Queue retrieval
queue = self.controller.get("test")
self.assertEqual(queue["name"], "test")
self.assertEqual(queue["ttl"], 10)
# Test Queue Update
self.controller.update("tests", name="test1")
queue = self.controller.get("test1")
self.assertEqual(queue["ttl"], 10)
# Test Queue Deletion
self.controller.delete("test1")
# Test DoesNotExist Exception
self.assertRaises(storage.exceptions.DoesNotExist,
self.controller.get, "test1")
class MessageControllerTest(ControllerBaseTest):
"""
Message Controller base tests
NOTE(flaper87): Implementations of this class should
override the tearDown method in order
to clean up storage's state.
"""
queue_name = "test_queue"
controller_base_class = storage.MessageBase
def setUp(self):
super(MessageControllerTest, self).setUp()
# Lets create a queue
self.queue_controller = self.driver.queue_controller()
self.queue_controller.create(self.queue_name)
def tearDown(self):
self.queue_controller.delete(self.queue_name)
super(MessageControllerTest, self).tearDown()
def test_message_lifecycle(self):
queue_name = self.queue_name
messages = [
{
"body": {
"event": "BackupStarted",
"backupId": "c378813c-3f0b-11e2-ad92-7823d2b0f3ce"
}
},
]
# Test Message Creation
created = self.controller.post(queue_name, messages)
self.assertEqual(len(created), 1)
# Test Message Get
self.controller.get(queue_name, message_id=created[0])
# Test Message Deletion
self.controller.delete(queue_name, created[0])
# Test DoesNotExist
self.assertRaises(storage.exceptions.DoesNotExist,
self.controller.get,
queue_name, created[0])