Introducing driver framework. db and glance implemented as drivers

Change-Id: If47bb1b7eb92e3eafe978ad63d60d801621b8952
This commit is contained in:
Lakshmi N Sampath 2014-04-22 15:14:29 -07:00
parent c897e9d9f0
commit 313eb511e2
23 changed files with 775 additions and 222 deletions

View File

@ -15,6 +15,8 @@
from oslo.config import cfg
from graffiti.common import driver_factory
# Server Specific Configurations
server = {
'port': '21075',
@ -142,3 +144,7 @@ pydevd = {
'port': 22075,
'bindhost': 'localhost'
}
# Discover and load drivers
df = driver_factory.DriverFactory()

View File

@ -21,103 +21,97 @@ from wsme.api import Response
from wsmeext.pecan import wsexpose
from graffiti.api.model.v1.resource import Resource
from graffiti.api.plugins.glance_image import GlanceImage
from graffiti.api.model.v1.resource_dao_factory import \
ResourceDAOFactory
from graffiti.common.utils import _
from oslo.config import cfg
from graffiti.common import driver_factory
import six
import keystoneclient.v2_0.client as ksclient
resource_controller_group = cfg.OptGroup('resource_controller')
resource_controller_opts = [
cfg.StrOpt('type',
help=_("The resource controller plugin"))
]
cfg.CONF.register_group(resource_controller_group)
cfg.CONF.register_opts(resource_controller_opts,
group=resource_controller_group)
class ResourceController(RestController):
# TODO(Lakshmi): Lookup supported types from plugin registry
local_resource_type = 'GFT:Local'
glance_resource_type = 'OS::Glance:Image'
def __init__(self):
super(ResourceController, self).__init__()
self.status = 200
self.default_resource_type = "GFT::Local"
self._controller = self._load_controller('Local')
@wsexpose(None, six.text_type, six.text_type, six.text_type)
def options(self, param1, param2=None, param3=None):
return Response(None, status_code=204)
def _load_controller(self, which_one):
controller_type = cfg.CONF.resource_controller.type
controller_type = controller_type if controller_type else 'Local'
@wsexpose(Resource, six.text_type, six.text_type, six.text_type)
def get_one(self, param1, param2=None, param3=None):
"""Retrieve the resource based on the passed parameters
Depending on the number of parameters passed, the meaning
of the parameter is determined.
_controller = ResourceDAOFactory.create(controller_type)
Use case #1: only param1 is set
eg. /v1/resource/12345
param1 is treated as resource id and resource type is defaulted
to graffiti local resource
return _controller
Use case #2: param1 and param2 are set
eg /v1/resource/OS::Glance::Image/d24a33343
param1 = resource type
param2 = resource id
@wsexpose()
def options(self):
pass
Use case #3: param1, param2 and param3 are set
eg /v1/resource/OS::Glance::Image/d24a33343/e8dd383a838c83
param1 = resource type
param2 = resource id
param3 = endpoint id
@wsexpose(Resource, six.text_type, six.text_type, six.text_type,
six.text_type)
def get_one(self, resource_id, resource_type=None, param1=None,
param2=None):
print "args:", resource_id, resource_type, param1, param2
error_str = None
if not resource_type:
res = self._controller.get_resource(resource_id)
"""
print "args:", param1, param2, param3
auth_token = pecan.request.headers.get('X-Auth-Token')
endpoint_id = None
if not param2:
#Use case #1
resource_id = param1
resource_type = self.default_resource_type
else:
#Use case #2
resource_type = param1
resource_id = param2
if param3:
endpoint_id = param3
driver = driver_factory.get_driver(resource_type)
if driver.resource:
res = driver.resource.get_resource(
resource_id,
auth_token,
endpoint_id
)
return res
elif resource_type.lower() == \
ResourceController.glance_resource_type.lower():
auth_token = pecan.request.headers.get('X-Auth-Token')
endpoint_id = param1
image_id = resource_id
glance_public_url = None
keystone = ksclient.Client(
auth_url=cfg.CONF.keystone.auth_url,
username=cfg.CONF.keystone.username,
password=cfg.CONF.keystone.password,
tenant_name=cfg.CONF.keystone.tenant_name)
for endpoint in keystone.endpoints.list():
if endpoint.id == endpoint_id:
glance_public_url = endpoint.publicurl
# TODO(Lakshmi): Load plugins with plugin framework
if auth_token and glance_public_url:
glance_plugin = GlanceImage(
glance_public_url,
keystone.auth_token
)
res = glance_plugin.get_resource(image_id)
if res:
return res
else:
error_str = "Resource not found"
else:
error_str = "auth_token and/or endpointid not found"
else:
error_str = "Driver not found for the resource type %s", \
resource_type
res = Response(Resource(), status_code=404, error=error_str)
return res
@wsexpose([Resource], six.text_type)
def get_all(self, query_string=None):
res_list = self._controller.find_resources(query_string)
if res_list:
return res_list.itervalues()
@wsexpose([Resource], six.text_type, six.text_type)
def get_all(self, resource_type=None, query_string=None):
auth_token = pecan.request.headers.get('X-Auth-Token')
if not resource_type:
resource_type = self.default_resource_type
driver = driver_factory.get_driver(resource_type)
if driver.resource:
res_list = driver.resource.find_resources(
query_string,
auth_token
)
if res_list:
return res_list.itervalues()
else:
resource = Response(
Resource(),
status_code=404,
error="Driver not found for the resource type")
return resource
return []
@ -126,42 +120,43 @@ class ResourceController(RestController):
"""Modify resource
:resource param: graffiti.api.model.v1.resource.Resource
"""
resource_type = resource.type
if not resource_type:
resource_type = ResourceController.local_resource_type
if resource_type.lower() == \
ResourceController.local_resource_type.lower():
self._controller.set_resource(
resource_id,
resource_definition=resource
)
elif resource_type.lower() == \
ResourceController.glance_resource_type.lower():
auth_token = pecan.request.headers.get('X-Auth-Token')
endpoint_id = resource.provider.id
glance_public_url = None
keystone = ksclient.Client(
auth_url=cfg.CONF.keystone.auth_url,
username=cfg.CONF.keystone.username,
password=cfg.CONF.keystone.password,
tenant_name=cfg.CONF.keystone.tenant_name)
for endpoint in keystone.endpoints.list():
if endpoint.id == endpoint_id:
glance_public_url = endpoint.publicurl
# TODO(Lakshmi): Load plugins with plugin framework
if auth_token and glance_public_url:
glance_plugin = GlanceImage(
glance_public_url,
keystone.auth_token
)
glance_plugin.update_resource(resource)
auth_token = pecan.request.headers.get('X-Auth-Token')
endpoint_id = resource.provider.id
if not resource.type:
resource_type = self.default_resource_type
else:
resource_type = resource.type
driver = driver_factory.get_driver(resource_type)
if driver.resource:
driver.resource.update_resource(
resource_id,
resource,
auth_token,
endpoint_id=endpoint_id
)
else:
resource = Response(
Resource(),
status_code=404,
error="Driver not found for the resource type"
)
return resource
@wsexpose(Resource, body=Resource)
def post(self, resource):
auth_token = pecan.request.headers.get('X-Auth-Token')
id = resource.id if hasattr(resource, 'id') else None
self._controller.set_resource(id, resource_definition=resource)
if not resource.type:
resource_type = self.default_resource_type
else:
resource_type = resource.type
driver = driver_factory.get_driver(resource_type)
if driver.resource:
resource = driver.resource.create_resource(resource, auth_token)
return resource

View File

@ -24,7 +24,7 @@ class CorsHook(PecanHook):
state.response.headers['Access-Control-Allow-Methods'] = \
'GET, PUT, POST, DELETE, OPTIONS'
state.response.headers['Access-Control-Allow-Headers'] = \
'origin, authorization, accept, content-type'
'origin, authorization, accept, content-type, X-Auth-Token'
if not state.response.headers['Content-Length']:
state.response.headers['Content-Length'] = \

View File

@ -55,6 +55,7 @@ class LocalResourceDAO(ResourceDAOBase):
id = self._generate_id()
self._resources[id] = resource_definition
return id
def _generate_id(self):
return_value = self._last_id

View File

@ -23,7 +23,8 @@ class ResourceDAOFactory(object):
@staticmethod
def create(dao_type, **kwargs):
if dao_type.lower() == 'local':
if dao_type.lower() == 'memory':
print "Directory persistence = memory"
return LocalResourceDAO(**kwargs)
return None

View File

@ -1,95 +0,0 @@
# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
#
# 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 glanceclient import Client
from graffiti.api.model.v1.capability import Capability
from graffiti.api.model.v1.property import Property
from graffiti.api.model.v1.resource import Resource
class GlanceImage(object):
def __init__(self, glance_endpoint, auth_token):
self.glance_endpoint = glance_endpoint
self.auth_token = auth_token
self.glance = Client('1', endpoint=glance_endpoint, token=auth_token)
self.separator = "."
def get_resource(self, image_id):
# glance_image_properties = {
# "GLANCE.MySQL.Port": "3605",
# "GLANCE.MySQL.Home": "/opt/mysql",
# "GLANCE.Apache.Port": "8080",
# "GLANCE.Apache.docroot": "/var/apache/static"
# }
image = self.glance.images.get(image_id)
glance_image_properties = image.properties
image_resource = Resource()
image_capability = Capability()
image_capabilities = []
image_resource.capabilities = image_capabilities
image_resource.id = image_id
image_resource.type = 'image'
# image_resource.name = "ubuntu 12.04"
image_resource.name = image.name
for key in glance_image_properties:
# replace if check with pattern matching
if key.count(self.separator) == 2:
(namespace, capability_type, prop_name) = key.split(".")
image_properties = []
image_property = Property()
image_property.name = prop_name
image_property.value = glance_image_properties[key]
image_capability = None
for capability in image_resource.capabilities:
if capability.capability_type_namespace == namespace and \
capability.capability_type == capability_type:
image_capability = capability
if not image_capability:
image_capability = Capability()
image_resource.capabilities.append(image_capability)
image_capability.capability_type_namespace = namespace
image_capability.capability_type = capability_type
image_properties.append(image_property)
image_capability.properties = image_properties
return image_resource
def update_resource(self, resource):
"""Update Glance Image
:type param: graffiti.api.model.v1.resource.Resource
"""
image_properties = {}
for capability in resource.capabilities:
properties = capability.properties
capability_type = capability.capability_type
capability_type_namespace = capability.capability_type_namespace
for property in properties:
prop_name = capability_type_namespace + \
self.separator + \
capability_type + \
self.separator + \
property.name
image_properties[prop_name] = property.value
image = self.glance.images.get(resource.id)
image.update(properties=image_properties, purge_props=False)

View File

@ -24,9 +24,10 @@ import os
import pecan
import pecan.testing
from oslo.config import cfg
#from oslo.config import cfg
from graffiti.api.tests import base
from graffiti.common import driver_factory
class TestCase(base.TestCase):
@ -35,8 +36,9 @@ class TestCase(base.TestCase):
def setUp(self):
super(TestCase, self).setUp()
self.app = self._make_app()
cfg.CONF.set_override(name='type', override='Local',
group='resource_controller')
#cfg.CONF.set_override(name='type', override='Local',
# group='resource_controller')
driver_factory.DriverFactory()
def _make_app(self):
root_dir = self.path_get()

View File

@ -53,7 +53,7 @@
"capability_type_namespace": "TEST:RESOURCE:2014-1",
"criterion": "StandardCriterion2"
}],
"type": "TEST:RESOURCE:2014-1:StandardResource"
"type": "GFT::Local"
}]
}

View File

@ -78,7 +78,7 @@ class TestControllerV1(base.TestCase):
self.assertIn(hasattr(v1, 'resource'), [True])
def test_v1_resource_controller_factory__local(self):
rc = ResourceDAOFactory.create('local')
rc = ResourceDAOFactory.create('memory')
self.assertEquals(rc.get_type(), 'LocalResourceDAO')
def test_v1_resource_controller_factory__unknown(self):

View File

@ -0,0 +1,119 @@
# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
#
# 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 graffiti.common import exception
from oslo.config import cfg
from stevedore import dispatch
driver_opts = [
cfg.ListOpt('enabled_drivers',
default=['local', 'glance'],
help='List of drivers to enable. Missing drivers, or '
'drivers which can not be loaded will be '
'treated as a fatal exception.'),
]
CONF = cfg.CONF
CONF.register_opts(driver_opts)
def get_driver(resource_type):
"""Simple method to get a ref to an instance of a driver by the
supported resource type.
Driver loading is handled by the DriverFactory class. This method
conveniently wraps that class and returns the actual driver object.
:param resource_type: the resource type supported by a driver
:returns: An instance of a class which implements
graffiti.drivers.base.BaseResourceDriver
:raises: DriverNotFound if the requested driver_name could not be
found in the "graffiti.drivers" namespace.
"""
try:
factory = DriverFactory()
print "resource types", factory.resource_types
print "resource type", resource_type
if resource_type in factory.resource_types.keys():
driver_name = factory.resource_types[resource_type]
return factory[driver_name].obj
else:
raise exception.DriverNotFoundForResourceType(
resource_type=resource_type
)
except KeyError:
raise exception.DriverNotFound(driver_name=driver_name)
class DriverFactory(object):
"""Discover, load and manage the drivers available."""
_driver_manager = None
_resource_types = {}
def __init__(self):
if not DriverFactory._driver_manager:
DriverFactory._init_driver_manager()
print "Loaded drivers:", self.names
def __getitem__(self, name):
return self._driver_manager[name]
@classmethod
def _init_driver_manager(self):
if self._driver_manager:
return
def _catch_driver_not_found(mgr, ep, exc):
if (isinstance(exc, exception.DriverLoadError) and
ep.name not in CONF.enabled_drivers):
return
raise exc
def _check_func(ext):
return ext.name in CONF.enabled_drivers
self._driver_manager = dispatch.NameDispatchExtensionManager(
'graffiti.drivers',
_check_func,
invoke_on_load=True,
on_load_failure_callback=_catch_driver_not_found
)
#Get supported resource types
for driver_name in self._driver_manager.names():
driver = self._driver_manager[driver_name].obj
driver_resource_types = driver.get_resource_types()
for type in driver_resource_types:
self._resource_types[type] = driver_name
@property
def names(self):
"""The list of driver names available."""
return self._driver_manager.names()
@property
def resource_types(self):
"""Returns all resource types supported by all the drivers
:returns dictionary with resource type as key and driver name
as its value
"""
return self._resource_types

View File

@ -13,34 +13,55 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from graffiti.openstack.common.gettextutils import _
class GraffitiException(Exception):
"""Base Exception for the project
To correctly use this class, inherit from it and define
the 'message' property.
That message will get printf'd
with the keyword arguments provided to the constructor.
"""
message = "An unknown exception occurred"
message = _("An unknown exception occurred")
def __str__(self):
return self.message
def __init__(self):
super(GraffitiException, self).__init__(self.message)
def __init__(self, **kwargs):
self.kwargs = kwargs
try:
message = self.message % kwargs
except KeyError:
#TODO(Any): print to log
pass
super(GraffitiException, self).__init__(message)
class NotFound(GraffitiException):
message = "Object not found"
def __init__(self, message=None):
if message:
self.message = message
message = _("Object not found")
class DuplicateEntry(GraffitiException):
message = "Database object already exists"
message = _("Database object already exists")
def __init__(self, message=None):
if message:
self.message = message
class DriverNotFound(NotFound):
message = _("Failed to load driver %(driver_name)s.")
class DriverLoadError(GraffitiException):
message = _("Driver %(driver)s could not be loaded. Reason: %(reason)s.")
class MethodNotSupported(GraffitiException):
message = _("Method %(method)s is not supported by this driver")
class DriverNotFoundForResourceType(NotFound):
message = _("Cannot find a registered driver for the resource "
"type %(resource_type)s")

103
graffiti/drivers/base.py Normal file
View File

@ -0,0 +1,103 @@
# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
#
# 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.
"""
Abstract base class for graffiti resource drivers.
"""
import abc
import six
@six.add_metaclass(abc.ABCMeta)
class BaseDriver(object):
"""Base class for all drivers.
Defines resource and definitions interface.
Any loadable driver must implement the interfaces it supports
"""
resource = None
#TBD in future
#definitions = None
@abc.abstractmethod
def __init__(self):
pass
@abc.abstractmethod
def get_resource_types(self):
"""Returns the resource types supported by the implementing driver
:returns [str] List of resource type strings
"""
@six.add_metaclass(abc.ABCMeta)
class ResourceInterface(object):
@abc.abstractmethod
def get_resource(self, resource_id, auth_token, endpoint_id=None,
**kwargs):
"""Retrieve the resource detail
:param resource_id: unique resource identifier
:param auth_token: keystone auth_token of request user
:param endpoint_id: id for locating the cloud resource provider
:param **kwargs: Include additional info required by the driver,
:returns resource detail
"""
@abc.abstractmethod
def find_resources(self, query_string, auth_token, endpoint_id=None,
**kwargs):
"""Find resources matching the query
:param query_string: query expression
:param auth_token: keystone auth_token of request user
:param endpoint_id: id for locating the cloud resource provider
:param **kwargs: Include additional info required by the driver,
:returns list of resources
"""
@abc.abstractmethod
def create_resource(self, resource, auth_token, endpoint_id=None,
**kwargs):
"""Create resource
:param resource: resource detail
:param auth_token: keystone auth_token of request user
:param endpoint_id: id for locating the cloud resource provider
:param **kwargs: Include additional info required by the driver,
"""
@abc.abstractmethod
def update_resource(self, resource_id, resource, auth_token,
endpoint_id=None, **kwargs):
"""Update resource
:param resource_id: unique resource identifier
:param resource: resource detail
:param auth_token: keystone auth_token of request user
:param endpoint_id: id for locating the cloud resource provider
:param **kwargs: Include additional info required by the driver,
"""
@abc.abstractmethod
def delete_resource(self, resource_id, auth_token, endpoint_id=None,
**kwargs):
"""Delete resource
:param resource_id: unique resource identifier
:param auth_token: keystone auth_token of request user
:param endpoint_id: id for locating the cloud resource provider
:param **kwargs: Include additional info required by the driver,
"""

View File

@ -0,0 +1,32 @@
# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
#
# 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 graffiti.drivers import base
from graffiti.drivers.modules import glance
class GlanceResourceDriver(base.BaseDriver):
"""This driver implements glance resource driver interface
"""
def __init__(self):
self.resource = glance.GlanceResourceDriver()
self.resource_types = ["OS::Glance::Image"]
def get_resource_types(self):
"""Returns the resource types supported by the implementing driver
:returns [str] List of resource type strings
"""
return self.resource_types

33
graffiti/drivers/local.py Normal file
View File

@ -0,0 +1,33 @@
# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
#
# 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 graffiti.drivers import base
from graffiti.drivers.modules import local
class LocalResourceDriver(base.BaseDriver):
"""This driver implements resource interface locally by graffiti
"""
def __init__(self):
self.resource = local.LocalResourceDriver()
self.resource_types = ["GFT::Local"]
def get_resource_types(self):
"""Returns the resource types supported by the implementing
driver
:returns [str] List of resource type strings
"""
return self.resource_types

View File

View File

@ -0,0 +1,167 @@
# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
#
# 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 glanceclient import Client
from graffiti.api.model.v1.capability import Capability
from graffiti.api.model.v1.property import Property
from graffiti.api.model.v1.resource import Resource
from graffiti.common import exception
from graffiti.drivers import base
import keystoneclient.v2_0.client as ksclient
from oslo.config import cfg
class GlanceResourceDriver(base.ResourceInterface):
def __init__(self):
super(GlanceResourceDriver, self).__init__()
self.separator = "."
def get_resource(self, resource_id, auth_token, endpoint_id=None,
**kwargs):
"""Retrieve the resource detail
:param resource_id: unique resource identifier
:param auth_token: keystone auth_token of request user
:param endpoint_id: id for locating the cloud resource provider
:param **kwargs: Include additional info required by the driver,
:returns resource detail
"""
# glance_image_properties = {
# "GLANCE.MySQL.Port": "3605",
# "GLANCE.MySQL.Home": "/opt/mysql",
# "GLANCE.Apache.Port": "8080",
# "GLANCE.Apache.docroot": "/var/apache/static"
# }
glance_client = self.__get_glance_client(endpoint_id, auth_token)
image = glance_client.images.get(resource_id)
glance_image_properties = image.properties
image_resource = Resource()
image_capabilities = []
image_resource.capabilities = image_capabilities
image_resource.id = resource_id
image_resource.type = 'image'
image_resource.name = image.name
for key in glance_image_properties:
# replace if check with pattern matching
if key.count(self.separator) == 2:
(namespace, capability_type, prop_name) = key.split(".")
image_properties = []
image_property = Property()
image_property.name = prop_name
image_property.value = glance_image_properties[key]
image_capability = None
for capability in image_resource.capabilities:
if capability.capability_type_namespace == namespace and \
capability.capability_type == capability_type:
image_capability = capability
if not image_capability:
image_capability = Capability()
image_resource.capabilities.append(image_capability)
image_capability.capability_type_namespace = namespace
image_capability.capability_type = capability_type
image_properties.append(image_property)
image_capability.properties = image_properties
return image_resource
def update_resource(self, resource_id, resource, auth_token,
endpoint_id=None, **kwargs):
"""Update resource
:param resource_id: unique resource identifier
:param resource: resource detail
:type param: graffiti.api.model.v1.resource.Resource
:param auth_token: keystone auth_token of request user
:param endpoint_id: id for locating the cloud resource provider
:param **kwargs: Include additional info required by the driver,
"""
glance_client = self.__get_glance_client(endpoint_id, auth_token)
image_properties = {}
for capability in resource.capabilities:
properties = capability.properties
capability_type = capability.capability_type
capability_type_namespace = capability.capability_type_namespace
for property in properties:
prop_name = capability_type_namespace + \
self.separator + \
capability_type + \
self.separator + \
property.name
image_properties[prop_name] = property.value
image = glance_client.images.get(resource.id)
image.update(properties=image_properties, purge_props=False)
def find_resources(self, query_string, auth_token, endpoint_id=None,
**kwargs):
"""Find resources matching the query
:param query_string: query expression
:param auth_token: keystone auth_token of request user
:param endpoint_id: id for locating the cloud resource provider
:param **kwargs: Include additional info required by the driver,
:returns list of resources
"""
#TODO(Lakshmi): Implement this method
pass
def create_resource(self, resource, auth_token, endpoint_id=None,
**kwargs):
"""Create resource
:param resource: resource detail
:param auth_token: keystone auth_token of request user
:param endpoint_id: id for locating the cloud resource provider
:param **kwargs: Include additional info required by the driver,
"""
raise exception.MethodNotSupported(method="create_resource")
def delete_resource(self, resource_id, auth_token, endpoint_id=None,
**kwargs):
"""Delete resource
:param resource_id: unique resource identifier
:param auth_token: keystone auth_token of request user
:param endpoint_id: id for locating the cloud resource provider
:param **kwargs: Include additional info required by the driver,
"""
raise exception.MethodNotSupported(method="delete_resource")
def __get_glance_client(self, endpoint_id, auth_token):
keystone = ksclient.Client(
auth_url=cfg.CONF.keystone.auth_url,
username=cfg.CONF.keystone.username,
password=cfg.CONF.keystone.password,
tenant_name=cfg.CONF.keystone.tenant_name
)
self.__endpoint_list = keystone.endpoints.list()
for endpoint in self.__endpoint_list:
if endpoint.id == endpoint_id:
glance_public_url = endpoint.publicurl
glance_client = Client(
'1',
endpoint=glance_public_url,
token=auth_token
)
return glance_client

View File

@ -0,0 +1,97 @@
# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
#
# 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 graffiti.api.model.v1.resource_dao_factory import \
ResourceDAOFactory
from graffiti.drivers import base
from oslo.config import cfg
class LocalResourceDriver(base.ResourceInterface):
def __init__(self):
super(LocalResourceDriver, self).__init__()
persistence_type = cfg.CONF.DEFAULT.persistence_type
self._resource_dao = ResourceDAOFactory.create(persistence_type)
def get_resource(self, resource_id, auth_token, endpoint_id=None,
**kwargs):
"""Retrieve the resource detail
:param resource_id: unique resource identifier
:param auth_token: keystone auth_token of request user
:param endpoint_id: id for locating the cloud resource provider
:param **kwargs: Include additional info required by the driver,
:returns resource detail
"""
res = self._resource_dao.get_resource(resource_id)
return res
def find_resources(self, query_string, auth_token, endpoint_id=None,
**kwargs):
"""Find resources matching the query
:param query_string: query expression
:param auth_token: keystone auth_token of request user
:param endpoint_id: id for locating the cloud resource provider
:param **kwargs: Include additional info required by the driver,
:returns list of resources
"""
res_list = self._resource_dao.find_resources(query_string)
if res_list:
return res_list
return []
def create_resource(self, resource, auth_token, endpoint_id=None,
**kwargs):
"""Create resource
:param resource: resource detail
:param auth_token: keystone auth_token of request user
:param endpoint_id: id for locating the cloud resource provider
:param **kwargs: Include additional info required by the driver,
"""
id = resource.id if hasattr(resource, 'id') else None
self._resource_dao.set_resource(id, resource_definition=resource)
return resource
def update_resource(self, resource_id, resource, auth_token,
endpoint_id=None, **kwargs):
"""Update resource
:param resource_id: unique resource identifier
:param resource: resource detail
:param auth_token: keystone auth_token of request user
:param endpoint_id: id for locating the cloud resource provider
:param **kwargs: Include additional info required by the driver,
"""
self._resource_dao.set_resource(
resource_id,
resource_definition=resource
)
return resource
def delete_resource(self, resource_id, auth_token, endpoint_id=None,
**kwargs):
"""Delete resource
:param resource_id: unique resource identifier
:param auth_token: keystone auth_token of request user
:param endpoint_id: id for locating the cloud resource provider
:param **kwargs: Include additional info required by the driver,
"""
#TODO(Lakshmi): Implement delete
pass

View File

View File

@ -0,0 +1,32 @@
# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
#
# 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 graffiti.api.tests import pecan_base
from graffiti.common import driver_factory
from graffiti.drivers import base as driver_base
class TestLocalResourceDriver(pecan_base.TestCase):
def setUp(self):
super(TestLocalResourceDriver, self).setUp()
self.driver = driver_factory.get_driver("GFT::Local")
def test_driver_interfaces(self):
self.assertIsInstance(
self.driver.resource,
driver_base.ResourceInterface
)

View File

@ -0,0 +1,32 @@
# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
#
# 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 graffiti.api.tests import pecan_base
from graffiti.common import driver_factory
from graffiti.drivers import base as driver_base
class TestGlanceResourceDriver(pecan_base.TestCase):
def setUp(self):
super(TestGlanceResourceDriver, self).setUp()
self.driver = driver_factory.get_driver("OS::Glance::Image")
def test_driver_interfaces(self):
self.assertIsInstance(
self.driver.resource,
driver_base.ResourceInterface
)

View File

@ -9,3 +9,4 @@ iso8601>=0.1.8
requests>=1.1
six>=1.5.2
SQLAlchemy>=0.8,<=0.8.99
stevedore>=0.14

View File

@ -23,6 +23,12 @@ classifier =
packages =
graffiti
[entry_points]
graffiti.drivers =
local = graffiti.drivers.local:LocalResourceDriver
glance = graffiti.drivers.glance:GlanceResourceDriver
[build_sphinx]
source-dir = doc/source
build-dir = doc/build