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 # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from oslo.config import cfg
# Server Specific Configurations # Server Specific Configurations
server = { server = {
'port': '21075', 'port': '21075',
@ -59,9 +61,84 @@ wsme = {
'debug': True 'debug': True
} }
# Custom Configurations must be in Python dictionary format:: # Custom Configurations must be in Python dictionary format::
# #
# foo = {'bar':'baz'} # foo = {'bar':'baz'}
# #
# All configurations are accessible at:: # All configurations are accessible at::
# pecan.conf # 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): 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() model.init_model()
app_conf = dict(config.app) app_conf = dict(config.app)

View File

@ -15,42 +15,122 @@
from pecan.rest import RestController from pecan.rest import RestController
from wsme.api import Response
from wsmeext.pecan import wsexpose 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 graffiti.api.model.v1.capability_type import CapabilityType
from ns_controller_factory import NSControllerFactory
from oslo.config import cfg
import six import six
capability_types = []
class CapabilityTypeController(RestController): class CapabilityTypeController(RestController):
def __init__(self): def __init__(self):
super(RestController, self).__init__() super(RestController, self).__init__()
self.status = 200 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 @wsexpose
def options(): def options():
pass pass
@wsexpose(CapabilityType, six.text_type) @wsexpose(CapabilityType, six.text_type, six.text_type)
def get_one(self, name): def get_one(self, name, namespace):
global capability_types captype = self._cap_controller.get_capability_type(name, namespace)
return captype
for capability_type in capability_types: @wsexpose([CapabilityType], six.text_type)
if capability_type.name.lower() == name.lower(): def get_all(self, query_string=None):
return capability_type captype_list = self._cap_controller.find_capability_types(query_string)
return captype_list
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, body=CapabilityType) @wsexpose(CapabilityType, body=CapabilityType)
def post(self, capability_type): def post(self, capability_type):
global capability_types """Create Capability Type
capability_types.append(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 wsmeext.pecan import wsexpose
from graffiti.api.controllers.v1.ns_controller_factory\
import NSControllerFactory
from graffiti.api.model.v1.namespace import Namespace from graffiti.api.model.v1.namespace import Namespace
from oslo.config import cfg
import six import six
namespaces = []
class NamespaceController(RestController): class NamespaceController(RestController):
def __init__(self): def __init__(self):
super(RestController, self).__init__() super(RestController, self).__init__()
self.status = 200 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 @wsexpose
def options(): def options(self):
pass pass
@wsexpose(Namespace, six.text_type) @wsexpose(Namespace, six.text_type)
def get_one(self, name): def get_one(self, namespace_name):
global namespaces namespace = self._controller.get_namespace(namespace_name)
return namespace
for namespace in namespaces:
if namespace.name.lower() == name.lower():
return namespace
res = Namespace(Namespace(), status_code=404,
error="Namespace Not Found")
return res
@wsexpose([Namespace]) @wsexpose([Namespace])
def get_all(self): def get_all(self, query_string=None):
global namespaces namespace_list = self._controller.find_namespaces(query_string)
return namespaces return namespace_list
@wsexpose(Namespace, body=Namespace) @wsexpose(Namespace, body=Namespace)
def post(self, namespace): def post(self, namespace):
global namespaces """Create Namespace
namespaces.append(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 # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import pecan
from pecan.rest import RestController from pecan.rest import RestController
from wsme.api import Response from wsme.api import Response
from wsmeext.pecan import wsexpose from wsmeext.pecan import wsexpose
from graffiti.api.model.v1.resource import Resource 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 _ from graffiti.common.utils import _
@ -29,6 +33,8 @@ from oslo.config import cfg
import six import six
import keystoneclient.v2_0.client as ksclient
resource_controller_group = cfg.OptGroup('resource_controller') resource_controller_group = cfg.OptGroup('resource_controller')
resource_controller_opts = [ resource_controller_opts = [
@ -42,6 +48,11 @@ cfg.CONF.register_opts(resource_controller_opts,
class ResourceController(RestController): 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): def __init__(self):
super(ResourceController, self).__init__() super(ResourceController, self).__init__()
@ -53,37 +64,98 @@ class ResourceController(RestController):
controller_type = cfg.CONF.resource_controller.type controller_type = cfg.CONF.resource_controller.type
controller_type = controller_type if controller_type else 'Local' controller_type = controller_type if controller_type else 'Local'
_controller = ResourceControllerFactory.create(controller_type) _controller = ResourceDAOFactory.create(controller_type)
return _controller return _controller
@wsexpose() @wsexpose()
def options(): def options(self):
pass pass
@wsexpose(Resource, six.text_type) @wsexpose(Resource, six.text_type, six.text_type, six.text_type,
def get_one(self, id): six.text_type)
res = self._controller.get_resource(id) def get_one(self, resource_id, resource_type=None, param1=None,
if res: 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 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 return res
@wsexpose([Resource], six.text_type) @wsexpose([Resource], six.text_type)
def get_all(self, query_string=None): def get_all(self, query_string=None):
res_list = self._controller.find_resources(query_string) res_list = self._controller.find_resources(query_string)
if res_list: if res_list:
return res_list return res_list.itervalues()
return [] return []
@wsexpose(Resource, six.text_type, body=Resource) @wsexpose(Resource, six.text_type, body=Resource)
def put(self, id, resource): def put(self, resource_id, resource):
"""Modify resource
self._controller.set_resource(id, resource_definition=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 return resource
@wsexpose(Resource, body=Resource) @wsexpose(Resource, body=Resource)

View File

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

View File

@ -16,11 +16,17 @@
import wsme import wsme
from wsme import types 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): class CapabilityType(types.Base):
name = wsme.wsattr(types.text, mandatory=True) name = wsme.wsattr(types.text, mandatory=True)
namespace = wsme.wsattr(types.text, mandatory=True) namespace = wsme.wsattr(types.text, mandatory=True)
description = wsme.wsattr(types.text, mandatory=False) 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): def __init__(self, **kwargs):
super(CapabilityType, self).__init__(**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 # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import wsme import wsme
from wsme import types from wsme import types
@ -20,7 +21,7 @@ from wsme import types
class Namespace(types.Base): class Namespace(types.Base):
name = wsme.wsattr(types.text, mandatory=True) name = wsme.wsattr(types.text, mandatory=True)
scope = 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): def __init__(self, **kwargs):
super(Namespace, self).__init__(**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. # limitations under the License.
class ResourceControllerBase(object): class ResourceDAOBase(object):
def __init__(self, **kwargs): def __init__(self, **kwargs):
super(ResourceControllerBase, self).__init__(**kwargs) super(ResourceDAOBase, self).__init__(**kwargs)
self._type = 'None' self._type = 'None'
@ -34,12 +34,12 @@ class ResourceControllerBase(object):
pass pass
class LocalResourceController(ResourceControllerBase): class LocalResourceDAO(ResourceDAOBase):
def __init__(self, **kwargs): def __init__(self, **kwargs):
super(LocalResourceController, self).__init__(**kwargs) super(LocalResourceDAO, self).__init__(**kwargs)
self._type = 'LocalResourceController' self._type = 'LocalResourceDAO'
self._resources = dict() self._resources = dict()
self._last_id = 0 self._last_id = 0

View File

@ -13,17 +13,17 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # 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): def __init__(self, **kwargs):
super(ResourceControllerFactory, self).__init__(**kwargs) super(ResourceDAOFactory, self).__init__(**kwargs)
@staticmethod @staticmethod
def create(controller_type, **kwargs): def create(dao_type, **kwargs):
if controller_type.lower() == 'local': if dao_type.lower() == 'local':
return LocalResourceController(**kwargs) return LocalResourceDAO(**kwargs)
return None 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 os
import fixtures import fixtures
from oslo.config import cfg
import testtools import testtools
_TRUE_VALUES = ('True', 'true', '1', 'yes') _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): 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.root import RootController
from graffiti.api.controllers.versions import V1Controller from graffiti.api.controllers.versions import V1Controller
from graffiti.api.model.v1.resource_controller_factory \ from graffiti.api.controllers.v1.captype_controller_factory \
import ResourceControllerFactory 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): class TestControllerV1(base.TestCase):
@ -35,14 +39,48 @@ class TestControllerV1(base.TestCase):
root = RootController() root = RootController()
self.assertIn(hasattr(root, 'v1'), [True]) 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): def test_v1_resource_exists(self):
v1 = V1Controller() v1 = V1Controller()
self.assertIn(hasattr(v1, 'resource'), [True]) self.assertIn(hasattr(v1, 'resource'), [True])
def test_v1_resource_controller_factory__local(self): def test_v1_resource_controller_factory__local(self):
rc = ResourceControllerFactory.create('local') rc = ResourceDAOFactory.create('local')
self.assertEquals(rc.get_type(), 'LocalResourceController') self.assertEquals(rc.get_type(), 'LocalResourceDAO')
def test_v1_resource_controller_factory__unknown(self): def test_v1_resource_controller_factory__unknown(self):
rc = ResourceControllerFactory.create('invalid_controller') rc = ResourceDAOFactory.create('invalid_controller')
self.assertTrue(rc is None) self.assertTrue(rc is None)

View File

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

View File

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