Add the validation for /NetworkDriver.CreateNetwork
This patch adds the validation for /NetworkDriver.CreateNetwork with the JSON schema. This patch also introdueces the basic foundation for the following validations with JSON schemata. The common part of the scheamta is separated in commons.py and it's injected into each schema. Change-Id: I1cd849db2eeadb03b4488e1842fbd22e62fff169 Signed-off-by: Taku Fukushima <f.tac.mac@gmail.com>changes/49/336549/1
parent
c7e49bb878
commit
a1d65edb3f
|
@ -14,12 +14,14 @@ import os
|
|||
|
||||
from flask import jsonify
|
||||
from flask import request
|
||||
from jsonschema import validate
|
||||
import netaddr
|
||||
from neutronclient.common import exceptions as n_exceptions
|
||||
|
||||
from kuryr import app
|
||||
from kuryr.constants import SCHEMA
|
||||
from kuryr import exceptions
|
||||
from kuryr import schemata
|
||||
from kuryr import utils
|
||||
|
||||
|
||||
|
@ -198,7 +200,8 @@ def network_driver_create_network():
|
|||
json_data = request.get_json(force=True)
|
||||
app.logger.debug("Received JSON data {0} for /NetworkDriver.CreateNetwork"
|
||||
.format(json_data))
|
||||
# TODO(tfukushima): Add a validation of the JSON data for the network.
|
||||
validate(json_data, schemata.NETWORK_CREATE_SCHEMA)
|
||||
|
||||
neutron_network_name = json_data['NetworkID']
|
||||
|
||||
network = app.neutron.create_network(
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
# 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 kuryr.schemata.network_create import NETWORK_CREATE_SCHEMA # noqa
|
|
@ -0,0 +1,112 @@
|
|||
# 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.
|
||||
|
||||
COMMONS = {
|
||||
u'description': u'Common data schemata shared among other schemata.',
|
||||
u'links': [],
|
||||
u'title': u'Kuryr Common Data Schema Definitions',
|
||||
u'properties': {
|
||||
u'options': {u'$ref': u'/schemata/commons#/definitions/options'},
|
||||
u'mac': {u'$ref': u'/schemata/commons#/definitions/mac'},
|
||||
u'cidrv6': {u'$ref': u'/schemata/commons#/definitions/cidrv6'},
|
||||
u'interface': {u'$ref': u'/schemata/commons#/definitions/interface'},
|
||||
u'cidr': {u'$ref': u'/schemata/commons#/definitions/cidr'},
|
||||
u'id': {u'$ref': u'/schemata/commons#/definitions/id'}
|
||||
},
|
||||
u'definitions': {
|
||||
u'options': {
|
||||
u'type': u'object',
|
||||
u'description': u'Options.',
|
||||
u'example': {}
|
||||
},
|
||||
u'mac': {
|
||||
u'pattern': (u'^((?:[0-9a-f]{2}:){5}[0-9a-f]{2}|'
|
||||
u'(?:[0-9A-F]{2}:){5}[0-9A-F]{2})$'),
|
||||
u'type': u'string',
|
||||
u'description': u'A MAC address.',
|
||||
u'example': u'aa:bb:cc:dd:ee:ff'
|
||||
},
|
||||
u'cidrv6': {
|
||||
u'pattern': (u'^(('
|
||||
u'([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|'
|
||||
u'([0-9a-fA-F]{1,4}:){1,7}:|'
|
||||
u'([0-9a-fA-F]{1,4}:){1,6}\:[0-9a-fA-F]{1,4}|'
|
||||
u'([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|'
|
||||
u'([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|'
|
||||
u'([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|'
|
||||
u'([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|'
|
||||
u'[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|'
|
||||
u':((:[0-9a-fA-F]{1,4}){1,7}|:)|'
|
||||
u'fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|'
|
||||
u'::(ffff(:0{1,4}){0,1}:){0,1}'
|
||||
u'((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}'
|
||||
u'(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|'
|
||||
u'([0-9a-fA-F]{1,4}:){1,4}:'
|
||||
u'((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}'
|
||||
u'(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))'
|
||||
u'(/(1[0-2][0-8]|[1-9]?[0-9])))$'),
|
||||
u'type': u'string',
|
||||
u'description': u'A IPv6 CIDR of the subnet'
|
||||
},
|
||||
u'interface': {
|
||||
u'properties': {
|
||||
u'ID': {
|
||||
u'description': u'Index of the interface',
|
||||
u'type': u'number',
|
||||
},
|
||||
u'AddressIPv6': {
|
||||
u'description': u'IPv6 CIDR',
|
||||
u'$ref': u'#/definitions/commons/definitions/cidrv6'
|
||||
},
|
||||
u'MacAddress': {
|
||||
u'description': u'MAC address',
|
||||
u'$ref': u'#/definitions/commons/definitions/mac'
|
||||
},
|
||||
u'Address': {
|
||||
u'description': u'IPv4 CIDR',
|
||||
u'$ref': u'#/definitions/commons/definitions/cidr'
|
||||
}
|
||||
},
|
||||
u'type': u'object',
|
||||
u'description': u'Interface used in requests against Endpoints.',
|
||||
u'example': {
|
||||
u'AddressIPv6': u'fe80::f816:3eff:fe20:57c3/64',
|
||||
u'MacAddress': u'fa:16:3e:20:57:c3',
|
||||
u'Address': u'192.168.1.42/24'
|
||||
}
|
||||
},
|
||||
u'cidr': {
|
||||
u'pattern': (u'^((25[0-5]|2[0-4][0-9]|1?[0-9]?[0-9])\\.){3}'
|
||||
u'(25[0-5]|2[0-4][0-9]|1?[0-9]?[0-9])'
|
||||
u'/(3[0-2]|((1|2)?[0-9]))$'),
|
||||
u'type': u'string',
|
||||
u'description': u'A IPv4 CIDR of the subnet.',
|
||||
u'example': u'10.0.0.0/24'
|
||||
},
|
||||
u'id': {
|
||||
u'pattern': u'^([0-9a-f]{64})$',
|
||||
u'type': u'string',
|
||||
u'description': u'256 bits ID value of Docker.',
|
||||
u'example':
|
||||
u'51c75a2515d47edecc3f720bb541e287224416fb66715eb7802011d6ffd499f1'
|
||||
},
|
||||
u'sandbox_key': {
|
||||
u'pattern': u'^(/var/run/docker/netns/[0-9a-f]{12})$',
|
||||
u'type': u'string',
|
||||
u'description': u'Sandbox information of netns.',
|
||||
u'example': '/var/run/docker/netns/12bbda391ed0'
|
||||
}
|
||||
},
|
||||
u'$schema': u'http://json-schema.org/draft-04/hyper-schema',
|
||||
u'type': u'object',
|
||||
u'id': u'schemata/commons'
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
# 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 kuryr.schemata.commons import COMMONS
|
||||
|
||||
NETWORK_CREATE_SCHEMA = {
|
||||
u'links': [{
|
||||
u'method': u'POST',
|
||||
u'href': u'/NetworkDriver.CreateNetwork',
|
||||
u'description': u'Create a Network',
|
||||
u'rel': u'self',
|
||||
u'title': u'Create'
|
||||
}],
|
||||
u'title': u'Create network',
|
||||
u'required': [u'NetworkID'],
|
||||
u'definitions': {u'commons': {}},
|
||||
u'$schema': u'http://json-schema.org/draft-04/hyper-schema',
|
||||
u'type': u'object',
|
||||
u'properties': {
|
||||
u'NetworkID': {
|
||||
u'description': u'ID of a Network to be created',
|
||||
u'$ref': u'#/definitions/commons/definitions/id'
|
||||
},
|
||||
u'Options':
|
||||
{u'type': u'object',
|
||||
u'description': u'Options',
|
||||
u'example': {}}
|
||||
}
|
||||
}
|
||||
|
||||
NETWORK_CREATE_SCHEMA[u'definitions'][u'commons'] = COMMONS
|
|
@ -61,6 +61,17 @@ class TestKuryrNetworkCreateFailures(base.TestKuryrFailures):
|
|||
self.assertEqual(
|
||||
{'Err': exceptions.Unauthorized.message}, decoded_json)
|
||||
|
||||
def test_create_network_bad_request(self):
|
||||
invalid_docker_network_id = 'id-should-be-hexdigits'
|
||||
response = self._invoke_create_request(invalid_docker_network_id)
|
||||
|
||||
self.assertEqual(400, response.status_code)
|
||||
decoded_json = jsonutils.loads(response.data)
|
||||
self.assertTrue('Err' in decoded_json)
|
||||
# TODO(tfukushima): Add the better error message validation.
|
||||
self.assertTrue(invalid_docker_network_id in decoded_json['Err'])
|
||||
self.assertTrue('NetworkID' in decoded_json['Err'])
|
||||
|
||||
|
||||
@ddt
|
||||
class TestKuryrNetworkDeleteFailures(base.TestKuryrFailures):
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
# under the License.
|
||||
|
||||
from flask import Flask, jsonify
|
||||
from jsonschema import ValidationError
|
||||
from neutronclient.common.exceptions import NeutronClientException
|
||||
from neutronclient.neutron import client
|
||||
from neutronclient.v2_0 import client as client_v2
|
||||
|
@ -54,12 +55,16 @@ def make_json_app(import_name, **kwargs):
|
|||
app = Flask(import_name, **kwargs)
|
||||
|
||||
@app.errorhandler(NeutronClientException)
|
||||
@app.errorhandler(ValidationError)
|
||||
def make_json_error(ex):
|
||||
response = jsonify({"Err": str(ex)})
|
||||
response.status_code = (ex.code if isinstance(ex, HTTPException)
|
||||
else ex.status_code
|
||||
if isinstance(ex, NeutronClientException)
|
||||
else 500)
|
||||
response.status_code = 500
|
||||
if isinstance(ex, HTTPException):
|
||||
response.status_code = ex.code
|
||||
elif isinstance(ex, NeutronClientException):
|
||||
response.status_code = ex.status_code
|
||||
elif isinstance(ex, ValidationError):
|
||||
response.status_code = 400
|
||||
content_type = 'application/vnd.docker.plugins.v1+json; charset=utf-8'
|
||||
response.headers['Content-Type'] = content_type
|
||||
return response
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
pbr<2.0,>=1.3
|
||||
Babel>=1.3
|
||||
Flask>=0.10,<1.0
|
||||
jsonschema!=2.5.0,<3.0.0,>=2.0.0
|
||||
netaddr>=0.7.12
|
||||
oslo.serialization>=1.4.0 # Apache-2.0
|
||||
python-neutronclient>=2.3.11,<3
|
||||
|
|
Loading…
Reference in New Issue