summaryrefslogtreecommitdiffstats
path: root/compass-tasks/db/api/utils.py
diff options
context:
space:
mode:
authorHarry Huang <huangxiangyu5@huawei.com>2017-11-17 14:53:44 +0800
committerHarry Huang <huangxiangyu5@huawei.com>2017-12-21 16:36:30 +0800
commit8646b8d62cf4ca7b6bccae537a0c9e72ba45eab3 (patch)
tree73a9a983e0dd1423e9df928a78a5023a09d5a7f9 /compass-tasks/db/api/utils.py
parent6234176ae292a75dcda5520324cb7857d6105988 (diff)
Merge compass-tasks-osa and compass-tasks-k8s
JIRA: COMPASS-568 rename compass-tasks to compass-tasks-base. add both osa and k8s support in compass-tasks Change-Id: I438f5b17e509d4cb751ced0ffe640ec70899882f Signed-off-by: Harry Huang <huangxiangyu5@huawei.com>
Diffstat (limited to 'compass-tasks/db/api/utils.py')
-rw-r--r--compass-tasks/db/api/utils.py1286
1 files changed, 0 insertions, 1286 deletions
diff --git a/compass-tasks/db/api/utils.py b/compass-tasks/db/api/utils.py
deleted file mode 100644
index a44f26e..0000000
--- a/compass-tasks/db/api/utils.py
+++ /dev/null
@@ -1,1286 +0,0 @@
-# Copyright 2014 Huawei Technologies Co. Ltd
-#
-# 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.
-
-"""Utils for database usage."""
-
-import functools
-import inspect
-import logging
-import netaddr
-import re
-
-from inspect import isfunction
-from sqlalchemy import and_
-from sqlalchemy import or_
-
-from compass.db import exception
-from compass.db import models
-from compass.utils import util
-
-
-def model_query(session, model):
- """model query.
-
- Return sqlalchemy query object.
- """
- if not issubclass(model, models.BASE):
- raise exception.DatabaseException("model should be sublass of BASE!")
-
- return session.query(model)
-
-
-def _default_list_condition_func(col_attr, value, condition_func):
- """The default condition func for a list of data.
-
- Given the condition func for single item of data, this function
- wrap the condition_func and return another condition func using
- or_ to merge the conditions of each single item to deal with a
- list of data item.
-
- Args:
- col_attr: the colomn name
- value: the column value need to be compared.
- condition_func: the sqlalchemy condition object like ==
-
- Examples:
- col_attr is name, value is ['a', 'b', 'c'] and
- condition_func is ==, the returned condition is
- name == 'a' or name == 'b' or name == 'c'
- """
- conditions = []
- for sub_value in value:
- condition = condition_func(col_attr, sub_value)
- if condition is not None:
- conditions.append(condition)
- if conditions:
- return or_(*conditions)
- else:
- return None
-
-
-def _one_item_list_condition_func(col_attr, value, condition_func):
- """The wrapper condition func to deal with one item data list.
-
- For simplification, it is used to reduce generating too complex
- sql conditions.
- """
- if value:
- return condition_func(col_attr, value[0])
- else:
- return None
-
-
-def _model_condition_func(
- col_attr, value,
- item_condition_func,
- list_condition_func=_default_list_condition_func
-):
- """Return sql condition based on value type."""
- if isinstance(value, list):
- if not value:
- return None
- if len(value) == 1:
- return item_condition_func(col_attr, value)
- return list_condition_func(
- col_attr, value, item_condition_func
- )
- else:
- return item_condition_func(col_attr, value)
-
-
-def _between_condition(col_attr, value):
- """Return sql range condition."""
- if value[0] is not None and value[1] is not None:
- return col_attr.between(value[0], value[1])
- if value[0] is not None:
- return col_attr >= value[0]
- if value[1] is not None:
- return col_attr <= value[1]
- return None
-
-
-def model_order_by(query, model, order_by):
- """append order by into sql query model."""
- if not order_by:
- return query
- order_by_cols = []
- for key in order_by:
- if isinstance(key, tuple):
- key, is_desc = key
- else:
- is_desc = False
- if isinstance(key, basestring):
- if hasattr(model, key):
- col_attr = getattr(model, key)
- else:
- continue
- else:
- col_attr = key
- if is_desc:
- order_by_cols.append(col_attr.desc())
- else:
- order_by_cols.append(col_attr)
- return query.order_by(*order_by_cols)
-
-
-def _model_condition(col_attr, value):
- """Generate condition for one column.
-
- Example for col_attr is name:
- value is 'a': name == 'a'
- value is ['a']: name == 'a'
- value is ['a', 'b']: name == 'a' or name == 'b'
- value is {'eq': 'a'}: name == 'a'
- value is {'lt': 'a'}: name < 'a'
- value is {'le': 'a'}: name <= 'a'
- value is {'gt': 'a'}: name > 'a'
- value is {'ge': 'a'}: name >= 'a'
- value is {'ne': 'a'}: name != 'a'
- value is {'in': ['a', 'b']}: name in ['a', 'b']
- value is {'notin': ['a', 'b']}: name not in ['a', 'b']
- value is {'startswith': 'abc'}: name like 'abc%'
- value is {'endswith': 'abc'}: name like '%abc'
- value is {'like': 'abc'}: name like '%abc%'
- value is {'between': ('a', 'c')}: name >= 'a' and name <= 'c'
- value is [{'lt': 'a'}]: name < 'a'
- value is [{'lt': 'a'}, {'gt': c'}]: name < 'a' or name > 'c'
- value is {'lt': 'c', 'gt': 'a'}: name > 'a' and name < 'c'
-
- If value is a list, the condition is the or relationship among
- conditions of each item.
- If value is dict and there are multi keys in the dict, the relationship
- is and conditions of each key.
- Otherwise the condition is to compare the column with the value.
- """
- if isinstance(value, list):
- basetype_values = []
- composite_values = []
- for item in value:
- if isinstance(item, (list, dict)):
- composite_values.append(item)
- else:
- basetype_values.append(item)
- conditions = []
- if basetype_values:
- if len(basetype_values) == 1:
- condition = (col_attr == basetype_values[0])
- else:
- condition = col_attr.in_(basetype_values)
- conditions.append(condition)
- for composite_value in composite_values:
- condition = _model_condition(col_attr, composite_value)
- if condition is not None:
- conditions.append(condition)
- if not conditions:
- return None
- if len(conditions) == 1:
- return conditions[0]
- return or_(*conditions)
- elif isinstance(value, dict):
- conditions = []
- if 'eq' in value:
- conditions.append(_model_condition_func(
- col_attr, value['eq'],
- lambda attr, data: attr == data,
- lambda attr, data, item_condition_func: attr.in_(data)
- ))
- if 'lt' in value:
- conditions.append(_model_condition_func(
- col_attr, value['lt'],
- lambda attr, data: attr < data,
- _one_item_list_condition_func
- ))
- if 'gt' in value:
- conditions.append(_model_condition_func(
- col_attr, value['gt'],
- lambda attr, data: attr > data,
- _one_item_list_condition_func
- ))
- if 'le' in value:
- conditions.append(_model_condition_func(
- col_attr, value['le'],
- lambda attr, data: attr <= data,
- _one_item_list_condition_func
- ))
- if 'ge' in value:
- conditions.append(_model_condition_func(
- col_attr, value['ge'],
- lambda attr, data: attr >= data,
- _one_item_list_condition_func
- ))
- if 'ne' in value:
- conditions.append(_model_condition_func(
- col_attr, value['ne'],
- lambda attr, data: attr != data,
- lambda attr, data, item_condition_func: attr.notin_(data)
- ))
- if 'in' in value:
- conditions.append(col_attr.in_(value['in']))
- if 'notin' in value:
- conditions.append(col_attr.notin_(value['notin']))
- if 'startswith' in value:
- conditions.append(_model_condition_func(
- col_attr, value['startswith'],
- lambda attr, data: attr.like('%s%%' % data)
- ))
- if 'endswith' in value:
- conditions.append(_model_condition_func(
- col_attr, value['endswith'],
- lambda attr, data: attr.like('%%%s' % data)
- ))
- if 'like' in value:
- conditions.append(_model_condition_func(
- col_attr, value['like'],
- lambda attr, data: attr.like('%%%s%%' % data)
- ))
- if 'between' in value:
- conditions.append(_model_condition_func(
- col_attr, value['between'],
- _between_condition
- ))
- conditions = [
- condition
- for condition in conditions
- if condition is not None
- ]
- if not conditions:
- return None
- if len(conditions) == 1:
- return conditions[0]
- return and_(conditions)
- else:
- condition = (col_attr == value)
- return condition
-
-
-def model_filter(query, model, **filters):
- """Append conditons to query for each possible column."""
- for key, value in filters.items():
- if isinstance(key, basestring):
- if hasattr(model, key):
- col_attr = getattr(model, key)
- else:
- continue
- else:
- col_attr = key
- condition = _model_condition(col_attr, value)
- if condition is not None:
- query = query.filter(condition)
- return query
-
-
-def replace_output(**output_mapping):
- """Decorator to recursively relace output by output mapping.
-
- The replacement detail is described in _replace_output.
- """
- def decorator(func):
- @functools.wraps(func)
- def wrapper(*args, **kwargs):
- return _replace_output(
- func(*args, **kwargs), **output_mapping
- )
- return wrapper
- return decorator
-
-
-def _replace_output(data, **output_mapping):
- """Helper to replace output data.
-
- Example:
- data = {'a': 'hello'}
- output_mapping = {'a': 'b'}
- returns: {'b': 'hello'}
-
- data = {'a': {'b': 'hello'}}
- output_mapping = {'a': 'b'}
- returns: {'b': {'b': 'hello'}}
-
- data = {'a': {'b': 'hello'}}
- output_mapping = {'a': {'b': 'c'}}
- returns: {'a': {'c': 'hello'}}
-
- data = [{'a': 'hello'}, {'a': 'hi'}]
- output_mapping = {'a': 'b'}
- returns: [{'b': 'hello'}, {'b': 'hi'}]
- """
- if isinstance(data, list):
- return [
- _replace_output(item, **output_mapping)
- for item in data
- ]
- if not isinstance(data, dict):
- raise exception.InvalidResponse(
- '%s type is not dict' % data
- )
- info = {}
- for key, value in data.items():
- if key in output_mapping:
- output_key = output_mapping[key]
- if isinstance(output_key, basestring):
- info[output_key] = value
- else:
- info[key] = (
- _replace_output(value, **output_key)
- )
- else:
- info[key] = value
- return info
-
-
-def get_wrapped_func(func):
- """Get wrapped function instance.
-
- Example:
- @dec1
- @dec2
- myfunc(*args, **kwargs)
-
- get_wrapped_func(myfunc) returns function object with
- following attributes:
- __name__: 'myfunc'
- args: args
- kwargs: kwargs
- otherwise myfunc is function object with following attributes:
- __name__: partial object ...
- args: ...
- kwargs: ...
- """
- if func.func_closure:
- for closure in func.func_closure:
- if isfunction(closure.cell_contents):
- return get_wrapped_func(closure.cell_contents)
- return func
- else:
- return func
-
-
-def wrap_to_dict(support_keys=[], **filters):
- """Decrator to convert returned object to dict.
-
- The details is decribed in _wrapper_dict.
- """
- def decorator(func):
- @functools.wraps(func)
- def wrapper(*args, **kwargs):
- return _wrapper_dict(
- func(*args, **kwargs), support_keys, **filters
- )
- return wrapper
- return decorator
-
-
-def _wrapper_dict(data, support_keys, **filters):
- """Helper for warpping db object into dictionary.
-
- If data is list, convert it to a list of dict
- If data is Base model, convert it to dict
- for the data as a dict, filter it with the supported keys.
- For each filter_key, filter_value in filters, also filter
- data[filter_key] by filter_value recursively if it exists.
-
- Example:
- data is models.Switch, it will be converted to
- {
- 'id': 1, 'ip': '10.0.0.1', 'ip_int': 123456,
- 'credentials': {'version': 2, 'password': 'abc'}
- }
- Then if support_keys are ['id', 'ip', 'credentials'],
- it will be filtered to {
- 'id': 1, 'ip': '10.0.0.1',
- 'credentials': {'version': 2, 'password': 'abc'}
- }
- Then if filters is {'credentials': ['version']},
- it will be filtered to {
- 'id': 1, 'ip': '10.0.0.1',
- 'credentials': {'version': 2}
- }
- """
- logging.debug(
- 'wrap dict %s by support_keys=%s filters=%s',
- data, support_keys, filters
- )
- if isinstance(data, list):
- return [
- _wrapper_dict(item, support_keys, **filters)
- for item in data
- ]
- if isinstance(data, models.HelperMixin):
- data = data.to_dict()
- if not isinstance(data, dict):
- raise exception.InvalidResponse(
- 'response %s type is not dict' % data
- )
- info = {}
- try:
- for key in support_keys:
- if key in data and data[key] is not None:
- if key in filters:
- filter_keys = filters[key]
- if isinstance(filter_keys, dict):
- info[key] = _wrapper_dict(
- data[key], filter_keys.keys(),
- **filter_keys
- )
- else:
- info[key] = _wrapper_dict(
- data[key], filter_keys
- )
- else:
- info[key] = data[key]
- return info
- except Exception as error:
- logging.exception(error)
- raise error
-
-
-def replace_filters(**kwarg_mapping):
- """Decorator to replace kwargs.
-
- Examples:
- kwargs: {'a': 'b'}, kwarg_mapping: {'a': 'c'}
- replaced kwargs to decorated func:
- {'c': 'b'}
-
- replace_filters is used to replace caller's input
- to make it understandable by models.py.
- """
- def decorator(func):
- @functools.wraps(func)
- def wrapper(*args, **kwargs):
- replaced_kwargs = {}
- for key, value in kwargs.items():
- if key in kwarg_mapping:
- replaced_kwargs[kwarg_mapping[key]] = value
- else:
- replaced_kwargs[key] = value
- return func(*args, **replaced_kwargs)
- return wrapper
- return decorator
-
-
-def supported_filters(
- support_keys=[],
- optional_support_keys=[],
- ignore_support_keys=[],
-):
- """Decorator to check kwargs keys.
-
- keys in kwargs and in ignore_support_keys will be removed.
- If any unsupported keys found, a InvalidParameter
- exception raises.
-
- Args:
- support_keys: keys that must exist.
- optional_support_keys: keys that may exist.
- ignore_support_keys: keys should be ignored.
-
- Assumption: args without default value is supposed to exist.
- You can add them in support_keys or not but we will make sure
- it appears when we call the decorated function.
- We do best match on both args and kwargs to make sure if the
- key appears or not.
-
- Examples:
- decorated func: func(a, b, c=3, d=4, **kwargs)
-
- support_keys=['e'] and call func(e=5):
- raises: InvalidParameter: missing declared arg
- support_keys=['e'] and call func(1,2,3,4,5,e=6):
- raises: InvalidParameter: caller sending more args
- support_keys=['e'] and call func(1,2):
- raises: InvalidParameter: supported keys ['e'] missing
- support_keys=['d', 'e'] and call func(1,2,e=3):
- raises: InvalidParameter: supported keys ['d'] missing
- support_keys=['d', 'e'] and call func(1,2,d=4, e=3):
- passed
- support_keys=['d'], optional_support_keys=['e']
- and call func(1,2, d=3):
- passed
- support_keys=['d'], optional_support_keys=['e']
- and call func(1,2, d=3, e=4, f=5):
- raises: InvalidParameter: unsupported keys ['f']
- support_keys=['d'], optional_support_keys=['e'],
- ignore_support_keys=['f']
- and call func(1,2, d=3, e=4, f=5):
- passed to decorated keys: func(1,2, d=3, e=4)
- """
- def decorator(func):
- @functools.wraps(func)
- def wrapper(*args, **filters):
- wrapped_func = get_wrapped_func(func)
- argspec = inspect.getargspec(wrapped_func)
- wrapped_args = argspec.args
- args_defaults = argspec.defaults
- # wrapped_must_args are positional args caller must pass in.
- if args_defaults:
- wrapped_must_args = wrapped_args[:-len(args_defaults)]
- else:
- wrapped_must_args = wrapped_args[:]
- # make sure any positional args without default value in
- # decorated function should appear in args or filters.
- if len(args) < len(wrapped_must_args):
- remain_args = wrapped_must_args[len(args):]
- for remain_arg in remain_args:
- if remain_arg not in filters:
- raise exception.InvalidParameter(
- 'function missing declared arg %s '
- 'while caller sends args %s' % (
- remain_arg, args
- )
- )
- # make sure args should be no more than positional args
- # declared in decorated function.
- if len(args) > len(wrapped_args):
- raise exception.InvalidParameter(
- 'function definition args %s while the caller '
- 'sends args %s' % (
- wrapped_args, args
- )
- )
- # exist_args are positional args caller has given.
- exist_args = dict(zip(wrapped_args, args)).keys()
- must_support_keys = set(support_keys)
- all_support_keys = must_support_keys | set(optional_support_keys)
- wrapped_supported_keys = set(filters) | set(exist_args)
- unsupported_keys = (
- set(filters) - set(wrapped_args) -
- all_support_keys - set(ignore_support_keys)
- )
- # unsupported_keys are the keys that are not in support_keys,
- # optional_support_keys, ignore_support_keys and are not passed in
- # by positional args. It means the decorated function may
- # not understand these parameters.
- if unsupported_keys:
- raise exception.InvalidParameter(
- 'filter keys %s are not supported for %s' % (
- list(unsupported_keys), wrapped_func
- )
- )
- # missing_keys are the keys that must exist but missing in
- # both positional args or kwargs.
- missing_keys = must_support_keys - wrapped_supported_keys
- if missing_keys:
- raise exception.InvalidParameter(
- 'filter keys %s not found for %s' % (
- list(missing_keys), wrapped_func
- )
- )
- # We filter kwargs to eliminate ignore_support_keys in kwargs
- # passed to decorated function.
- filtered_filters = dict([
- (key, value)
- for key, value in filters.items()
- if key not in ignore_support_keys
- ])
- return func(*args, **filtered_filters)
- return wrapper
- return decorator
-
-
-def input_filters(
- **filters
-):
- """Decorator to filter kwargs.
-
- For key in kwargs, if the key exists and filters
- and the return of call filters[key] is False, the key
- will be removed from kwargs.
-
- The function definition of filters[key] is
- func(value, *args, **kwargs) compared with decorated
- function func(*args, **kwargs)
-
- The function is used to filter kwargs in case some
- kwargs should be removed conditionally depends on the
- related filters.
-
- Examples:
- filters={'a': func(value, *args, **kwargs)}
- @input_filters(**filters)
- decorated_func(*args, **kwargs)
- func returns False.
- Then when call decorated_func(a=1, b=2)
- it will be actually called the decorated func with
- b=2. a=1 will be removed since it does not pass filtering.
- """
- def decorator(func):
- @functools.wraps(func)
- def wrapper(*args, **kwargs):
- filtered_kwargs = {}
- for key, value in kwargs.items():
- if key in filters:
- if filters[key](value, *args, **kwargs):
- filtered_kwargs[key] = value
- else:
- logging.debug(
- 'ignore filtered input key %s' % key
- )
- else:
- filtered_kwargs[key] = value
- return func(*args, **filtered_kwargs)
- return wrapper
- return decorator
-
-
-def _obj_equal_or_subset(check, obj):
- """Used by output filter to check if obj is in check."""
- if check == obj:
- return True
- if not issubclass(obj.__class__, check.__class__):
- return False
- if isinstance(obj, dict):
- return _dict_equal_or_subset(check, obj)
- elif isinstance(obj, list):
- return _list_equal_or_subset(check, obj)
- else:
- return False
-
-
-def _list_equal_or_subset(check_list, obj_list):
- """Used by output filter to check if obj_list is in check_list"""
- if not isinstance(check_list, list):
- return False
- return set(check_list).issubset(set(obj_list))
-
-
-def _dict_equal_or_subset(check_dict, obj_dict):
- """Used by output filter to check if obj_dict in check_dict."""
- if not isinstance(check_dict, dict):
- return False
- for key, value in check_dict.items():
- if (
- key not in obj_dict or
- not _obj_equal_or_subset(check_dict[key], obj_dict[key])
- ):
- return False
- return True
-
-
-def general_filter_callback(general_filter, obj):
- """General filter function to filter output.
-
- Since some fields stored in database is json encoded and
- we want to do the deep match for the json encoded field to
- do the filtering in some cases, we introduces the output_filters
- and general_filter_callback to deal with this kind of cases.
-
- We do special treatment for key 'resp_eq' to check if
- obj is the recursively subset of general_filter['resp_eq']
-
-
- Example:
- obj: 'b'
- general_filter: {}
- returns: True
-
- obj: 'b'
- general_filter: {'resp_in': ['a', 'b']}
- returns: True
-
- obj: 'b'
- general_filter: {'resp_in': ['a']}
- returns: False
-
- obj: 'b'
- general_filter: {'resp_eq': 'b'}
- returns: True
-
- obj: 'b'
- general_filter: {'resp_eq': 'a'}
- returns: False
-
- obj: 'b'
- general_filter: {'resp_range': ('a', 'c')}
- returns: True
-
- obj: 'd'
- general_filter: {'resp_range': ('a', 'c')}
- returns: False
-
- If there are multi keys in dict, the output is filtered
- by and relationship.
-
- If the general_filter is a list, the output is filtered
- by or relationship.
-
- Supported general filters: [
- 'resp_eq', 'resp_in', 'resp_lt',
- 'resp_le', 'resp_gt', 'resp_ge',
- 'resp_match', 'resp_range'
- ]
- """
- if isinstance(general_filter, list):
- if not general_filter:
- return True
- return any([
- general_filter_callback(item, obj)
- for item in general_filter
- ])
- elif isinstance(general_filter, dict):
- if 'resp_eq' in general_filter:
- if not _obj_equal_or_subset(
- general_filter['resp_eq'], obj
- ):
- return False
- if 'resp_in' in general_filter:
- in_filters = general_filter['resp_in']
- if not any([
- _obj_equal_or_subset(in_filer, obj)
- for in_filer in in_filters
- ]):
- return False
- if 'resp_lt' in general_filter:
- if obj >= general_filter['resp_lt']:
- return False
- if 'resp_le' in general_filter:
- if obj > general_filter['resp_le']:
- return False
- if 'resp_gt' in general_filter:
- if obj <= general_filter['resp_gt']:
- return False
- if 'resp_ge' in general_filter:
- if obj < general_filter['resp_gt']:
- return False
- if 'resp_match' in general_filter:
- if not re.match(general_filter['resp_match'], obj):
- return False
- if 'resp_range' in general_filter:
- resp_range = general_filter['resp_range']
- if not isinstance(resp_range, list):
- resp_range = [resp_range]
- in_range = False
- for range_start, range_end in resp_range:
- if range_start <= obj <= range_end:
- in_range = True
- if not in_range:
- return False
- return True
- else:
- return True
-
-
-def filter_output(filter_callbacks, kwargs, obj, missing_ok=False):
- """Filter ouput.
-
- For each key in filter_callbacks, if it exists in kwargs,
- kwargs[key] tells what we need to filter. If the call of
- filter_callbacks[key] returns False, it tells the obj should be
- filtered out of output.
- """
- for callback_key, callback_value in filter_callbacks.items():
- if callback_key not in kwargs:
- continue
- if callback_key not in obj:
- if missing_ok:
- continue
- else:
- raise exception.InvalidResponse(
- '%s is not in %s' % (callback_key, obj)
- )
- if not callback_value(
- kwargs[callback_key], obj[callback_key]
- ):
- return False
- return True
-
-
-def output_filters(missing_ok=False, **filter_callbacks):
- """Decorator to filter output list.
-
- Each filter_callback should have the definition like:
- func({'resp_eq': 'a'}, 'a')
- """
- def decorator(func):
- @functools.wraps(func)
- def wrapper(*args, **kwargs):
- filtered_obj_list = []
- obj_list = func(*args, **kwargs)
- for obj in obj_list:
- if filter_output(
- filter_callbacks, kwargs, obj, missing_ok
- ):
- filtered_obj_list.append(obj)
- return filtered_obj_list
- return wrapper
- return decorator
-
-
-def _input_validates(args_validators, kwargs_validators, *args, **kwargs):
- """Used by input_validators to validate inputs."""
- for i, value in enumerate(args):
- if i < len(args_validators) and args_validators[i]:
- args_validators[i](value)
- for key, value in kwargs.items():
- if kwargs_validators.get(key):
- kwargs_validators[key](value)
-
-
-def input_validates(*args_validators, **kwargs_validators):
- """Decorator to validate input.
-
- Each validator should have definition like:
- func('00:01:02:03:04:05')
- """
- def decorator(func):
- @functools.wraps(func)
- def wrapper(*args, **kwargs):
- _input_validates(
- args_validators, kwargs_validators,
- *args, **kwargs
- )
- return func(*args, **kwargs)
- return wrapper
- return decorator
-
-
-def _input_validates_with_args(
- args_validators, kwargs_validators, *args, **kwargs
-):
- """Validate input with validators.
-
- Each validator takes the arguments of the decorated function
- as its arguments. The function definition is like:
- func(value, *args, **kwargs) compared with the decorated
- function func(*args, **kwargs).
- """
- for i, value in enumerate(args):
- if i < len(args_validators) and args_validators[i]:
- args_validators[i](value, *args, **kwargs)
- for key, value in kwargs.items():
- if kwargs_validators.get(key):
- kwargs_validators[key](value, *args, **kwargs)
-
-
-def input_validates_with_args(
- *args_validators, **kwargs_validators
-):
- """Decorator to validate input."""
- def decorator(func):
- @functools.wraps(func)
- def wrapper(*args, **kwargs):
- _input_validates_with_args(
- args_validators, kwargs_validators,
- *args, **kwargs
- )
- return func(*args, **kwargs)
- return wrapper
- return decorator
-
-
-def _output_validates_with_args(
- kwargs_validators, obj, *args, **kwargs
-):
- """Validate output with validators.
-
- Each validator takes the arguments of the decorated function
- as its arguments. The function definition is like:
- func(value, *args, **kwargs) compared with the decorated
- function func(*args, **kwargs).
- """
- if isinstance(obj, list):
- for item in obj:
- _output_validates_with_args(
- kwargs_validators, item, *args, **kwargs
- )
- return
- if isinstance(obj, models.HelperMixin):
- obj = obj.to_dict()
- if not isinstance(obj, dict):
- raise exception.InvalidResponse(
- 'response %s type is not dict' % str(obj)
- )
- try:
- for key, value in obj.items():
- if key in kwargs_validators:
- kwargs_validators[key](value, *args, **kwargs)
- except Exception as error:
- logging.exception(error)
- raise error
-
-
-def output_validates_with_args(**kwargs_validators):
- """Decorator to validate output.
-
- The validator can take the arguments of the decorated
- function as its arguments.
- """
- def decorator(func):
- @functools.wraps(func)
- def wrapper(*args, **kwargs):
- obj = func(*args, **kwargs)
- if isinstance(obj, list):
- for obj_item in obj:
- _output_validates_with_args(
- kwargs_validators, obj_item,
- *args, **kwargs
- )
- else:
- _output_validates_with_args(
- kwargs_validators, obj,
- *args, **kwargs
- )
- return obj
- return wrapper
- return decorator
-
-
-def _output_validates(kwargs_validators, obj):
- """Validate output.
-
- Each validator has following signature:
- func(value)
- """
- if isinstance(obj, list):
- for item in obj:
- _output_validates(kwargs_validators, item)
- return
- if isinstance(obj, models.HelperMixin):
- obj = obj.to_dict()
- if not isinstance(obj, dict):
- raise exception.InvalidResponse(
- 'response %s type is not dict' % str(obj)
- )
- try:
- for key, value in obj.items():
- if key in kwargs_validators:
- kwargs_validators[key](value)
- except Exception as error:
- logging.exception(error)
- raise error
-
-
-def output_validates(**kwargs_validators):
- """Decorator to validate output."""
- def decorator(func):
- @functools.wraps(func)
- def wrapper(*args, **kwargs):
- obj = func(*args, **kwargs)
- if isinstance(obj, list):
- for obj_item in obj:
- _output_validates(kwargs_validators, obj_item)
- else:
- _output_validates(kwargs_validators, obj)
- return obj
- return wrapper
- return decorator
-
-
-def get_db_object(session, table, exception_when_missing=True, **kwargs):
- """Get db object.
-
- If not exception_when_missing and the db object can not be found,
- return None instead of raising exception.
- """
- if not session:
- raise exception.DatabaseException('session param is None')
- with session.begin(subtransactions=True):
- logging.debug(
- 'session %s get db object %s from table %s',
- id(session), kwargs, table.__name__)
- db_object = model_filter(
- model_query(session, table), table, **kwargs
- ).first()
- logging.debug(
- 'session %s got db object %s', id(session), db_object
- )
- if db_object:
- return db_object
-
- if not exception_when_missing:
- return None
-
- raise exception.RecordNotExists(
- 'Cannot find the record in table %s: %s' % (
- table.__name__, kwargs
- )
- )
-
-
-def add_db_object(session, table, exception_when_existing=True,
- *args, **kwargs):
- """Create db object.
-
- If not exception_when_existing and the db object exists,
- Instead of raising exception, updating the existing db object.
- """
- if not session:
- raise exception.DatabaseException('session param is None')
- with session.begin(subtransactions=True):
- logging.debug(
- 'session %s add object %s atributes %s to table %s',
- id(session), args, kwargs, table.__name__)
- argspec = inspect.getargspec(table.__init__)
- arg_names = argspec.args[1:]
- arg_defaults = argspec.defaults
- if not arg_defaults:
- arg_defaults = []
- if not (
- len(arg_names) - len(arg_defaults) <= len(args) <= len(arg_names)
- ):
- raise exception.InvalidParameter(
- 'arg names %s does not match arg values %s' % (
- arg_names, args)
- )
- db_keys = dict(zip(arg_names, args))
- if db_keys:
- db_object = session.query(table).filter_by(**db_keys).first()
- else:
- db_object = None
-
- new_object = False
- if db_object:
- logging.debug(
- 'got db object %s: %s', db_keys, db_object
- )
- if exception_when_existing:
- raise exception.DuplicatedRecord(
- '%s exists in table %s' % (db_keys, table.__name__)
- )
- else:
- db_object = table(**db_keys)
- new_object = True
-
- for key, value in kwargs.items():
- setattr(db_object, key, value)
-
- if new_object:
- session.add(db_object)
- session.flush()
- db_object.initialize()
- db_object.validate()
- logging.debug(
- 'session %s db object %s added', id(session), db_object
- )
- return db_object
-
-
-def list_db_objects(session, table, order_by=[], **filters):
- """List db objects.
-
- If order by given, the db objects should be sorted by the ordered keys.
- """
- if not session:
- raise exception.DatabaseException('session param is None')
- with session.begin(subtransactions=True):
- logging.debug(
- 'session %s list db objects by filters %s in table %s',
- id(session), filters, table.__name__
- )
- db_objects = model_order_by(
- model_filter(
- model_query(session, table),
- table,
- **filters
- ),
- table,
- order_by
- ).all()
- logging.debug(
- 'session %s got listed db objects: %s',
- id(session), db_objects
- )
- return db_objects
-
-
-def del_db_objects(session, table, **filters):
- """delete db objects."""
- if not session:
- raise exception.DatabaseException('session param is None')
- with session.begin(subtransactions=True):
- logging.debug(
- 'session %s delete db objects by filters %s in table %s',
- id(session), filters, table.__name__
- )
- query = model_filter(
- model_query(session, table), table, **filters
- )
- db_objects = query.all()
- query.delete(synchronize_session=False)
- logging.debug(
- 'session %s db objects %s deleted', id(session), db_objects
- )
- return db_objects
-
-
-def update_db_objects(session, table, updates={}, **filters):
- """Update db objects."""
- if not session:
- raise exception.DatabaseException('session param is None')
- with session.begin(subtransactions=True):
- logging.debug(
- 'session %s update db objects by filters %s in table %s',
- id(session), filters, table.__name__)
- db_objects = model_filter(
- model_query(session, table), table, **filters
- ).all()
- for db_object in db_objects:
- logging.debug('update db object %s: %s', db_object, updates)
- update_db_object(session, db_object, **updates)
- logging.debug(
- 'session %s db objects %s updated',
- id(session), db_objects
- )
- return db_objects
-
-
-def update_db_object(session, db_object, **kwargs):
- """Update db object."""
- if not session:
- raise exception.DatabaseException('session param is None')
- with session.begin(subtransactions=True):
- logging.debug(
- 'session %s update db object %s by value %s',
- id(session), db_object, kwargs
- )
- for key, value in kwargs.items():
- setattr(db_object, key, value)
- session.flush()
- db_object.update()
- db_object.validate()
- logging.debug(
- 'session %s db object %s updated',
- id(session), db_object
- )
- return db_object
-
-
-def del_db_object(session, db_object):
- """Delete db object."""
- if not session:
- raise exception.DatabaseException('session param is None')
- with session.begin(subtransactions=True):
- logging.debug(
- 'session %s delete db object %s',
- id(session), db_object
- )
- session.delete(db_object)
- logging.debug(
- 'session %s db object %s deleted',
- id(session), db_object
- )
- return db_object
-
-
-def check_ip(ip):
- """Check ip is ip address formatted."""
- try:
- netaddr.IPAddress(ip)
- except Exception as error:
- logging.exception(error)
- raise exception.InvalidParameter(
- 'ip address %s format uncorrect' % ip
- )
-
-
-def check_mac(mac):
- """Check mac is mac address formatted."""
- try:
- netaddr.EUI(mac)
- except Exception as error:
- logging.exception(error)
- raise exception.InvalidParameter(
- 'invalid mac address %s' % mac
- )
-
-
-NAME_PATTERN = re.compile(r'[a-zA-Z0-9][a-zA-Z0-9_-]*')
-
-
-def check_name(name):
- """Check name meeting name format requirement."""
- if not NAME_PATTERN.match(name):
- raise exception.InvalidParameter(
- 'name %s does not match the pattern %s' % (
- name, NAME_PATTERN.pattern
- )
- )
-
-
-def _check_ipmi_credentials_ip(ip):
- check_ip(ip)
-
-
-def check_ipmi_credentials(ipmi_credentials):
- """Check ipmi credentials format is correct."""
- if not ipmi_credentials:
- return
- if not isinstance(ipmi_credentials, dict):
- raise exception.InvalidParameter(
- 'invalid ipmi credentials %s' % ipmi_credentials
-
- )
- for key in ipmi_credentials:
- if key not in ['ip', 'username', 'password']:
- raise exception.InvalidParameter(
- 'unrecognized field %s in ipmi credentials %s' % (
- key, ipmi_credentials
- )
- )
- for key in ['ip', 'username', 'password']:
- if key not in ipmi_credentials:
- raise exception.InvalidParameter(
- 'no field %s in ipmi credentials %s' % (
- key, ipmi_credentials
- )
- )
- check_ipmi_credential_field = '_check_ipmi_credentials_%s' % key
- this_module = globals()
- if check_ipmi_credential_field in this_module:
- this_module[check_ipmi_credential_field](
- ipmi_credentials[key]
- )
- else:
- logging.debug(
- 'function %s is not defined', check_ipmi_credential_field
- )
-
-
-def _check_switch_credentials_version(version):
- if version not in ['1', '2c', '3']:
- raise exception.InvalidParameter(
- 'unknown snmp version %s' % version
- )
-
-
-def check_switch_credentials(credentials):
- """Check switch credentials format is correct."""
- if not credentials:
- return
- if not isinstance(credentials, dict):
- raise exception.InvalidParameter(
- 'credentials %s is not dict' % credentials
- )
- for key in credentials:
- if key not in ['version', 'community']:
- raise exception.InvalidParameter(
- 'unrecognized key %s in credentials %s' % (key, credentials)
- )
- for key in ['version', 'community']:
- if key not in credentials:
- raise exception.InvalidParameter(
- 'there is no %s field in credentials %s' % (key, credentials)
- )
-
- key_check_func_name = '_check_switch_credentials_%s' % key
- this_module = globals()
- if key_check_func_name in this_module:
- this_module[key_check_func_name](
- credentials[key]
- )
- else:
- logging.debug(
- 'function %s is not defined',
- key_check_func_name
- )