bp/capability-type-persistence - capability_type/batch service

Change-Id: Idde50f5350adfd4861e1156468f597bbb2b42caa
This commit is contained in:
Wayne Okuma 2014-05-21 02:42:34 -07:00
parent 2148458f67
commit e34a15348e
8 changed files with 298 additions and 3 deletions

View File

@ -5,3 +5,7 @@ persistence_type=memory
[FILE_PERSISTENCE]
dictionary_folder=/tmp/graffiti-dictionary/
[DATABASE]
#connection = sqlite:////var/tmp/graffiti.db
#connection = mysql://graffiti:graffiti@127.0.0.1:3306/graffiti

View File

@ -18,6 +18,8 @@ from pecan.rest import RestController
from wsme.api import Response
from wsmeext.pecan import wsexpose
from graffiti.api.controllers.v1.capability_type_batch import\
CapabilityTypeBatchController
from graffiti.api.controllers.v1.capability_type_derived import\
CapabilityTypeDerivedController
from graffiti.api.model.v1.capability_type import CapabilityType
@ -32,6 +34,7 @@ import six
class CapabilityTypeController(RestController):
batch = CapabilityTypeBatchController()
derived_properties = CapabilityTypeDerivedController()
def __init__(self):

View File

@ -0,0 +1,102 @@
# 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.capability_type import CapabilityType
from graffiti.api.model.v1.dao.captype_dao_factory \
import CapabilityTypeDAOFactory
from graffiti.api.model.v1.dao.ns_dao_factory import NSDAOFactory
from graffiti.common import exception as exc
from graffiti.common.utilities.capability_type_tree import CapabilityTypeTree
from oslo.config import cfg
from pecan.rest import RestController
from wsmeext.pecan import wsexpose
class CapabilityTypeBatchController(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):
dao_type = cfg.CONF.DEFAULT.persistence_type
self._cap_controller = CapabilityTypeDAOFactory.create(dao_type)
self._ns_controller = NSDAOFactory.get()
@wsexpose
def options(self):
pass
@wsexpose([CapabilityType], body=[CapabilityType])
def post(self, capability_types):
"""Batch create capability types
@param capability_types: list of CapabilityTypes
"""
cap_types = []
# Verify all namespaces exists
self.__verify_namespaces(capability_types)
tree = CapabilityTypeTree()
tree.build(capability_types)
# TODO(wko): verify external derived roots
# self.__verify_external_derived_roots_exist(
# tree.types_with_external_root)
for cap_key, cap_node in tree.root_types.iteritems():
self.create_capability_type_recursively(cap_node, cap_types)
return cap_types
def create_capability_type_recursively(self, tree_node, cap_types):
if tree_node:
capability_type = tree_node.cap_type
exists_ct = self._cap_controller.get_capability_type(
capability_type.name, capability_type.namespace)
if exists_ct:
# update
self._cap_controller.put_capability_type(
capability_type.name, capability_type.namespace,
capability_type
)
cap_types.append(capability_type)
else:
# add
new_ct = self._cap_controller.set_capability_type(
capability_type)
cap_types.append(new_ct)
for cap_key, child_node in tree_node.children.iteritems():
self.create_capability_type_recursively(child_node, cap_types)
def __verify_namespaces(self, capability_types):
namespaces = []
for ct in capability_types:
if ct.namespace not in namespaces:
namespaces.append(ct.namespace)
found_namespace = False
for namespace in namespaces:
found_namespace = self._ns_controller.get_namespace(namespace)
if not found_namespace:
raise exc.NotFound("namespace:{0} - does not exist".
format(namespace))

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.
import wsme
from wsme import types
class CapabilityTypeKey(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(CapabilityTypeKey, self).__init__(**kwargs)
def __hash__(self):
return hash((self.name, self.namespace))
def __eq__(self, other):
return (self.name, self.namespace) == (other.name, other.namespace)

View File

@ -109,9 +109,7 @@ class DBCapabilityTypeDAO(CapabilityTypeDAOBase):
def get_capability_type(self, name, namespace):
db_capability_type = dbapi.capability_type_get(name, namespace)
if not db_capability_type:
res = CapabilityType(CapabilityType(), status_code=404,
error="CapabilityType Not Found")
return res
return None
return self._to_model(db_capability_type)

View File

View File

@ -0,0 +1,133 @@
# 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.capability_type_key import CapabilityTypeKey
from graffiti.common.utilities.capability_type_tree_node \
import CapabilityTypeTreeNode
class CapabilityTypeTree():
def __init__(self, **kwargs):
self.root_types = {}
self.types_with_external_root = {}
def build(self, capability_type_list):
capability_types = {}
for cap_type in capability_type_list:
# todo(wko): raise error if duplicate found
key = CapabilityTypeKey(name=cap_type.name,
namespace=cap_type.namespace)
capability_types[key] = cap_type
# Handle: 1) No parent 2) No children (no-op)
# 3) Parent in tree
# 4) Parent not processed, yet
# 5) More than one root in input (not common ancestor)
# 6) Type has parent, but not in input (external parent)
types_with_unmapped_parents = {}
for current_key, current_cap_type in capability_types.iteritems():
current_node = CapabilityTypeTreeNode()
current_node.cap_type = current_cap_type
# Scenario 1 & 5
if not current_cap_type.derived_from \
or not current_cap_type.derived_from.name:
self.root_types[current_key] = current_node
continue
if self.insert_node(self.root_types, current_key, current_node):
# Scenario 3
continue
elif self.insert_node(types_with_unmapped_parents,
current_key, current_node):
# Scenario 3 (not converged)
continue
else:
# Scenario 4 part a
types_with_unmapped_parents[current_key] = current_node
# Scenario 4 part b
# Perform eventual convergence on roots
self.converge_unmapped_types(self.root_types,
types_with_unmapped_parents)
# Perform eventual convergence on types_with_unmapped_parents
self.converge_unmapped_types(types_with_unmapped_parents,
types_with_unmapped_parents)
# Scenario 6
self.types_with_external_root.update(types_with_unmapped_parents)
def insert_node(self, cap_types, current_key, current_node):
# For each cap_type
# if it is the parent of the current_node.cap_type
# set root_node as the current_node.parent_node
# add the current_node to root_node.children
# break
# else
# recursively check if parent is in root_node.children
# break if found
result = False
if cap_types:
i = 0
for root_key, root_node in cap_types.iteritems():
# todo(wko): derived_from should be a CapabilityTypeKey
current_parent_name = current_node.cap_type.derived_from.name
current_parent_namesp = \
current_node.cap_type.derived_from.namespace
if root_key.name == current_parent_name and\
root_key.namespace == current_parent_namesp:
current_node.parent_node = root_node
root_node.children[current_key] = current_node
result = True
break
result = self.insert_node(root_node.children, current_key,
current_node)
if result:
break
i += 1
return result
def converge_unmapped_types(self, root_types, types_with_unmapped_parents):
previous_loop_unmapped_parents = 0
num_loops_without_change = 0
while len(types_with_unmapped_parents) > 0 \
and num_loops_without_change < 2:
types_with_found_parent = []
for unmapped_key, unmapped_node in \
types_with_unmapped_parents.iteritems():
result = self.insert_node(root_types, unmapped_key,
unmapped_node)
if result:
types_with_found_parent.append(unmapped_key)
continue
for mapped_parent in types_with_found_parent:
del types_with_unmapped_parents[mapped_parent]
this_loop_unmapped_parents = len(types_with_unmapped_parents)
if previous_loop_unmapped_parents == this_loop_unmapped_parents:
num_loops_without_change += 1
else:
num_loops_without_change = 0
previous_loop_unmapped_parents = this_loop_unmapped_parents

View File

@ -0,0 +1,22 @@
# 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 CapabilityTypeTreeNode():
def __init__(self, **kwargs):
self.children = {}
self.parent_node = None
self.cap_type = None