Browse Source

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
changes/84/336784/12
vikaschoudhary16 6 years ago
parent
commit
47490acec9
  1. 4
      etc/kuryr.json
  2. 1
      etc/kuryr.spec
  3. 16
      kuryr/__init__.py
  4. 1356
      kuryr/controllers.py
  5. 0
      kuryr/lib/__init__.py
  6. 0
      kuryr/lib/_i18n.py
  7. 6
      kuryr/lib/binding.py
  8. 4
      kuryr/lib/config.py
  9. 0
      kuryr/lib/constants.py
  10. 0
      kuryr/lib/exceptions.py
  11. 2
      kuryr/lib/opts.py
  12. 99
      kuryr/lib/utils.py
  13. 0
      kuryr/lib/version.py
  14. 35
      kuryr/schemata/__init__.py
  15. 249
      kuryr/schemata/commons.py
  16. 48
      kuryr/schemata/endpoint_create.py
  17. 40
      kuryr/schemata/endpoint_delete.py
  18. 52
      kuryr/schemata/join.py
  19. 24
      kuryr/schemata/leave.py
  20. 55
      kuryr/schemata/network_create.py
  21. 36
      kuryr/schemata/network_delete.py
  22. 41
      kuryr/schemata/release_address.py
  23. 36
      kuryr/schemata/release_pool.py
  24. 47
      kuryr/schemata/request_address.py
  25. 58
      kuryr/schemata/request_pool.py
  26. 36
      kuryr/server.py
  27. 4
      kuryr/tests/contrib/gate_hook.sh
  28. 4
      kuryr/tests/contrib/post_test_hook.sh
  29. 0
      kuryr/tests/fullstack/__init__.py
  30. 31
      kuryr/tests/fullstack/kuryr_base.py
  31. 88
      kuryr/tests/fullstack/test_container.py
  32. 125
      kuryr/tests/fullstack/test_network.py
  33. 267
      kuryr/tests/unit/base.py
  34. 21
      kuryr/tests/unit/test_config.py
  35. 94
      kuryr/tests/unit/test_ipam_pool.py
  36. 127
      kuryr/tests/unit/test_join.py
  37. 872
      kuryr/tests/unit/test_kuryr.py
  38. 252
      kuryr/tests/unit/test_kuryr_endpoint.py
  39. 181
      kuryr/tests/unit/test_kuryr_existing_network.py
  40. 485
      kuryr/tests/unit/test_kuryr_ipam.py
  41. 256
      kuryr/tests/unit/test_kuryr_network.py
  42. 104
      kuryr/tests/unit/test_leave.py
  43. 35
      kuryr/tests/unit/test_utils.py
  44. 6
      setup.cfg

4
etc/kuryr.json

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

1
etc/kuryr.spec

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

16
kuryr/__init__.py

@ -1,16 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from kuryr import utils
app = utils.make_json_app(__name__)

1356
kuryr/controllers.py

File diff suppressed because it is too large Load Diff

0
kuryr/common/__init__.py → kuryr/lib/__init__.py

0
kuryr/_i18n.py → kuryr/lib/_i18n.py

6
kuryr/binding.py → kuryr/lib/binding.py

@ -17,9 +17,9 @@ from oslo_concurrency import processutils
from oslo_utils import excutils
import pyroute2
from kuryr.common import config
from kuryr.common import exceptions
from kuryr import utils
from kuryr.lib import config
from kuryr.lib import exceptions
from kuryr.lib import utils
BINDING_SUBCOMMAND = 'bind'

4
kuryr/common/config.py → kuryr/lib/config.py

@ -19,8 +19,8 @@ import os
from oslo_config import cfg
from oslo_log import log
from kuryr._i18n import _
from kuryr import version
from kuryr.lib._i18n import _
from kuryr.lib import version
core_opts = [

0
kuryr/common/constants.py → kuryr/lib/constants.py

0
kuryr/common/exceptions.py → kuryr/lib/exceptions.py

2
kuryr/opts.py → kuryr/lib/opts.py

@ -19,7 +19,7 @@ import itertools
from oslo_log import _options
from kuryr.common import config
from kuryr.lib import config
_core_opts_with_logging = config.core_opts

99
kuryr/utils.py → kuryr/lib/utils.py

@ -11,25 +11,14 @@
# under the License.
import hashlib
import os
import random
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.v2_0 import client as client_v2
from oslo_concurrency import processutils
from oslo_config import cfg
from werkzeug import exceptions as w_exceptions
from kuryr._i18n import _LE
from kuryr.common import constants as const
from kuryr.common import exceptions
from kuryr.lib import constants as const
DOCKER_NETNS_BASE = '/var/run/docker/netns'
PORT_POSTFIX = 'port'
@ -50,64 +39,9 @@ def get_neutron_client(url, username, tenant_name, password,
ca_cert=ca_cert, insecure=insecure)
# Return all errors as JSON. From http://flask.pocoo.org/snippets/83/
def make_json_app(import_name, **kwargs):
"""Creates a JSON-oriented Flask app.
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_hostname():
"""Returns the host name."""
return socket.gethostname()
def get_veth_pair_names(port_id):
@ -118,11 +52,6 @@ def get_veth_pair_names(port_id):
return ifname, peer_name
def get_hostname():
"""Returns the host name."""
return socket.gethostname()
def get_neutron_subnetpool_name(subnet_cidr):
"""Returns a Neutron subnetpool name.
@ -162,26 +91,6 @@ def get_hash(bit_size=256):
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):
"""Make a string out of the mapping list"""
details = ''

0
kuryr/version.py → kuryr/lib/version.py

35
kuryr/schemata/__init__.py

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

249
kuryr/schemata/commons.py

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

48
kuryr/schemata/endpoint_create.py

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

40
kuryr/schemata/endpoint_delete.py

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

52
kuryr/schemata/join.py

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

24
kuryr/schemata/leave.py

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

55
kuryr/schemata/network_create.py

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

36
kuryr/schemata/network_delete.py

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

41
kuryr/schemata/release_address.py

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

36
kuryr/schemata/release_pool.py

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

47
kuryr/schemata/request_address.py

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

58
kuryr/schemata/request_pool.py

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

36
kuryr/server.py

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

4
kuryr/tests/contrib/gate_hook.sh

@ -2,9 +2,9 @@
set -ex
VENV=${1:-"fullstack"}
VENV=${1:-"debug-py27"}
GATE_DEST=$BASE/new
DEVSTACK_PATH=$GATE_DEST/devstack
$BASE/new/devstack-gate/devstack-vm-gate.sh
$BASE/new/devstack-gate/devstack-vm-gate.sh

4
kuryr/tests/contrib/post_test_hook.sh

@ -6,7 +6,7 @@ KURYR_DIR="$BASE/new/kuryr"
TEMPEST_DIR="$BASE/new/tempest"
SCRIPTS_DIR="/usr/os-testr-env/bin/"
venv=${1:-"fullstack"}
venv=${1:-"debug-py27"}
function generate_test_logs {
local path="$1"
@ -57,4 +57,4 @@ set -e
# Collect and parse results
generate_testr_results
exit $testr_exit_code
exit $testr_exit_code

0
kuryr/tests/fullstack/__init__.py

31
kuryr/tests/fullstack/kuryr_base.py

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

88
kuryr/tests/fullstack/test_container.py

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

125
kuryr/tests/fullstack/test_network.py

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

267
kuryr/tests/unit/base.py

@ -10,274 +10,11 @@
# License for the specific language governing permissions and limitations
# 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."""
def setUp(self):
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