5534c51281
Change-Id: I24f61adfdef269dceb72ba0c5f7d694cde527ce8
194 lines
6.0 KiB
Python
194 lines
6.0 KiB
Python
# Copyright (c) 2013 Mirantis Inc.
|
|
#
|
|
# 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 re
|
|
|
|
import jsonschema
|
|
from oslo_utils import uuidutils
|
|
import six
|
|
import six.moves.urllib.parse as urlparse
|
|
|
|
from sahara.swift import utils as su
|
|
from sahara.utils.openstack import manila as m
|
|
|
|
|
|
@jsonschema.FormatChecker.cls_checks('valid_name_hostname')
|
|
def validate_name_hostname_format(entry):
|
|
if not isinstance(entry, six.string_types) or not entry:
|
|
# should fail type or length validation
|
|
return True
|
|
|
|
res = re.match(r"^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]"
|
|
r"*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z]"
|
|
r"[A-Za-z0-9\-]*[A-Za-z0-9])$", entry)
|
|
return res is not None
|
|
|
|
|
|
@jsonschema.FormatChecker.cls_checks('valid_name')
|
|
def validate_name_format(entry):
|
|
if not isinstance(entry, six.string_types):
|
|
# should fail type validation
|
|
return True
|
|
|
|
res = re.match(r"^[a-zA-Z0-9][a-zA-Z0-9\-_\.]*$", entry)
|
|
return res is not None
|
|
|
|
|
|
@jsonschema.FormatChecker.cls_checks('valid_keypair_name')
|
|
def validate_keypair_name_format(entry):
|
|
if not isinstance(entry, six.string_types):
|
|
# should fail type validation
|
|
return True
|
|
|
|
# this follows the validation put forth by nova for keypair names
|
|
res = re.match(r'^[a-zA-Z0-9\-_ ]+$', entry)
|
|
return res is not None
|
|
|
|
|
|
@jsonschema.FormatChecker.cls_checks('valid_job_location')
|
|
def validate_job_location_format(entry):
|
|
if not isinstance(entry, six.string_types):
|
|
# should fail type validation
|
|
return True
|
|
|
|
if entry.startswith('internal-db://'):
|
|
return uuidutils.is_uuid_like(entry[len("internal-db://"):])
|
|
|
|
if entry.startswith(su.SWIFT_INTERNAL_PREFIX):
|
|
# TODO(nprivalova):add hostname validation
|
|
return True
|
|
|
|
if entry.startswith(m.MANILA_PREFIX):
|
|
url = urlparse.urlparse(entry)
|
|
if (uuidutils.is_uuid_like(url.netloc) and
|
|
len(url.path) > 1):
|
|
return True
|
|
return False
|
|
|
|
|
|
@jsonschema.FormatChecker.cls_checks('valid_tag')
|
|
def validate_valid_tag_format(entry):
|
|
if not isinstance(entry, six.string_types):
|
|
# should fail type validation
|
|
return True
|
|
|
|
res = re.match(r"^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-_]"
|
|
r"*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9]"
|
|
r"[A-Za-z0-9\-_]*[A-Za-z0-9])$", entry)
|
|
return res is not None
|
|
|
|
|
|
@jsonschema.FormatChecker.cls_checks('uuid')
|
|
def validate_uuid_format(entry):
|
|
if not isinstance(entry, six.string_types):
|
|
# should fail type validation
|
|
return True
|
|
|
|
return uuidutils.is_uuid_like(entry)
|
|
|
|
|
|
@jsonschema.FormatChecker.cls_checks('posix_path')
|
|
def validate_posix_path(entry):
|
|
if not isinstance(entry, six.string_types):
|
|
# should fail type validation
|
|
return True
|
|
|
|
res = re.match("^(/([A-Z]|[a-z]|[0-9]|\-|_)+)+$", entry)
|
|
return res is not None
|
|
|
|
|
|
class ConfigTypeMeta(type):
|
|
def __instancecheck__(cls, instance):
|
|
# configs should be dict
|
|
if not isinstance(instance, dict):
|
|
return False
|
|
|
|
# check dict content
|
|
for applicable_target, configs in six.iteritems(instance):
|
|
# upper-level dict keys (applicable targets) should be strings
|
|
if not isinstance(applicable_target, six.string_types):
|
|
return False
|
|
|
|
# upper-level dict values should be dicts
|
|
if not isinstance(configs, dict):
|
|
return False
|
|
|
|
# check internal dict content
|
|
for config_name, config_value in six.iteritems(configs):
|
|
# internal dict keys should be strings
|
|
if not isinstance(config_name, six.string_types):
|
|
return False
|
|
|
|
# internal dict values should be strings or integers or bools
|
|
if not isinstance(config_value,
|
|
(six.string_types, six.integer_types)):
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
class SimpleConfigTypeMeta(type):
|
|
def __instancecheck__(cls, instance):
|
|
# configs should be dict
|
|
if not isinstance(instance, dict):
|
|
return False
|
|
|
|
# check dict content
|
|
for conf_name, conf_value in six.iteritems(instance):
|
|
# keys should be strings, values should be int, string or bool
|
|
if not isinstance(conf_name, six.string_types):
|
|
return False
|
|
if not isinstance(conf_value,
|
|
(six.string_types, six.integer_types)):
|
|
return False
|
|
return True
|
|
|
|
|
|
@six.add_metaclass(ConfigTypeMeta)
|
|
class ConfigsType(dict):
|
|
pass
|
|
|
|
|
|
@six.add_metaclass(SimpleConfigTypeMeta)
|
|
class SimpleConfigsType(dict):
|
|
pass
|
|
|
|
|
|
class FlavorTypeMeta(type):
|
|
def __instancecheck__(cls, instance):
|
|
try:
|
|
int(instance)
|
|
except (ValueError, TypeError):
|
|
return (isinstance(instance, six.string_types)
|
|
and uuidutils.is_uuid_like(instance))
|
|
return (isinstance(instance, six.integer_types + six.string_types)
|
|
and type(instance) != bool)
|
|
|
|
|
|
@six.add_metaclass(FlavorTypeMeta)
|
|
class FlavorType(object):
|
|
pass
|
|
|
|
|
|
class ApiValidator(jsonschema.Draft4Validator):
|
|
def __init__(self, schema):
|
|
format_checker = jsonschema.FormatChecker()
|
|
super(ApiValidator, self).__init__(
|
|
schema, format_checker=format_checker, types={
|
|
"configs": ConfigsType,
|
|
"flavor": FlavorType,
|
|
"simple_config": SimpleConfigsType,
|
|
})
|