Refactoring: Drop all the code except common one
Related patchset in kuryr-libnetwork: https://review.openstack.org/#/c/337350/ Implements blueprint code-refactoring Change-Id: I91a402a159817462535e77296217a9dd7eb0fd08
This commit is contained in:
parent
f6c8674bdb
commit
47490acec9
|
@ -1,4 +0,0 @@
|
||||||
{
|
|
||||||
"Name": "kuryr",
|
|
||||||
"Addr": "http://127.0.0.1:2377"
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
http://127.0.0.1:2377
|
|
|
@ -1,16 +0,0 @@
|
||||||
# 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 import utils
|
|
||||||
|
|
||||||
|
|
||||||
app = utils.make_json_app(__name__)
|
|
1356
kuryr/controllers.py
1356
kuryr/controllers.py
File diff suppressed because it is too large
Load Diff
|
@ -17,9 +17,9 @@ from oslo_concurrency import processutils
|
||||||
from oslo_utils import excutils
|
from oslo_utils import excutils
|
||||||
import pyroute2
|
import pyroute2
|
||||||
|
|
||||||
from kuryr.common import config
|
from kuryr.lib import config
|
||||||
from kuryr.common import exceptions
|
from kuryr.lib import exceptions
|
||||||
from kuryr import utils
|
from kuryr.lib import utils
|
||||||
|
|
||||||
|
|
||||||
BINDING_SUBCOMMAND = 'bind'
|
BINDING_SUBCOMMAND = 'bind'
|
|
@ -19,8 +19,8 @@ import os
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
|
|
||||||
from kuryr._i18n import _
|
from kuryr.lib._i18n import _
|
||||||
from kuryr import version
|
from kuryr.lib import version
|
||||||
|
|
||||||
|
|
||||||
core_opts = [
|
core_opts = [
|
|
@ -19,7 +19,7 @@ import itertools
|
||||||
|
|
||||||
from oslo_log import _options
|
from oslo_log import _options
|
||||||
|
|
||||||
from kuryr.common import config
|
from kuryr.lib import config
|
||||||
|
|
||||||
|
|
||||||
_core_opts_with_logging = config.core_opts
|
_core_opts_with_logging = config.core_opts
|
|
@ -11,25 +11,14 @@
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import os
|
|
||||||
import random
|
import random
|
||||||
import socket
|
import socket
|
||||||
import sys
|
|
||||||
import traceback
|
|
||||||
|
|
||||||
import flask
|
|
||||||
import jsonschema
|
|
||||||
|
|
||||||
from neutronclient.common import exceptions as n_exceptions
|
|
||||||
from neutronclient.neutron import client
|
from neutronclient.neutron import client
|
||||||
from neutronclient.v2_0 import client as client_v2
|
from neutronclient.v2_0 import client as client_v2
|
||||||
from oslo_concurrency import processutils
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from werkzeug import exceptions as w_exceptions
|
|
||||||
|
|
||||||
from kuryr._i18n import _LE
|
from kuryr.lib import constants as const
|
||||||
from kuryr.common import constants as const
|
|
||||||
from kuryr.common import exceptions
|
|
||||||
|
|
||||||
DOCKER_NETNS_BASE = '/var/run/docker/netns'
|
DOCKER_NETNS_BASE = '/var/run/docker/netns'
|
||||||
PORT_POSTFIX = 'port'
|
PORT_POSTFIX = 'port'
|
||||||
|
@ -50,64 +39,9 @@ def get_neutron_client(url, username, tenant_name, password,
|
||||||
ca_cert=ca_cert, insecure=insecure)
|
ca_cert=ca_cert, insecure=insecure)
|
||||||
|
|
||||||
|
|
||||||
# Return all errors as JSON. From http://flask.pocoo.org/snippets/83/
|
def get_hostname():
|
||||||
def make_json_app(import_name, **kwargs):
|
"""Returns the host name."""
|
||||||
"""Creates a JSON-oriented Flask app.
|
return socket.gethostname()
|
||||||
|
|
||||||
All error responses that you don't specifically manage yourself will have
|
|
||||||
application/json content type, and will contain JSON that follows the
|
|
||||||
libnetwork remote driver protocol.
|
|
||||||
|
|
||||||
|
|
||||||
{ "Err": "405: Method Not Allowed" }
|
|
||||||
|
|
||||||
|
|
||||||
See:
|
|
||||||
- https://github.com/docker/libnetwork/blob/3c8e06bc0580a2a1b2440fe0792fbfcd43a9feca/docs/remote.md#errors # noqa
|
|
||||||
"""
|
|
||||||
app = flask.Flask(import_name, **kwargs)
|
|
||||||
|
|
||||||
@app.errorhandler(exceptions.KuryrException)
|
|
||||||
@app.errorhandler(n_exceptions.NeutronClientException)
|
|
||||||
@app.errorhandler(jsonschema.ValidationError)
|
|
||||||
@app.errorhandler(processutils.ProcessExecutionError)
|
|
||||||
def make_json_error(ex):
|
|
||||||
app.logger.error(_LE("Unexpected error happened: %s"), ex)
|
|
||||||
traceback.print_exc(file=sys.stderr)
|
|
||||||
response = flask.jsonify({"Err": str(ex)})
|
|
||||||
response.status_code = w_exceptions.InternalServerError.code
|
|
||||||
if isinstance(ex, w_exceptions.HTTPException):
|
|
||||||
response.status_code = ex.code
|
|
||||||
elif isinstance(ex, n_exceptions.NeutronClientException):
|
|
||||||
response.status_code = ex.status_code
|
|
||||||
elif isinstance(ex, jsonschema.ValidationError):
|
|
||||||
response.status_code = w_exceptions.BadRequest.code
|
|
||||||
content_type = 'application/vnd.docker.plugins.v1+json; charset=utf-8'
|
|
||||||
response.headers['Content-Type'] = content_type
|
|
||||||
return response
|
|
||||||
|
|
||||||
for code in w_exceptions.default_exceptions:
|
|
||||||
app.register_error_handler(code, make_json_error)
|
|
||||||
|
|
||||||
return app
|
|
||||||
|
|
||||||
|
|
||||||
def get_sandbox_key(container_id):
|
|
||||||
"""Returns a sandbox key constructed with the given container ID.
|
|
||||||
|
|
||||||
:param container_id: the ID of the Docker container as string
|
|
||||||
:returns: the constructed sandbox key as string
|
|
||||||
"""
|
|
||||||
return os.path.join(DOCKER_NETNS_BASE, container_id[:12])
|
|
||||||
|
|
||||||
|
|
||||||
def get_neutron_port_name(docker_endpoint_id):
|
|
||||||
"""Returns a Neutron port name.
|
|
||||||
|
|
||||||
:param docker_endpoint_id: the EndpointID
|
|
||||||
:returns: the Neutron port name formatted appropriately
|
|
||||||
"""
|
|
||||||
return '-'.join([docker_endpoint_id, PORT_POSTFIX])
|
|
||||||
|
|
||||||
|
|
||||||
def get_veth_pair_names(port_id):
|
def get_veth_pair_names(port_id):
|
||||||
|
@ -118,11 +52,6 @@ def get_veth_pair_names(port_id):
|
||||||
return ifname, peer_name
|
return ifname, peer_name
|
||||||
|
|
||||||
|
|
||||||
def get_hostname():
|
|
||||||
"""Returns the host name."""
|
|
||||||
return socket.gethostname()
|
|
||||||
|
|
||||||
|
|
||||||
def get_neutron_subnetpool_name(subnet_cidr):
|
def get_neutron_subnetpool_name(subnet_cidr):
|
||||||
"""Returns a Neutron subnetpool name.
|
"""Returns a Neutron subnetpool name.
|
||||||
|
|
||||||
|
@ -162,26 +91,6 @@ def get_hash(bit_size=256):
|
||||||
return hashlib.sha256(getrandbits(bit_size=bit_size)).hexdigest()
|
return hashlib.sha256(getrandbits(bit_size=bit_size)).hexdigest()
|
||||||
|
|
||||||
|
|
||||||
def create_net_tags(tag):
|
|
||||||
tags = []
|
|
||||||
tags.append(const.NEUTRON_ID_LH_OPTION + ':' + tag[:32])
|
|
||||||
if len(tag) > 32:
|
|
||||||
tags.append(const.NEUTRON_ID_UH_OPTION + ':' + tag[32:64])
|
|
||||||
|
|
||||||
return tags
|
|
||||||
|
|
||||||
|
|
||||||
def make_net_tags(tag):
|
|
||||||
tags = create_net_tags(tag)
|
|
||||||
return ','.join(map(str, tags))
|
|
||||||
|
|
||||||
|
|
||||||
def make_net_name(netid, tags=True):
|
|
||||||
if tags:
|
|
||||||
return const.NET_NAME_PREFIX + netid[:8]
|
|
||||||
return netid
|
|
||||||
|
|
||||||
|
|
||||||
def string_mappings(mapping_list):
|
def string_mappings(mapping_list):
|
||||||
"""Make a string out of the mapping list"""
|
"""Make a string out of the mapping list"""
|
||||||
details = ''
|
details = ''
|
|
@ -1,35 +0,0 @@
|
||||||
# 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 import endpoint_create
|
|
||||||
from kuryr.schemata import endpoint_delete
|
|
||||||
from kuryr.schemata import join
|
|
||||||
from kuryr.schemata import leave
|
|
||||||
from kuryr.schemata import network_create
|
|
||||||
from kuryr.schemata import network_delete
|
|
||||||
from kuryr.schemata import release_address
|
|
||||||
from kuryr.schemata import release_pool
|
|
||||||
from kuryr.schemata import request_address
|
|
||||||
from kuryr.schemata import request_pool
|
|
||||||
|
|
||||||
|
|
||||||
# Aliases for schemata in each module
|
|
||||||
ENDPOINT_CREATE_SCHEMA = endpoint_create.ENDPOINT_CREATE_SCHEMA
|
|
||||||
ENDPOINT_DELETE_SCHEMA = endpoint_delete.ENDPOINT_DELETE_SCHEMA
|
|
||||||
JOIN_SCHEMA = join.JOIN_SCHEMA
|
|
||||||
LEAVE_SCHEMA = leave.LEAVE_SCHEMA
|
|
||||||
NETWORK_CREATE_SCHEMA = network_create.NETWORK_CREATE_SCHEMA
|
|
||||||
NETWORK_DELETE_SCHEMA = network_delete.NETWORK_DELETE_SCHEMA
|
|
||||||
RELEASE_ADDRESS_SCHEMA = release_address.RELEASE_ADDRESS_SCHEMA
|
|
||||||
RELEASE_POOL_SCHEMA = release_pool.RELEASE_POOL_SCHEMA
|
|
||||||
REQUEST_ADDRESS_SCHEMA = request_address.REQUEST_ADDRESS_SCHEMA
|
|
||||||
REQUEST_POOL_SCHEMA = request_pool.REQUEST_POOL_SCHEMA
|
|
|
@ -1,249 +0,0 @@
|
||||||
# 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.
|
|
||||||
|
|
||||||
EPSILON_PATTERN = '^$'
|
|
||||||
IPV4_PATTERN_BASE = (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])')
|
|
||||||
IPV4_PATTERN = EPSILON_PATTERN + u'|^' + IPV4_PATTERN_BASE + u'$'
|
|
||||||
CIDRV4_PATTERN = EPSILON_PATTERN + '|^(' + IPV4_PATTERN_BASE + \
|
|
||||||
u'(/(1[0-2][0-8]|[1-9]?[0-9]))' + u')$'
|
|
||||||
|
|
||||||
IPV6_PATTERN_BASE = (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]))')
|
|
||||||
IPV6_PATTERN = EPSILON_PATTERN + u'|^' + IPV6_PATTERN_BASE + u'$'
|
|
||||||
CIDRV6_PATTERN = EPSILON_PATTERN + u'|^(' + IPV6_PATTERN_BASE + \
|
|
||||||
u'(/(1[0-2][0-8]|[1-9]?[0-9]))' + u')$'
|
|
||||||
IPV4_OR_IPV6_PATTERN = IPV4_PATTERN + u'|^' + IPV6_PATTERN_BASE + u'$'
|
|
||||||
UUID_BASE = u'^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'
|
|
||||||
UUID_PATTERN = EPSILON_PATTERN + u'|' + UUID_BASE
|
|
||||||
|
|
||||||
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'uuid': {u'$ref': u'/schemata/commons#/definitions/uuid'},
|
|
||||||
u'ipv4': {u'$ref': u'/schemata/commons#/definitions/ipv4'},
|
|
||||||
u'ipv4_or_ipv6': {
|
|
||||||
u'$ref': u'/schemata/commons#/definitions/ipv4_or_ipv6'}
|
|
||||||
},
|
|
||||||
u'definitions': {
|
|
||||||
u'options': {
|
|
||||||
u'type': [u'object', u'null'],
|
|
||||||
u'description': u'Options.',
|
|
||||||
u'example': {}
|
|
||||||
},
|
|
||||||
u'mac': {
|
|
||||||
u'pattern': (EPSILON_PATTERN + u'|'
|
|
||||||
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': CIDRV6_PATTERN,
|
|
||||||
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'null'],
|
|
||||||
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': CIDRV4_PATTERN,
|
|
||||||
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'ipv4': {
|
|
||||||
u'pattern': IPV4_PATTERN,
|
|
||||||
u'type': u'string',
|
|
||||||
u'description': u'An IPv4 address',
|
|
||||||
u'example': u'10.0.0.1'
|
|
||||||
},
|
|
||||||
u'ipv4datum': {
|
|
||||||
u'description': u'IPv4 data',
|
|
||||||
u'required': [
|
|
||||||
u'AddressSpace', u'Pool'],
|
|
||||||
u'type': u'object',
|
|
||||||
u'example': {
|
|
||||||
u'AddressSpace': u'foo',
|
|
||||||
u'Pool': u'192.168.42.0/24',
|
|
||||||
u'Gateway': u'192.168.42.1/24',
|
|
||||||
u'AuxAddresses': {
|
|
||||||
u'web': u'192.168.42.2',
|
|
||||||
u'db': u'192.168.42.3'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
u'properties': {
|
|
||||||
u'AddressSpace': {
|
|
||||||
u'description': u'The name of the address space.',
|
|
||||||
u'type': u'string',
|
|
||||||
u'example': u'foo',
|
|
||||||
},
|
|
||||||
u'Pool': {
|
|
||||||
u'description': u'A range of IP Addresses requested in '
|
|
||||||
u'CIDR format address/mask.',
|
|
||||||
u'$ref': u'#/definitions/commons/definitions/cidr'
|
|
||||||
},
|
|
||||||
u'Gateway': {
|
|
||||||
u'description': u'Optionally, the IPAM driver may provide '
|
|
||||||
u'a Gateway for the subnet represented by '
|
|
||||||
u'the Pool.',
|
|
||||||
u'$ref': u'#/definitions/commons/definitions/cidr',
|
|
||||||
},
|
|
||||||
u'AuxAddresses': {
|
|
||||||
u'description': u'A list of pre-allocated ip-addresses '
|
|
||||||
u'with an associated identifier as '
|
|
||||||
u'provided by the user to assist network '
|
|
||||||
u'driver if it requires specific '
|
|
||||||
u'ip-addresses for its operation.',
|
|
||||||
u'type': u'object',
|
|
||||||
u'patternProperties': {
|
|
||||||
u'.+': {
|
|
||||||
u'description': u'key-value pair of the ID and '
|
|
||||||
u'the IP address',
|
|
||||||
u'$ref': u'#/definitions/commons/definitions/ipv4'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
u'ipv6': {
|
|
||||||
u'pattern': IPV6_PATTERN,
|
|
||||||
u'type': u'string',
|
|
||||||
u'description': u'An IPv6 address.',
|
|
||||||
u'example': u'fe80::f816:3eff:fe20:57c4'
|
|
||||||
},
|
|
||||||
u'ipv6datum': {
|
|
||||||
u'description': u'IPv6 data',
|
|
||||||
u'required': [
|
|
||||||
u'AddressSpace', u'Pool', u'Gateway'],
|
|
||||||
u'type': u'object',
|
|
||||||
u'example': {
|
|
||||||
u'AddressCpace': u'bar',
|
|
||||||
u'Pool': u'fe80::/64',
|
|
||||||
u'Gateway': u'fe80::f816:3eff:fe20:57c3/64',
|
|
||||||
u'AuxAddresses': {
|
|
||||||
u'web': u'fe80::f816:3eff:fe20:57c4',
|
|
||||||
u'db': u'fe80::f816:3eff:fe20:57c5'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
u'properties': {
|
|
||||||
u'AddressSpace': {
|
|
||||||
u'description': u'The name of the address space.',
|
|
||||||
u'type': u'string',
|
|
||||||
u'example': u'foo',
|
|
||||||
},
|
|
||||||
u'Pool': {
|
|
||||||
u'description': u'A range of IP Addresses requested in '
|
|
||||||
u'CIDR format address/mask.',
|
|
||||||
u'$ref': u'#/definitions/commons/definitions/cidrv6'
|
|
||||||
},
|
|
||||||
u'Gateway': {
|
|
||||||
u'description': u'Optionally, the IPAM driver may provide '
|
|
||||||
u'a Gateway for the subnet represented by '
|
|
||||||
u'the Pool.',
|
|
||||||
u'$ref': u'#/definitions/commons/definitions/cidrv6',
|
|
||||||
},
|
|
||||||
u'AuxAddresses': {
|
|
||||||
u'description': u'A list of pre-allocated ip-addresses '
|
|
||||||
u'with an associated identifier as '
|
|
||||||
u'provided by the user to assist network '
|
|
||||||
u'driver if it requires specific '
|
|
||||||
u'ip-addresses for its operation.',
|
|
||||||
u'type': u'object',
|
|
||||||
u'patternProperties': {
|
|
||||||
u'.+': {
|
|
||||||
u'description': u'key-vavule pair of the ID and '
|
|
||||||
u'the IP address',
|
|
||||||
u'$ref': u'#/definitions/commons/definitions/ipv6'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
u'ipv4_or_ipv6': {
|
|
||||||
u'pattern': IPV4_OR_IPV6_PATTERN,
|
|
||||||
u'type': u'string',
|
|
||||||
u'description': u'An IPv4 or IPv6 address.',
|
|
||||||
u'example': u'fe80::f816:3eff:fe20:57c4'
|
|
||||||
},
|
|
||||||
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'uuid': {
|
|
||||||
u'pattern': UUID_PATTERN,
|
|
||||||
u'type': u'string',
|
|
||||||
u'description': u'uuid of neutron resources.',
|
|
||||||
u'example': 'dfe39822-ad5e-40bd-babd-3954113b3687'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
u'$schema': u'http://json-schema.org/draft-04/hyper-schema',
|
|
||||||
u'type': u'object',
|
|
||||||
u'id': u'schemata/commons'
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
# 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 import commons
|
|
||||||
|
|
||||||
ENDPOINT_CREATE_SCHEMA = {
|
|
||||||
u'links': [{
|
|
||||||
u'method': u'POST',
|
|
||||||
u'href': u'/NetworkDriver.CreateEndpoint',
|
|
||||||
u'description': u'Create an Endpoint',
|
|
||||||
u'rel': u'self',
|
|
||||||
u'title': u'Create'
|
|
||||||
}],
|
|
||||||
u'title': u'Create endpoint',
|
|
||||||
u'required': [u'NetworkID', u'EndpointID', u'Options', u'Interface'],
|
|
||||||
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'Network ID',
|
|
||||||
u'$ref': u'#/definitions/commons/definitions/id'
|
|
||||||
},
|
|
||||||
u'Interface': {
|
|
||||||
u'$ref': u'#/definitions/commons/definitions/interface',
|
|
||||||
u'description': u'Interface information'
|
|
||||||
},
|
|
||||||
u'Options': {
|
|
||||||
u'description': u'Options',
|
|
||||||
u'$ref': u'#/definitions/commons/definitions/options'
|
|
||||||
},
|
|
||||||
u'EndpointID': {
|
|
||||||
u'description': u'Endpoint ID',
|
|
||||||
u'$ref': u'#/definitions/commons/definitions/id'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ENDPOINT_CREATE_SCHEMA[u'definitions'][u'commons'] = commons.COMMONS
|
|
|
@ -1,40 +0,0 @@
|
||||||
# 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 import commons
|
|
||||||
|
|
||||||
ENDPOINT_DELETE_SCHEMA = {
|
|
||||||
u'links': [{
|
|
||||||
u'method': u'POST',
|
|
||||||
u'href': u'/NetworkDriver.DeleteEndpoint',
|
|
||||||
u'description': u'Delete an Endpoint',
|
|
||||||
u'rel': u'self',
|
|
||||||
u'title': u'Delete'
|
|
||||||
}],
|
|
||||||
u'title': u'Delete endpoint',
|
|
||||||
u'required': [u'NetworkID', u'EndpointID'],
|
|
||||||
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'Network ID',
|
|
||||||
u'$ref': u'#/definitions/commons/definitions/id'
|
|
||||||
},
|
|
||||||
u'EndpointID': {
|
|
||||||
u'description': u'Endpoint ID',
|
|
||||||
u'$ref': u'#/definitions/commons/definitions/id'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ENDPOINT_DELETE_SCHEMA[u'definitions'][u'commons'] = commons.COMMONS
|
|
|
@ -1,52 +0,0 @@
|
||||||
# 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
|
|
||||||
|
|
||||||
|
|
||||||
JOIN_SCHEMA = {
|
|
||||||
u'links': [{
|
|
||||||
u'method': u'POST',
|
|
||||||
u'href': u'/NetworkDriver.Join',
|
|
||||||
u'description': u'Join the network',
|
|
||||||
u'rel': u'self',
|
|
||||||
u'title': u'Create'
|
|
||||||
}],
|
|
||||||
u'title': u'Join endpoint',
|
|
||||||
u'required': [
|
|
||||||
u'NetworkID',
|
|
||||||
u'EndpointID',
|
|
||||||
u'SandboxKey'
|
|
||||||
],
|
|
||||||
u'properties': {
|
|
||||||
u'NetworkID': {
|
|
||||||
u'description': u'Network ID',
|
|
||||||
u'$ref': u'#/definitions/commons/definitions/id'
|
|
||||||
},
|
|
||||||
u'SandboxKey': {
|
|
||||||
u'description': u'Sandbox Key',
|
|
||||||
u'$ref': u'#/definitions/commons/definitions/sandbox_key'
|
|
||||||
},
|
|
||||||
u'Options': {
|
|
||||||
u'$ref': u'#/definitions/commons/definitions/options'
|
|
||||||
},
|
|
||||||
u'EndpointID': {
|
|
||||||
u'description': u'Endpoint ID',
|
|
||||||
u'$ref': u'#/definitions/commons/definitions/id'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
u'definitions': {u'commons': {}},
|
|
||||||
u'$schema': u'http://json-schema.org/draft-04/hyper-schema',
|
|
||||||
u'type': u'object',
|
|
||||||
}
|
|
||||||
|
|
||||||
JOIN_SCHEMA[u'definitions'][u'commons'] = COMMONS
|
|
|
@ -1,24 +0,0 @@
|
||||||
# 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 import endpoint_delete
|
|
||||||
|
|
||||||
|
|
||||||
LEAVE_SCHEMA = endpoint_delete.ENDPOINT_DELETE_SCHEMA
|
|
||||||
LEAVE_SCHEMA[u'title'] = u'Leave endpoint'
|
|
||||||
LEAVE_SCHEMA[u'links'] = [{
|
|
||||||
u'method': u'POST',
|
|
||||||
u'href': u'/NetworkDriver.Leave',
|
|
||||||
u'description': u'Unbinds the endpoint from the container.',
|
|
||||||
u'rel': u'self',
|
|
||||||
u'title': u'Leave'
|
|
||||||
}]
|
|
|
@ -1,55 +0,0 @@
|
||||||
# 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 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'IPv4Data', u'IPv6Data'],
|
|
||||||
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'IPv4Data': {
|
|
||||||
u'description': u'IPv4 data for the network',
|
|
||||||
u'type': u'array',
|
|
||||||
u'items': {
|
|
||||||
u'$ref': u'#/definitions/commons/definitions/ipv4datum'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
u'IPv6Data': {
|
|
||||||
u'description': u'IPv6 data for the network',
|
|
||||||
u'type': u'array',
|
|
||||||
u'items': {
|
|
||||||
u'$ref': u'#/definitions/commons/definitions/ipv6datum'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
u'Options': {
|
|
||||||
u'type': [u'object', u'null'],
|
|
||||||
u'description': u'Options',
|
|
||||||
u'example': {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NETWORK_CREATE_SCHEMA[u'definitions'][u'commons'] = commons.COMMONS
|
|
|
@ -1,36 +0,0 @@
|
||||||
# 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 import commons
|
|
||||||
|
|
||||||
NETWORK_DELETE_SCHEMA = {
|
|
||||||
u'links': [{
|
|
||||||
u'method': u'POST',
|
|
||||||
u'href': u'/NetworkDriver.DeleteNetwork',
|
|
||||||
u'description': u'Delete a Network',
|
|
||||||
u'rel': u'self',
|
|
||||||
u'title': u'Delete'
|
|
||||||
}],
|
|
||||||
u'title': u'Delete 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 the Network ID to be deleted',
|
|
||||||
u'$ref': u'#/definitions/commons/definitions/id'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NETWORK_DELETE_SCHEMA[u'definitions'][u'commons'] = commons.COMMONS
|
|
|
@ -1,41 +0,0 @@
|
||||||
# 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 import commons
|
|
||||||
|
|
||||||
RELEASE_ADDRESS_SCHEMA = {
|
|
||||||
u'links': [{
|
|
||||||
u'method': u'POST',
|
|
||||||
u'href': u'/IpamDriver.ReleaseAddress',
|
|
||||||
u'description': u'Release an ip address',
|
|
||||||
u'rel': u'self',
|
|
||||||
u'title': u'Release'
|
|
||||||
}],
|
|
||||||
u'title': u'Release an IP',
|
|
||||||
u'required': [u'PoolID', u'Address'],
|
|
||||||
u'definitions': {u'commons': {}},
|
|
||||||
u'$schema': u'http://json-schema.org/draft-04/hyper-schema',
|
|
||||||
u'type': u'object',
|
|
||||||
u'properties': {
|
|
||||||
u'PoolID': {
|
|
||||||
u'description': u'neutron uuid of allocated subnetpool',
|
|
||||||
u'$ref': u'#/definitions/commons/definitions/uuid'
|
|
||||||
},
|
|
||||||
u'Address': {
|
|
||||||
u'description': u'Address in IP(v4 or v6) form',
|
|
||||||
u'$ref': u'#/definitions/commons/definitions/ipv4_or_ipv6'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
RELEASE_ADDRESS_SCHEMA[u'definitions'][u'commons'] = commons.COMMONS
|
|
|
@ -1,36 +0,0 @@
|
||||||
# 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 import commons
|
|
||||||
|
|
||||||
RELEASE_POOL_SCHEMA = {
|
|
||||||
u'links': [{
|
|
||||||
u'method': u'POST',
|
|
||||||
u'href': u'/IpamDriver.ReleasePool',
|
|
||||||
u'description': u'Release an ip pool',
|
|
||||||
u'rel': u'self',
|
|
||||||
u'title': u'Release'
|
|
||||||
}],
|
|
||||||
u'title': u'Release an IP pool',
|
|
||||||
u'required': [u'PoolID'],
|
|
||||||
u'definitions': {u'commons': {}},
|
|
||||||
u'$schema': u'http://json-schema.org/draft-04/hyper-schema',
|
|
||||||
u'type': u'object',
|
|
||||||
u'properties': {
|
|
||||||
u'PoolID': {
|
|
||||||
u'description': u'neutron ID of allocated subnetpool',
|
|
||||||
u'$ref': u'#/definitions/commons/definitions/uuid'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RELEASE_POOL_SCHEMA[u'definitions'][u'commons'] = commons.COMMONS
|
|
|
@ -1,47 +0,0 @@
|
||||||
# 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 import commons
|
|
||||||
|
|
||||||
REQUEST_ADDRESS_SCHEMA = {
|
|
||||||
u'links': [{
|
|
||||||
u'method': u'POST',
|
|
||||||
u'href': u'/IpamDriver.RequestAddress',
|
|
||||||
u'description': u'Allocate an ip addresses',
|
|
||||||
u'rel': u'self',
|
|
||||||
u'title': u'Create'
|
|
||||||
}],
|
|
||||||
u'title': u'Create an IP',
|
|
||||||
u'required': [u'PoolID', u'Address', u'Options'],
|
|
||||||
u'definitions': {u'commons': {}},
|
|
||||||
u'$schema': u'http://json-schema.org/draft-04/hyper-schema',
|
|
||||||
u'type': u'object',
|
|
||||||
u'properties': {
|
|
||||||
u'PoolID': {
|
|
||||||
u'description': u'neutron uuid of allocated subnetpool',
|
|
||||||
u'$ref': u'#/definitions/commons/definitions/uuid'
|
|
||||||
},
|
|
||||||
u'Address': {
|
|
||||||
u'description': u'Preferred address in regular IP form.',
|
|
||||||
u'example': u'10.0.0.1',
|
|
||||||
u'$ref': u'#/definitions/commons/definitions/ipv4_or_ipv6'
|
|
||||||
},
|
|
||||||
u'Options': {
|
|
||||||
u'type': [u'object', u'null'],
|
|
||||||
u'description': u'Options',
|
|
||||||
u'example': {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
REQUEST_ADDRESS_SCHEMA[u'definitions'][u'commons'] = commons.COMMONS
|
|
|
@ -1,58 +0,0 @@
|
||||||
# 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 import commons
|
|
||||||
|
|
||||||
REQUEST_POOL_SCHEMA = {
|
|
||||||
u'links': [{
|
|
||||||
u'method': u'POST',
|
|
||||||
u'href': u'/IpamDriver.RequestPool',
|
|
||||||
u'description': u'Allocate pool of ip addresses',
|
|
||||||
u'rel': u'self',
|
|
||||||
u'title': u'Create'
|
|
||||||
}],
|
|
||||||
u'title': u'Create pool',
|
|
||||||
u'required': [u'AddressSpace', u'Pool', u'SubPool', u'V6'],
|
|
||||||
u'definitions': {u'commons': {}},
|
|
||||||
u'$schema': u'http://json-schema.org/draft-04/hyper-schema',
|
|
||||||
u'type': u'object',
|
|
||||||
u'properties': {
|
|
||||||
u'AddressSpace': {
|
|
||||||
u'description': u'The name of the address space.',
|
|
||||||
u'type': u'string',
|
|
||||||
u'example': u'foo',
|
|
||||||
},
|
|
||||||
u'Pool': {
|
|
||||||
u'description': u'A range of IP Addresses represented in '
|
|
||||||
u'CIDR format address/mask.',
|
|
||||||
u'$ref': u'#/definitions/commons/definitions/cidr'
|
|
||||||
},
|
|
||||||
u'SubPool': {
|
|
||||||
u'description': u'A subset of IP range from Pool in'
|
|
||||||
u'CIDR format address/mask.',
|
|
||||||
u'$ref': u'#/definitions/commons/definitions/cidr'
|
|
||||||
},
|
|
||||||
u'Options': {
|
|
||||||
u'type': [u'object', u'null'],
|
|
||||||
u'description': u'Options',
|
|
||||||
u'example': {},
|
|
||||||
},
|
|
||||||
u'V6': {
|
|
||||||
u'description': u'If set to "True", requesting IPv6 pool and '
|
|
||||||
u'vice-versa.',
|
|
||||||
u'type': u'boolean',
|
|
||||||
u'example': False
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
REQUEST_POOL_SCHEMA[u'definitions'][u'commons'] = commons.COMMONS
|
|
|
@ -1,36 +0,0 @@
|
||||||
# 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 sys
|
|
||||||
|
|
||||||
from oslo_log import log
|
|
||||||
|
|
||||||
from kuryr import app
|
|
||||||
from kuryr.common import config
|
|
||||||
from kuryr import controllers
|
|
||||||
|
|
||||||
|
|
||||||
config.init(sys.argv[1:])
|
|
||||||
controllers.neutron_client()
|
|
||||||
controllers.check_for_neutron_ext_support()
|
|
||||||
controllers.check_for_neutron_ext_tag()
|
|
||||||
|
|
||||||
log.setup(config.CONF, 'Kuryr')
|
|
||||||
|
|
||||||
|
|
||||||
def start():
|
|
||||||
port = int(config.CONF.kuryr_uri.split(':')[-1])
|
|
||||||
app.run("0.0.0.0", port)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
start()
|
|
|
@ -2,9 +2,9 @@
|
||||||
|
|
||||||
set -ex
|
set -ex
|
||||||
|
|
||||||
VENV=${1:-"fullstack"}
|
VENV=${1:-"debug-py27"}
|
||||||
|
|
||||||
GATE_DEST=$BASE/new
|
GATE_DEST=$BASE/new
|
||||||
DEVSTACK_PATH=$GATE_DEST/devstack
|
DEVSTACK_PATH=$GATE_DEST/devstack
|
||||||
|
|
||||||
$BASE/new/devstack-gate/devstack-vm-gate.sh
|
$BASE/new/devstack-gate/devstack-vm-gate.sh
|
||||||
|
|
|
@ -6,7 +6,7 @@ KURYR_DIR="$BASE/new/kuryr"
|
||||||
TEMPEST_DIR="$BASE/new/tempest"
|
TEMPEST_DIR="$BASE/new/tempest"
|
||||||
SCRIPTS_DIR="/usr/os-testr-env/bin/"
|
SCRIPTS_DIR="/usr/os-testr-env/bin/"
|
||||||
|
|
||||||
venv=${1:-"fullstack"}
|
venv=${1:-"debug-py27"}
|
||||||
|
|
||||||
function generate_test_logs {
|
function generate_test_logs {
|
||||||
local path="$1"
|
local path="$1"
|
||||||
|
@ -57,4 +57,4 @@ set -e
|
||||||
|
|
||||||
# Collect and parse results
|
# Collect and parse results
|
||||||
generate_testr_results
|
generate_testr_results
|
||||||
exit $testr_exit_code
|
exit $testr_exit_code
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
# 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 docker
|
|
||||||
|
|
||||||
from oslotest import base
|
|
||||||
|
|
||||||
from kuryr import controllers
|
|
||||||
|
|
||||||
|
|
||||||
class KuryrBaseTest(base.BaseTestCase):
|
|
||||||
"""Basic class for Kuryr fullstack testing
|
|
||||||
|
|
||||||
This class has common code shared for Kuryr fullstack testing
|
|
||||||
including the various clients (docker, neutron) and common
|
|
||||||
setup/cleanup code.
|
|
||||||
"""
|
|
||||||
def setUp(self):
|
|
||||||
super(KuryrBaseTest, self).setUp()
|
|
||||||
self.docker_client = docker.Client(
|
|
||||||
base_url='tcp://0.0.0.0:2375')
|
|
||||||
self.neutron_client = controllers.get_neutron_client()
|
|
|
@ -1,88 +0,0 @@
|
||||||
# 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.tests.fullstack import kuryr_base
|
|
||||||
from kuryr import utils
|
|
||||||
|
|
||||||
|
|
||||||
class ContainerTest(kuryr_base.KuryrBaseTest):
|
|
||||||
"""Test Container related operations
|
|
||||||
|
|
||||||
Test container connect/disconnect from docker to Neutron
|
|
||||||
"""
|
|
||||||
def setUp(self):
|
|
||||||
super(ContainerTest, self).setUp()
|
|
||||||
self.docker_client.pull(repository='busybox', tag='1')
|
|
||||||
|
|
||||||
fake_ipam = {
|
|
||||||
"Driver": "kuryr",
|
|
||||||
"Options": {},
|
|
||||||
"Config": [
|
|
||||||
{
|
|
||||||
"Subnet": "10.3.0.0/16",
|
|
||||||
"IPRange": "10.3.0.0/24",
|
|
||||||
"Gateway": "10.3.0.1"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
net_name = utils.get_random_string(8)
|
|
||||||
res = self.docker_client.create_network(name=net_name,
|
|
||||||
driver='kuryr',
|
|
||||||
ipam=fake_ipam)
|
|
||||||
self.net_id = res.get('Id')
|
|
||||||
|
|
||||||
networks = self.neutron_client.list_networks(
|
|
||||||
tags=utils.make_net_tags(self.net_id))
|
|
||||||
self.assertEqual(1, len(networks['networks']))
|
|
||||||
self.neutron_net_id = networks['networks'][0]['id']
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
self.docker_client.remove_network(self.net_id)
|
|
||||||
networks = self.neutron_client.list_networks(
|
|
||||||
tags=utils.make_net_tags(self.net_id))
|
|
||||||
self.assertEqual(0, len(networks['networks']))
|
|
||||||
super(ContainerTest, self).tearDown()
|
|
||||||
|
|
||||||
def test_connect_disconnect_container(self):
|
|
||||||
# Test if support connect/disconnect operations
|
|
||||||
container_name = utils.get_random_string(8)
|
|
||||||
container = self.docker_client.create_container(
|
|
||||||
image='busybox:1',
|
|
||||||
command='/bin/sleep 600',
|
|
||||||
hostname='kuryr_test_container',
|
|
||||||
name=container_name)
|
|
||||||
warn_msg = container.get('Warning')
|
|
||||||
container_id = container.get('Id')
|
|
||||||
self.assertIsNone(warn_msg, 'Warn in creating container')
|
|
||||||
self.assertIsNotNone(container_id, 'Create container id must not '
|
|
||||||
'be None')
|
|
||||||
self.docker_client.start(container=container_id)
|
|
||||||
self.docker_client.connect_container_to_network(container_id,
|
|
||||||
self.net_id)
|
|
||||||
ports = self.neutron_client.list_ports(
|
|
||||||
network_id=self.neutron_net_id)
|
|
||||||
# A dhcp port gets created as well; dhcp is enabled by default
|
|
||||||
self.assertEqual(2, len(ports['ports']))
|
|
||||||
self.docker_client.disconnect_container_from_network(container_id,
|
|
||||||
self.net_id)
|
|
||||||
ports = self.neutron_client.list_ports(
|
|
||||||
network_id=self.neutron_net_id)
|
|
||||||
self.assertEqual(1, len(ports['ports']))
|
|
||||||
self.docker_client.stop(container=container_id)
|
|
||||||
|
|
||||||
# TODO(banix) Stopping the container is enough for the
|
|
||||||
# container to get disconnected from the network. Therefore,
|
|
||||||
# the following is not necessary for this test. The problem
|
|
||||||
# with removing container is not related to the networking
|
|
||||||
# but we should find out how the container can be removed.
|
|
||||||
# self.docker_client.remove_container(container=container_id,
|
|
||||||
# force=True)
|
|
|
@ -1,125 +0,0 @@
|
||||||
# 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.tests.fullstack import kuryr_base
|
|
||||||
from kuryr import utils
|
|
||||||
|
|
||||||
|
|
||||||
class NetworkTest(kuryr_base.KuryrBaseTest):
|
|
||||||
"""Test Networks operation
|
|
||||||
|
|
||||||
Test networks creation/deletion from docker to Neutron
|
|
||||||
"""
|
|
||||||
def test_create_delete_network_with_kuryr_driver(self):
|
|
||||||
"""Create and Delete docker network with Kuryr
|
|
||||||
|
|
||||||
This method creates a docker network with Kuryr driver
|
|
||||||
and tests it was created in Neutron.
|
|
||||||
It then deletes the docker network and tests that it was
|
|
||||||
deleted from Neutron.
|
|
||||||
"""
|
|
||||||
fake_ipam = {
|
|
||||||
"Driver": "kuryr",
|
|
||||||
"Options": {},
|
|
||||||
"Config": [
|
|
||||||
{
|
|
||||||
"Subnet": "10.0.0.0/16",
|
|
||||||
"IPRange": "10.0.0.0/24",
|
|
||||||
"Gateway": "10.0.0.1"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
net_name = utils.get_random_string(8)
|
|
||||||
res = self.docker_client.create_network(name=net_name, driver='kuryr',
|
|
||||||
ipam=fake_ipam)
|
|
||||||
net_id = res['Id']
|
|
||||||
network = self.neutron_client.list_networks(
|
|
||||||
tags=utils.make_net_tags(net_id))
|
|
||||||
self.assertEqual(1, len(network['networks']))
|
|
||||||
self.docker_client.remove_network(net_id)
|
|
||||||
network = self.neutron_client.list_networks(
|
|
||||||
tags=utils.make_net_tags(net_id))
|
|
||||||
self.assertEqual(0, len(network['networks']))
|
|
||||||
|
|
||||||
def test_create_delete_network_without_kuryr_driver(self):
|
|
||||||
"""Create and Delete docker network without Kuryr
|
|
||||||
|
|
||||||
This method create a docker network with the default
|
|
||||||
docker driver, It tests that it was created correctly, but
|
|
||||||
not added to Neutron
|
|
||||||
"""
|
|
||||||
net_name = utils.get_random_string(8)
|
|
||||||
res = self.docker_client.create_network(name=net_name)
|
|
||||||
net_id = res['Id']
|
|
||||||
network = self.neutron_client.list_networks(
|
|
||||||
tags=utils.make_net_tags(net_id))
|
|
||||||
self.assertEqual(0, len(network['networks']))
|
|
||||||
docker_networks = self.docker_client.networks()
|
|
||||||
network_found = False
|
|
||||||
for docker_net in docker_networks:
|
|
||||||
if docker_net['Id'] == net_id:
|
|
||||||
network_found = True
|
|
||||||
self.assertTrue(network_found)
|
|
||||||
self.docker_client.remove_network(net_id)
|
|
||||||
|
|
||||||
def test_create_network_with_same_name(self):
|
|
||||||
"""Create docker network with same name
|
|
||||||
|
|
||||||
Create two docker networks with same name,
|
|
||||||
delete them and see that neutron networks are
|
|
||||||
deleted as well
|
|
||||||
"""
|
|
||||||
fake_ipam_1 = {
|
|
||||||
"Driver": "kuryr",
|
|
||||||
"Options": {},
|
|
||||||
"Config": [
|
|
||||||
{
|
|
||||||
"Subnet": "10.1.0.0/16",
|
|
||||||
"IPRange": "10.1.0.0/24",
|
|
||||||
"Gateway": "10.1.0.1"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
fake_ipam_2 = {
|
|
||||||
"Driver": "kuryr",
|
|
||||||
"Options": {},
|
|
||||||
"Config": [
|
|
||||||
{
|
|
||||||
"Subnet": "10.2.0.0/16",
|
|
||||||
"IPRange": "10.2.0.0/24",
|
|
||||||
"Gateway": "10.2.0.1"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
net_name = utils.get_random_string(8)
|
|
||||||
res = self.docker_client.create_network(name=net_name, driver='kuryr',
|
|
||||||
ipam=fake_ipam_1)
|
|
||||||
net_id1 = res['Id']
|
|
||||||
|
|
||||||
res = self.docker_client.create_network(name=net_name, driver='kuryr',
|
|
||||||
ipam=fake_ipam_2)
|
|
||||||
net_id2 = res['Id']
|
|
||||||
network = self.neutron_client.list_networks(
|
|
||||||
tags=utils.make_net_tags(net_id1))
|
|
||||||
self.assertEqual(1, len(network['networks']))
|
|
||||||
network = self.neutron_client.list_networks(
|
|
||||||
tags=utils.make_net_tags(net_id2))
|
|
||||||
self.assertEqual(1, len(network['networks']))
|
|
||||||
self.docker_client.remove_network(net_id1)
|
|
||||||
self.docker_client.remove_network(net_id2)
|
|
||||||
network = self.neutron_client.list_networks(
|
|
||||||
tags=utils.make_net_tags(net_id1))
|
|
||||||
self.assertEqual(0, len(network['networks']))
|
|
||||||
network = self.neutron_client.list_networks(
|
|
||||||
tags=utils.make_net_tags(net_id2))
|
|
||||||
self.assertEqual(0, len(network['networks']))
|
|
|
@ -10,274 +10,11 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from neutronclient.tests.unit import test_cli20
|
from oslotest import base
|
||||||
|
|
||||||
from kuryr import app
|
|
||||||
from kuryr import binding
|
|
||||||
from kuryr.common import constants as const
|
|
||||||
from kuryr import controllers
|
|
||||||
from kuryr import utils
|
|
||||||
|
|
||||||
|
|
||||||
class TestCase(test_cli20.CLITestV20Base):
|
class TestCase(base.BaseTestCase):
|
||||||
"""Test case base class for all unit tests."""
|
"""Test case base class for all unit tests."""
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestCase, self).setUp()
|
super(TestCase, self).setUp()
|
||||||
app.config['DEBUG'] = True
|
|
||||||
app.config['TESTING'] = True
|
|
||||||
self.app = app.test_client()
|
|
||||||
self.app.neutron = self.client
|
|
||||||
app.tag = True
|
|
||||||
|
|
||||||
|
|
||||||
class TestKuryrBase(TestCase):
|
|
||||||
"""Base class for all Kuryr unittests."""
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(TestKuryrBase, self).setUp()
|
|
||||||
controllers.neutron_client()
|
|
||||||
self.app.neutron.format = 'json'
|
|
||||||
self.addCleanup(self.mox.VerifyAll)
|
|
||||||
self.addCleanup(self.mox.UnsetStubs)
|
|
||||||
if hasattr(app, 'DEFAULT_POOL_IDS'):
|
|
||||||
del app.DEFAULT_POOL_IDS
|
|
||||||
|
|
||||||
def _mock_out_binding(self, endpoint_id, neutron_port, neutron_subnets):
|
|
||||||
self.mox.StubOutWithMock(binding, 'port_bind')
|
|
||||||
fake_binding_response = (
|
|
||||||
'fake-veth', 'fake-veth_c', ('fake stdout', ''))
|
|
||||||
binding.port_bind(endpoint_id, neutron_port,
|
|
||||||
neutron_subnets).AndReturn(fake_binding_response)
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
return fake_binding_response
|
|
||||||
|
|
||||||
def _mock_out_unbinding(self, endpoint_id, neutron_port):
|
|
||||||
self.mox.StubOutWithMock(binding, 'port_unbind')
|
|
||||||
fake_unbinding_response = ('fake stdout', '')
|
|
||||||
binding.port_unbind(endpoint_id, neutron_port).AndReturn(
|
|
||||||
fake_unbinding_response)
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
return fake_unbinding_response
|
|
||||||
|
|
||||||
def _mock_out_network(self, neutron_network_id, docker_network_id,
|
|
||||||
check_existing=False):
|
|
||||||
no_networks_response = {
|
|
||||||
"networks": []
|
|
||||||
}
|
|
||||||
fake_list_response = {
|
|
||||||
"networks": [{
|
|
||||||
"status": "ACTIVE",
|
|
||||||
"subnets": [],
|
|
||||||
"admin_state_up": True,
|
|
||||||
"tenant_id": "9bacb3c5d39d41a79512987f338cf177",
|
|
||||||
"router:external": False,
|
|
||||||
"segments": [],
|
|
||||||
"shared": False,
|
|
||||||
"id": neutron_network_id
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_networks')
|
|
||||||
t = utils.make_net_tags(docker_network_id)
|
|
||||||
if check_existing:
|
|
||||||
te = t + ',' + const.KURYR_EXISTING_NEUTRON_NET
|
|
||||||
app.neutron.list_networks(tags=te).AndReturn(
|
|
||||||
no_networks_response)
|
|
||||||
app.neutron.list_networks(tags=t).AndReturn(fake_list_response)
|
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
return neutron_network_id
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _get_fake_v4_subnetpools(subnetpool_id, prefixes=["192.168.1.0/24"],
|
|
||||||
name="kuryr"):
|
|
||||||
# The following fake response is retrieved from the Neutron doc:
|
|
||||||
# http://developer.openstack.org/api-ref-networking-v2-ext.html#listSubnetPools # noqa
|
|
||||||
v4_subnetpools = {
|
|
||||||
"subnetpools": [{
|
|
||||||
"min_prefixlen": "24",
|
|
||||||
"address_scope_id": None,
|
|
||||||
"default_prefixlen": "24",
|
|
||||||
"id": subnetpool_id,
|
|
||||||
"max_prefixlen": "24",
|
|
||||||
"name": name,
|
|
||||||
"default_quota": None,
|
|
||||||
"tenant_id": "9fadcee8aa7c40cdb2114fff7d569c08",
|
|
||||||
"prefixes": prefixes,
|
|
||||||
"ip_version": 4,
|
|
||||||
"shared": False
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
|
|
||||||
return v4_subnetpools
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _get_fake_v6_subnetpools(subnetpool_id, prefixes=['fe80::/64']):
|
|
||||||
# The following fake response is retrieved from the Neutron doc:
|
|
||||||
# http://developer.openstack.org/api-ref-networking-v2-ext.html#listSubnetPools # noqa
|
|
||||||
v6_subnetpools = {
|
|
||||||
"subnetpools": [{
|
|
||||||
"min_prefixlen": "64",
|
|
||||||
"address_scope_id": None,
|
|
||||||
"default_prefixlen": "64",
|
|
||||||
"id": subnetpool_id,
|
|
||||||
"max_prefixlen": "64",
|
|
||||||
"name": "kuryr6",
|
|
||||||
"default_quota": None,
|
|
||||||
"tenant_id": "9fadcee8aa7c40cdb2114fff7d569c08",
|
|
||||||
"prefixes": prefixes,
|
|
||||||
"ip_version": 6,
|
|
||||||
"shared": False
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
|
|
||||||
return v6_subnetpools
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _get_fake_subnets(docker_endpoint_id, neutron_network_id,
|
|
||||||
fake_neutron_subnet_v4_id,
|
|
||||||
fake_neutron_subnet_v6_id):
|
|
||||||
# The following fake response is retrieved from the Neutron doc:
|
|
||||||
# http://developer.openstack.org/api-ref-networking-v2.html#createSubnet # noqa
|
|
||||||
fake_subnet_response = {
|
|
||||||
"subnets": [
|
|
||||||
{"name": '-'.join([docker_endpoint_id, '192.168.1.0']),
|
|
||||||
"network_id": neutron_network_id,
|
|
||||||
"tenant_id": "c1210485b2424d48804aad5d39c61b8f",
|
|
||||||
"allocation_pools": [{"start": "192.168.1.2",
|
|
||||||
"end": "192.168.1.254"}],
|
|
||||||
"gateway_ip": "192.168.1.1",
|
|
||||||
"ip_version": 4,
|
|
||||||
"cidr": "192.168.1.0/24",
|
|
||||||
"id": fake_neutron_subnet_v4_id,
|
|
||||||
"enable_dhcp": True,
|
|
||||||
"subnetpool_id": ''},
|
|
||||||
{"name": '-'.join([docker_endpoint_id, 'fe80::']),
|
|
||||||
"network_id": neutron_network_id,
|
|
||||||
"tenant_id": "c1210485b2424d48804aad5d39c61b8f",
|
|
||||||
"allocation_pools": [{"start": "fe80::f816:3eff:fe20:57c4",
|
|
||||||
"end": "fe80::ffff:ffff:ffff:ffff"}],
|
|
||||||
"gateway_ip": "fe80::f816:3eff:fe20:57c3",
|
|
||||||
"ip_version": 6,
|
|
||||||
"cidr": "fe80::/64",
|
|
||||||
"id": fake_neutron_subnet_v6_id,
|
|
||||||
"enable_dhcp": True,
|
|
||||||
"subnetpool_id": ''}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
return fake_subnet_response
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _get_fake_port(docker_endpoint_id, neutron_network_id,
|
|
||||||
neutron_port_id,
|
|
||||||
neutron_port_status=const.PORT_STATUS_DOWN,
|
|
||||||
neutron_subnet_v4_id=None,
|
|
||||||
neutron_subnet_v6_id=None,
|
|
||||||
neutron_subnet_v4_address="192.168.1.2",
|
|
||||||
neutron_subnet_v6_address="fe80::f816:3eff:fe20:57c4"):
|
|
||||||
# The following fake response is retrieved from the Neutron doc:
|
|
||||||
# http://developer.openstack.org/api-ref-networking-v2.html#createPort # noqa
|
|
||||||
fake_port = {
|
|
||||||
'port': {
|
|
||||||
"status": neutron_port_status,
|
|
||||||
"name": utils.get_neutron_port_name(docker_endpoint_id),
|
|
||||||
"allowed_address_pairs": [],
|
|
||||||
"admin_state_up": True,
|
|
||||||
"network_id": neutron_network_id,
|
|
||||||
"tenant_id": "d6700c0c9ffa4f1cb322cd4a1f3906fa",
|
|
||||||
"device_owner": "",
|
|
||||||
"mac_address": "fa:16:3e:20:57:c3",
|
|
||||||
"fixed_ips": [],
|
|
||||||
"id": neutron_port_id,
|
|
||||||
"security_groups": [],
|
|
||||||
"device_id": ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if neutron_subnet_v4_id:
|
|
||||||
fake_port['port']['fixed_ips'].append({
|
|
||||||
"subnet_id": neutron_subnet_v4_id,
|
|
||||||
"ip_address": neutron_subnet_v4_address
|
|
||||||
})
|
|
||||||
if neutron_subnet_v6_id:
|
|
||||||
fake_port['port']['fixed_ips'].append({
|
|
||||||
"subnet_id": neutron_subnet_v6_id,
|
|
||||||
"ip_address": neutron_subnet_v6_address
|
|
||||||
})
|
|
||||||
return fake_port
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _get_fake_ports(cls, docker_endpoint_id, neutron_network_id,
|
|
||||||
fake_neutron_port_id, neutron_port_status,
|
|
||||||
fake_neutron_subnet_v4_id, fake_neutron_subnet_v6_id):
|
|
||||||
fake_port = cls._get_fake_port(
|
|
||||||
docker_endpoint_id, neutron_network_id,
|
|
||||||
fake_neutron_port_id, neutron_port_status,
|
|
||||||
fake_neutron_subnet_v4_id, fake_neutron_subnet_v6_id)
|
|
||||||
fake_port = fake_port['port']
|
|
||||||
fake_ports = {
|
|
||||||
'ports': [
|
|
||||||
fake_port
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
return fake_ports
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _get_fake_v4_subnet(neutron_network_id, docker_endpoint_id=None,
|
|
||||||
subnet_v4_id=None, subnetpool_id=None,
|
|
||||||
cidr='192.168.1.0/24',
|
|
||||||
name=None):
|
|
||||||
if not name:
|
|
||||||
name = str('-'.join([docker_endpoint_id,
|
|
||||||
'192.168.1.0']))
|
|
||||||
fake_v4_subnet = {
|
|
||||||
'subnet': {
|
|
||||||
"name": name,
|
|
||||||
"network_id": neutron_network_id,
|
|
||||||
"tenant_id": "c1210485b2424d48804aad5d39c61b8f",
|
|
||||||
"allocation_pools": [{
|
|
||||||
"start": "192.168.1.2",
|
|
||||||
"end": "192.168.1.254"
|
|
||||||
}],
|
|
||||||
"gateway_ip": "192.168.1.1",
|
|
||||||
"ip_version": 4,
|
|
||||||
"cidr": '192.168.1.0/24',
|
|
||||||
"id": subnet_v4_id,
|
|
||||||
"enable_dhcp": True,
|
|
||||||
"subnetpool_id": ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if subnetpool_id:
|
|
||||||
fake_v4_subnet['subnet'].update(subnetpool_id=subnetpool_id)
|
|
||||||
|
|
||||||
return fake_v4_subnet
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _get_fake_v6_subnet(docker_network_id, docker_endpoint_id,
|
|
||||||
subnet_v6_id, subnetpool_id=None):
|
|
||||||
fake_v6_subnet = {
|
|
||||||
'subnet': {
|
|
||||||
"name": '-'.join([docker_endpoint_id,
|
|
||||||
'fe80::']),
|
|
||||||
"network_id": docker_network_id,
|
|
||||||
"tenant_id": "c1210485b2424d48804aad5d39c61b8f",
|
|
||||||
"allocation_pools": [{
|
|
||||||
"start": "fe80::f816:3eff:fe20:57c4",
|
|
||||||
"end": "fe80::ffff:ffff:ffff:ffff"
|
|
||||||
}],
|
|
||||||
"gateway_ip": "fe80::f816:3eff:fe20:57c3",
|
|
||||||
"ip_version": 6,
|
|
||||||
"cidr": 'fe80::/64',
|
|
||||||
"id": subnet_v6_id,
|
|
||||||
"enable_dhcp": True
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if subnetpool_id:
|
|
||||||
fake_v6_subnet['subnet'].update(subnetpool_id=subnetpool_id)
|
|
||||||
|
|
||||||
return fake_v6_subnet
|
|
||||||
|
|
||||||
|
|
||||||
class TestKuryrFailures(TestKuryrBase):
|
|
||||||
"""Unitests for checking if Kuryr handles the failures appropriately."""
|
|
||||||
|
|
|
@ -10,18 +10,14 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import mock
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from neutronclient.common import exceptions as n_exceptions
|
|
||||||
|
|
||||||
from kuryr.common import config
|
from kuryr.lib import config
|
||||||
from kuryr.common import exceptions
|
|
||||||
from kuryr import controllers
|
|
||||||
from kuryr.tests.unit import base
|
from kuryr.tests.unit import base
|
||||||
|
|
||||||
|
|
||||||
class ConfigurationTest(base.TestKuryrBase):
|
class ConfigurationTest(base.TestCase):
|
||||||
|
|
||||||
def test_defaults(self):
|
def test_defaults(self):
|
||||||
basepath = os.path.abspath(os.path.join(os.path.dirname(__file__),
|
basepath = os.path.abspath(os.path.join(os.path.dirname(__file__),
|
||||||
|
@ -44,16 +40,3 @@ class ConfigurationTest(base.TestKuryrBase):
|
||||||
|
|
||||||
self.assertEqual('http://127.0.0.1:35357/v2.0',
|
self.assertEqual('http://127.0.0.1:35357/v2.0',
|
||||||
config.CONF.keystone_client.auth_uri)
|
config.CONF.keystone_client.auth_uri)
|
||||||
|
|
||||||
def test_check_for_neutron_ext_support_with_ex(self):
|
|
||||||
with mock.patch.object(controllers.app.neutron,
|
|
||||||
'show_extension') as mock_extension:
|
|
||||||
ext_alias = "subnet_allocation"
|
|
||||||
err = n_exceptions.NotFound.status_code
|
|
||||||
ext_not_found_ex = n_exceptions.NeutronClientException(
|
|
||||||
status_code=err,
|
|
||||||
message="")
|
|
||||||
mock_extension.side_effect = ext_not_found_ex
|
|
||||||
ex = exceptions.MandatoryApiMissing
|
|
||||||
self.assertRaises(ex, controllers.check_for_neutron_ext_support)
|
|
||||||
mock_extension.assert_called_once_with(ext_alias)
|
|
||||||
|
|
|
@ -1,94 +0,0 @@
|
||||||
# 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 ddt
|
|
||||||
from neutronclient.common import exceptions
|
|
||||||
from oslo_serialization import jsonutils
|
|
||||||
|
|
||||||
from kuryr import app
|
|
||||||
from kuryr.tests.unit import base
|
|
||||||
from kuryr import utils
|
|
||||||
|
|
||||||
|
|
||||||
@ddt.ddt
|
|
||||||
class TestIpamRequestPoolFailures(base.TestKuryrFailures):
|
|
||||||
"""Unit tests for testing request pool failures.
|
|
||||||
|
|
||||||
This test covers error responses listed in the spec:
|
|
||||||
http://developer.openstack.org/api-ref-networking-v2-ext.html#createSubnetPool
|
|
||||||
http://developer.openstack.org/api-ref-networking-v2-ext.html#listSubnetPools
|
|
||||||
"""
|
|
||||||
def _invoke_create_request(self, pool):
|
|
||||||
fake_request = {
|
|
||||||
'AddressSpace': '',
|
|
||||||
'Pool': pool,
|
|
||||||
'SubPool': '', # In the case --ip-range is not given
|
|
||||||
'Options': {},
|
|
||||||
'V6': False
|
|
||||||
}
|
|
||||||
response = self.app.post('/IpamDriver.RequestPool',
|
|
||||||
content_type='application/json',
|
|
||||||
data=jsonutils.dumps(fake_request))
|
|
||||||
return response
|
|
||||||
|
|
||||||
@ddt.data(exceptions.Unauthorized, exceptions.Forbidden,
|
|
||||||
exceptions.NotFound)
|
|
||||||
def test_request_pool_create_failures(self, GivenException):
|
|
||||||
pool_name = utils.get_neutron_subnetpool_name("10.0.0.0/16")
|
|
||||||
new_subnetpool = {
|
|
||||||
'name': pool_name,
|
|
||||||
'default_prefixlen': 16,
|
|
||||||
'prefixes': ['10.0.0.0/16']}
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnetpools')
|
|
||||||
fake_name = pool_name
|
|
||||||
app.neutron.list_subnetpools(name=fake_name).AndReturn(
|
|
||||||
{'subnetpools': []})
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'create_subnetpool')
|
|
||||||
app.neutron.create_subnetpool(
|
|
||||||
{'subnetpool': new_subnetpool}).AndRaise(GivenException)
|
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
pool = '10.0.0.0/16'
|
|
||||||
response = self._invoke_create_request(pool)
|
|
||||||
|
|
||||||
self.assertEqual(GivenException.status_code, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertIn('Err', decoded_json)
|
|
||||||
self.assertEqual(
|
|
||||||
{'Err': GivenException.message}, decoded_json)
|
|
||||||
|
|
||||||
def test_request_pool_bad_request_failure(self):
|
|
||||||
pool = 'pool-should-be-cidr'
|
|
||||||
response = self._invoke_create_request(pool)
|
|
||||||
|
|
||||||
self.assertEqual(400, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertIn('Err', decoded_json)
|
|
||||||
self.assertIn(pool, decoded_json['Err'])
|
|
||||||
self.assertIn('Pool', decoded_json['Err'])
|
|
||||||
|
|
||||||
def test_request_pool_list_subnetpool_failure(self):
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnetpools')
|
|
||||||
pool_name = utils.get_neutron_subnetpool_name("10.0.0.0/16")
|
|
||||||
fake_name = pool_name
|
|
||||||
ex = exceptions.Unauthorized
|
|
||||||
app.neutron.list_subnetpools(name=fake_name).AndRaise(ex)
|
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
pool = '10.0.0.0/16'
|
|
||||||
response = self._invoke_create_request(pool)
|
|
||||||
|
|
||||||
self.assertEqual(ex.status_code, response.status_code)
|
|
|
@ -1,127 +0,0 @@
|
||||||
# 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 uuid
|
|
||||||
|
|
||||||
import ddt
|
|
||||||
from oslo_concurrency import processutils
|
|
||||||
from oslo_serialization import jsonutils
|
|
||||||
from werkzeug import exceptions as w_exceptions
|
|
||||||
|
|
||||||
from kuryr import app
|
|
||||||
from kuryr import binding
|
|
||||||
from kuryr.common import constants as const
|
|
||||||
from kuryr.common import exceptions
|
|
||||||
from kuryr.tests.unit import base
|
|
||||||
from kuryr import utils
|
|
||||||
|
|
||||||
|
|
||||||
@ddt.ddt
|
|
||||||
class TestKuryrJoinFailures(base.TestKuryrFailures):
|
|
||||||
"""Unit tests for the failures for binding a Neutron port."""
|
|
||||||
def _invoke_join_request(self, docker_network_id,
|
|
||||||
docker_endpoint_id, container_id):
|
|
||||||
data = {
|
|
||||||
'NetworkID': docker_network_id,
|
|
||||||
'EndpointID': docker_endpoint_id,
|
|
||||||
'SandboxKey': utils.get_sandbox_key(container_id),
|
|
||||||
'Options': {},
|
|
||||||
}
|
|
||||||
response = self.app.post('/NetworkDriver.Join',
|
|
||||||
content_type='application/json',
|
|
||||||
data=jsonutils.dumps(data))
|
|
||||||
|
|
||||||
return response
|
|
||||||
|
|
||||||
def _port_bind_with_exeption(self, docker_endpiont_id, neutron_port,
|
|
||||||
neutron_subnets, ex):
|
|
||||||
fake_ifname = 'fake-veth'
|
|
||||||
fake_binding_response = (
|
|
||||||
fake_ifname,
|
|
||||||
const.CONTAINER_VETH_PREFIX + fake_ifname,
|
|
||||||
('fake stdout', '')
|
|
||||||
)
|
|
||||||
self.mox.StubOutWithMock(binding, 'port_bind')
|
|
||||||
if ex:
|
|
||||||
binding.port_bind(
|
|
||||||
docker_endpiont_id, neutron_port, neutron_subnets).AndRaise(ex)
|
|
||||||
else:
|
|
||||||
binding.port_bind(
|
|
||||||
docker_endpiont_id, neutron_port, neutron_subnets).AndReturn(
|
|
||||||
fake_binding_response)
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
return fake_binding_response
|
|
||||||
|
|
||||||
@ddt.data(exceptions.VethCreationFailure,
|
|
||||||
processutils.ProcessExecutionError)
|
|
||||||
def test_join_veth_failures(self, GivenException):
|
|
||||||
fake_docker_network_id = utils.get_hash()
|
|
||||||
fake_docker_endpoint_id = utils.get_hash()
|
|
||||||
fake_container_id = utils.get_hash()
|
|
||||||
|
|
||||||
fake_neutron_network_id = str(uuid.uuid4())
|
|
||||||
self._mock_out_network(fake_neutron_network_id, fake_docker_network_id)
|
|
||||||
fake_neutron_port_id = str(uuid.uuid4())
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_ports')
|
|
||||||
neutron_port_name = utils.get_neutron_port_name(
|
|
||||||
fake_docker_endpoint_id)
|
|
||||||
fake_neutron_v4_subnet_id = str(uuid.uuid4())
|
|
||||||
fake_neutron_v6_subnet_id = str(uuid.uuid4())
|
|
||||||
fake_neutron_ports_response = self._get_fake_ports(
|
|
||||||
fake_docker_endpoint_id, fake_neutron_network_id,
|
|
||||||
fake_neutron_port_id, const.PORT_STATUS_ACTIVE,
|
|
||||||
fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id)
|
|
||||||
app.neutron.list_ports(name=neutron_port_name).AndReturn(
|
|
||||||
fake_neutron_ports_response)
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnets')
|
|
||||||
fake_neutron_subnets_response = self._get_fake_subnets(
|
|
||||||
fake_docker_endpoint_id, fake_neutron_network_id,
|
|
||||||
fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id)
|
|
||||||
app.neutron.list_subnets(network_id=fake_neutron_network_id).AndReturn(
|
|
||||||
fake_neutron_subnets_response)
|
|
||||||
fake_neutron_port = fake_neutron_ports_response['ports'][0]
|
|
||||||
fake_neutron_subnets = fake_neutron_subnets_response['subnets']
|
|
||||||
|
|
||||||
fake_message = "fake message"
|
|
||||||
fake_exception = GivenException(fake_message)
|
|
||||||
self._port_bind_with_exeption(
|
|
||||||
fake_docker_endpoint_id, fake_neutron_port,
|
|
||||||
fake_neutron_subnets, fake_exception)
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
response = self._invoke_join_request(
|
|
||||||
fake_docker_network_id, fake_docker_endpoint_id, fake_container_id)
|
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
w_exceptions.InternalServerError.code, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertIn('Err', decoded_json)
|
|
||||||
self.assertIn(fake_message, decoded_json['Err'])
|
|
||||||
|
|
||||||
def test_join_bad_request(self):
|
|
||||||
fake_docker_network_id = utils.get_hash()
|
|
||||||
invalid_docker_endpoint_id = 'id-should-be-hexdigits'
|
|
||||||
fake_container_id = utils.get_hash()
|
|
||||||
|
|
||||||
response = self._invoke_join_request(
|
|
||||||
fake_docker_network_id, invalid_docker_endpoint_id,
|
|
||||||
fake_container_id)
|
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
w_exceptions.BadRequest.code, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertIn('Err', decoded_json)
|
|
||||||
# TODO(tfukushima): Add the better error message validation.
|
|
||||||
self.assertIn(invalid_docker_endpoint_id, decoded_json['Err'])
|
|
||||||
self.assertIn('EndpointID', decoded_json['Err'])
|
|
|
@ -1,872 +0,0 @@
|
||||||
# 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 uuid
|
|
||||||
|
|
||||||
import ddt
|
|
||||||
from oslo_serialization import jsonutils
|
|
||||||
|
|
||||||
from kuryr import app
|
|
||||||
from kuryr.common import config
|
|
||||||
from kuryr.common import constants
|
|
||||||
from kuryr.tests.unit import base
|
|
||||||
from kuryr import utils
|
|
||||||
|
|
||||||
|
|
||||||
@ddt.ddt
|
|
||||||
class TestKuryr(base.TestKuryrBase):
|
|
||||||
"""Basic unitests for libnetwork remote driver URI endpoints.
|
|
||||||
|
|
||||||
This test class covers the following HTTP methods and URIs as described in
|
|
||||||
the remote driver specification as below:
|
|
||||||
|
|
||||||
https://github.com/docker/libnetwork/blob/3c8e06bc0580a2a1b2440fe0792fbfcd43a9feca/docs/remote.md # noqa
|
|
||||||
|
|
||||||
- POST /Plugin.Activate
|
|
||||||
- POST /NetworkDriver.GetCapabilities
|
|
||||||
- POST /NetworkDriver.CreateNetwork
|
|
||||||
- POST /NetworkDriver.DeleteNetwork
|
|
||||||
- POST /NetworkDriver.CreateEndpoint
|
|
||||||
- POST /NetworkDriver.EndpointOperInfo
|
|
||||||
- POST /NetworkDriver.DeleteEndpoint
|
|
||||||
- POST /NetworkDriver.Join
|
|
||||||
- POST /NetworkDriver.Leave
|
|
||||||
- POST /NetworkDriver.DiscoverNew
|
|
||||||
- POST /NetworkDriver.DiscoverDelete
|
|
||||||
"""
|
|
||||||
@ddt.data(('/Plugin.Activate', constants.SCHEMA['PLUGIN_ACTIVATE']),
|
|
||||||
('/NetworkDriver.GetCapabilities',
|
|
||||||
{'Scope': config.CONF.capability_scope}),
|
|
||||||
('/NetworkDriver.DiscoverNew', constants.SCHEMA['SUCCESS']),
|
|
||||||
('/NetworkDriver.DiscoverDelete', constants.SCHEMA['SUCCESS']),
|
|
||||||
('/NetworkDriver.EndpointOperInfo',
|
|
||||||
constants.SCHEMA['ENDPOINT_OPER_INFO']))
|
|
||||||
@ddt.unpack
|
|
||||||
def test_remote_driver_endpoint(self, endpoint, expected):
|
|
||||||
response = self.app.post(endpoint)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertEqual(expected, decoded_json)
|
|
||||||
|
|
||||||
def test_network_driver_create_network(self):
|
|
||||||
docker_network_id = utils.get_hash()
|
|
||||||
self.mox.StubOutWithMock(app.neutron, "create_network")
|
|
||||||
fake_request = {
|
|
||||||
"network": {
|
|
||||||
"name": utils.make_net_name(docker_network_id),
|
|
||||||
"admin_state_up": True
|
|
||||||
}
|
|
||||||
}
|
|
||||||
# The following fake response is retrieved from the Neutron doc:
|
|
||||||
# http://developer.openstack.org/api-ref-networking-v2.html#createNetwork # noqa
|
|
||||||
fake_neutron_net_id = "4e8e5957-649f-477b-9e5b-f1f75b21c03c"
|
|
||||||
fake_response = {
|
|
||||||
"network": {
|
|
||||||
"status": "ACTIVE",
|
|
||||||
"subnets": [],
|
|
||||||
"name": utils.make_net_name(docker_network_id),
|
|
||||||
"admin_state_up": True,
|
|
||||||
"tenant_id": "9bacb3c5d39d41a79512987f338cf177",
|
|
||||||
"router:external": False,
|
|
||||||
"segments": [],
|
|
||||||
"shared": False,
|
|
||||||
"id": fake_neutron_net_id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
app.neutron.create_network(fake_request).AndReturn(fake_response)
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, "add_tag")
|
|
||||||
tags = utils.create_net_tags(docker_network_id)
|
|
||||||
for tag in tags:
|
|
||||||
app.neutron.add_tag('networks', fake_neutron_net_id, tag)
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnets')
|
|
||||||
fake_existing_subnets_response = {
|
|
||||||
"subnets": []
|
|
||||||
}
|
|
||||||
fake_cidr_v4 = '192.168.42.0/24'
|
|
||||||
app.neutron.list_subnets(
|
|
||||||
network_id=fake_neutron_net_id,
|
|
||||||
cidr=fake_cidr_v4).AndReturn(fake_existing_subnets_response)
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'create_subnet')
|
|
||||||
fake_subnet_request = {
|
|
||||||
"subnets": [{
|
|
||||||
'name': fake_cidr_v4,
|
|
||||||
'network_id': fake_neutron_net_id,
|
|
||||||
'ip_version': 4,
|
|
||||||
'cidr': fake_cidr_v4,
|
|
||||||
'enable_dhcp': app.enable_dhcp,
|
|
||||||
'gateway_ip': '192.168.42.1',
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
subnet_v4_id = str(uuid.uuid4())
|
|
||||||
fake_v4_subnet = self._get_fake_v4_subnet(
|
|
||||||
fake_neutron_net_id, subnet_v4_id,
|
|
||||||
name=fake_cidr_v4, cidr=fake_cidr_v4)
|
|
||||||
fake_subnet_response = {
|
|
||||||
'subnets': [
|
|
||||||
fake_v4_subnet['subnet']
|
|
||||||
]
|
|
||||||
}
|
|
||||||
app.neutron.create_subnet(
|
|
||||||
fake_subnet_request).AndReturn(fake_subnet_response)
|
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
network_request = {
|
|
||||||
'NetworkID': docker_network_id,
|
|
||||||
'IPv4Data': [{
|
|
||||||
'AddressSpace': 'foo',
|
|
||||||
'Pool': '192.168.42.0/24',
|
|
||||||
'Gateway': '192.168.42.1/24',
|
|
||||||
}],
|
|
||||||
'IPv6Data': [{
|
|
||||||
'AddressSpace': 'bar',
|
|
||||||
'Pool': 'fe80::/64',
|
|
||||||
'Gateway': 'fe80::f816:3eff:fe20:57c3/64',
|
|
||||||
}],
|
|
||||||
'Options': {}
|
|
||||||
}
|
|
||||||
response = self.app.post('/NetworkDriver.CreateNetwork',
|
|
||||||
content_type='application/json',
|
|
||||||
data=jsonutils.dumps(network_request))
|
|
||||||
|
|
||||||
self.assertEqual(200, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertEqual(constants.SCHEMA['SUCCESS'], decoded_json)
|
|
||||||
|
|
||||||
def test_network_driver_create_network_with_net_name_option(self):
|
|
||||||
docker_network_id = utils.get_hash()
|
|
||||||
fake_neutron_net_id = "4e8e5957-649f-477b-9e5b-f1f75b21c03c"
|
|
||||||
self.mox.StubOutWithMock(app.neutron, "list_networks")
|
|
||||||
fake_neutron_net_name = 'my_network_name'
|
|
||||||
fake_existing_networks_response = {
|
|
||||||
"networks": [{
|
|
||||||
"status": "ACTIVE",
|
|
||||||
"subnets": [],
|
|
||||||
"admin_state_up": True,
|
|
||||||
"tenant_id": "9bacb3c5d39d41a79512987f338cf177",
|
|
||||||
"router:external": False,
|
|
||||||
"segments": [],
|
|
||||||
"shared": False,
|
|
||||||
"id": fake_neutron_net_id,
|
|
||||||
"name": "my_network_name"
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
app.neutron.list_networks(
|
|
||||||
name=fake_neutron_net_name).AndReturn(
|
|
||||||
fake_existing_networks_response)
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, "add_tag")
|
|
||||||
tags = utils.create_net_tags(docker_network_id)
|
|
||||||
for tag in tags:
|
|
||||||
app.neutron.add_tag('networks', fake_neutron_net_id, tag)
|
|
||||||
|
|
||||||
app.neutron.add_tag(
|
|
||||||
'networks', fake_neutron_net_id, 'kuryr.net.existing')
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnets')
|
|
||||||
fake_existing_subnets_response = {
|
|
||||||
"subnets": []
|
|
||||||
}
|
|
||||||
fake_cidr_v4 = '192.168.42.0/24'
|
|
||||||
app.neutron.list_subnets(
|
|
||||||
network_id=fake_neutron_net_id,
|
|
||||||
cidr=fake_cidr_v4).AndReturn(fake_existing_subnets_response)
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'create_subnet')
|
|
||||||
fake_subnet_request = {
|
|
||||||
"subnets": [{
|
|
||||||
'name': fake_cidr_v4,
|
|
||||||
'network_id': fake_neutron_net_id,
|
|
||||||
'ip_version': 4,
|
|
||||||
'cidr': fake_cidr_v4,
|
|
||||||
'enable_dhcp': app.enable_dhcp,
|
|
||||||
'gateway_ip': '192.168.42.1',
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
subnet_v4_id = str(uuid.uuid4())
|
|
||||||
fake_v4_subnet = self._get_fake_v4_subnet(
|
|
||||||
fake_neutron_net_id, subnet_v4_id,
|
|
||||||
name=fake_cidr_v4, cidr=fake_cidr_v4)
|
|
||||||
fake_subnet_response = {
|
|
||||||
'subnets': [
|
|
||||||
fake_v4_subnet['subnet']
|
|
||||||
]
|
|
||||||
}
|
|
||||||
app.neutron.create_subnet(
|
|
||||||
fake_subnet_request).AndReturn(fake_subnet_response)
|
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
network_request = {
|
|
||||||
'NetworkID': docker_network_id,
|
|
||||||
'IPv4Data': [{
|
|
||||||
'AddressSpace': 'foo',
|
|
||||||
'Pool': '192.168.42.0/24',
|
|
||||||
'Gateway': '192.168.42.1/24',
|
|
||||||
}],
|
|
||||||
'IPv6Data': [{
|
|
||||||
'AddressSpace': 'bar',
|
|
||||||
'Pool': 'fe80::/64',
|
|
||||||
'Gateway': 'fe80::f816:3eff:fe20:57c3/64',
|
|
||||||
}],
|
|
||||||
'Options': {
|
|
||||||
'com.docker.network.enable_ipv6': False,
|
|
||||||
'com.docker.network.generic': {
|
|
||||||
'neutron.net.name': 'my_network_name'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
response = self.app.post('/NetworkDriver.CreateNetwork',
|
|
||||||
content_type='application/json',
|
|
||||||
data=jsonutils.dumps(network_request))
|
|
||||||
|
|
||||||
self.assertEqual(200, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertEqual(constants.SCHEMA['SUCCESS'], decoded_json)
|
|
||||||
|
|
||||||
def test_network_driver_create_network_with_netid_option(self):
|
|
||||||
docker_network_id = utils.get_hash()
|
|
||||||
fake_neutron_net_id = "4e8e5957-649f-477b-9e5b-f1f75b21c03c"
|
|
||||||
self.mox.StubOutWithMock(app.neutron, "list_networks")
|
|
||||||
fake_existing_networks_response = {
|
|
||||||
"networks": [{
|
|
||||||
"status": "ACTIVE",
|
|
||||||
"subnets": [],
|
|
||||||
"admin_state_up": True,
|
|
||||||
"tenant_id": "9bacb3c5d39d41a79512987f338cf177",
|
|
||||||
"router:external": False,
|
|
||||||
"segments": [],
|
|
||||||
"shared": False,
|
|
||||||
"id": fake_neutron_net_id,
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
app.neutron.list_networks(
|
|
||||||
id=fake_neutron_net_id).AndReturn(
|
|
||||||
fake_existing_networks_response)
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, "add_tag")
|
|
||||||
tags = utils.create_net_tags(docker_network_id)
|
|
||||||
for tag in tags:
|
|
||||||
app.neutron.add_tag('networks', fake_neutron_net_id, tag)
|
|
||||||
|
|
||||||
app.neutron.add_tag(
|
|
||||||
'networks', fake_neutron_net_id, 'kuryr.net.existing')
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnets')
|
|
||||||
fake_existing_subnets_response = {
|
|
||||||
"subnets": []
|
|
||||||
}
|
|
||||||
fake_cidr_v4 = '192.168.42.0/24'
|
|
||||||
app.neutron.list_subnets(
|
|
||||||
network_id=fake_neutron_net_id,
|
|
||||||
cidr=fake_cidr_v4).AndReturn(fake_existing_subnets_response)
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'create_subnet')
|
|
||||||
fake_subnet_request = {
|
|
||||||
"subnets": [{
|
|
||||||
'name': fake_cidr_v4,
|
|
||||||
'network_id': fake_neutron_net_id,
|
|
||||||
'ip_version': 4,
|
|
||||||
'cidr': fake_cidr_v4,
|
|
||||||
'enable_dhcp': app.enable_dhcp,
|
|
||||||
'gateway_ip': '192.168.42.1',
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
subnet_v4_id = str(uuid.uuid4())
|
|
||||||
fake_v4_subnet = self._get_fake_v4_subnet(
|
|
||||||
fake_neutron_net_id, subnet_v4_id,
|
|
||||||
name=fake_cidr_v4, cidr=fake_cidr_v4)
|
|
||||||
fake_subnet_response = {
|
|
||||||
'subnets': [
|
|
||||||
fake_v4_subnet['subnet']
|
|
||||||
]
|
|
||||||
}
|
|
||||||
app.neutron.create_subnet(
|
|
||||||
fake_subnet_request).AndReturn(fake_subnet_response)
|
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
network_request = {
|
|
||||||
'NetworkID': docker_network_id,
|
|
||||||
'IPv4Data': [{
|
|
||||||
'AddressSpace': 'foo',
|
|
||||||
'Pool': '192.168.42.0/24',
|
|
||||||
'Gateway': '192.168.42.1/24',
|
|
||||||
}],
|
|
||||||
'IPv6Data': [{
|
|
||||||
'AddressSpace': 'bar',
|
|
||||||
'Pool': 'fe80::/64',
|
|
||||||
'Gateway': 'fe80::f816:3eff:fe20:57c3/64',
|
|
||||||
}],
|
|
||||||
'Options': {
|
|
||||||
'com.docker.network.enable_ipv6': False,
|
|
||||||
'com.docker.network.generic': {
|
|
||||||
'neutron.net.uuid': '4e8e5957-649f-477b-9e5b-f1f75b21c03c'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
response = self.app.post('/NetworkDriver.CreateNetwork',
|
|
||||||
content_type='application/json',
|
|
||||||
data=jsonutils.dumps(network_request))
|
|
||||||
|
|
||||||
self.assertEqual(200, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertEqual(constants.SCHEMA['SUCCESS'], decoded_json)
|
|
||||||
|
|
||||||
def test_network_driver_create_network_with_pool_name_option(self):
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnetpools')
|
|
||||||
fake_kuryr_subnetpool_id = str(uuid.uuid4())
|
|
||||||
fake_name = "fake_pool_name"
|
|
||||||
kuryr_subnetpools = self._get_fake_v4_subnetpools(
|
|
||||||
fake_kuryr_subnetpool_id, name=fake_name)
|
|
||||||
app.neutron.list_subnetpools(name=fake_name).AndReturn(
|
|
||||||
{'subnetpools': kuryr_subnetpools['subnetpools']})
|
|
||||||
docker_network_id = utils.get_hash()
|
|
||||||
self.mox.StubOutWithMock(app.neutron, "create_network")
|
|
||||||
fake_request = {
|
|
||||||
"network": {
|
|
||||||
"name": utils.make_net_name(docker_network_id),
|
|
||||||
"admin_state_up": True
|
|
||||||
}
|
|
||||||
}
|
|
||||||
# The following fake response is retrieved from the Neutron doc:
|
|
||||||
# http://developer.openstack.org/api-ref-networking-v2.html#createNetwork # noqa
|
|
||||||
fake_neutron_net_id = "4e8e5957-649f-477b-9e5b-f1f75b21c03c"
|
|
||||||
fake_response = {
|
|
||||||
"network": {
|
|
||||||
"status": "ACTIVE",
|
|
||||||
"subnets": [],
|
|
||||||
"name": utils.make_net_name(docker_network_id),
|
|
||||||
"admin_state_up": True,
|
|
||||||
"tenant_id": "9bacb3c5d39d41a79512987f338cf177",
|
|
||||||
"router:external": False,
|
|
||||||
"segments": [],
|
|
||||||
"shared": False,
|
|
||||||
"id": fake_neutron_net_id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
app.neutron.create_network(fake_request).AndReturn(fake_response)
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, "add_tag")
|
|
||||||
tags = utils.create_net_tags(docker_network_id)
|
|
||||||
for tag in tags:
|
|
||||||
app.neutron.add_tag('networks', fake_neutron_net_id, tag)
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnets')
|
|
||||||
fake_existing_subnets_response = {
|
|
||||||
"subnets": []
|
|
||||||
}
|
|
||||||
fake_cidr_v4 = '192.168.42.0/24'
|
|
||||||
app.neutron.list_subnets(
|
|
||||||
network_id=fake_neutron_net_id,
|
|
||||||
cidr=fake_cidr_v4).AndReturn(fake_existing_subnets_response)
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'create_subnet')
|
|
||||||
fake_subnet_request = {
|
|
||||||
"subnets": [{
|
|
||||||
'name': fake_cidr_v4,
|
|
||||||
'network_id': fake_neutron_net_id,
|
|
||||||
'ip_version': 4,
|
|
||||||
'cidr': fake_cidr_v4,
|
|
||||||
'enable_dhcp': app.enable_dhcp,
|
|
||||||
'gateway_ip': '192.168.42.1',
|
|
||||||
'subnetpool_id': fake_kuryr_subnetpool_id,
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
subnet_v4_id = str(uuid.uuid4())
|
|
||||||
fake_v4_subnet = self._get_fake_v4_subnet(
|
|
||||||
fake_neutron_net_id, subnet_v4_id,
|
|
||||||
name=fake_cidr_v4, cidr=fake_cidr_v4)
|
|
||||||
fake_subnet_response = {
|
|
||||||
'subnets': [
|
|
||||||
fake_v4_subnet['subnet']
|
|
||||||
]
|
|
||||||
}
|
|
||||||
app.neutron.create_subnet(
|
|
||||||
fake_subnet_request).AndReturn(fake_subnet_response)
|
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
network_request = {
|
|
||||||
'NetworkID': docker_network_id,
|
|
||||||
'IPv4Data': [{
|
|
||||||
'AddressSpace': 'foo',
|
|
||||||
'Pool': '192.168.42.0/24',
|
|
||||||
'Gateway': '192.168.42.1/24',
|
|
||||||
}],
|
|
||||||
'IPv6Data': [{
|
|
||||||
'AddressSpace': 'bar',
|
|
||||||
'Pool': 'fe80::/64',
|
|
||||||
'Gateway': 'fe80::f816:3eff:fe20:57c3/64',
|
|
||||||
}],
|
|
||||||
'Options': {
|
|
||||||
'com.docker.network.enable_ipv6': False,
|
|
||||||
'com.docker.network.generic': {
|
|
||||||
'neutron.pool.name': 'fake_pool_name'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
response = self.app.post('/NetworkDriver.CreateNetwork',
|
|
||||||
content_type='application/json',
|
|
||||||
data=jsonutils.dumps(network_request))
|
|
||||||
|
|
||||||
self.assertEqual(200, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertEqual(constants.SCHEMA['SUCCESS'], decoded_json)
|
|
||||||
|
|
||||||
def test_network_driver_create_network_wo_gw(self):
|
|
||||||
docker_network_id = utils.get_hash()
|
|
||||||
self.mox.StubOutWithMock(app.neutron, "create_network")
|
|
||||||
fake_request = {
|
|
||||||
"network": {
|
|
||||||
"name": utils.make_net_name(docker_network_id),
|
|
||||||
"admin_state_up": True
|
|
||||||
}
|
|
||||||
}
|
|
||||||
# The following fake response is retrieved from the Neutron doc:
|
|
||||||
# http://developer.openstack.org/api-ref-networking-v2.html#createNetwork # noqa
|
|
||||||
fake_neutron_net_id = "4e8e5957-649f-477b-9e5b-f1f75b21c03c"
|
|
||||||
fake_response = {
|
|
||||||
"network": {
|
|
||||||
"status": "ACTIVE",
|
|
||||||
"subnets": [],
|
|
||||||
"name": utils.make_net_name(docker_network_id),
|
|
||||||
"admin_state_up": True,
|
|
||||||
"tenant_id": "9bacb3c5d39d41a79512987f338cf177",
|
|
||||||
"router:external": False,
|
|
||||||
"segments": [],
|
|
||||||
"shared": False,
|
|
||||||
"id": fake_neutron_net_id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
app.neutron.create_network(fake_request).AndReturn(fake_response)
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, "add_tag")
|
|
||||||
tags = utils.create_net_tags(docker_network_id)
|
|
||||||
for tag in tags:
|
|
||||||
app.neutron.add_tag('networks', fake_neutron_net_id, tag)
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnets')
|
|
||||||
fake_existing_subnets_response = {
|
|
||||||
"subnets": []
|
|
||||||
}
|
|
||||||
fake_cidr_v4 = '192.168.42.0/24'
|
|
||||||
app.neutron.list_subnets(
|
|
||||||
network_id=fake_neutron_net_id,
|
|
||||||
cidr=fake_cidr_v4).AndReturn(fake_existing_subnets_response)
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'create_subnet')
|
|
||||||
fake_subnet_request = {
|
|
||||||
"subnets": [{
|
|
||||||
'name': fake_cidr_v4,
|
|
||||||
'network_id': fake_neutron_net_id,
|
|
||||||
'ip_version': 4,
|
|
||||||
'cidr': fake_cidr_v4,
|
|
||||||
'enable_dhcp': app.enable_dhcp,
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
subnet_v4_id = str(uuid.uuid4())
|
|
||||||
fake_v4_subnet = self._get_fake_v4_subnet(
|
|
||||||
fake_neutron_net_id, subnet_v4_id,
|
|
||||||
name=fake_cidr_v4, cidr=fake_cidr_v4)
|
|
||||||
fake_subnet_response = {
|
|
||||||
'subnets': [
|
|
||||||
fake_v4_subnet['subnet']
|
|
||||||
]
|
|
||||||
}
|
|
||||||
app.neutron.create_subnet(
|
|
||||||
fake_subnet_request).AndReturn(fake_subnet_response)
|
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
network_request = {
|
|
||||||
'NetworkID': docker_network_id,
|
|
||||||
'IPv4Data': [{
|
|
||||||
'AddressSpace': 'foo',
|
|
||||||
'Pool': '192.168.42.0/24',
|
|
||||||
}],
|
|
||||||
'IPv6Data': [{
|
|
||||||
'AddressSpace': 'bar',
|
|
||||||
'Pool': 'fe80::/64',
|
|
||||||
'Gateway': 'fe80::f816:3eff:fe20:57c3/64',
|
|
||||||
}],
|
|
||||||
'Options': {}
|
|
||||||
}
|
|
||||||
response = self.app.post('/NetworkDriver.CreateNetwork',
|
|
||||||
content_type='application/json',
|
|
||||||
data=jsonutils.dumps(network_request))
|
|
||||||
|
|
||||||
self.assertEqual(200, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertEqual(constants.SCHEMA['SUCCESS'], decoded_json)
|
|
||||||
|
|
||||||
def test_network_driver_create_network_with_network_id_not_exist(self):
|
|
||||||
docker_network_id = utils.get_hash()
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, "list_networks")
|
|
||||||
fake_neutron_net_id = str(uuid.uuid4())
|
|
||||||
fake_existing_networks_response = {
|
|
||||||
"networks": []
|
|
||||||
}
|
|
||||||
app.neutron.list_networks(
|
|
||||||
id=fake_neutron_net_id).AndReturn(
|
|
||||||
fake_existing_networks_response)
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
network_request = {
|
|
||||||
'NetworkID': docker_network_id,
|
|
||||||
'IPv4Data': [{
|
|
||||||
'AddressSpace': 'foo',
|
|
||||||
'Pool': '192.168.42.0/24',
|
|
||||||
}],
|
|
||||||
'IPv6Data': [{
|
|
||||||
'AddressSpace': 'bar',
|
|
||||||
'Pool': 'fe80::/64',
|
|
||||||
'Gateway': 'fe80::f816:3eff:fe20:57c3/64',
|
|
||||||
}],
|
|
||||||
'Options': {
|
|
||||||
constants.NETWORK_GENERIC_OPTIONS: {
|
|
||||||
constants.NEUTRON_UUID_OPTION: fake_neutron_net_id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
response = self.app.post('/NetworkDriver.CreateNetwork',
|
|
||||||
content_type='application/json',
|
|
||||||
data=jsonutils.dumps(network_request))
|
|
||||||
self.assertEqual(500, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertIn('Err', decoded_json)
|
|
||||||
err_message = ("Specified network id/name({0}) does not "
|
|
||||||
"exist.").format(fake_neutron_net_id)
|
|
||||||
self.assertEqual({'Err': err_message}, decoded_json)
|
|
||||||
|
|
||||||
def test_network_driver_create_network_with_network_name_not_exist(self):
|
|
||||||
docker_network_id = utils.get_hash()
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, "list_networks")
|
|
||||||
fake_neutron_network_name = "fake_network"
|
|
||||||
fake_existing_networks_response = {
|
|
||||||
"networks": []
|
|
||||||
}
|
|
||||||
app.neutron.list_networks(
|
|
||||||
name=fake_neutron_network_name).AndReturn(
|
|
||||||
fake_existing_networks_response)
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
network_request = {
|
|
||||||
'NetworkID': docker_network_id,
|
|
||||||
'IPv4Data': [{
|
|
||||||
'AddressSpace': 'foo',
|
|
||||||
'Pool': '192.168.42.0/24',
|
|
||||||
}],
|
|
||||||
'IPv6Data': [{
|
|
||||||
'AddressSpace': 'bar',
|
|
||||||
'Pool': 'fe80::/64',
|
|
||||||
'Gateway': 'fe80::f816:3eff:fe20:57c3/64',
|
|
||||||
}],
|
|
||||||
'Options': {
|
|
||||||
constants.NETWORK_GENERIC_OPTIONS: {
|
|
||||||
constants.NEUTRON_NAME_OPTION: fake_neutron_network_name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
response = self.app.post('/NetworkDriver.CreateNetwork',
|
|
||||||
content_type='application/json',
|
|
||||||
data=jsonutils.dumps(network_request))
|
|
||||||
self.assertEqual(500, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertIn('Err', decoded_json)
|
|
||||||
err_message = ("Specified network id/name({0}) does not "
|
|
||||||
"exist.").format(fake_neutron_network_name)
|
|
||||||
self.assertEqual({'Err': err_message}, decoded_json)
|
|
||||||
|
|
||||||
def test_network_driver_delete_network(self):
|
|
||||||
docker_network_id = utils.get_hash()
|
|
||||||
fake_neutron_net_id = str(uuid.uuid4())
|
|
||||||
self._mock_out_network(fake_neutron_net_id, docker_network_id,
|
|
||||||
check_existing=True)
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnets')
|
|
||||||
fake_neutron_subnets_response = {"subnets": []}
|
|
||||||
app.neutron.list_subnets(network_id=fake_neutron_net_id).AndReturn(
|
|
||||||
fake_neutron_subnets_response)
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'delete_network')
|
|
||||||
app.neutron.delete_network(fake_neutron_net_id).AndReturn(None)
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
data = {'NetworkID': docker_network_id}
|
|
||||||
response = self.app.post('/NetworkDriver.DeleteNetwork',
|
|
||||||
content_type='application/json',
|
|
||||||
data=jsonutils.dumps(data))
|
|
||||||
|
|
||||||
self.assertEqual(200, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertEqual(constants.SCHEMA['SUCCESS'], decoded_json)
|
|
||||||
|
|
||||||
def test_network_driver_delete_network_with_subnets(self):
|
|
||||||
docker_network_id = utils.get_hash()
|
|
||||||
docker_endpoint_id = utils.get_hash()
|
|
||||||
|
|
||||||
fake_neutron_net_id = str(uuid.uuid4())
|
|
||||||
self._mock_out_network(fake_neutron_net_id, docker_network_id,
|
|
||||||
check_existing=True)
|
|
||||||
# The following fake response is retrieved from the Neutron doc:
|
|
||||||
# http://developer.openstack.org/api-ref-networking-v2.html#createSubnet # noqa
|
|
||||||
subnet_v4_id = "9436e561-47bf-436a-b1f1-fe23a926e031"
|
|
||||||
subnet_v6_id = "64dd4a98-3d7a-4bfd-acf4-91137a8d2f51"
|
|
||||||
fake_v4_subnet = self._get_fake_v4_subnet(
|
|
||||||
docker_network_id, docker_endpoint_id, subnet_v4_id)
|
|
||||||
fake_v6_subnet = self._get_fake_v6_subnet(
|
|
||||||
docker_network_id, docker_endpoint_id, subnet_v6_id)
|
|
||||||
fake_subnets_response = {
|
|
||||||
"subnets": [
|
|
||||||
fake_v4_subnet['subnet'],
|
|
||||||
fake_v6_subnet['subnet']
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnets')
|
|
||||||
app.neutron.list_subnets(network_id=fake_neutron_net_id).AndReturn(
|
|
||||||
fake_subnets_response)
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnetpools')
|
|
||||||
fake_subnetpools_response = {"subnetpools": []}
|
|
||||||
app.neutron.list_subnetpools(name='kuryr').AndReturn(
|
|
||||||
fake_subnetpools_response)
|
|
||||||
app.neutron.list_subnetpools(name='kuryr6').AndReturn(
|
|
||||||
fake_subnetpools_response)
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'delete_subnet')
|
|
||||||
app.neutron.delete_subnet(subnet_v4_id).AndReturn(None)
|
|
||||||
app.neutron.delete_subnet(subnet_v6_id).AndReturn(None)
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'delete_network')
|
|
||||||
app.neutron.delete_network(fake_neutron_net_id).AndReturn(None)
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
data = {'NetworkID': docker_network_id}
|
|
||||||
response = self.app.post('/NetworkDriver.DeleteNetwork',
|
|
||||||
content_type='application/json',
|
|
||||||
data=jsonutils.dumps(data))
|
|
||||||
|
|
||||||
self.assertEqual(200, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertEqual(constants.SCHEMA['SUCCESS'], decoded_json)
|
|
||||||
|
|
||||||
def test_network_driver_create_endpoint(self):
|
|
||||||
docker_network_id = utils.get_hash()
|
|
||||||
docker_endpoint_id = utils.get_hash()
|
|
||||||
|
|
||||||
fake_neutron_net_id = str(uuid.uuid4())
|
|
||||||
self._mock_out_network(fake_neutron_net_id, docker_network_id)
|
|
||||||
|
|
||||||
# The following fake response is retrieved from the Neutron doc:
|
|
||||||
# http://developer.openstack.org/api-ref-networking-v2.html#createSubnet # noqa
|
|
||||||
subnet_v4_id = "9436e561-47bf-436a-b1f1-fe23a926e031"
|
|
||||||
subnet_v6_id = "64dd4a98-3d7a-4bfd-acf4-91137a8d2f51"
|
|
||||||
fake_v4_subnet = self._get_fake_v4_subnet(
|
|
||||||
docker_network_id, docker_endpoint_id, subnet_v4_id)
|
|
||||||
fake_v6_subnet = self._get_fake_v6_subnet(
|
|
||||||
docker_network_id, docker_endpoint_id, subnet_v6_id)
|
|
||||||
|
|
||||||
fake_subnetv4_response = {
|
|
||||||
"subnets": [
|
|
||||||
fake_v4_subnet['subnet']
|
|
||||||
]
|
|
||||||
}
|
|
||||||
fake_subnetv6_response = {
|
|
||||||
"subnets": [
|
|
||||||
fake_v6_subnet['subnet']
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnets')
|
|
||||||
app.neutron.list_subnets(network_id=fake_neutron_net_id,
|
|
||||||
cidr='192.168.1.0/24').AndReturn(fake_subnetv4_response)
|
|
||||||
app.neutron.list_subnets(
|
|
||||||
network_id=fake_neutron_net_id,
|
|
||||||
cidr='fe80::/64').AndReturn(fake_subnetv6_response)
|
|
||||||
|
|
||||||
fake_ipv4cidr = '192.168.1.2/24'
|
|
||||||
fake_ipv6cidr = 'fe80::f816:3eff:fe20:57c4/64'
|
|
||||||
fake_port_id = str(uuid.uuid4())
|
|
||||||
fake_port = self._get_fake_port(
|
|
||||||
docker_endpoint_id, fake_neutron_net_id,
|
|
||||||
fake_port_id, constants.PORT_STATUS_ACTIVE,
|
|
||||||
subnet_v4_id, subnet_v6_id)
|
|
||||||
fake_fixed_ips = ['subnet_id=%s' % subnet_v4_id,
|
|
||||||
'ip_address=192.168.1.2',
|
|
||||||
'subnet_id=%s' % subnet_v6_id,
|
|
||||||
'ip_address=fe80::f816:3eff:fe20:57c4']
|
|
||||||
fake_port_response = {
|
|
||||||
"ports": [
|
|
||||||
fake_port['port']
|
|
||||||
]
|
|
||||||
}
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_ports')
|
|
||||||
app.neutron.list_ports(fixed_ips=fake_fixed_ips).AndReturn(
|
|
||||||
fake_port_response)
|
|
||||||
fake_updated_port = fake_port['port']
|
|
||||||
fake_updated_port['name'] = '-'.join([docker_endpoint_id, 'port'])
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'update_port')
|
|
||||||
app.neutron.update_port(fake_updated_port['id'], {'port': {
|
|
||||||
'name': fake_updated_port['name'],
|
|
||||||
'device_owner': constants.DEVICE_OWNER,
|
|
||||||
'device_id': docker_endpoint_id}}).AndReturn(fake_port)
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
data = {
|
|
||||||
'NetworkID': docker_network_id,
|
|
||||||
'EndpointID': docker_endpoint_id,
|
|
||||||
'Options': {},
|
|
||||||
'Interface': {
|
|
||||||
'Address': fake_ipv4cidr,
|
|
||||||
'AddressIPv6': fake_ipv6cidr,
|
|
||||||
'MacAddress': "fa:16:3e:20:57:c3"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
response = self.app.post('/NetworkDriver.CreateEndpoint',
|
|
||||||
content_type='application/json',
|
|
||||||
data=jsonutils.dumps(data))
|
|
||||||
|
|
||||||
self.assertEqual(200, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
expected = {'Interface': {}}
|
|
||||||
self.assertEqual(expected, decoded_json)
|
|
||||||
|
|
||||||
def test_network_driver_delete_endpoint(self):
|
|
||||||
docker_network_id = utils.get_hash()
|
|
||||||
docker_endpoint_id = utils.get_hash()
|
|
||||||
data = {
|
|
||||||
'NetworkID': docker_network_id,
|
|
||||||
'EndpointID': docker_endpoint_id,
|
|
||||||
}
|
|
||||||
response = self.app.post('/NetworkDriver.DeleteEndpoint',
|
|
||||||
content_type='application/json',
|
|
||||||
data=jsonutils.dumps(data))
|
|
||||||
|
|
||||||
self.assertEqual(200, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertEqual(constants.SCHEMA['SUCCESS'], decoded_json)
|
|
||||||
|
|
||||||
@ddt.data(
|
|
||||||
(False), (True))
|
|
||||||
def test_network_driver_join(self, vif_plug_is_fatal):
|
|
||||||
if vif_plug_is_fatal:
|
|
||||||
self.mox.StubOutWithMock(app, "vif_plug_is_fatal")
|
|
||||||
app.vif_plug_is_fatal = True
|
|
||||||
|
|
||||||
fake_docker_net_id = utils.get_hash()
|
|
||||||
fake_docker_endpoint_id = utils.get_hash()
|
|
||||||
fake_container_id = utils.get_hash()
|
|
||||||
|
|
||||||
fake_neutron_net_id = str(uuid.uuid4())
|
|
||||||
self._mock_out_network(fake_neutron_net_id, fake_docker_net_id)
|
|
||||||
fake_neutron_port_id = str(uuid.uuid4())
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_ports')
|
|
||||||
neutron_port_name = utils.get_neutron_port_name(
|
|
||||||
fake_docker_endpoint_id)
|
|
||||||
fake_neutron_v4_subnet_id = str(uuid.uuid4())
|
|
||||||
fake_neutron_v6_subnet_id = str(uuid.uuid4())
|
|
||||||
fake_neutron_ports_response = self._get_fake_ports(
|
|
||||||
fake_docker_endpoint_id, fake_neutron_net_id,
|
|
||||||
fake_neutron_port_id, constants.PORT_STATUS_DOWN,
|
|
||||||
fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id)
|
|
||||||
app.neutron.list_ports(name=neutron_port_name).AndReturn(
|
|
||||||
fake_neutron_ports_response)
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnets')
|
|
||||||
fake_neutron_subnets_response = self._get_fake_subnets(
|
|
||||||
fake_docker_endpoint_id, fake_neutron_net_id,
|
|
||||||
fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id)
|
|
||||||
app.neutron.list_subnets(network_id=fake_neutron_net_id).AndReturn(
|
|
||||||
fake_neutron_subnets_response)
|
|
||||||
fake_neutron_port = fake_neutron_ports_response['ports'][0]
|
|
||||||
fake_neutron_subnets = fake_neutron_subnets_response['subnets']
|
|
||||||
_, fake_peer_name, _ = self._mock_out_binding(
|
|
||||||
fake_docker_endpoint_id, fake_neutron_port, fake_neutron_subnets)
|
|
||||||
|
|
||||||
if vif_plug_is_fatal:
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'show_port')
|
|
||||||
fake_neutron_ports_response_2 = self._get_fake_port(
|
|
||||||
fake_docker_endpoint_id, fake_neutron_net_id,
|
|
||||||
fake_neutron_port_id, constants.PORT_STATUS_ACTIVE,
|
|
||||||
fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id)
|
|
||||||
app.neutron.show_port(fake_neutron_port_id).AndReturn(
|
|
||||||
fake_neutron_ports_response_2)
|
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
fake_subnets_dict_by_id = {subnet['id']: subnet
|
|
||||||
for subnet in fake_neutron_subnets}
|
|
||||||
|
|
||||||
join_request = {
|
|
||||||
'NetworkID': fake_docker_net_id,
|
|
||||||
'EndpointID': fake_docker_endpoint_id,
|
|
||||||
'SandboxKey': utils.get_sandbox_key(fake_container_id),
|
|
||||||
'Options': {},
|
|
||||||
}
|
|
||||||
response = self.app.post('/NetworkDriver.Join',
|
|
||||||
content_type='application/json',
|
|
||||||
data=jsonutils.dumps(join_request))
|
|
||||||
|
|
||||||
self.assertEqual(200, response.status_code)
|
|
||||||
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
fake_neutron_v4_subnet = fake_subnets_dict_by_id[
|
|
||||||
fake_neutron_v4_subnet_id]
|
|
||||||
fake_neutron_v6_subnet = fake_subnets_dict_by_id[
|
|
||||||
fake_neutron_v6_subnet_id]
|
|
||||||
expected_response = {
|
|
||||||
'Gateway': fake_neutron_v4_subnet['gateway_ip'],
|
|
||||||
'GatewayIPv6': fake_neutron_v6_subnet['gateway_ip'],
|
|
||||||
'InterfaceName': {
|
|
||||||
'DstPrefix': config.CONF.binding.veth_dst_prefix,
|
|
||||||
'SrcName': fake_peer_name,
|
|
||||||
},
|
|
||||||
'StaticRoutes': []
|
|
||||||
}
|
|
||||||
self.assertEqual(expected_response, decoded_json)
|
|
||||||
|
|
||||||
def test_network_driver_leave(self):
|
|
||||||
fake_docker_net_id = utils.get_hash()
|
|
||||||
fake_docker_endpoint_id = utils.get_hash()
|
|
||||||
|
|
||||||
fake_neutron_net_id = str(uuid.uuid4())
|
|
||||||
self._mock_out_network(fake_neutron_net_id, fake_docker_net_id)
|
|
||||||
fake_neutron_port_id = str(uuid.uuid4())
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_ports')
|
|
||||||
neutron_port_name = utils.get_neutron_port_name(
|
|
||||||
fake_docker_endpoint_id)
|
|
||||||
fake_neutron_v4_subnet_id = str(uuid.uuid4())
|
|
||||||
fake_neutron_v6_subnet_id = str(uuid.uuid4())
|
|
||||||
fake_neutron_ports_response = self._get_fake_ports(
|
|
||||||
fake_docker_endpoint_id, fake_neutron_net_id,
|
|
||||||
fake_neutron_port_id, constants.PORT_STATUS_ACTIVE,
|
|
||||||
fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id)
|
|
||||||
app.neutron.list_ports(name=neutron_port_name).AndReturn(
|
|
||||||
fake_neutron_ports_response)
|
|
||||||
|
|
||||||
fake_neutron_port = fake_neutron_ports_response['ports'][0]
|
|
||||||
self._mock_out_unbinding(fake_docker_endpoint_id, fake_neutron_port)
|
|
||||||
|
|
||||||
leave_request = {
|
|
||||||
'NetworkID': fake_docker_net_id,
|
|
||||||
'EndpointID': fake_docker_endpoint_id,
|
|
||||||
}
|
|
||||||
response = self.app.post('/NetworkDriver.Leave',
|
|
||||||
content_type='application/json',
|
|
||||||
data=jsonutils.dumps(leave_request))
|
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
self.assertEqual(200, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertEqual(constants.SCHEMA['SUCCESS'], decoded_json)
|
|
|
@ -1,252 +0,0 @@
|
||||||
# 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 uuid
|
|
||||||
|
|
||||||
import ddt
|
|
||||||
from neutronclient.common import exceptions
|
|
||||||
from oslo_serialization import jsonutils
|
|
||||||
|
|
||||||
from kuryr import app
|
|
||||||
from kuryr.common import constants
|
|
||||||
from kuryr.tests.unit import base
|
|
||||||
from kuryr import utils
|
|
||||||
|
|
||||||
|
|
||||||
class TestKuryrEndpointFailures(base.TestKuryrFailures):
|
|
||||||
"""Base class that has the methods commonly shared among endpoint tests.
|
|
||||||
|
|
||||||
This class mainly has the methods for mocking API calls against Neutron.
|
|
||||||
"""
|
|
||||||
def _create_subnet_with_exception(self, neutron_network_id,
|
|
||||||
docker_endpoint_id, ex):
|
|
||||||
fake_neutron_subnet_v4_id = str(uuid.uuid4())
|
|
||||||
fake_neutron_subnet_v6_id = str(uuid.uuid4())
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'create_subnet')
|
|
||||||
fake_subnet_request = {
|
|
||||||
'subnets': [{
|
|
||||||
'name': '-'.join([docker_endpoint_id, '192.168.1.0']),
|
|
||||||
'network_id': neutron_network_id,
|
|
||||||
'ip_version': 4,
|
|
||||||
"cidr": '192.168.1.0/24',
|
|
||||||
'enable_dhcp': 'False',
|
|
||||||
'subnetpool_id': ''
|
|
||||||
}, {
|
|
||||||
'name': '-'.join([docker_endpoint_id, 'fe80::']),
|
|
||||||
'network_id': neutron_network_id,
|
|
||||||
'ip_version': 6,
|
|
||||||
"cidr": 'fe80::/64',
|
|
||||||
'enable_dhcp': 'False',
|
|
||||||
'subnetpool_id': ''
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
fake_subnets = self._get_fake_subnets(
|
|
||||||
docker_endpoint_id, neutron_network_id,
|
|
||||||
fake_neutron_subnet_v4_id, fake_neutron_subnet_v6_id)
|
|
||||||
|
|
||||||
if ex:
|
|
||||||
app.neutron.create_subnet(fake_subnet_request).AndRaise(ex)
|
|
||||||
else:
|
|
||||||
app.neutron.create_subnet(
|
|
||||||
fake_subnet_request).AndReturn(fake_subnets)
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
return (fake_neutron_subnet_v4_id, fake_neutron_subnet_v6_id)
|
|
||||||
|
|
||||||
def _delete_subnet_with_exception(self, neutron_subnet_id, ex):
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'delete_subnet')
|
|
||||||
if ex:
|
|
||||||
app.neutron.delete_subnet(neutron_subnet_id).AndRaise(ex)
|
|
||||||
else:
|
|
||||||
app.neutron.delete_subnet(neutron_subnet_id).AndReturn(None)
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
def _delete_subnets_with_exception(self, neutron_subnet_ids, ex):
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'delete_subnet')
|
|
||||||
for neutron_subnet_id in neutron_subnet_ids:
|
|
||||||
if ex:
|
|
||||||
app.neutron.delete_subnet(neutron_subnet_id).AndRaise(ex)
|
|
||||||
else:
|
|
||||||
app.neutron.delete_subnet(neutron_subnet_id).AndReturn(None)
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
def _create_port_with_exception(self, neutron_network_id,
|
|
||||||
docker_endpoint_id, neutron_subnetv4_id,
|
|
||||||
neutron_subnetv6_id, ex):
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'create_port')
|
|
||||||
fake_port_request = {
|
|
||||||
'port': {
|
|
||||||
'name': utils.get_neutron_port_name(docker_endpoint_id),
|
|
||||||
'admin_state_up': True,
|
|
||||||
"binding:host_id": utils.get_hostname(),
|
|
||||||
'device_owner': constants.DEVICE_OWNER,
|
|
||||||
'device_id': docker_endpoint_id,
|
|
||||||
'fixed_ips': [{
|
|
||||||
'subnet_id': neutron_subnetv4_id,
|
|
||||||
'ip_address': '192.168.1.2'
|
|
||||||
}, {
|
|
||||||
'subnet_id': neutron_subnetv6_id,
|
|
||||||
'ip_address': 'fe80::f816:3eff:fe20:57c4'
|
|
||||||
}],
|
|
||||||
'mac_address': "fa:16:3e:20:57:c3",
|
|
||||||
'network_id': neutron_network_id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
# The following fake response is retrieved from the Neutron doc:
|
|
||||||
# http://developer.openstack.org/api-ref-networking-v2.html#createPort # noqa
|
|
||||||
fake_port = {
|
|
||||||
"port": {
|
|
||||||
"status": "DOWN",
|
|
||||||
"name": utils.get_neutron_port_name(docker_endpoint_id),
|
|
||||||
"allowed_address_pairs": [],
|
|
||||||
"admin_state_up": True,
|
|
||||||
"binding:host_id": utils.get_hostname(),
|
|
||||||
"network_id": neutron_network_id,
|
|
||||||
"tenant_id": "d6700c0c9ffa4f1cb322cd4a1f3906fa",
|
|
||||||
"device_owner": constants.DEVICE_OWNER,
|
|
||||||
'device_id': docker_endpoint_id,
|
|
||||||
"mac_address": "fa:16:3e:20:57:c3",
|
|
||||||
'fixed_ips': [{
|
|
||||||
'subnet_id': neutron_subnetv4_id,
|
|
||||||
'ip_address': '192.168.1.2'
|
|
||||||
}, {
|
|
||||||
'subnet_id': neutron_subnetv6_id,
|
|
||||||
'ip_address': 'fe80::f816:3eff:fe20:57c4'
|
|
||||||
}],
|
|
||||||
"id": "65c0ee9f-d634-4522-8954-51021b570b0d",
|
|
||||||
"security_groups": [],
|
|
||||||
"device_id": ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ex:
|
|
||||||
app.neutron.create_port(fake_port_request).AndRaise(ex)
|
|
||||||
else:
|
|
||||||
app.neutron.create_port(fake_port_request).AndReturn(fake_port)
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
def _delete_port_with_exception(self, neutron_port_id, ex):
|
|
||||||
self.mox.StubOutWithMock(app.neutron, "delete_port")
|
|
||||||
if ex:
|
|
||||||
app.neutron.delete_port(neutron_port_id).AndRaise(ex)
|
|
||||||
else:
|
|
||||||
app.neutron.delete_port(neutron_port_id).AndReturn(None)
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
|
|
||||||
@ddt.ddt
|
|
||||||
class TestKuryrEndpointCreateFailures(TestKuryrEndpointFailures):
|
|
||||||
"""Unit tests for the failures for creating endpoints.
|
|
||||||
|
|
||||||
This test covers error responses listed in the spec:
|
|
||||||
http://developer.openstack.org/api-ref-networking-v2.html#createSubnet # noqa
|
|
||||||
http://developer.openstack.org/api-ref-networking-v2-ext.html#createPort # noqa
|
|
||||||
"""
|
|
||||||
def _invoke_create_request(self, docker_network_id, docker_endpoint_id):
|
|
||||||
data = {
|
|
||||||
'NetworkID': docker_network_id,
|
|
||||||
'EndpointID': docker_endpoint_id,
|
|
||||||
'Options': {},
|
|
||||||
'Interface': {
|
|
||||||
'Address': '192.168.1.2/24',
|
|
||||||
'AddressIPv6': 'fe80::f816:3eff:fe20:57c4/64',
|
|
||||||
'MacAddress': "fa:16:3e:20:57:c3"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
response = self.app.post('/NetworkDriver.CreateEndpoint',
|
|
||||||
content_type='application/json',
|
|
||||||
data=jsonutils.dumps(data))
|
|
||||||
return response
|
|
||||||
|
|
||||||
@ddt.data(exceptions.Unauthorized, exceptions.Forbidden,
|
|
||||||
exceptions.NotFound, exceptions.ServiceUnavailable)
|
|
||||||
def test_create_endpoint_port_failures(self, GivenException):
|
|
||||||
fake_docker_network_id = utils.get_hash()
|
|
||||||
fake_docker_endpoint_id = utils.get_hash()
|
|
||||||
fake_neutron_network_id = str(uuid.uuid4())
|
|
||||||
fake_neutron_subnet_v4_id = str(uuid.uuid4())
|
|
||||||
fake_neutron_subnet_v6_id = str(uuid.uuid4())
|
|
||||||
fake_subnets = self._get_fake_subnets(
|
|
||||||
fake_docker_endpoint_id, fake_neutron_network_id,
|
|
||||||
fake_neutron_subnet_v4_id, fake_neutron_subnet_v6_id)
|
|
||||||
|
|
||||||
fake_fixed_ips = ['subnet_id=%s' % fake_neutron_subnet_v4_id,
|
|
||||||
'ip_address=192.168.1.2',
|
|
||||||
'subnet_id=%s' % fake_neutron_subnet_v6_id,
|
|
||||||
'ip_address=fe80::f816:3eff:fe20:57c4']
|
|
||||||
fake_port_response = {"ports": []}
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_ports')
|
|
||||||
app.neutron.list_ports(fixed_ips=fake_fixed_ips).AndReturn(
|
|
||||||
fake_port_response)
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnets')
|
|
||||||
app.neutron.list_subnets(
|
|
||||||
network_id=fake_neutron_network_id,
|
|
||||||
cidr='192.168.1.0/24').AndReturn(fake_subnets)
|
|
||||||
app.neutron.list_subnets(
|
|
||||||
network_id=fake_neutron_network_id,
|
|
||||||
cidr='fe80::/64').AndReturn({'subnets': []})
|
|
||||||
|
|
||||||
self._create_port_with_exception(fake_neutron_network_id,
|
|
||||||
fake_docker_endpoint_id,
|
|
||||||
fake_neutron_subnet_v4_id,
|
|
||||||
fake_neutron_subnet_v6_id,
|
|
||||||
GivenException())
|
|
||||||
self._mock_out_network(fake_neutron_network_id, fake_docker_network_id)
|
|
||||||
|
|
||||||
response = self._invoke_create_request(
|
|
||||||
fake_docker_network_id, fake_docker_endpoint_id)
|
|
||||||
|
|
||||||
self.assertEqual(GivenException.status_code, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertIn('Err', decoded_json)
|
|
||||||
self.assertEqual({'Err': GivenException.message}, decoded_json)
|
|
||||||
|
|
||||||
def test_create_endpoint_bad_request(self):
|
|
||||||
fake_docker_network_id = utils.get_hash()
|
|
||||||
invalid_docker_endpoint_id = 'id-should-be-hexdigits'
|
|
||||||
|
|
||||||
response = self._invoke_create_request(
|
|
||||||
fake_docker_network_id, invalid_docker_endpoint_id)
|
|
||||||
|
|
||||||
self.assertEqual(400, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertIn('Err', decoded_json)
|
|
||||||
# TODO(tfukushima): Add the better error message validation.
|
|
||||||
self.assertIn(invalid_docker_endpoint_id, decoded_json['Err'])
|
|
||||||
self.assertIn('EndpointID', decoded_json['Err'])
|
|
||||||
|
|
||||||
|
|
||||||
@ddt.ddt
|
|
||||||
class TestKuryrEndpointDeleteFailures(TestKuryrEndpointFailures):
|
|
||||||
"""Unit tests for the failures for deleting endpoints."""
|
|
||||||
def _invoke_delete_request(self, docker_network_id, docker_endpoint_id):
|
|
||||||
data = {'NetworkID': docker_network_id,
|
|
||||||
'EndpointID': docker_endpoint_id}
|
|
||||||
response = self.app.post('/NetworkDriver.DeleteEndpoint',
|
|
||||||
content_type='application/json',
|
|
||||||
data=jsonutils.dumps(data))
|
|
||||||
return response
|
|
||||||
|
|
||||||
def test_delete_endpoint_bad_request(self):
|
|
||||||
fake_docker_network_id = utils.get_hash()
|
|
||||||
invalid_docker_endpoint_id = 'id-should-be-hexdigits'
|
|
||||||
|
|
||||||
response = self._invoke_delete_request(
|
|
||||||
fake_docker_network_id, invalid_docker_endpoint_id)
|
|
||||||
|
|
||||||
self.assertEqual(400, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertIn('Err', decoded_json)
|
|
||||||
# TODO(tfukushima): Add the better error message validation.
|
|
||||||
self.assertIn(invalid_docker_endpoint_id, decoded_json['Err'])
|
|
||||||
self.assertIn('EndpointID', decoded_json['Err'])
|
|
|
@ -1,181 +0,0 @@
|
||||||
# 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 uuid
|
|
||||||
|
|
||||||
import ddt
|
|
||||||
from oslo_serialization import jsonutils
|
|
||||||
|
|
||||||
from kuryr import app
|
|
||||||
from kuryr.common import constants as const
|
|
||||||
from kuryr.tests.unit import base
|
|
||||||
from kuryr import utils
|
|
||||||
|
|
||||||
|
|
||||||
@ddt.ddt
|
|
||||||
class TestKuryrNetworkPreExisting(base.TestKuryrBase):
|
|
||||||
|
|
||||||
def _ids(self):
|
|
||||||
docker_network_id = utils.get_hash()
|
|
||||||
fake_neutron_net_id = "4e8e5957-649f-477b-9e5b-f1f75b21c03c"
|
|
||||||
fake_response = {
|
|
||||||
'networks':
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"status": "ACTIVE",
|
|
||||||
"subnets": [],
|
|
||||||
"admin_state_up": True,
|
|
||||||
"tenant_id": "9bacb3c5d39d41a79512987f338cf177",
|
|
||||||
"router:external": False,
|
|
||||||
"segments": [],
|
|
||||||
"shared": False,
|
|
||||||
"id": fake_neutron_net_id
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
return docker_network_id, fake_neutron_net_id, fake_response
|
|
||||||
|
|
||||||
@ddt.data(
|
|
||||||
(True), (False))
|
|
||||||
def test_create_network_pre_existing(self, use_tags):
|
|
||||||
if not use_tags:
|
|
||||||
self.mox.StubOutWithMock(app, "tag")
|
|
||||||
app.tag = use_tags
|
|
||||||
|
|
||||||
docker_network_id, fake_neutron_net_id, fake_response = self._ids()
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, "list_networks")
|
|
||||||
app.neutron.list_networks(id=fake_neutron_net_id).AndReturn(
|
|
||||||
fake_response)
|
|
||||||
|
|
||||||
if app.tag:
|
|
||||||
self.mox.StubOutWithMock(app.neutron, "add_tag")
|
|
||||||
tags = utils.create_net_tags(docker_network_id)
|
|
||||||
for tag in tags:
|
|
||||||
app.neutron.add_tag('networks', fake_neutron_net_id, tag)
|
|
||||||
app.neutron.add_tag('networks', fake_neutron_net_id,
|
|
||||||
const.KURYR_EXISTING_NEUTRON_NET)
|
|
||||||
else:
|
|
||||||
self.mox.StubOutWithMock(app.neutron, "update_network")
|
|
||||||
app.neutron.update_network(
|
|
||||||
fake_neutron_net_id, {'network':
|
|
||||||
{'name': docker_network_id}}).AndReturn(
|
|
||||||
fake_response)
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnets')
|
|
||||||
fake_existing_subnets_response = {
|
|
||||||
"subnets": []
|
|
||||||
}
|
|
||||||
fake_cidr_v4 = '192.168.42.0/24'
|
|
||||||
app.neutron.list_subnets(
|
|
||||||
network_id=fake_neutron_net_id,
|
|
||||||
cidr=fake_cidr_v4).AndReturn(fake_existing_subnets_response)
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'create_subnet')
|
|
||||||
fake_subnet_request = {
|
|
||||||
"subnets": [{
|
|
||||||
'name': fake_cidr_v4,
|
|
||||||
'network_id': fake_neutron_net_id,
|
|
||||||
'ip_version': 4,
|
|
||||||
'cidr': fake_cidr_v4,
|
|
||||||
'enable_dhcp': app.enable_dhcp,
|
|
||||||
'gateway_ip': '192.168.42.1',
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
subnet_v4_id = str(uuid.uuid4())
|
|
||||||
fake_v4_subnet = self._get_fake_v4_subnet(
|
|
||||||
fake_neutron_net_id, subnet_v4_id,
|
|
||||||
name=fake_cidr_v4, cidr=fake_cidr_v4)
|
|
||||||
fake_subnet_response = {
|
|
||||||
'subnets': [
|
|
||||||
fake_v4_subnet['subnet']
|
|
||||||
]
|
|
||||||
}
|
|
||||||
app.neutron.create_subnet(
|
|
||||||
fake_subnet_request).AndReturn(fake_subnet_response)
|
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
network_request = {
|
|
||||||
'NetworkID': docker_network_id,
|
|
||||||
'IPv4Data': [{
|
|
||||||
'AddressSpace': 'foo',
|
|
||||||
'Pool': '192.168.42.0/24',
|
|
||||||
'Gateway': '192.168.42.1/24',
|
|
||||||
}],
|
|
||||||
'IPv6Data': [{
|
|
||||||
'AddressSpace': 'bar',
|
|
||||||
'Pool': 'fe80::/64',
|
|
||||||
'Gateway': 'fe80::f816:3eff:fe20:57c3/64',
|
|
||||||
}],
|
|
||||||
'Options': {
|
|
||||||
const.NETWORK_GENERIC_OPTIONS: {
|
|
||||||
const.NEUTRON_UUID_OPTION: fake_neutron_net_id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
response = self.app.post('/NetworkDriver.CreateNetwork',
|
|
||||||
content_type='application/json',
|
|
||||||
data=jsonutils.dumps(network_request))
|
|
||||||
|
|
||||||
self.assertEqual(200, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertEqual(const.SCHEMA['SUCCESS'], decoded_json)
|
|
||||||
|
|
||||||
@ddt.data(
|
|
||||||
(True), (False))
|
|
||||||
def test_delete_network_pre_existing(self, use_tags):
|
|
||||||
if not use_tags:
|
|
||||||
self.mox.StubOutWithMock(app, "tag")
|
|
||||||
app.tag = use_tags
|
|
||||||
|
|
||||||
docker_network_id, fake_neutron_net_id, fake_response = self._ids()
|
|
||||||
|
|
||||||
if app.tag:
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_networks')
|
|
||||||
t = utils.make_net_tags(docker_network_id)
|
|
||||||
te = t + ',' + const.KURYR_EXISTING_NEUTRON_NET
|
|
||||||
app.neutron.list_networks(tags=te).AndReturn(
|
|
||||||
fake_response)
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, "remove_tag")
|
|
||||||
tags = utils.create_net_tags(docker_network_id)
|
|
||||||
for tag in tags:
|
|
||||||
app.neutron.remove_tag('networks', fake_neutron_net_id, tag)
|
|
||||||
app.neutron.remove_tag('networks', fake_neutron_net_id,
|
|
||||||
const.KURYR_EXISTING_NEUTRON_NET)
|
|
||||||
else:
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_networks')
|
|
||||||
app.neutron.list_networks(name=docker_network_id).AndReturn(
|
|
||||||
fake_response)
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnets')
|
|
||||||
fake_existing_subnets_response = {
|
|
||||||
"subnets": []
|
|
||||||
}
|
|
||||||
app.neutron.list_subnets(
|
|
||||||
network_id=fake_neutron_net_id).AndReturn(
|
|
||||||
fake_existing_subnets_response)
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'delete_network')
|
|
||||||
app.neutron.delete_network(fake_neutron_net_id).AndReturn(None)
|
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
data = {'NetworkID': docker_network_id}
|
|
||||||
response = self.app.post('/NetworkDriver.DeleteNetwork',
|
|
||||||
content_type='application/json',
|
|
||||||
data=jsonutils.dumps(data))
|
|
||||||
|
|
||||||
self.assertEqual(200, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertEqual(const.SCHEMA['SUCCESS'], decoded_json)
|
|
|
@ -1,485 +0,0 @@
|
||||||
# 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 ddt
|
|
||||||
from oslo_serialization import jsonutils
|
|
||||||
import uuid
|
|
||||||
|
|
||||||
from kuryr.common import config
|
|
||||||
from kuryr.common import constants as const
|
|
||||||
from kuryr.controllers import app
|
|
||||||
from kuryr.tests.unit import base
|
|
||||||
from kuryr import utils
|
|
||||||
|
|
||||||
|
|
||||||
FAKE_IP4_CIDR = '10.0.0.0/16'
|
|
||||||
|
|
||||||
|
|
||||||
@ddt.ddt
|
|
||||||
class TestKuryrIpam(base.TestKuryrBase):
|
|
||||||
"""Basic unit tests for libnetwork remote IPAM driver URI endpoints.
|
|
||||||
|
|
||||||
This test class covers the following HTTP methods and URIs as described in
|
|
||||||
the remote IPAM driver specification as below:
|
|
||||||
|
|
||||||
https://github.com/docker/libnetwork/blob/9bf339f27e9f5c7c922036706c9bcc410899f249/docs/ipam.md # noqa
|
|
||||||
|
|
||||||
- POST /IpamDriver.GetDefaultAddressSpaces
|
|
||||||
- POST /IpamDriver.RequestPool
|
|
||||||
- POST /IpamDriver.ReleasePool
|
|
||||||
- POST /IpamDriver.RequestAddress
|
|
||||||
- POST /IpamDriver.ReleaseAddress
|
|
||||||
"""
|
|
||||||
@ddt.data(
|
|
||||||
('/IpamDriver.GetDefaultAddressSpaces',
|
|
||||||
{"LocalDefaultAddressSpace":
|
|
||||||
config.CONF.local_default_address_space,
|
|
||||||
"GlobalDefaultAddressSpace":
|
|
||||||
config.CONF.global_default_address_space}),
|
|
||||||
('/IpamDriver.GetCapabilities',
|
|
||||||
{"RequiresMACAddress": False}))
|
|
||||||
@ddt.unpack
|
|
||||||
def test_remote_ipam_driver_endpoint(self, endpoint, expected):
|
|
||||||
response = self.app.post(endpoint)
|
|
||||||
self.assertEqual(200, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertEqual(expected, decoded_json)
|
|
||||||
|
|
||||||
def test_ipam_driver_request_pool_with_user_pool(self):
|
|
||||||
pool_name = utils.get_neutron_subnetpool_name(FAKE_IP4_CIDR)
|
|
||||||
new_subnetpool = {
|
|
||||||
'name': pool_name,
|
|
||||||
'default_prefixlen': 16,
|
|
||||||
'prefixes': [FAKE_IP4_CIDR]}
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnetpools')
|
|
||||||
fake_kuryr_subnetpool_id = str(uuid.uuid4())
|
|
||||||
fake_name = pool_name
|
|
||||||
kuryr_subnetpools = self._get_fake_v4_subnetpools(
|
|
||||||
fake_kuryr_subnetpool_id, prefixes=[FAKE_IP4_CIDR],
|
|
||||||
name=fake_name)
|
|
||||||
app.neutron.list_subnetpools(name=fake_name).AndReturn(
|
|
||||||
{'subnetpools': []})
|
|
||||||
fake_subnetpool_response = {
|
|
||||||
'subnetpool': kuryr_subnetpools['subnetpools'][0]
|
|
||||||
}
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'create_subnetpool')
|
|
||||||
app.neutron.create_subnetpool(
|
|
||||||
{'subnetpool': new_subnetpool}).AndReturn(fake_subnetpool_response)
|
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
fake_request = {
|
|
||||||
'AddressSpace': '',
|
|
||||||
'Pool': FAKE_IP4_CIDR,
|
|
||||||
'SubPool': '', # In the case --ip-range is not given
|
|
||||||
'Options': {},
|
|
||||||
'V6': False
|
|
||||||
}
|
|
||||||
response = self.app.post('/IpamDriver.RequestPool',
|
|
||||||
content_type='application/json',
|
|
||||||
data=jsonutils.dumps(fake_request))
|
|
||||||
|
|
||||||
self.assertEqual(200, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertEqual(fake_kuryr_subnetpool_id, decoded_json['PoolID'])
|
|
||||||
|
|
||||||
def test_ipam_driver_request_pool_with_pool_name_option(self):
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnetpools')
|
|
||||||
fake_kuryr_subnetpool_id = str(uuid.uuid4())
|
|
||||||
fake_name = 'fake_pool_name'
|
|
||||||
new_subnetpool = {
|
|
||||||
'name': fake_name,
|
|
||||||
'default_prefixlen': 16,
|
|
||||||
'prefixes': [FAKE_IP4_CIDR]}
|
|
||||||
|
|
||||||
kuryr_subnetpools = self._get_fake_v4_subnetpools(
|
|
||||||
fake_kuryr_subnetpool_id, prefixes=[FAKE_IP4_CIDR],
|
|
||||||
name=fake_name)
|
|
||||||
fake_subnetpool_response = {
|
|
||||||
'subnetpool': kuryr_subnetpools['subnetpools'][0]
|
|
||||||
}
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'create_subnetpool')
|
|
||||||
app.neutron.create_subnetpool(
|
|
||||||
{'subnetpool': new_subnetpool}).AndReturn(fake_subnetpool_response)
|
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
fake_request = {
|
|
||||||
'AddressSpace': '',
|
|
||||||
'Pool': FAKE_IP4_CIDR,
|
|
||||||
'SubPool': '', # In the case --ip-range is not given
|
|
||||||
'Options': {'neutron.pool.name': 'fake_pool_name'},
|
|
||||||
'V6': False
|
|
||||||
}
|
|
||||||
response = self.app.post('/IpamDriver.RequestPool',
|
|
||||||
content_type='application/json',
|
|
||||||
data=jsonutils.dumps(fake_request))
|
|
||||||
|
|
||||||
self.assertEqual(200, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertEqual(fake_kuryr_subnetpool_id, decoded_json['PoolID'])
|
|
||||||
|
|
||||||
def test_ipam_driver_request_pool_with_default_v6pool(self):
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnetpools')
|
|
||||||
fake_kuryr_subnetpool_id = str(uuid.uuid4())
|
|
||||||
fake_name = 'kuryr6'
|
|
||||||
kuryr_subnetpools = self._get_fake_v6_subnetpools(
|
|
||||||
fake_kuryr_subnetpool_id, prefixes=['fe80::/64'])
|
|
||||||
app.neutron.list_subnetpools(name=fake_name).AndReturn(
|
|
||||||
{'subnetpools': kuryr_subnetpools['subnetpools']})
|
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
fake_request = {
|
|
||||||
'AddressSpace': '',
|
|
||||||
'Pool': '',
|
|
||||||
'SubPool': '', # In the case --ip-range is not given
|
|
||||||
'Options': {},
|
|
||||||
'V6': True
|
|
||||||
}
|
|
||||||
response = self.app.post('/IpamDriver.RequestPool',
|
|
||||||
content_type='application/json',
|
|
||||||
data=jsonutils.dumps(fake_request))
|
|
||||||
|
|
||||||
self.assertEqual(200, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertEqual(fake_kuryr_subnetpool_id, decoded_json['PoolID'])
|
|
||||||
|
|
||||||
def test_ipam_driver_release_pool(self):
|
|
||||||
fake_kuryr_subnetpool_id = str(uuid.uuid4())
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'delete_subnetpool')
|
|
||||||
app.neutron.delete_subnetpool(fake_kuryr_subnetpool_id).AndReturn(
|
|
||||||
{})
|
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
fake_request = {
|
|
||||||
'PoolID': fake_kuryr_subnetpool_id
|
|
||||||
}
|
|
||||||
response = self.app.post('/IpamDriver.ReleasePool',
|
|
||||||
content_type='application/json',
|
|
||||||
data=jsonutils.dumps(fake_request))
|
|
||||||
|
|
||||||
self.assertEqual(200, response.status_code)
|
|
||||||
|
|
||||||
def test_ipam_driver_request_address(self):
|
|
||||||
# faking list_subnetpools
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnetpools')
|
|
||||||
fake_kuryr_subnetpool_id = str(uuid.uuid4())
|
|
||||||
fake_name = utils.get_neutron_subnetpool_name(FAKE_IP4_CIDR)
|
|
||||||
kuryr_subnetpools = self._get_fake_v4_subnetpools(
|
|
||||||
fake_kuryr_subnetpool_id, prefixes=[FAKE_IP4_CIDR],
|
|
||||||
name=fake_name)
|
|
||||||
app.neutron.list_subnetpools(id=fake_kuryr_subnetpool_id).AndReturn(
|
|
||||||
kuryr_subnetpools)
|
|
||||||
|
|
||||||
# faking list_subnets
|
|
||||||
docker_endpoint_id = utils.get_hash()
|
|
||||||
neutron_network_id = str(uuid.uuid4())
|
|
||||||
subnet_v4_id = str(uuid.uuid4())
|
|
||||||
fake_v4_subnet = self._get_fake_v4_subnet(
|
|
||||||
neutron_network_id, docker_endpoint_id, subnet_v4_id,
|
|
||||||
subnetpool_id=fake_kuryr_subnetpool_id,
|
|
||||||
cidr=FAKE_IP4_CIDR)
|
|
||||||
fake_subnet_response = {
|
|
||||||
'subnets': [
|
|
||||||
fake_v4_subnet['subnet']
|
|
||||||
]
|
|
||||||
}
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnets')
|
|
||||||
app.neutron.list_subnets(cidr=FAKE_IP4_CIDR).AndReturn(
|
|
||||||
fake_subnet_response)
|
|
||||||
|
|
||||||
# faking create_port
|
|
||||||
fake_neutron_port_id = str(uuid.uuid4())
|
|
||||||
fake_port = base.TestKuryrBase._get_fake_port(
|
|
||||||
docker_endpoint_id, neutron_network_id,
|
|
||||||
fake_neutron_port_id, const.PORT_STATUS_ACTIVE,
|
|
||||||
subnet_v4_id,
|
|
||||||
neutron_subnet_v4_address="10.0.0.5")
|
|
||||||
port_request = {
|
|
||||||
'name': 'kuryr-unbound-port',
|
|
||||||
'admin_state_up': True,
|
|
||||||
'network_id': neutron_network_id,
|
|
||||||
'binding:host_id': utils.get_hostname(),
|
|
||||||
}
|
|
||||||
fixed_ips = port_request['fixed_ips'] = []
|
|
||||||
fixed_ip = {'subnet_id': subnet_v4_id}
|
|
||||||
fixed_ips.append(fixed_ip)
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'create_port')
|
|
||||||
app.neutron.create_port({'port': port_request}).AndReturn(fake_port)
|
|
||||||
|
|
||||||
# Apply mocks
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
# Testing container ip allocation
|
|
||||||
fake_request = {
|
|
||||||
'PoolID': fake_kuryr_subnetpool_id,
|
|
||||||
'Address': '', # Querying for container address
|
|
||||||
'Options': {}
|
|
||||||
}
|
|
||||||
response = self.app.post('/IpamDriver.RequestAddress',
|
|
||||||
content_type='application/json',
|
|
||||||
data=jsonutils.dumps(fake_request))
|
|
||||||
|
|
||||||
self.assertEqual(200, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertEqual('10.0.0.5/16', decoded_json['Address'])
|
|
||||||
|
|
||||||
def test_ipam_driver_request_address_overlapping_cidr(self):
|
|
||||||
# faking list_subnetpools
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnetpools')
|
|
||||||
|
|
||||||
fake_kuryr_subnetpool_id = str(uuid.uuid4())
|
|
||||||
fake_kuryr_subnetpool_id2 = str(uuid.uuid4())
|
|
||||||
|
|
||||||
fake_name = utils.get_neutron_subnetpool_name(FAKE_IP4_CIDR)
|
|
||||||
kuryr_subnetpools = self._get_fake_v4_subnetpools(
|
|
||||||
fake_kuryr_subnetpool_id, prefixes=[FAKE_IP4_CIDR],
|
|
||||||
name=fake_name)
|
|
||||||
app.neutron.list_subnetpools(id=fake_kuryr_subnetpool_id).AndReturn(
|
|
||||||
kuryr_subnetpools)
|
|
||||||
|
|
||||||
# faking list_subnets
|
|
||||||
docker_endpoint_id = utils.get_hash()
|
|
||||||
|
|
||||||
neutron_network_id = str(uuid.uuid4())
|
|
||||||
neutron_network_id2 = str(uuid.uuid4())
|
|
||||||
|
|
||||||
neutron_subnet_v4_id = str(uuid.uuid4())
|
|
||||||
neutron_subnet_v4_id2 = str(uuid.uuid4())
|
|
||||||
|
|
||||||
fake_v4_subnet = self._get_fake_v4_subnet(
|
|
||||||
neutron_network_id, docker_endpoint_id, neutron_subnet_v4_id,
|
|
||||||
subnetpool_id=fake_kuryr_subnetpool_id,
|
|
||||||
cidr=FAKE_IP4_CIDR)
|
|
||||||
|
|
||||||
fake_v4_subnet2 = self._get_fake_v4_subnet(
|
|
||||||
neutron_network_id2, docker_endpoint_id, neutron_subnet_v4_id2,
|
|
||||||
subnetpool_id=fake_kuryr_subnetpool_id2,
|
|
||||||
cidr=FAKE_IP4_CIDR)
|
|
||||||
|
|
||||||
fake_subnet_response = {
|
|
||||||
'subnets': [
|
|
||||||
fake_v4_subnet2['subnet'],
|
|
||||||
fake_v4_subnet['subnet']
|
|
||||||
]
|
|
||||||
}
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnets')
|
|
||||||
app.neutron.list_subnets(cidr=FAKE_IP4_CIDR).AndReturn(
|
|
||||||
fake_subnet_response)
|
|
||||||
# faking create_port
|
|
||||||
fake_neutron_port_id = str(uuid.uuid4())
|
|
||||||
fake_port = base.TestKuryrBase._get_fake_port(
|
|
||||||
docker_endpoint_id, neutron_network_id,
|
|
||||||
fake_neutron_port_id,
|
|
||||||
neutron_subnet_v4_id=neutron_subnet_v4_id,
|
|
||||||
neutron_subnet_v4_address="10.0.0.5")
|
|
||||||
port_request = {
|
|
||||||
'name': 'kuryr-unbound-port',
|
|
||||||
'admin_state_up': True,
|
|
||||||
'network_id': neutron_network_id,
|
|
||||||
'binding:host_id': utils.get_hostname(),
|
|
||||||
}
|
|
||||||
port_request['fixed_ips'] = []
|
|
||||||
fixed_ip = {'subnet_id': neutron_subnet_v4_id}
|
|
||||||
port_request['fixed_ips'].append(fixed_ip)
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'create_port')
|
|
||||||
app.neutron.create_port({'port': port_request}).AndReturn(fake_port)
|
|
||||||
|
|
||||||
# Apply mocks
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
# Testing container ip allocation
|
|
||||||
fake_request = {
|
|
||||||
'PoolID': fake_kuryr_subnetpool_id,
|
|
||||||
'Address': '', # Querying for container address
|
|
||||||
'Options': {}
|
|
||||||
}
|
|
||||||
response = self.app.post('/IpamDriver.RequestAddress',
|
|
||||||
content_type='application/json',
|
|
||||||
data=jsonutils.dumps(fake_request))
|
|
||||||
|
|
||||||
self.assertEqual(200, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertEqual('10.0.0.5/16', decoded_json['Address'])
|
|
||||||
|
|
||||||
def test_ipam_driver_request_address_for_same_gateway(self):
|
|
||||||
# faking list_subnetpools
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnetpools')
|
|
||||||
fake_kuryr_subnetpool_id = str(uuid.uuid4())
|
|
||||||
fake_name = utils.get_neutron_subnetpool_name(FAKE_IP4_CIDR)
|
|
||||||
kuryr_subnetpools = self._get_fake_v4_subnetpools(
|
|
||||||
fake_kuryr_subnetpool_id, prefixes=[FAKE_IP4_CIDR],
|
|
||||||
name=fake_name)
|
|
||||||
app.neutron.list_subnetpools(id=fake_kuryr_subnetpool_id).AndReturn(
|
|
||||||
kuryr_subnetpools)
|
|
||||||
|
|
||||||
# faking list_subnets
|
|
||||||
docker_endpoint_id = utils.get_hash()
|
|
||||||
neutron_network_id = str(uuid.uuid4())
|
|
||||||
subnet_v4_id = str(uuid.uuid4())
|
|
||||||
fake_v4_subnet = self._get_fake_v4_subnet(
|
|
||||||
neutron_network_id, docker_endpoint_id, subnet_v4_id,
|
|
||||||
subnetpool_id=fake_kuryr_subnetpool_id,
|
|
||||||
cidr=FAKE_IP4_CIDR)
|
|
||||||
fake_v4_subnet['subnet'].update(gateway_ip='10.0.0.1')
|
|
||||||
fake_subnet_response = {
|
|
||||||
'subnets': [
|
|
||||||
fake_v4_subnet['subnet']
|
|
||||||
]
|
|
||||||
}
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnets')
|
|
||||||
app.neutron.list_subnets(cidr=FAKE_IP4_CIDR).AndReturn(
|
|
||||||
fake_subnet_response)
|
|
||||||
|
|
||||||
# Apply mocks
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
# Testing container ip allocation
|
|
||||||
fake_request = {
|
|
||||||
'PoolID': fake_kuryr_subnetpool_id,
|
|
||||||
'Address': '10.0.0.1',
|
|
||||||
'Options': {
|
|
||||||
const.REQUEST_ADDRESS_TYPE: const.NETWORK_GATEWAY_OPTIONS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
response = self.app.post('/IpamDriver.RequestAddress',
|
|
||||||
content_type='application/json',
|
|
||||||
data=jsonutils.dumps(fake_request))
|
|
||||||
|
|
||||||
self.assertEqual(200, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertEqual('10.0.0.1/16', decoded_json['Address'])
|
|
||||||
|
|
||||||
def test_ipam_driver_request_address_for_different_gateway(self):
|
|
||||||
# faking list_subnetpools
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnetpools')
|
|
||||||
fake_kuryr_subnetpool_id = str(uuid.uuid4())
|
|
||||||
fake_name = utils.get_neutron_subnetpool_name(FAKE_IP4_CIDR)
|
|
||||||
kuryr_subnetpools = self._get_fake_v4_subnetpools(
|
|
||||||
fake_kuryr_subnetpool_id, prefixes=[FAKE_IP4_CIDR],
|
|
||||||
name=fake_name)
|
|
||||||
app.neutron.list_subnetpools(id=fake_kuryr_subnetpool_id).AndReturn(
|
|
||||||
kuryr_subnetpools)
|
|
||||||
|
|
||||||
# faking list_subnets
|
|
||||||
docker_endpoint_id = utils.get_hash()
|
|
||||||
neutron_network_id = str(uuid.uuid4())
|
|
||||||
subnet_v4_id = str(uuid.uuid4())
|
|
||||||
fake_v4_subnet = self._get_fake_v4_subnet(
|
|
||||||
neutron_network_id, docker_endpoint_id, subnet_v4_id,
|
|
||||||
subnetpool_id=fake_kuryr_subnetpool_id,
|
|
||||||
cidr=FAKE_IP4_CIDR)
|
|
||||||
fake_v4_subnet['subnet'].update(gateway_ip='10.0.0.1')
|
|
||||||
fake_subnet_response = {
|
|
||||||
'subnets': [
|
|
||||||
fake_v4_subnet['subnet']
|
|
||||||
]
|
|
||||||
}
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnets')
|
|
||||||
app.neutron.list_subnets(cidr=FAKE_IP4_CIDR).AndReturn(
|
|
||||||
fake_subnet_response)
|
|
||||||
|
|
||||||
# Apply mocks
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
# Testing container ip allocation
|
|
||||||
fake_request = {
|
|
||||||
'PoolID': fake_kuryr_subnetpool_id,
|
|
||||||
'Address': '10.0.0.5', # Different with existed gw ip
|
|
||||||
'Options': {
|
|
||||||
const.REQUEST_ADDRESS_TYPE: const.NETWORK_GATEWAY_OPTIONS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
response = self.app.post('/IpamDriver.RequestAddress',
|
|
||||||
content_type='application/json',
|
|
||||||
data=jsonutils.dumps(fake_request))
|
|
||||||
|
|
||||||
self.assertEqual(500, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertIn('Err', decoded_json)
|
|
||||||
err_message = ("Requested gateway {0} does not match with "
|
|
||||||
"gateway {1} in existed network.").format(
|
|
||||||
'10.0.0.5', '10.0.0.1')
|
|
||||||
self.assertEqual({'Err': err_message}, decoded_json)
|
|
||||||
|
|
||||||
def test_ipam_driver_release_address(self):
|
|
||||||
# faking list_subnetpools
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnetpools')
|
|
||||||
fake_kuryr_subnetpool_id = str(uuid.uuid4())
|
|
||||||
fake_name = str('-'.join(['kuryrPool', FAKE_IP4_CIDR]))
|
|
||||||
kuryr_subnetpools = self._get_fake_v4_subnetpools(
|
|
||||||
fake_kuryr_subnetpool_id, prefixes=[FAKE_IP4_CIDR], name=fake_name)
|
|
||||||
app.neutron.list_subnetpools(id=fake_kuryr_subnetpool_id).AndReturn(
|
|
||||||
kuryr_subnetpools)
|
|
||||||
fake_ip4 = '10.0.0.5'
|
|
||||||
|
|
||||||
# faking list_subnets
|
|
||||||
docker_network_id = utils.get_hash()
|
|
||||||
docker_endpoint_id = utils.get_hash()
|
|
||||||
neutron_network_id = docker_network_id = str(uuid.uuid4())
|
|
||||||
subnet_v4_id = str(uuid.uuid4())
|
|
||||||
fake_v4_subnet = self._get_fake_v4_subnet(
|
|
||||||
docker_network_id, docker_endpoint_id, subnet_v4_id,
|
|
||||||
subnetpool_id=fake_kuryr_subnetpool_id,
|
|
||||||
cidr=FAKE_IP4_CIDR)
|
|
||||||
fake_subnet_response = {
|
|
||||||
'subnets': [
|
|
||||||
fake_v4_subnet['subnet']
|
|
||||||
]
|
|
||||||
}
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnets')
|
|
||||||
app.neutron.list_subnets(cidr=FAKE_IP4_CIDR).AndReturn(
|
|
||||||
fake_subnet_response)
|
|
||||||
|
|
||||||
#faking list_ports and delete_port
|
|
||||||
fake_neutron_port_id = str(uuid.uuid4())
|
|
||||||
fake_port = base.TestKuryrBase._get_fake_port(
|
|
||||||
docker_endpoint_id, neutron_network_id,
|
|
||||||
fake_neutron_port_id, const.PORT_STATUS_ACTIVE,
|
|
||||||
subnet_v4_id,
|
|
||||||
neutron_subnet_v4_address=fake_ip4)
|
|
||||||
port_request = {
|
|
||||||
'name': 'demo-port',
|
|
||||||
'admin_state_up': True,
|
|
||||||
'network_id': neutron_network_id,
|
|
||||||
}
|
|
||||||
rel_fixed_ips = port_request['fixed_ips'] = []
|
|
||||||
fixed_ip = {'subnet_id': subnet_v4_id}
|
|
||||||
fixed_ip['ip_address'] = fake_ip4
|
|
||||||
rel_fixed_ips.append(fixed_ip)
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_ports')
|
|
||||||
|
|
||||||
list_port_response = {'ports': [fake_port['port']]}
|
|
||||||
app.neutron.list_ports().AndReturn(
|
|
||||||
list_port_response)
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'delete_port')
|
|
||||||
app.neutron.delete_port(fake_port['port']['id']).AndReturn({})
|
|
||||||
|
|
||||||
# Apply mocks
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
fake_request = {
|
|
||||||
'PoolID': fake_kuryr_subnetpool_id,
|
|
||||||
'Address': fake_ip4
|
|
||||||
}
|
|
||||||
|
|
||||||
response = self.app.post('/IpamDriver.ReleaseAddress',
|
|
||||||
content_type='application/json',
|
|
||||||
data=jsonutils.dumps(fake_request))
|
|
||||||
|
|
||||||
self.assertEqual(200, response.status_code)
|
|
|
@ -1,256 +0,0 @@
|
||||||
# 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 ddt import data
|
|
||||||
from ddt import ddt
|
|
||||||
from neutronclient.common import exceptions
|
|
||||||
from oslo_serialization import jsonutils
|
|
||||||
|
|
||||||
from kuryr import app
|
|
||||||
from kuryr.common import constants as const
|
|
||||||
from kuryr.tests.unit import base
|
|
||||||
from kuryr import utils
|
|
||||||
|
|
||||||
|
|
||||||
class TestKuryrNetworkCreateFailures(base.TestKuryrFailures):
|
|
||||||
"""Unittests for the failures for creating networks.
|
|
||||||
|
|
||||||
This test covers error responses listed in the spec:
|
|
||||||
http://developer.openstack.org/api-ref-networking-v2-ext.html#createProviderNetwork # noqa
|
|
||||||
"""
|
|
||||||
|
|
||||||
def _create_network_with_exception(self, network_name, ex):
|
|
||||||
self.mox.StubOutWithMock(app.neutron, "create_network")
|
|
||||||
fake_request = {
|
|
||||||
"network": {
|
|
||||||
"name": utils.make_net_name(network_name),
|
|
||||||
"admin_state_up": True
|
|
||||||
}
|
|
||||||
}
|
|
||||||
app.neutron.create_network(fake_request).AndRaise(ex)
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
def _invoke_create_request(self, network_name):
|
|
||||||
network_request = {
|
|
||||||
'NetworkID': network_name,
|
|
||||||
'IPv4Data': [{
|
|
||||||
'AddressSpace': 'foo',
|
|
||||||
'Pool': '192.168.42.0/24',
|
|
||||||
'Gateway': '192.168.42.1/24',
|
|
||||||
'AuxAddresses': {}
|
|
||||||
}],
|
|
||||||
'IPv6Data': [{
|
|
||||||
'AddressSpace': 'bar',
|
|
||||||
'Pool': 'fe80::/64',
|
|
||||||
'Gateway': 'fe80::f816:3eff:fe20:57c3/64',
|
|
||||||
'AuxAddresses': {}
|
|
||||||
}],
|
|
||||||
'Options': {}
|
|
||||||
}
|
|
||||||
response = self.app.post('/NetworkDriver.CreateNetwork',
|
|
||||||
content_type='application/json',
|
|
||||||
data=jsonutils.dumps(network_request))
|
|
||||||
return response
|
|
||||||
|
|
||||||
def test_create_network_unauthorized(self):
|
|
||||||
docker_network_id = utils.get_hash()
|
|
||||||
self._create_network_with_exception(
|
|
||||||
docker_network_id, exceptions.Unauthorized())
|
|
||||||
|
|
||||||
response = self._invoke_create_request(docker_network_id)
|
|
||||||
|
|
||||||
self.assertEqual(401, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertIn('Err', decoded_json)
|
|
||||||
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.assertIn('Err', decoded_json)
|
|
||||||
# TODO(tfukushima): Add the better error message validation.
|
|
||||||
self.assertIn(invalid_docker_network_id, decoded_json['Err'])
|
|
||||||
self.assertIn('NetworkID', decoded_json['Err'])
|
|
||||||
|
|
||||||
|
|
||||||
@ddt
|
|
||||||
class TestKuryrNetworkDeleteFailures(base.TestKuryrFailures):
|
|
||||||
"""Unittests for the failures for deleting networks.
|
|
||||||
|
|
||||||
This test covers error responses listed in the spec:
|
|
||||||
http://developer.openstack.org/api-ref-networking-v2-ext.html#deleteProviderNetwork # noqa
|
|
||||||
"""
|
|
||||||
def _delete_network_with_exception(self, network_id, ex):
|
|
||||||
fake_neutron_network_id = "4e8e5957-649f-477b-9e5b-f1f75b21c03c"
|
|
||||||
no_networks_response = {
|
|
||||||
"networks": []
|
|
||||||
}
|
|
||||||
if ex == exceptions.NotFound:
|
|
||||||
fake_networks_response = no_networks_response
|
|
||||||
else:
|
|
||||||
fake_networks_response = {
|
|
||||||
"networks": [{
|
|
||||||
"status": "ACTIVE",
|
|
||||||
"subnets": [],
|
|
||||||
"name": network_id,
|
|
||||||
"admin_state_up": True,
|
|
||||||
"tenant_id": "9bacb3c5d39d41a79512987f338cf177",
|
|
||||||
"router:external": False,
|
|
||||||
"segments": [],
|
|
||||||
"shared": False,
|
|
||||||
"id": fake_neutron_network_id
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_networks')
|
|
||||||
t = utils.make_net_tags(network_id)
|
|
||||||
te = t + ',' + const.KURYR_EXISTING_NEUTRON_NET
|
|
||||||
app.neutron.list_networks(tags=te).AndReturn(no_networks_response)
|
|
||||||
app.neutron.list_networks(tags=t).AndReturn(fake_networks_response)
|
|
||||||
subnet_v4_id = "9436e561-47bf-436a-b1f1-fe23a926e031"
|
|
||||||
subnet_v6_id = "64dd4a98-3d7a-4bfd-acf4-91137a8d2f51"
|
|
||||||
|
|
||||||
docker_network_id = utils.get_hash()
|
|
||||||
docker_endpoint_id = utils.get_hash()
|
|
||||||
|
|
||||||
fake_v4_subnet = self._get_fake_v4_subnet(
|
|
||||||
docker_network_id, docker_endpoint_id, subnet_v4_id)
|
|
||||||
fake_v6_subnet = self._get_fake_v6_subnet(
|
|
||||||
docker_network_id, docker_endpoint_id, subnet_v6_id)
|
|
||||||
fake_subnets_response = {
|
|
||||||
"subnets": [
|
|
||||||
fake_v4_subnet['subnet'],
|
|
||||||
fake_v6_subnet['subnet']
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnets')
|
|
||||||
app.neutron.list_subnets(network_id=fake_neutron_network_id).AndReturn(
|
|
||||||
fake_subnets_response)
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnetpools')
|
|
||||||
fake_subnetpools_response = {"subnetpools": []}
|
|
||||||
app.neutron.list_subnetpools(name='kuryr').AndReturn(
|
|
||||||
fake_subnetpools_response)
|
|
||||||
app.neutron.list_subnetpools(name='kuryr6').AndReturn(
|
|
||||||
fake_subnetpools_response)
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'delete_subnet')
|
|
||||||
app.neutron.delete_subnet(subnet_v4_id).AndReturn(None)
|
|
||||||
app.neutron.delete_subnet(subnet_v6_id).AndReturn(None)
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'delete_network')
|
|
||||||
app.neutron.delete_network(fake_neutron_network_id).AndRaise(ex)
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
def _delete_network_with_subnet_exception(self, network_id, ex):
|
|
||||||
fake_neutron_network_id = "4e8e5957-649f-477b-9e5b-f1f75b21c03c"
|
|
||||||
no_networks_response = {
|
|
||||||
"networks": []
|
|
||||||
}
|
|
||||||
fake_networks_response = {
|
|
||||||
"networks": [{
|
|
||||||
"status": "ACTIVE",
|
|
||||||
"subnets": [],
|
|
||||||
"name": network_id,
|
|
||||||
"admin_state_up": True,
|
|
||||||
"tenant_id": "9bacb3c5d39d41a79512987f338cf177",
|
|
||||||
"router:external": False,
|
|
||||||
"segments": [],
|
|
||||||
"shared": False,
|
|
||||||
"id": fake_neutron_network_id
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_networks')
|
|
||||||
t = utils.make_net_tags(network_id)
|
|
||||||
te = t + ',' + const.KURYR_EXISTING_NEUTRON_NET
|
|
||||||
app.neutron.list_networks(tags=te).AndReturn(no_networks_response)
|
|
||||||
app.neutron.list_networks(tags=t).AndReturn(fake_networks_response)
|
|
||||||
subnet_v4_id = "9436e561-47bf-436a-b1f1-fe23a926e031"
|
|
||||||
subnet_v6_id = "64dd4a98-3d7a-4bfd-acf4-91137a8d2f51"
|
|
||||||
|
|
||||||
docker_network_id = utils.get_hash()
|
|
||||||
docker_endpoint_id = utils.get_hash()
|
|
||||||
|
|
||||||
fake_v4_subnet = self._get_fake_v4_subnet(
|
|
||||||
docker_network_id, docker_endpoint_id, subnet_v4_id)
|
|
||||||
fake_v6_subnet = self._get_fake_v6_subnet(
|
|
||||||
docker_network_id, docker_endpoint_id, subnet_v6_id)
|
|
||||||
fake_subnets_response = {
|
|
||||||
"subnets": [
|
|
||||||
fake_v4_subnet['subnet'],
|
|
||||||
fake_v6_subnet['subnet']
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnets')
|
|
||||||
app.neutron.list_subnets(network_id=fake_neutron_network_id).AndReturn(
|
|
||||||
fake_subnets_response)
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnetpools')
|
|
||||||
fake_subnetpools_response = {"subnetpools": []}
|
|
||||||
app.neutron.list_subnetpools(name='kuryr').AndReturn(
|
|
||||||
fake_subnetpools_response)
|
|
||||||
app.neutron.list_subnetpools(name='kuryr6').AndReturn(
|
|
||||||
fake_subnetpools_response)
|
|
||||||
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'delete_subnet')
|
|
||||||
app.neutron.delete_subnet(subnet_v4_id).AndRaise(ex)
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
def _invoke_delete_request(self, network_name):
|
|
||||||
data = {'NetworkID': network_name}
|
|
||||||
response = self.app.post('/NetworkDriver.DeleteNetwork',
|
|
||||||
content_type='application/json',
|
|
||||||
data=jsonutils.dumps(data))
|
|
||||||
return response
|
|
||||||
|
|
||||||
@data(exceptions.Unauthorized, exceptions.NotFound, exceptions.Conflict)
|
|
||||||
def test_delete_network_failures(self, GivenException):
|
|
||||||
docker_network_id = utils.get_hash()
|
|
||||||
self._delete_network_with_exception(
|
|
||||||
docker_network_id, GivenException())
|
|
||||||
|
|
||||||
response = self._invoke_delete_request(docker_network_id)
|
|
||||||
|
|
||||||
self.assertEqual(GivenException.status_code, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertIn('Err', decoded_json)
|
|
||||||
self.assertEqual({'Err': GivenException.message}, decoded_json)
|
|
||||||
|
|
||||||
def test_delete_network_bad_request(self):
|
|
||||||
invalid_docker_network_id = 'invalid-network-id'
|
|
||||||
|
|
||||||
response = self._invoke_delete_request(invalid_docker_network_id)
|
|
||||||
|
|
||||||
self.assertEqual(400, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertIn('Err', decoded_json)
|
|
||||||
self.assertIn(invalid_docker_network_id, decoded_json['Err'])
|
|
||||||
self.assertIn('NetworkID', decoded_json['Err'])
|
|
||||||
|
|
||||||
@data(exceptions.Unauthorized, exceptions.NotFound, exceptions.Conflict)
|
|
||||||
def test_delete_network_with_subnet_deletion_failures(self,
|
|
||||||
GivenException):
|
|
||||||
docker_network_id = utils.get_hash()
|
|
||||||
self._delete_network_with_subnet_exception(
|
|
||||||
docker_network_id, GivenException())
|
|
||||||
|
|
||||||
response = self._invoke_delete_request(docker_network_id)
|
|
||||||
|
|
||||||
self.assertEqual(GivenException.status_code, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertIn('Err', decoded_json)
|
|
||||||
self.assertEqual({'Err': GivenException.message}, decoded_json)
|
|
|
@ -1,104 +0,0 @@
|
||||||
# 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 uuid
|
|
||||||
|
|
||||||
import ddt
|
|
||||||
from oslo_concurrency import processutils
|
|
||||||
from oslo_serialization import jsonutils
|
|
||||||
from werkzeug import exceptions as w_exceptions
|
|
||||||
|
|
||||||
from kuryr import app
|
|
||||||
from kuryr import binding
|
|
||||||
from kuryr.common import constants as const
|
|
||||||
from kuryr.common import exceptions
|
|
||||||
from kuryr.tests.unit import base
|
|
||||||
from kuryr import utils
|
|
||||||
|
|
||||||
|
|
||||||
@ddt.ddt
|
|
||||||
class TestKuryrLeaveFailures(base.TestKuryrFailures):
|
|
||||||
"""Unit tests for the failures for unbinding a Neutron port."""
|
|
||||||
def _invoke_leave_request(self, docker_network_id,
|
|
||||||
docker_endpoint_id):
|
|
||||||
data = {
|
|
||||||
'NetworkID': docker_network_id,
|
|
||||||
'EndpointID': docker_endpoint_id,
|
|
||||||
}
|
|
||||||
response = self.app.post('/NetworkDriver.Leave',
|
|
||||||
content_type='application/json',
|
|
||||||
data=jsonutils.dumps(data))
|
|
||||||
|
|
||||||
return response
|
|
||||||
|
|
||||||
def _port_unbind_with_exception(self, docker_endpoint_id,
|
|
||||||
neutron_port, ex):
|
|
||||||
fake_unbinding_response = ('fake stdout', '')
|
|
||||||
self.mox.StubOutWithMock(binding, 'port_unbind')
|
|
||||||
if ex:
|
|
||||||
binding.port_unbind(docker_endpoint_id, neutron_port).AndRaise(ex)
|
|
||||||
else:
|
|
||||||
binding.port_unbind(docker_endpoint_id, neutron_port).AndReturn(
|
|
||||||
fake_unbinding_response)
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
return fake_unbinding_response
|
|
||||||
|
|
||||||
@ddt.data(exceptions.VethDeletionFailure,
|
|
||||||
processutils.ProcessExecutionError)
|
|
||||||
def test_leave_unbinding_failure(self, GivenException):
|
|
||||||
fake_docker_network_id = utils.get_hash()
|
|
||||||
fake_docker_endpoint_id = utils.get_hash()
|
|
||||||
|
|
||||||
fake_neutron_network_id = str(uuid.uuid4())
|
|
||||||
self._mock_out_network(fake_neutron_network_id, fake_docker_network_id)
|
|
||||||
fake_neutron_port_id = str(uuid.uuid4())
|
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_ports')
|
|
||||||
neutron_port_name = utils.get_neutron_port_name(
|
|
||||||
fake_docker_endpoint_id)
|
|
||||||
fake_neutron_v4_subnet_id = str(uuid.uuid4())
|
|
||||||
fake_neutron_v6_subnet_id = str(uuid.uuid4())
|
|
||||||
fake_neutron_ports_response = self._get_fake_ports(
|
|
||||||
fake_docker_endpoint_id, fake_neutron_network_id,
|
|
||||||
fake_neutron_port_id, const.PORT_STATUS_ACTIVE,
|
|
||||||
fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id)
|
|
||||||
app.neutron.list_ports(name=neutron_port_name).AndReturn(
|
|
||||||
fake_neutron_ports_response)
|
|
||||||
fake_neutron_port = fake_neutron_ports_response['ports'][0]
|
|
||||||
|
|
||||||
fake_message = "fake message"
|
|
||||||
fake_exception = GivenException(fake_message)
|
|
||||||
self._port_unbind_with_exception(
|
|
||||||
fake_docker_endpoint_id, fake_neutron_port, fake_exception)
|
|
||||||
|
|
||||||
response = self._invoke_leave_request(
|
|
||||||
fake_docker_network_id, fake_docker_endpoint_id)
|
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
w_exceptions.InternalServerError.code, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertIn('Err', decoded_json)
|
|
||||||
self.assertIn(fake_message, decoded_json['Err'])
|
|
||||||
|
|
||||||
def test_leave_bad_request(self):
|
|
||||||
fake_docker_network_id = utils.get_hash()
|
|
||||||
invalid_docker_endpoint_id = 'id-should-be-hexdigits'
|
|
||||||
|
|
||||||
response = self._invoke_leave_request(
|
|
||||||
fake_docker_network_id, invalid_docker_endpoint_id)
|
|
||||||
|
|
||||||
self.assertEqual(w_exceptions.BadRequest.code, response.status_code)
|
|
||||||
decoded_json = jsonutils.loads(response.data)
|
|
||||||
self.assertIn('Err', decoded_json)
|
|
||||||
# TODO(tfukushima): Add the better error message validation.
|
|
||||||
self.assertIn(invalid_docker_endpoint_id, decoded_json['Err'])
|
|
||||||
self.assertIn('EndpointID', decoded_json['Err'])
|
|
|
@ -13,30 +13,18 @@
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
import ddt
|
import ddt
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
|
|
||||||
from kuryr.common import constants as const
|
from kuryr.lib import constants as const
|
||||||
|
from kuryr.lib import utils
|
||||||
from kuryr.tests.unit import base
|
from kuryr.tests.unit import base
|
||||||
from kuryr import utils
|
|
||||||
|
|
||||||
|
|
||||||
@ddt.ddt
|
@ddt.ddt
|
||||||
class TestKuryrUtils(base.TestKuryrBase):
|
class TestKuryrUtils(base.TestCase):
|
||||||
"""Unit tests for utilities."""
|
"""Unit tests for utilities."""
|
||||||
|
|
||||||
@ddt.data(utils.get_hash(), '51c75a2515d4' '51c75a')
|
|
||||||
def test_get_sandbox_key(self, fake_container_id):
|
|
||||||
sandbox_key = utils.get_sandbox_key(fake_container_id)
|
|
||||||
expected = '/'.join([utils.DOCKER_NETNS_BASE, fake_container_id[:12]])
|
|
||||||
self.assertEqual(expected, sandbox_key)
|
|
||||||
|
|
||||||
def test_get_port_name(self):
|
|
||||||
fake_docker_endpoint_id = utils.get_hash()
|
|
||||||
generated_neutron_port_name = utils.get_neutron_port_name(
|
|
||||||
fake_docker_endpoint_id)
|
|
||||||
self.assertIn(utils.PORT_POSTFIX, generated_neutron_port_name)
|
|
||||||
self.assertIn(fake_docker_endpoint_id, generated_neutron_port_name)
|
|
||||||
|
|
||||||
def test_get_veth_pair_names(self):
|
def test_get_veth_pair_names(self):
|
||||||
fake_neutron_port_id = str(uuid.uuid4())
|
fake_neutron_port_id = str(uuid.uuid4())
|
||||||
generated_ifname, generated_peer = utils.get_veth_pair_names(
|
generated_ifname, generated_peer = utils.get_veth_pair_names(
|
||||||
|
@ -60,18 +48,3 @@ class TestKuryrUtils(base.TestKuryrBase):
|
||||||
name_prefix = cfg.CONF.subnetpool_name_prefix
|
name_prefix = cfg.CONF.subnetpool_name_prefix
|
||||||
self.assertIn(name_prefix, generated_neutron_subnetpool_name)
|
self.assertIn(name_prefix, generated_neutron_subnetpool_name)
|
||||||
self.assertIn(fake_subnet_cidr, generated_neutron_subnetpool_name)
|
self.assertIn(fake_subnet_cidr, generated_neutron_subnetpool_name)
|
||||||
|
|
||||||
def test_get_dict_format_fixed_ips_from_kv_format(self):
|
|
||||||
fake_fixed_ips_kv_format = \
|
|
||||||
['subnet_id=5083bda8-1b7c-4625-97f3-1d4c33bfeea8',
|
|
||||||
'ip_address=192.168.1.2',
|
|
||||||
'subnet_id=6607a230-f3eb-4937-b09f-9dd659211139',
|
|
||||||
'ip_address=fdfa:8456:1afa:0:f816:3eff:fe67:885e']
|
|
||||||
expected_dict_form = \
|
|
||||||
[{'subnet_id': '5083bda8-1b7c-4625-97f3-1d4c33bfeea8',
|
|
||||||
'ip_address': '192.168.1.2'},
|
|
||||||
{'subnet_id': '6607a230-f3eb-4937-b09f-9dd659211139',
|
|
||||||
'ip_address': 'fdfa:8456:1afa:0:f816:3eff:fe67:885e'}]
|
|
||||||
fixed_ips = utils.get_dict_format_fixed_ips_from_kv_format(
|
|
||||||
fake_fixed_ips_kv_format)
|
|
||||||
self.assertEqual(expected_dict_form, fixed_ips)
|
|
||||||
|
|
|
@ -22,10 +22,7 @@ classifier =
|
||||||
|
|
||||||
[entry_points]
|
[entry_points]
|
||||||
oslo.config.opts =
|
oslo.config.opts =
|
||||||
kuryr = kuryr.opts:list_kuryr_opts
|
kuryr = kuryr.lib.opts:list_kuryr_opts
|
||||||
|
|
||||||
console_scripts =
|
|
||||||
kuryr-server = kuryr.server:start
|
|
||||||
|
|
||||||
[files]
|
[files]
|
||||||
packages =
|
packages =
|
||||||
|
@ -38,7 +35,6 @@ data_files =
|
||||||
usr/libexec/kuryr/ovs
|
usr/libexec/kuryr/ovs
|
||||||
usr/libexec/kuryr/tap
|
usr/libexec/kuryr/tap
|
||||||
usr/libexec/kuryr/unbound
|
usr/libexec/kuryr/unbound
|
||||||
/usr/lib/docker/plugins/kuryr = etc/kuryr.spec
|
|
||||||
|
|
||||||
[build_sphinx]
|
[build_sphinx]
|
||||||
source-dir = doc/source
|
source-dir = doc/source
|
||||||
|
|
Loading…
Reference in New Issue