added manager driver, and base drivers

This commit is contained in:
amitgandhinz 2014-07-18 16:52:12 -04:00
parent 6a39fa41fc
commit 0f5ad48553
30 changed files with 501 additions and 45 deletions

View File

@ -28,7 +28,7 @@ _DRIVER_OPTIONS = [
cfg.StrOpt('manager', default='default',
help='Manager driver to use'),
cfg.StrOpt('storage', default='mockdb',
help='Storage driver to use')
help='Storage driver to use'),
]
_DRIVER_GROUP = 'drivers'

0
cdn/manager/__init__.py Normal file
View File

View File

@ -0,0 +1,22 @@
# Copyright (c) 2014 Rackspace, 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 cdn.manager.base import driver
from cdn.manager.base import services
Driver = driver.ManagerDriverBase
ServicesController = services.ServicesControllerBase

View File

@ -0,0 +1,30 @@
# Copyright (c) 2014 Rackspace, 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.
import abc
import six
@six.add_metaclass(abc.ABCMeta)
class ManagerControllerBase(object):
"""Top-level class for controllers.
:param driver: Instance of the driver
instantiating this controller.
"""
def __init__(self, driver):
self._driver = driver

View File

@ -0,0 +1,40 @@
# Copyright (c) 2014 Rackspace, 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.
import abc
import six
@six.add_metaclass(abc.ABCMeta)
class ManagerDriverBase(object):
"""Add some docstrings"""
def __init__(self, conf, storage, providers):
self._conf = conf
self._storage = storage
self._providers = providers
@property
def storage(self):
return self._storage
@property
def providers(self):
return self._providers
@abc.abstractproperty
def services_controller(self):
"""Returns the driver's services controller."""
raise NotImplementedError

View File

@ -0,0 +1,46 @@
# Copyright (c) 2014 Rackspace, 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.
import abc
import six
from cdn.manager.base import controller
@six.add_metaclass(abc.ABCMeta)
class ServicesControllerBase(controller.ManagerControllerBase):
def __init__(self, driver):
super(ServicesControllerBase, self).__init__(driver)
@abc.abstractmethod
def list(self, project_id):
raise NotImplementedError
@abc.abstractmethod
def get(self, project_id, service_name):
raise NotImplementedError
@abc.abstractmethod
def create(self, project_id, service_name, service_json):
raise NotImplementedError
@abc.abstractmethod
def update(self, project_id, service_name, service_json):
raise NotImplementedError
@abc.abstractmethod
def delete(self, project_id, service_name):
raise NotImplementedError

View File

@ -0,0 +1,22 @@
# Copyright (c) 2014 Rackspace, 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.
"""Default Manager Driver"""
from cdn.manager.default import driver
# Hoist classes into package namespace
Driver = driver.DefaultManagerDriver

View File

@ -0,0 +1,19 @@
# Copyright (c) 2014 Rackspace, 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 cdn.manager.default import services
Services = services.DefaultServicesController

View File

@ -0,0 +1,30 @@
# Copyright (c) 2014 Rackspace, 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.
"""Default manager driver implementation."""
from cdn.common import decorators
from cdn.manager import base
from cdn.manager.default import controllers
class DefaultManagerDriver(base.Driver):
def __init__(self, conf, storage, providers):
super(DefaultManagerDriver, self).__init__(conf, storage, providers)
@decorators.lazy_property(write=False)
def services_controller(self):
return controllers.Services(self)

View File

@ -0,0 +1,86 @@
# Copyright (c) 2014 Rackspace, 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 cdn.manager import base
class ProviderController():
def create(self, ext, service_name, service_json):
return ext.obj.service_controller.create(service_name, service_json)
def update(self, ext, service_name, service_json):
return ext.obj.service_controller.update(service_name, service_json)
def delete(self, ext, service_name):
return ext.obj.service_controller.delete(service_name)
class DefaultServicesController(base.ServicesController):
def list(self, project_id):
services_controller = self._driver.storage.services_controller
return services_controller.list(project_id)
def get(self, project_id, service_name):
services_controller = self._driver.storage.services_controller
return services_controller.get(project_id, service_name)
def create(self, project_id, service_name, service_json):
services_controller = self._driver.storage.services_controller
services_controller.create(
project_id,
service_name,
service_json)
if (self._driver.providers is not None):
return self._driver.providers.map(
ProviderController.create,
service_name,
service_json)
else:
return None
def update(self, project_id, service_name, service_json):
services_controller = self._driver.storage.services_controller
services_controller.update(
project_id,
service_name,
service_json
)
if (self._driver.providers is not None):
return self._driver.providers.map(
ProviderController.update,
service_name,
service_json)
else:
return None
def delete(self, project_id, service_name):
services_controller = self._driver.storage.services_controller
services_controller.delete(project_id, service_name)
if (self._driver.providers is not None):
return self._driver.providers.map(
ProviderController.delete,
service_name)
else:
return None

View File

@ -1,7 +0,0 @@
"""CDN Storage Drivers"""
from cdn.storage import base
# Hoist classes into package namespace
StorageDriverBase = base.StorageDriverBase
ServicesBase = base.ServicesBase

View File

@ -0,0 +1,22 @@
# Copyright (c) 2014 Rackspace, 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 cdn.storage.base import driver
from cdn.storage.base import services
Driver = driver.StorageDriverBase
ServicesController = services.ServicesControllerBase

View File

@ -0,0 +1,31 @@
# Copyright (c) 2014 Rackspace, 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.
import abc
import six
@six.add_metaclass(abc.ABCMeta)
class StorageControllerBase(object):
"""Top-level class for controllers.
:param driver: Instance of the driver
instantiating this controller.
"""
def __init__(self, driver):
self._driver = driver

View File

@ -0,0 +1,57 @@
# Copyright (c) 2014 Rackspace, 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.
import abc
import six
from oslo.config import cfg
_LIMITS_OPTIONS = [
cfg.IntOpt('default_services_paging', default=10,
help='Default services pagination size')
]
_LIMITS_GROUP = 'limits:storage'
@six.add_metaclass(abc.ABCMeta)
class StorageDriverBase(object):
"""Interface definition for storage drivers.
Data plane storage drivers are responsible for implementing the
core functionality of the system.
Connection information and driver-specific options are
loaded from the config file.
:param conf: Configuration containing options for this driver.
:type conf: `oslo.config.ConfigOpts`
"""
def __init__(self, conf):
self._conf = conf
self._conf.register_opts(_LIMITS_OPTIONS, group=_LIMITS_GROUP)
self.limits_conf = self._conf[_LIMITS_GROUP]
@abc.abstractmethod
def is_alive(self):
"""Check whether the storage is ready."""
raise NotImplementedError
@abc.abstractproperty
def service_controller(self):
"""Returns the driver's hostname controller."""
raise NotImplementedError

View File

@ -0,0 +1,47 @@
# Copyright (c) 2014 Rackspace, 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.
import abc
import six
from cdn.storage.base import controller
@six.add_metaclass(abc.ABCMeta)
class ServicesControllerBase(controller.StorageControllerBase):
def __init__(self, driver):
super(ServicesControllerBase, self).__init__(driver)
@abc.abstractmethod
def list(self, project_id):
raise NotImplementedError
@abc.abstractmethod
def create(self, project_id, service_name, service_json):
raise NotImplementedError
@abc.abstractmethod
def update(self, project_id, service_name, service_json):
raise NotImplementedError
@abc.abstractmethod
def delete(self, project_id, service_name):
raise NotImplementedError
@abc.abstractmethod
def get(self):
raise NotImplementedError

View File

@ -3,4 +3,4 @@
from cdn.storage.cassandra import driver
# Hoist classes into package namespace
Driver = driver.StorageDriver
Driver = driver.CassandraStorageDriver

View File

@ -47,9 +47,9 @@ class CassandraStorageDriver(base.Driver):
def __init__(self, conf):
super(CassandraStorageDriver, self).__init__(conf)
self.conf.register_opts(CASSANDRA_OPTIONS,
group=CASSANDRA_GROUP)
self.cassandra_conf = self.conf[CASSANDRA_GROUP]
self._conf.register_opts(CASSANDRA_OPTIONS,
group=CASSANDRA_GROUP)
self.cassandra_conf = self._conf[CASSANDRA_GROUP]
def is_alive(self):
return True

View File

@ -88,7 +88,7 @@ class ServicesController(base.ServicesController):
@property
def session(self):
return self.driver.service_database
return self._driver.service_database
def list(self, project_id):

View File

@ -3,4 +3,4 @@
from cdn.storage.mockdb import driver
# Hoist classes into package namespace
Driver = driver.StorageDriver
Driver = driver.MockDBStorageDriver

View File

@ -36,14 +36,14 @@ def _connection():
return None
class StorageDriver(base.Driver):
class MockDBStorageDriver(base.Driver):
def __init__(self, conf):
super(StorageDriver, self).__init__(conf)
super(MockDBStorageDriver, self).__init__(conf)
self.conf.register_opts(MOCKDB_OPTIONS,
group=MOCKDB_GROUP)
self.mockdb_conf = self.conf[MOCKDB_GROUP]
self._conf.register_opts(MOCKDB_OPTIONS,
group=MOCKDB_GROUP)
self.mockdb_conf = self._conf[MOCKDB_GROUP]
def is_alive(self):
return True

View File

@ -3,4 +3,4 @@
from cdn.storage.mongodb import driver
# Hoist classes into package namespace
Driver = driver.StorageDriver
Driver = driver.MongoDBStorageDriver

View File

@ -63,14 +63,14 @@ def _connection(conf):
return MongoClient(conf.uri)
class StorageDriver(base.Driver):
class MongoDBStorageDriver(base.Driver):
def __init__(self, conf):
super(StorageDriver, self).__init__(conf)
super(MongoDBStorageDriver, self).__init__(conf)
self.conf.register_opts(MONGODB_OPTIONS,
group=MONGODB_GROUP)
self.mongodb_conf = self.conf[MONGODB_GROUP]
self._conf.register_opts(MONGODB_OPTIONS,
group=MONGODB_GROUP)
self.mongodb_conf = self._conf[MONGODB_GROUP]
def is_alive(self):
try:

View File

@ -3,5 +3,6 @@
from cdn.transport import base
# Hoist into package namespace
DriverBase = base.DriverBase
Driver = base.TransportDriverBase

View File

@ -18,7 +18,7 @@ import six
@six.add_metaclass(abc.ABCMeta)
class DriverBase(object):
class TransportDriverBase(object):
"""Base class for Transport Drivers to document the expected interface.
:param conf: configuration instance
@ -29,6 +29,16 @@ class DriverBase(object):
self._conf = conf
self._manager = manager
self._app = None
@property
def app(self):
return self._app
@property
def manager(self):
return self._manager
@abc.abstractmethod
def listen():
"""Start listening for client requests (self-hosting mode)."""

View File

@ -42,7 +42,7 @@ LOG = logging.getLogger(__name__)
@six.add_metaclass(abc.ABCMeta)
class TransportDriver(transport.DriverBase):
class TransportDriver(transport.Driver):
def __init__(self, conf, manager):
super(TransportDriver, self).__init__(conf, manager)
@ -50,29 +50,28 @@ class TransportDriver(transport.DriverBase):
self._conf.register_opts(_WSGI_OPTIONS, group=_WSGI_GROUP)
self._wsgi_conf = self._conf[_WSGI_GROUP]
self.app = None
self._init_routes()
self._setup_app()
def _init_routes(self):
def _setup_app(self):
"""Initialize hooks and URI routes to resources."""
self.app = falcon.API()
self._app = falcon.API()
version_path = "/v1.0"
project_id = "/{project_id}"
prefix = version_path + project_id
# init the controllers
service_controller = self._manager.service_controller
service_controller = self.manager.services_controller
# setup the routes
self.app.add_route(prefix,
v1.V1Resource())
self._app.add_route(prefix,
v1.V1Resource())
self.app.add_route(prefix + '/services',
services.ServicesResource(service_controller))
self._app.add_route(prefix + '/services',
services.ServicesResource(service_controller))
self.app.add_route(prefix + '/services/{service_name}',
services.ServiceResource(service_controller))
self._app.add_route(prefix + '/services/{service_name}',
services.ServiceResource(service_controller))
def listen(self):
"""Self-host using 'bind' and 'port' from the WSGI config group."""

View File

@ -29,6 +29,9 @@ log_file = cdn.log
# Transport driver module (e.g., falcon, pecan)
transport = falcon
# Manager driver module (e.g. default)
manager = default
# Storage driver module (e.g., mongodb, sqlite, cassandra)
storage = mockdb

View File

@ -1,4 +1,5 @@
-r common.txt
-r storage/cassandra.txt
-r transport/falcon.txt
-r transport/pecan.txt
-r provider/fastly.txt

View File

@ -0,0 +1 @@
pecan==0.6.1

View File

@ -33,7 +33,7 @@ class CassandraStorageServiceTests(TestCase):
@patch.object(driver, 'CASSANDRA_OPTIONS', new=CASSANDRA_OPTIONS)
def setUp(self):
conf = cfg.ConfigOpts()
self.cassandra_driver = driver.StorageDriver(conf, None)
self.cassandra_driver = driver.CassandraStorageDriver(conf)
def test_storage_driver(self):
# assert that the configs are set up based on what was passed in
@ -61,7 +61,3 @@ class CassandraStorageServiceTests(TestCase):
def test_service_database(self, mock_cluster):
self.cassandra_driver.service_database
mock_cluster.assert_called_with('mock_cdn')
def test_providers(self):
providers = self.cassandra_driver.providers
self.assertEquals(providers, None)

View File

@ -34,7 +34,7 @@ class CassandraStorageServiceTests(TestCase):
# create mocked config and driver
conf = cfg.ConfigOpts()
cassandra_driver = driver.StorageDriver(conf, None)
cassandra_driver = driver.CassandraStorageDriver(conf)
# stubbed cassandra driver
self.sc = services.ServicesController(cassandra_driver)