bp/capability-type-persistence - capability_type/batch service
Change-Id: Idde50f5350adfd4861e1156468f597bbb2b42caa
This commit is contained in:
parent
2148458f67
commit
e34a15348e
@ -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
|
||||
|
@ -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):
|
||||
|
102
graffiti/api/controllers/v1/capability_type_batch.py
Normal file
102
graffiti/api/controllers/v1/capability_type_batch.py
Normal 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))
|
33
graffiti/api/model/v1/capability_type_key.py
Normal file
33
graffiti/api/model/v1/capability_type_key.py
Normal 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)
|
@ -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)
|
||||
|
||||
|
0
graffiti/common/utilities/__init__.py
Normal file
0
graffiti/common/utilities/__init__.py
Normal file
133
graffiti/common/utilities/capability_type_tree.py
Normal file
133
graffiti/common/utilities/capability_type_tree.py
Normal 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
|
22
graffiti/common/utilities/capability_type_tree_node.py
Normal file
22
graffiti/common/utilities/capability_type_tree_node.py
Normal 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
|
Loading…
x
Reference in New Issue
Block a user