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:
vikaschoudhary16 2016-07-02 15:56:45 +05:30
parent f6c8674bdb
commit 47490acec9
44 changed files with 23 additions and 5174 deletions

View File

@ -1,4 +0,0 @@
{
"Name": "kuryr",
"Addr": "http://127.0.0.1:2377"
}

View File

@ -1 +0,0 @@
http://127.0.0.1:2377

View File

@ -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__)

File diff suppressed because it is too large Load Diff

View File

@ -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'

View File

@ -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 = [

View File

@ -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

View File

@ -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 = ''

View File

@ -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

View File

@ -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'
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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'
}]

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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)

View File

@ -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']))

View File

@ -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."""

View File

@ -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)

View File

@ -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)

View File

@ -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'])

View File

@ -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)

View File

@ -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'])

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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'])

View File

@ -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)

View File

@ -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