dictionary controllers for namespace and capability_type

Change-Id: I931425d6fe6f95d0d616d5e3f6efe852b2863b53
This commit is contained in:
Lakshmi N Sampath 2014-04-16 18:19:49 -07:00
parent cd9adfe81d
commit 99287f3f00
30 changed files with 1137 additions and 71 deletions

View File

@ -13,6 +13,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from oslo.config import cfg
# Server Specific Configurations
server = {
'port': '21075',
@ -59,9 +61,84 @@ wsme = {
'debug': True
}
# Custom Configurations must be in Python dictionary format::
#
# foo = {'bar':'baz'}
#
# All configurations are accessible at::
# pecan.conf
# oslo config
keystone_group = cfg.OptGroup('keystone')
keystone_opts = [
cfg.StrOpt('auth_url',
default='http://192.168.40.10:5000/v2.0',
help='keystone authorization url'),
cfg.StrOpt('username',
default='admin',
help='keystone username'),
cfg.StrOpt('password',
default='secretword',
help='keystone password'),
cfg.StrOpt('tenant_name',
default='admin',
help='keystone tenant name')
]
cfg.CONF.register_group(keystone_group)
cfg.CONF.register_opts(keystone_opts, group=keystone_group)
# DEFAULT group
default_controller_group = cfg.OptGroup('DEFAULT')
default_controller_opts = [
cfg.StrOpt(
'persistence_type',
default="memory",
help=("persistence options. "
"values = 'memory' or 'file' or 'db"))
]
cfg.CONF.register_group(default_controller_group)
cfg.CONF.register_opts(default_controller_opts,
group=default_controller_group)
# FILE_PERSISTENCE group
file_controller_group = cfg.OptGroup('FILE_PERSISTENCE')
file_controller_opts = [
cfg.StrOpt(
'dictionary_folder',
default="/tmp/graffiti-dictionary/",
help=("Absolute path of the file for persisting dictionary")
)
]
cfg.CONF.register_group(file_controller_group)
cfg.CONF.register_opts(file_controller_opts,
group=file_controller_group)
# Used for remote debugging, like pychcharms or pydev
# To enable remote debugging in pycharms, requires that you put the
# pycharm-debug.egg in the python path. E.g.
#
# Include the pycharm-debug.egg archive.
# e.g. /home/<USERNAME>/pycharm-3.1.1/pycharm-debug.egg
# You can do it in a number of ways, for example:
# Add the archive to PYTHONPATH.e,g,
# export PYTHONPATH+=.:/home/<USERNAME>/pycharm-3.1.1/pycharm-debug.egg
# Append the archive to sys.path. e.g.
# import sys
# sys.path.append('/home/<USERNANE>/pycharm-3.1.1/pycharm-debug.egg')
# Just copy the pydev from the archive to the directory where your remote
# script resides.
#
# You will need to setup a debug configuration in your pycharms and start the
# debugger BEFORE starting pecan
# This is because the following code connects from here to your pycharms
# (or your pydev)
pydevd = {
'enabled': True,
'port': 22075,
'bindhost': 'localhost'
}

7
etc/graffiti.conf.sample Normal file
View File

@ -0,0 +1,7 @@
[DEFAULT]
#Allowed values= memory, file, db. Default value is memory
persistence_type=memory
[FILE_PERSISTENCE]
dictionary_folder=/tmp/graffiti-dictionary/

View File

@ -26,6 +26,22 @@ CONF = cfg.CONF
def setup_app(config):
if hasattr(config, 'pydevd') and config.pydevd.enabled:
try:
print(
'Remote debug set to true(config.pydevd). '
'Attempting connection'
)
import pydevd
pydevd.settrace(
config.pydevd.bindhost,
port=config.pydevd.port,
stdoutToServer=True,
stderrToServer=True,
suspend=False)
except Exception as e:
print "Debug Connection Error:", e
model.init_model()
app_conf = dict(config.app)

View File

@ -15,42 +15,122 @@
from pecan.rest import RestController
from wsme.api import Response
from wsmeext.pecan import wsexpose
from graffiti.api.controllers.v1.captype_controller_factory \
import CapTypeControllerFactory
from graffiti.api.model.v1.capability_type import CapabilityType
from ns_controller_factory import NSControllerFactory
from oslo.config import cfg
import six
capability_types = []
class CapabilityTypeController(RestController):
def __init__(self):
super(RestController, self).__init__()
self.status = 200
self._cap_controller = None
self._ns_controller = None
self._load_controller()
def _load_controller(self):
controller_type = cfg.CONF.DEFAULT.persistence_type
self._cap_controller = CapTypeControllerFactory.create(controller_type)
self._ns_controller = NSControllerFactory.get()
@wsexpose
def options():
pass
@wsexpose(CapabilityType, six.text_type)
def get_one(self, name):
global capability_types
@wsexpose(CapabilityType, six.text_type, six.text_type)
def get_one(self, name, namespace):
captype = self._cap_controller.get_capability_type(name, namespace)
return captype
for capability_type in capability_types:
if capability_type.name.lower() == name.lower():
return capability_type
res = CapabilityType(CapabilityType(), status_code=404,
error="CapabilityType Not Found")
return res
@wsexpose([CapabilityType])
def get_all(self):
global capability_types
return capability_types
@wsexpose([CapabilityType], six.text_type)
def get_all(self, query_string=None):
captype_list = self._cap_controller.find_capability_types(query_string)
return captype_list
@wsexpose(CapabilityType, body=CapabilityType)
def post(self, capability_type):
global capability_types
capability_types.append(capability_type)
"""Create Capability Type
@type capability_type:
graffiti.api.model.v1.capability_type.CapabilityType
@param capability_type: Capability type
"""
# Check if namespace exists
namespace_found = self.__check_existing_namespace(
capability_type.namespace
)
# Check if derived capability type exists
derived_checked = self.__check_derived_capability(
capability_type.derived_from
)
if namespace_found and derived_checked:
self._cap_controller.set_capability_type(
capability_type
)
return capability_type
else:
res = Response(
CapabilityType(),
status_code=404,
error="Provided namespace %s doesnt exist" %
capability_type.namespace)
return res
@wsexpose(CapabilityType, six.text_type, six.text_type,
body=CapabilityType)
def put(self, name, namespace, capability_type):
# Check if namespace exists
namespace_found = self.__check_existing_namespace(
capability_type.namespace
)
# Check if derived capability type exists
derived_checked = self.__check_derived_capability(
capability_type.derived_from
)
if namespace_found and derived_checked:
self._cap_controller.put_capability_type(
name, namespace, capability_type
)
return capability_type
else:
res = Response(
CapabilityType(),
status_code=404,
error="Provided namespace %s doesnt exist" %
capability_type.namespace)
return res
@wsexpose(CapabilityType, six.text_type, six.text_type)
def delete(self, name, namespace):
captype = self._cap_controller.delete_capability_type(
name,
namespace
)
return captype
def __check_derived_capability(self, derived_from):
derived_checked = True
if derived_from:
derived_checked = False
derived_cap_found = self._cap_controller.get_capability_type(
derived_from.name, derived_from.namespace)
if derived_cap_found:
derived_checked = True
return derived_checked
def __check_existing_namespace(self, namespace_name):
return self._ns_controller.get_namespace(namespace_name)

View File

@ -0,0 +1,39 @@
# 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.
class CapabilityTypeControllerBase(object):
def __init__(self, **kwargs):
super(CapabilityTypeControllerBase, self).__init__(**kwargs)
self._type = 'None'
def get_capability_type(self, name, namespace):
return None
def get_type(self):
return self._type
def find_capability_types(self, query_string):
return []
def set_capability_type(self, capability_type=None):
pass
def put_capability_type(self, name, namespace, capability_type=None):
pass
def delete_capability_type(self, name, namespace):
pass

View File

@ -0,0 +1,42 @@
# 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.controllers.v1.captype_db_controller \
import DBCapabilityTypeController
from graffiti.api.controllers.v1.captype_file_controller \
import FileCapabilityTypeController
from graffiti.api.controllers.v1.captype_mem_controller \
import MemCapabilityTypeController
class CapTypeControllerFactory(object):
def __init__(self, **kwargs):
super(CapTypeControllerFactory, self).__init__(**kwargs)
@staticmethod
def create(controller_type, **kwargs):
if controller_type.lower() == 'memory':
print "Dictionary persistence = memory"
return MemCapabilityTypeController(**kwargs)
elif controller_type.lower() == "db":
print "Dictionary persistence = db"
return DBCapabilityTypeController(**kwargs)
elif controller_type.lower() == "file":
print "Dictionary persistence = File"
return FileCapabilityTypeController(**kwargs)
return None

View File

@ -0,0 +1,39 @@
# 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 captype_controller import CapabilityTypeControllerBase
# TODO(Wayne): Implement the db controller
class DBCapabilityTypeController(CapabilityTypeControllerBase):
def __init__(self, **kwargs):
super(DBCapabilityTypeController, self).__init__(**kwargs)
self._type = 'DBCapabilityTypeController'
def get_capability_type(self, name, namespace):
pass
def find_capability_types(self, query_string):
pass
def set_capability_type(self, capability_type=None):
pass
def put_capability_type(self, name, namespace, capability_type=None):
pass
def delete_capability_type(self, name, namespace):
pass

View File

@ -0,0 +1,84 @@
# 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 captype_controller import CapabilityTypeControllerBase
from graffiti.api.model.v1.capability_type import CapabilityType
import json
from oslo.config import cfg
from wsme.rest.json import fromjson
from wsme.rest.json import tojson
class FileCapabilityTypeController(CapabilityTypeControllerBase):
def __init__(self, **kwargs):
super(FileCapabilityTypeController, self).__init__(**kwargs)
self._type = 'FileCapabilityTypeController'
self._graffiti_folder = cfg.CONF.FILE_PERSISTENCE.dictionary_folder
self._filename = "dictionary.json"
self._dictionaryfile = self._graffiti_folder + self._filename
self._capability_types = self.__file_to_memory()
def get_capability_type(self, name, namespace):
id = namespace + ":" + name
return self._capability_types[id]
def find_capability_types(self, query_string):
return self._capability_types.itervalues()
def set_capability_type(self, capability_type):
id = capability_type.namespace + ":" + capability_type.name
self._capability_types[id] = capability_type
self.__memory_to_file()
return capability_type
def put_capability_type(self, name, namespace, capability_type):
id = namespace + ":" + name
self._capability_types[id] = capability_type
self.__memory_to_file()
return capability_type
def delete_capability_type(self, name, namespace):
id = namespace + ":" + name
capability_type = None
if self._capability_types[id]:
capability_type = self._capability_types[id]
self._capability_types.pop(id)
self.__memory_to_file()
return capability_type
def __file_to_memory(self):
try:
capability_types = {}
with open(self._dictionaryfile, "r") as gfile:
doc = json.load(gfile)
for id in doc:
capability_types[id] = fromjson(CapabilityType, doc[id])
return capability_types
except IOError:
with open(self._dictionaryfile, "w+") as gfile:
gfile.write("")
return {}
def __memory_to_file(self):
file_capability_types = {}
for (id, capability_type) in self._capability_types.items():
json_data = tojson(CapabilityType, capability_type)
file_capability_types[id] = json_data
with open(self._dictionaryfile, "w+") as gfile:
json.dump(file_capability_types, gfile)

View File

@ -0,0 +1,52 @@
# 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 captype_controller import CapabilityTypeControllerBase
class MemCapabilityTypeController(CapabilityTypeControllerBase):
def __init__(self, **kwargs):
super(MemCapabilityTypeController, self).__init__(**kwargs)
self._type = 'MemCapabilityTypeController'
self._capability_types = {}
def get_capability_type(self, name, namespace):
id = namespace + ":" + name
return self._capability_types[id]
def find_capability_types(self, query_string):
return self._capability_types.itervalues()
def set_capability_type(self, capability_type):
id = capability_type.namespace + ":" + capability_type.name
self._capability_types[id] = capability_type
return capability_type
def put_capability_type(self, name, namespace, capability_type):
id = namespace + ":" + name
self._capability_types[id] = capability_type
return capability_type
def delete_capability_type(self, name, namespace):
id = namespace + ":" + name
capability_type = None
if self._capability_types[id]:
capability_type = self._capability_types[id]
self._capability_types.pop(id)
return capability_type

View File

@ -17,40 +17,55 @@ from pecan.rest import RestController
from wsmeext.pecan import wsexpose
from graffiti.api.controllers.v1.ns_controller_factory\
import NSControllerFactory
from graffiti.api.model.v1.namespace import Namespace
from oslo.config import cfg
import six
namespaces = []
class NamespaceController(RestController):
def __init__(self):
super(RestController, self).__init__()
self.status = 200
self._controller = self._load_controller()
def _load_controller(self):
controller_type = cfg.CONF.DEFAULT.persistence_type
_controller = NSControllerFactory.create(controller_type)
return _controller
@wsexpose
def options():
def options(self):
pass
@wsexpose(Namespace, six.text_type)
def get_one(self, name):
global namespaces
for namespace in namespaces:
if namespace.name.lower() == name.lower():
return namespace
res = Namespace(Namespace(), status_code=404,
error="Namespace Not Found")
return res
def get_one(self, namespace_name):
namespace = self._controller.get_namespace(namespace_name)
return namespace
@wsexpose([Namespace])
def get_all(self):
global namespaces
return namespaces
def get_all(self, query_string=None):
namespace_list = self._controller.find_namespaces(query_string)
return namespace_list
@wsexpose(Namespace, body=Namespace)
def post(self, namespace):
global namespaces
namespaces.append(namespace)
"""Create Namespace
:namespace param:
graffiti.api.model.v1.namespace.Namespace
"""
self._controller.set_namespace(namespace)
return namespace
@wsexpose(Namespace, six.text_type, body=Namespace)
def put(self, namespace_name, namespace):
self._controller.put_namespace(namespace_name, namespace)
return namespace
@wsexpose(Namespace, six.text_type)
def delete(self, namespace_name):
print "namespace", namespace_name
namespace = self._controller.delete_namespace(namespace_name)
return namespace

View File

@ -0,0 +1,39 @@
# 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.
class NSTypeControllerBase(object):
def __init__(self, **kwargs):
super(NSTypeControllerBase, self).__init__(**kwargs)
self._type = 'None'
def get_namespace(self, namespace_name):
return None
def get_type(self):
return self._type
def find_namespaces(self, query_string):
return []
def set_namespace(self, namespace):
pass
def put_namespace(self, namespace_name, namespace):
pass
def delete_namespace(self, namespace_name):
pass

View File

@ -0,0 +1,57 @@
# 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.controllers.v1.ns_db_controller \
import DBNSController
from graffiti.api.controllers.v1.ns_file_controller \
import FileNSController
from graffiti.api.controllers.v1.ns_mem_controller \
import MemNSController
from oslo.config import cfg
class NSControllerFactory(object):
__controller = None
__controller_type = cfg.CONF.DEFAULT.persistence_type
def __init__(self, **kwargs):
super(NSControllerFactory, self).__init__(**kwargs)
@staticmethod
def create(controller_type, **kwargs):
if controller_type.lower() == 'memory':
print "Namespace persistence = memory"
NSControllerFactory.__controller = MemNSController(**kwargs)
return NSControllerFactory.__controller
elif controller_type.lower() == "db":
print "Namespace persistence = db"
NSControllerFactory.__controller = DBNSController(**kwargs)
return NSControllerFactory.__controller
elif controller_type.lower() == "file":
print "Namespace persistence = File"
NSControllerFactory.__controller = FileNSController(**kwargs)
return NSControllerFactory.__controller
return None
@staticmethod
def get():
if NSControllerFactory.__controller:
return NSControllerFactory.__controller
else:
return NSControllerFactory.create(
NSControllerFactory.__controller_type)

View File

@ -0,0 +1,43 @@
# 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 ns_controller import NSTypeControllerBase
# TODO(Wayne): Implement the db controller
class DBNSController(NSTypeControllerBase):
def __init__(self, **kwargs):
super(DBNSController, self).__init__(**kwargs)
self._type = 'DBNSController'
def get_type(self):
return self._type
def get_namespace(self, namespace_name):
pass
def find_namespaces(self, query_string):
pass
def set_namespace(self, namespace):
pass
def put_namespace(self, namespace_name, namespace):
pass
def delete_namespace(self, namespace_name):
pass

View File

@ -0,0 +1,80 @@
# 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.namespace import Namespace
import json
from ns_controller import NSTypeControllerBase
from oslo.config import cfg
from wsme.rest.json import fromjson
from wsme.rest.json import tojson
class FileNSController(NSTypeControllerBase):
def __init__(self, **kwargs):
super(FileNSController, self).__init__(**kwargs)
self._type = 'FileNSController'
self._graffiti_folder = cfg.CONF.FILE_PERSISTENCE.dictionary_folder
self._filename = "namespaces.json"
self._namespacefile = self._graffiti_folder + self._filename
self._namespaces = self.__file_to_memory()
def get_namespace(self, namespace_name):
return self._namespaces[namespace_name]
def find_namespaces(self, query_string):
return self._namespaces.itervalues()
def set_namespace(self, namespace):
self._namespaces[namespace.name] = namespace
self.__memory_to_file()
return namespace
def put_namespace(self, namespace_name, namespace):
self._namespaces[namespace_name] = namespace
self.__memory_to_file()
return namespace
def delete_namespace(self, namespace_name):
namespace = None
if self._namespaces[namespace_name]:
namespace = self._namespaces[namespace_name]
self._namespaces.pop(namespace_name)
self.__memory_to_file()
return namespace
def __file_to_memory(self):
try:
namespaces = {}
with open(self._namespacefile, "r") as gfile:
doc = json.load(gfile)
for namespace in doc:
namespaces[namespace] = fromjson(Namespace, doc[namespace])
return namespaces
except IOError:
with open(self._namespacefile, "w+") as gfile:
gfile.write("")
return {}
def __memory_to_file(self):
namespaces = {}
for (namespace_name, namespace) in self._namespaces.items():
json_data = tojson(Namespace, namespace)
namespaces[namespace_name] = json_data
with open(self._namespacefile, "w+") as gfile:
json.dump(namespaces, gfile)

View File

@ -0,0 +1,49 @@
# 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 ns_controller import NSTypeControllerBase
class MemNSController(NSTypeControllerBase):
def __init__(self, **kwargs):
super(MemNSController, self).__init__(**kwargs)
self._type = 'MemNSController'
self._namespaces = {}
def get_type(self):
return self._type
def get_namespace(self, namespace_name):
return self._namespaces[namespace_name]
def find_namespaces(self, query_string):
return self._namespaces.itervalues()
def set_namespace(self, namespace):
self._namespaces[namespace.name] = namespace
return namespace
def put_namespace(self, namespace_name, namespace):
self._namespaces[namespace.name] = namespace
return namespace
def delete_namespace(self, namespace_name):
namespace = None
if self._namespaces[namespace_name]:
namespace = self._namespaces[namespace_name]
self._namespaces.pop(namespace_name)
return namespace

View File

@ -13,15 +13,19 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import pecan
from pecan.rest import RestController
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_controller_factory import \
ResourceControllerFactory
from graffiti.api.model.v1.resource_dao_factory import \
ResourceDAOFactory
from graffiti.common.utils import _
@ -29,6 +33,8 @@ from oslo.config import cfg
import six
import keystoneclient.v2_0.client as ksclient
resource_controller_group = cfg.OptGroup('resource_controller')
resource_controller_opts = [
@ -42,6 +48,11 @@ cfg.CONF.register_opts(resource_controller_opts,
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__()
@ -53,37 +64,98 @@ class ResourceController(RestController):
controller_type = cfg.CONF.resource_controller.type
controller_type = controller_type if controller_type else 'Local'
_controller = ResourceControllerFactory.create(controller_type)
_controller = ResourceDAOFactory.create(controller_type)
return _controller
@wsexpose()
def options():
def options(self):
pass
@wsexpose(Resource, six.text_type)
def get_one(self, id):
res = self._controller.get_resource(id)
if res:
@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)
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
res = Response(Resource(), status_code=404, error="Resource Not Found")
# 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"
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
return res_list.itervalues()
return []
@wsexpose(Resource, six.text_type, body=Resource)
def put(self, id, resource):
self._controller.set_resource(id, resource_definition=resource)
def put(self, resource_id, resource):
"""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)
return resource
@wsexpose(Resource, body=Resource)

View File

@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#import json
# import json
from pecan.hooks import PecanHook

View File

@ -16,11 +16,17 @@
import wsme
from wsme import types
from graffiti.api.model.v1.derived_type import DerivedType
from graffiti.api.model.v1.property_type import PropertyType
class CapabilityType(types.Base):
name = wsme.wsattr(types.text, mandatory=True)
namespace = wsme.wsattr(types.text, mandatory=True)
description = wsme.wsattr(types.text, mandatory=False)
properties = wsme.wsattr({types.text: PropertyType}, mandatory=False)
derived_from = wsme.wsattr(DerivedType, mandatory=False)
def __init__(self, **kwargs):
super(CapabilityType, self).__init__(**kwargs)

View File

@ -0,0 +1,27 @@
# 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.
import wsme
from wsme import types
class DerivedType(types.Base):
name = wsme.wsattr(types.text, mandatory=True)
namespace = wsme.wsattr(types.text, mandatory=True)
_wsme_attr_order = ('name', 'namespace')
def __init__(self, **kwargs):
super(DerivedType, self).__init__(**kwargs)

View File

@ -13,6 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import wsme
from wsme import types
@ -20,7 +21,7 @@ from wsme import types
class Namespace(types.Base):
name = wsme.wsattr(types.text, mandatory=True)
scope = wsme.wsattr(types.text, mandatory=True)
owner = wsme.wsattr(types.text, mandatory=True)
owner = wsme.wsattr(types.text, mandatory=False)
def __init__(self, **kwargs):
super(Namespace, self).__init__(**kwargs)

View File

@ -0,0 +1,27 @@
# 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.
import wsme
from wsme import types
class ItemType(types.Base):
type = wsme.wsattr(types.text, mandatory=True)
enum = wsme.wsattr([types.text], mandatory=False)
_wsme_attr_order = ('type', 'enum')
def __init__(self, **kwargs):
super(ItemType, self).__init__(**kwargs)

View File

@ -0,0 +1,50 @@
# 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.property_item_type import ItemType
import wsme
from wsme import types
class PropertyType(types.Base):
type = wsme.wsattr(types.text, mandatory=True)
description = wsme.wsattr(types.text, mandatory=False)
default = wsme.wsattr(types.text, mandatory=False)
required = wsme.wsattr(bool, mandatory=False, default=False)
# fields for type = string
minimum = wsme.wsattr(int, mandatory=False)
maximum = wsme.wsattr(int, mandatory=False)
# fields for type = integer, number
minLength = wsme.wsattr(int, mandatory=False)
maxLength = wsme.wsattr(int, mandatory=False)
pattern = wsme.wsattr(types.text, mandatory=False)
confidential = wsme.wsattr(bool, mandatory=False)
# fields for type = array
items = wsme.wsattr(ItemType, mandatory=False)
uniqueItems = wsme.wsattr(bool, mandatory=False)
minItems = wsme.wsattr(int, mandatory=False)
maxItems = wsme.wsattr(int, mandatory=False)
additionalItems = wsme.wsattr(bool, mandatory=False)
_wsme_attr_order = ('type', 'description', 'default', 'required',
'minimum', 'maximum', 'minLength', 'maxLength',
'pattern', 'confidential', 'items', 'uniqueItems',
'additionalItems')
def __init__(self, **kwargs):
super(PropertyType, self).__init__(**kwargs)

View File

@ -14,10 +14,10 @@
# limitations under the License.
class ResourceControllerBase(object):
class ResourceDAOBase(object):
def __init__(self, **kwargs):
super(ResourceControllerBase, self).__init__(**kwargs)
super(ResourceDAOBase, self).__init__(**kwargs)
self._type = 'None'
@ -34,12 +34,12 @@ class ResourceControllerBase(object):
pass
class LocalResourceController(ResourceControllerBase):
class LocalResourceDAO(ResourceDAOBase):
def __init__(self, **kwargs):
super(LocalResourceController, self).__init__(**kwargs)
super(LocalResourceDAO, self).__init__(**kwargs)
self._type = 'LocalResourceController'
self._type = 'LocalResourceDAO'
self._resources = dict()
self._last_id = 0

View File

@ -13,17 +13,17 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from graffiti.api.model.v1.resource_controller import LocalResourceController
from graffiti.api.model.v1.resource_dao import LocalResourceDAO
class ResourceControllerFactory(object):
class ResourceDAOFactory(object):
def __init__(self, **kwargs):
super(ResourceControllerFactory, self).__init__(**kwargs)
super(ResourceDAOFactory, self).__init__(**kwargs)
@staticmethod
def create(controller_type, **kwargs):
if controller_type.lower() == 'local':
return LocalResourceController(**kwargs)
def create(dao_type, **kwargs):
if dao_type.lower() == 'local':
return LocalResourceDAO(**kwargs)
return None

View File

@ -0,0 +1 @@
__author__ = 'lakshmi'

View File

@ -0,0 +1,95 @@
# 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

@ -18,10 +18,39 @@
import os
import fixtures
from oslo.config import cfg
import testtools
_TRUE_VALUES = ('True', 'true', '1', 'yes')
# DEFAULT group
default_controller_group = cfg.OptGroup('DEFAULT')
default_controller_opts = [
cfg.StrOpt(
'persistence_type',
default="memory",
help=("persistence options. "
"values = 'memory' or 'file' or 'db"))
]
cfg.CONF.register_group(default_controller_group)
cfg.CONF.register_opts(default_controller_opts,
group=default_controller_group)
# FILE_PERSISTENCE group
file_controller_group = cfg.OptGroup('FILE_PERSISTENCE')
file_controller_opts = [
cfg.StrOpt(
'dictionary_folder',
default="/tmp/graffiti-dictionary-test/",
help=("Absolute path of the file for persisting dictionary")
)
]
cfg.CONF.register_group(file_controller_group)
cfg.CONF.register_opts(file_controller_opts,
group=file_controller_group)
class TestCase(testtools.TestCase):

View File

@ -25,8 +25,12 @@ from graffiti.api.tests import base
from graffiti.api.controllers.root import RootController
from graffiti.api.controllers.versions import V1Controller
from graffiti.api.model.v1.resource_controller_factory \
import ResourceControllerFactory
from graffiti.api.controllers.v1.captype_controller_factory \
import CapTypeControllerFactory
from graffiti.api.controllers.v1.ns_controller_factory \
import NSControllerFactory
from graffiti.api.model.v1.resource_dao_factory \
import ResourceDAOFactory
class TestControllerV1(base.TestCase):
@ -35,14 +39,48 @@ class TestControllerV1(base.TestCase):
root = RootController()
self.assertIn(hasattr(root, 'v1'), [True])
def test_v1_namespace_exists(self):
v1 = V1Controller()
self.assertIn(hasattr(v1, 'namespace'), [True])
def test_v1_namespace_controller_factory__memory(self):
rc = NSControllerFactory.create('memory')
self.assertEquals(rc.get_type(), 'MemNSController')
# TODO(Lakshmi): Create folder before any tests run
# def test_v1_namespace_controller_factory__file(self):
# rc = NSControllerFactory.create('file')
# self.assertEquals(rc.get_type(), 'FileNSController')
def test_v1_namespace_controller_factory__db(self):
rc = NSControllerFactory.create('db')
self.assertEquals(rc.get_type(), 'DBNSController')
def test_v1_capability_type_exists(self):
v1 = V1Controller()
self.assertIn(hasattr(v1, 'capability_type'), [True])
def test_v1_capability_type_controller_factory__memory(self):
rc = CapTypeControllerFactory.create('memory')
self.assertEquals(rc.get_type(), 'MemCapabilityTypeController')
# TODO(Lakshmi): Create folder before any tests run
# def test_v1_capability_type_controller_factory__file(self):
# rc = CapTypeControllerFactory.create('file')
# self.assertEquals(rc.get_type(), 'FileCapabilityTypeController')
def test_v1_capability_type_controller_factory__db(self):
rc = CapTypeControllerFactory.create('db')
self.assertEquals(rc.get_type(), 'DBCapabilityTypeController')
def test_v1_resource_exists(self):
v1 = V1Controller()
self.assertIn(hasattr(v1, 'resource'), [True])
def test_v1_resource_controller_factory__local(self):
rc = ResourceControllerFactory.create('local')
self.assertEquals(rc.get_type(), 'LocalResourceController')
rc = ResourceDAOFactory.create('local')
self.assertEquals(rc.get_type(), 'LocalResourceDAO')
def test_v1_resource_controller_factory__unknown(self):
rc = ResourceControllerFactory.create('invalid_controller')
rc = ResourceDAOFactory.create('invalid_controller')
self.assertTrue(rc is None)

View File

@ -3,3 +3,4 @@ Babel>=0.9.6
pecan>=0.4.4
WSME>=0.6
oslo.config
python-glanceclient

View File

@ -1,6 +1,6 @@
[tox]
minversion = 1.6
envlist = py33,py27,py26,pep8
envlist = py27,py26,pep8
skipsdist = True
[testenv]