Browse Source

Merge "Remove (most) '/os-networks' REST APIs"

changes/10/686810/9
Zuul 2 weeks ago
parent
commit
991d675675
26 changed files with 174 additions and 1182 deletions
  1. +34
    -45
      api-ref/source/os-networks.inc
  2. +23
    -23
      doc/api_samples/os-networks/network-show-resp.json
  3. +20
    -54
      doc/api_samples/os-networks/networks-list-resp.json
  4. +11
    -75
      nova/api/openstack/compute/networks.py
  5. +6
    -53
      nova/api/openstack/compute/networks_associate.py
  6. +6
    -0
      nova/api/openstack/compute/rest_api_version_history.rst
  7. +0
    -77
      nova/api/openstack/compute/schemas/networks.py
  8. +0
    -24
      nova/api/openstack/compute/schemas/networks_associate.py
  9. +0
    -2
      nova/policies/__init__.py
  10. +0
    -26
      nova/policies/networks.py
  11. +0
    -50
      nova/policies/networks_associate.py
  12. +0
    -3
      nova/tests/functional/api_sample_tests/api_samples/os-networks-associate/network-associate-host-req.json.tpl
  13. +0
    -3
      nova/tests/functional/api_sample_tests/api_samples/os-networks-associate/network-disassociate-host-req.json.tpl
  14. +0
    -3
      nova/tests/functional/api_sample_tests/api_samples/os-networks-associate/network-disassociate-project-req.json.tpl
  15. +0
    -3
      nova/tests/functional/api_sample_tests/api_samples/os-networks-associate/network-disassociate-req.json.tpl
  16. +0
    -3
      nova/tests/functional/api_sample_tests/api_samples/os-networks/network-add-req.json.tpl
  17. +0
    -12
      nova/tests/functional/api_sample_tests/api_samples/os-networks/network-create-req.json.tpl
  18. +0
    -36
      nova/tests/functional/api_sample_tests/api_samples/os-networks/network-create-resp.json.tpl
  19. +22
    -22
      nova/tests/functional/api_sample_tests/api_samples/os-networks/network-show-resp.json.tpl
  20. +18
    -52
      nova/tests/functional/api_sample_tests/api_samples/os-networks/networks-list-resp.json.tpl
  21. +12
    -65
      nova/tests/functional/api_sample_tests/test_networks.py
  22. +12
    -35
      nova/tests/functional/api_sample_tests/test_networks_associate.py
  23. +1
    -512
      nova/tests/unit/api/openstack/compute/test_networks.py
  24. +0
    -2
      nova/tests/unit/fake_policy.py
  25. +0
    -2
      nova/tests/unit/test_policy.py
  26. +9
    -0
      releasenotes/notes/remove-nova-network-c02953ba72a1795d.yaml

+ 34
- 45
api-ref/source/os-networks.inc View File

@@ -1,28 +1,26 @@
.. -*- rst -*-
.. NOTE(sdague): These APIs are deprecated so do not update this
file even body, example or parameters are not complete.

=====================================
======================================
Networks (os-networks) (DEPRECATED)
=====================================
======================================

.. warning:: The networks API was designed to work with
``nova-network``. Some features are proxied to
``neutron`` when appropriate, but as with all translation
proxies, this is far from perfect compatibility. These
APIs should be avoided in new applications in favor of
using ``neutron`` directly. These will fail with a 404
starting from microversion 2.36.
See: `Relevant Network APIs
<https://docs.openstack.org/api-ref/network/v2/#networks>`__.
.. warning::
This API was designed to work with ``nova-network`` which was deprecated in
the 14.0.0 (Newton) release and removed in the 21.0.0 (Ussuri) release. Some
features are proxied to the Network service (neutron) when appropriate, but
as with all translation proxies, this is far from perfect compatibility.
These APIs should be avoided in new applications in favor of `using
neutron directly`__. These will fail with a 404 starting from microversion
2.36. They were removed in the 21.0.0 (Ussuri) release.

__ https://docs.openstack.org/api-ref/network/v2/#networks

Creates, lists, shows information for, and deletes networks.

Adds network to a project, disassociates a network from a project, and
disassociates a project from a network.


Associates host with and disassociates host from a network.

List Networks
@@ -60,7 +58,8 @@ these permissions through the ``policy.json`` file.

Normal response codes: 200

Error response codes: badRequest(400), unauthorized(401), forbidden(403), conflict(409), NotImplemented(501)
Error response codes: badRequest(400), unauthorized(401), forbidden(403),
conflict(409), gone(410), notImplemented(501)

Request
-------
@@ -91,7 +90,8 @@ this operation. Cloud providers can change these permissions through the

Normal response codes: 202

Error response codes: badRequest(400), unauthorized(401), forbidden(403), NotImplemented(501)
Error response codes: badRequest(400), unauthorized(401), forbidden(403),
gone(410), notImplemented(501)

Request
-------
@@ -146,7 +146,8 @@ these permissions through the ``policy.json`` file.

Normal response codes: 202

Error response codes: unauthorized(401), forbidden(403), itemNotFound(404), conflict(409)
Error response codes: unauthorized(401), forbidden(403), itemNotFound(404),
conflict(409), gone(410)

Request
-------
@@ -160,15 +161,11 @@ Response

There is no body content for the response of a successful DELETE query.

Associate Host (DEPRECATED)
===========================
Associate Host
==============

.. rest_method:: POST /os-networks/{network_id}/action

.. warning::
This API is only available with ``nova-network`` which is
deprecated. It should be avoided in any new applications.

Associates a network with a host.

Specify the ``associate_host`` action in the request body.
@@ -179,7 +176,8 @@ permissions through the ``policy.json`` file.

Normal response codes: 202

Error response codes: unauthorized(401), forbidden(403), itemNotFound(404), NotImplemented(501)
Error response codes: unauthorized(401), forbidden(403), itemNotFound(404),
gone(410), notImplemented(501)

Request
-------
@@ -199,15 +197,11 @@ Response

There is no body content for the response of a successful POST query.

Disassociate Network (DEPRECATED)
=================================
Disassociate Network
====================

.. rest_method:: POST /os-networks/{network_id}/action

.. warning::
This API is only available with ``nova-network`` which is
deprecated. It should be avoided in any new applications.

Disassociates a network from a project. You can then reuse the network.

Specify the ``disassociate`` action in the request body.
@@ -218,7 +212,8 @@ these permissions through the ``policy.json`` file.

Normal response codes: 202

Error response codes: unauthorized(401), forbidden(403), itemNotFound(404), NotImplemented(501)
Error response codes: unauthorized(401), forbidden(403), itemNotFound(404),
gone(410), notImplemented(501)

Request
-------
@@ -237,15 +232,11 @@ Response

There is no body content for the response of a successful POST query.

Disassociate Host (DEPRECATED)
==============================
Disassociate Host
=================

.. rest_method:: POST /os-networks/{network_id}/action

.. warning::
This API is only available with ``nova-network`` which is
deprecated. It should be avoided in any new applications.

Disassociates a host from a network.

Specify the ``disassociate_host`` action in the request body.
@@ -256,7 +247,8 @@ these permissions through the ``policy.json`` file.

Normal response codes: 202

Error response codes: unauthorized(401), forbidden(403), itemNotFound(404), NotImplemented(501)
Error response codes: unauthorized(401), forbidden(403), itemNotFound(404),
gone(410), notImplemented(501)

Request
-------
@@ -276,15 +268,11 @@ Response
There is no body content for the response of a successful POST query.


Disassociate Project (DEPRECATED)
=================================
Disassociate Project
====================

.. rest_method:: POST /os-networks/{network_id}/action

.. warning::
This API is only available with ``nova-network`` which is
deprecated. It should be avoided in any new applications.

Disassociates a project from a network.

Specify the ``disassociate_project`` action in the request body.
@@ -295,7 +283,8 @@ these permissions through the ``policy.json`` file.

Normal response codes: 202

Error response codes: unauthorized(401), forbidden(403), itemNotFound(404), NotImplemented(501)
Error response codes: unauthorized(401), forbidden(403), itemNotFound(404),
gone(410), notImplemented(501)

Request
-------

+ 23
- 23
doc/api_samples/os-networks/network-show-resp.json View File

@@ -1,36 +1,36 @@
{
"network": {
"bridge": "br100",
"bridge_interface": "eth0",
"broadcast": "10.0.0.7",
"cidr": "10.0.0.0/29",
"bridge": null,
"bridge_interface": null,
"broadcast": null,
"cidr": null,
"cidr_v6": null,
"created_at": "2011-08-15T06:19:19.387525",
"deleted": false,
"created_at": null,
"deleted": null,
"deleted_at": null,
"dhcp_server": "10.0.0.1",
"dhcp_start": "10.0.0.3",
"dhcp_server": null,
"dhcp_start": null,
"dns1": null,
"dns2": null,
"enable_dhcp": true,
"gateway": "10.0.0.1",
"enable_dhcp": null,
"gateway": null,
"gateway_v6": null,
"host": "nsokolov-desktop",
"host": null,
"id": "20c8acc0-f747-4d71-a389-46d078ebf047",
"injected": false,
"label": "mynet_0",
"injected": null,
"label": "private",
"mtu": null,
"multi_host": false,
"netmask": "255.255.255.248",
"multi_host": null,
"netmask": null,
"netmask_v6": null,
"priority": null,
"project_id": "6133f8b603924f45bc0c9e21f6df12fa",
"project_id": null,
"rxtx_base": null,
"share_address": false,
"updated_at": "2011-08-16T09:26:13.048257",
"vlan": 100,
"vpn_private_address": "10.0.0.2",
"vpn_public_address": "127.0.0.1",
"vpn_public_port": 1000
"share_address": null,
"updated_at": null,
"vlan": null,
"vpn_private_address": null,
"vpn_public_address": null,
"vpn_public_port": null
}
}
}

+ 20
- 54
doc/api_samples/os-networks/networks-list-resp.json View File

@@ -1,72 +1,38 @@
{
"networks": [
{
"bridge": "br100",
"bridge_interface": "eth0",
"broadcast": "10.0.0.7",
"cidr": "10.0.0.0/29",
"bridge": null,
"bridge_interface": null,
"broadcast": null,
"cidr": null,
"cidr_v6": null,
"created_at": "2011-08-15T06:19:19.387525",
"deleted": false,
"created_at": null,
"deleted": null,
"deleted_at": null,
"dhcp_server": "10.0.0.1",
"dhcp_start": "10.0.0.3",
"dhcp_server": null,
"dhcp_start": null,
"dns1": null,
"dns2": null,
"enable_dhcp": true,
"gateway": "10.0.0.1",
"gateway_v6": null,
"host": "nsokolov-desktop",
"id": "20c8acc0-f747-4d71-a389-46d078ebf047",
"injected": false,
"label": "mynet_0",
"mtu": null,
"multi_host": false,
"netmask": "255.255.255.248",
"netmask_v6": null,
"priority": null,
"project_id": "6133f8b603924f45bc0c9e21f6df12fa",
"rxtx_base": null,
"share_address": false,
"updated_at": "2011-08-16T09:26:13.048257",
"vlan": 100,
"vpn_private_address": "10.0.0.2",
"vpn_public_address": "127.0.0.1",
"vpn_public_port": 1000
},
{
"bridge": "br101",
"bridge_interface": "eth0",
"broadcast": "10.0.0.15",
"cidr": "10.0.0.10/29",
"cidr_v6": null,
"created_at": "2011-08-15T06:19:19.885495",
"deleted": false,
"deleted_at": null,
"dhcp_server": "10.0.0.9",
"dhcp_start": "10.0.0.11",
"dns1": null,
"dns2": null,
"enable_dhcp": true,
"gateway": "10.0.0.9",
"enable_dhcp": null,
"gateway": null,
"gateway_v6": null,
"host": null,
"id": "20c8acc0-f747-4d71-a389-46d078ebf000",
"injected": false,
"label": "mynet_1",
"id": "20c8acc0-f747-4d71-a389-46d078ebf047",
"injected": null,
"label": "private",
"mtu": null,
"multi_host": false,
"netmask": "255.255.255.248",
"multi_host": null,
"netmask": null,
"netmask_v6": null,
"priority": null,
"project_id": null,
"rxtx_base": null,
"share_address": false,
"share_address": null,
"updated_at": null,
"vlan": 101,
"vpn_private_address": "10.0.0.10",
"vlan": null,
"vpn_private_address": null,
"vpn_public_address": null,
"vpn_public_port": 1001
"vpn_public_port": null
}
]
}
}

+ 11
- 75
nova/api/openstack/compute/networks.py View File

@@ -14,15 +14,11 @@
# License for the specific language governing permissions and limitations
# under the License.

import netaddr
from webob import exc

from nova.api.openstack.api_version_request \
import MAX_PROXY_API_SUPPORT_VERSION
from nova.api.openstack import common
from nova.api.openstack.compute.schemas import networks as schema
from nova.api.openstack import wsgi
from nova.api import validation
from nova import exception
from nova.i18n import _
from nova import network
@@ -92,22 +88,6 @@ class NetworkController(wsgi.Controller):
result = [network_dict(context, net_ref) for net_ref in networks]
return {'networks': result}

@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
@wsgi.response(202)
@wsgi.expected_errors((404, 501))
@wsgi.action("disassociate")
def _disassociate_host_and_project(self, req, id, body):
context = req.environ['nova.context']
context.can(net_policies.BASE_POLICY_NAME)

try:
self.network_api.associate(context, id, host=None, project=None)
except exception.NetworkNotFound:
msg = _("Network not found")
raise exc.HTTPNotFound(explanation=msg)
except NotImplementedError:
common.raise_feature_not_supported()

@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
@wsgi.expected_errors(404)
def show(self, req, id):
@@ -121,63 +101,19 @@ class NetworkController(wsgi.Controller):
raise exc.HTTPNotFound(explanation=msg)
return {'network': network_dict(context, network)}

@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
@wsgi.response(202)
@wsgi.expected_errors((404, 409))
def delete(self, req, id):
context = req.environ['nova.context']
context.can(net_policies.BASE_POLICY_NAME)
@wsgi.expected_errors(410)
@wsgi.action("disassociate")
def _disassociate_host_and_project(self, req, id, body):
raise exc.HTTPGone()

try:
self.network_api.delete(context, id)
except exception.NetworkInUse as e:
raise exc.HTTPConflict(explanation=e.format_message())
except exception.NetworkNotFound:
msg = _("Network not found")
raise exc.HTTPNotFound(explanation=msg)
@wsgi.expected_errors(410)
def delete(self, req, id):
raise exc.HTTPGone()

@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
@wsgi.expected_errors((400, 409, 501))
@validation.schema(schema.create)
@wsgi.expected_errors(410)
def create(self, req, body):
context = req.environ['nova.context']
context.can(net_policies.BASE_POLICY_NAME)

params = body["network"]

cidr = params.get("cidr") or params.get("cidr_v6")
raise exc.HTTPGone()

params["num_networks"] = 1
params["network_size"] = netaddr.IPNetwork(cidr).size

try:
network = self.network_api.create(context, **params)[0]
except (exception.InvalidCidr,
exception.InvalidIntValue,
exception.InvalidAddress,
exception.NetworkNotCreated) as ex:
raise exc.HTTPBadRequest(explanation=ex.format_message)
except (exception.CidrConflict,
exception.DuplicateVlan) as ex:
raise exc.HTTPConflict(explanation=ex.format_message())
return {"network": network_dict(context, network)}

@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
@wsgi.response(202)
@wsgi.expected_errors((400, 501))
@validation.schema(schema.add_network_to_project)
@wsgi.expected_errors(410)
def add(self, req, body):
context = req.environ['nova.context']
context.can(net_policies.BASE_POLICY_NAME)

network_id = body['id']
project_id = context.project_id

try:
self.network_api.add_network_to_project(
context, project_id, network_id)
except NotImplementedError:
common.raise_feature_not_supported()
except (exception.NoMoreNetworks,
exception.NetworkNotFoundForUUID) as e:
raise exc.HTTPBadRequest(explanation=e.format_message())
raise exc.HTTPGone()

+ 6
- 53
nova/api/openstack/compute/networks_associate.py View File

@@ -12,70 +12,23 @@

from webob import exc

from nova.api.openstack.api_version_request \
import MAX_PROXY_API_SUPPORT_VERSION
from nova.api.openstack import common
from nova.api.openstack.compute.schemas import networks_associate
from nova.api.openstack import wsgi
from nova.api import validation
from nova import exception
from nova.i18n import _
from nova import network
from nova.policies import networks_associate as na_policies


class NetworkAssociateActionController(wsgi.Controller):
"""Network Association API Controller."""

def __init__(self, network_api=None):
super(NetworkAssociateActionController, self).__init__()
# TODO(stephenfin): 'network_api' is only being passed for use by tests
self.network_api = network_api or network.API()

@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
@wsgi.action("disassociate_host")
@wsgi.response(202)
@wsgi.expected_errors((404, 501))
@wsgi.expected_errors(410)
def _disassociate_host_only(self, req, id, body):
context = req.environ['nova.context']
context.can(na_policies.BASE_POLICY_NAME)
try:
self.network_api.associate(context, id, host=None)
except exception.NetworkNotFound:
msg = _("Network not found")
raise exc.HTTPNotFound(explanation=msg)
except NotImplementedError:
common.raise_feature_not_supported()
raise exc.HTTPGone()

@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
@wsgi.action("disassociate_project")
@wsgi.response(202)
@wsgi.expected_errors((404, 501))
@wsgi.expected_errors(410)
def _disassociate_project_only(self, req, id, body):
context = req.environ['nova.context']
context.can(na_policies.BASE_POLICY_NAME)
try:
self.network_api.associate(context, id, project=None)
except exception.NetworkNotFound:
msg = _("Network not found")
raise exc.HTTPNotFound(explanation=msg)
except NotImplementedError:
common.raise_feature_not_supported()
raise exc.HTTPGone()

@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
@wsgi.action("associate_host")
@wsgi.response(202)
@wsgi.expected_errors((404, 501))
@validation.schema(networks_associate.associate_host)
@wsgi.expected_errors(410)
def _associate_host(self, req, id, body):
context = req.environ['nova.context']
context.can(na_policies.BASE_POLICY_NAME)

try:
self.network_api.associate(context, id,
host=body['associate_host'])
except exception.NetworkNotFound:
msg = _("Network not found")
raise exc.HTTPNotFound(explanation=msg)
except NotImplementedError:
common.raise_feature_not_supported()
raise exc.HTTPGone()

+ 6
- 0
nova/api/openstack/compute/rest_api_version_history.rst View File

@@ -435,6 +435,12 @@ API endpoints as below::
21.0.0 (Ussuri) release. On deployments newer than this, the APIs will
return HTTP 410 (Gone) regadless of the requested microversion.

.. versionchanged:: 21.0.0

The ``os-networks`` API was partially removed in the 21.0.0 (Ussuri)
release. On deployments newer than this, some endpoints of the API will
return HTTP 410 (Gone) regadless of the requested microversion.

2.37
----


+ 0
- 77
nova/api/openstack/compute/schemas/networks.py View File

@@ -1,77 +0,0 @@
# Copyright 2015 NEC Corporation. All rights reserved.
#
# 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 nova.api.validation import parameter_types


create = {
'type': 'object',
'properties': {
'network': {
'type': 'object',
'properties': {
'label': {
'type': 'string', 'maxLength': 255
},
'ipam': parameter_types.boolean,
'cidr': parameter_types.cidr,
'cidr_v6': parameter_types.cidr,
'project_id': parameter_types.project_id,
'multi_host': parameter_types.boolean,
'gateway': parameter_types.ipv4,
'gateway_v6': parameter_types.ipv6,
'bridge': {
'type': 'string',
},
'bridge_interface': {
'type': 'string',
},
# NOTE: In _extract_subnets(), dns1, dns2 dhcp_server are
# used only for IPv4, not IPv6.
'dns1': parameter_types.ipv4,
'dns2': parameter_types.ipv4,
'dhcp_server': parameter_types.ipv4,

'fixed_cidr': parameter_types.cidr,
'allowed_start': parameter_types.ip_address,
'allowed_end': parameter_types.ip_address,
'enable_dhcp': parameter_types.boolean,
'share_address': parameter_types.boolean,
'mtu': parameter_types.positive_integer_with_empty_str,
'vlan': parameter_types.positive_integer_with_empty_str,
'vlan_start': parameter_types.positive_integer_with_empty_str,
'vpn_start': {
'type': 'string',
},
},
'required': ['label'],
'oneOf': [
{'required': ['cidr']},
{'required': ['cidr_v6']}
],
'additionalProperties': False,
},
},
'required': ['network'],
'additionalProperties': False,
}

add_network_to_project = {
'type': 'object',
'properties': {
'id': {'type': ['string', 'null']}
},
'required': ['id'],
'additionalProperties': False
}

+ 0
- 24
nova/api/openstack/compute/schemas/networks_associate.py View File

@@ -1,24 +0,0 @@
# Copyright 2015 NEC Corporation. All rights reserved.
#
# 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 nova.api.validation import parameter_types

associate_host = {
'type': 'object',
'properties': {
'associate_host': parameter_types.hostname
},
'required': ['associate_host'],
'additionalProperties': False
}

+ 0
- 2
nova/policies/__init__.py View File

@@ -47,7 +47,6 @@ from nova.policies import migrate_server
from nova.policies import migrations
from nova.policies import multinic
from nova.policies import networks
from nova.policies import networks_associate
from nova.policies import pause_server
from nova.policies import quota_class_sets
from nova.policies import quota_sets
@@ -109,7 +108,6 @@ def list_rules():
migrations.list_rules(),
multinic.list_rules(),
networks.list_rules(),
networks_associate.list_rules(),
pause_server.list_rules(),
quota_class_sets.list_rules(),
quota_sets.list_rules(),

+ 0
- 26
nova/policies/networks.py View File

@@ -18,36 +18,10 @@ from oslo_policy import policy
from nova.policies import base


BASE_POLICY_NAME = 'os_compute_api:os-networks'
POLICY_ROOT = 'os_compute_api:os-networks:%s'


networks_policies = [
policy.DocumentedRuleDefault(
BASE_POLICY_NAME,
base.RULE_ADMIN_API,
"""Create and delete a network, add and disassociate a network
from a project.

These APIs are only available with nova-network which is deprecated.""",
[
{
'method': 'POST',
'path': '/os-networks'
},
{
'method': 'POST',
'path': '/os-networks/add'
},
{
'method': 'DELETE',
'path': '/os-networks/{network_id}'
},
{
'method': 'POST',
'path': '/os-networks/{network_id}/action (disassociate)'
}
]),
policy.DocumentedRuleDefault(
POLICY_ROOT % 'view',
base.RULE_ADMIN_OR_OWNER,

+ 0
- 50
nova/policies/networks_associate.py View File

@@ -1,50 +0,0 @@
# Copyright 2016 Cloudbase Solutions Srl
# All Rights Reserved.
#
# 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 oslo_policy import policy

from nova.policies import base


BASE_POLICY_NAME = 'os_compute_api:os-networks-associate'


networks_associate_policies = [
policy.DocumentedRuleDefault(
BASE_POLICY_NAME,
base.RULE_ADMIN_API,
"""Associate or disassociate a network from a host or project.

These APIs are only available with nova-network which is deprecated.""",
[
{
'method': 'POST',
'path': '/os-networks/{network_id}/action (disassociate_host)'
},
{
'method': 'POST',
'path': '/os-networks/{network_id}/action'
' (disassociate_project)'
},
{
'method': 'POST',
'path': '/os-networks/{network_id}/action (associate_host)'
}
]),
]


def list_rules():
return networks_associate_policies

+ 0
- 3
nova/tests/functional/api_sample_tests/api_samples/os-networks-associate/network-associate-host-req.json.tpl View File

@@ -1,3 +0,0 @@
{
"associate_host": "%(host)s"
}

+ 0
- 3
nova/tests/functional/api_sample_tests/api_samples/os-networks-associate/network-disassociate-host-req.json.tpl View File

@@ -1,3 +0,0 @@
{
"disassociate_host": null
}

+ 0
- 3
nova/tests/functional/api_sample_tests/api_samples/os-networks-associate/network-disassociate-project-req.json.tpl View File

@@ -1,3 +0,0 @@
{
"disassociate_project": null
}

+ 0
- 3
nova/tests/functional/api_sample_tests/api_samples/os-networks-associate/network-disassociate-req.json.tpl View File

@@ -1,3 +0,0 @@
{
"disassociate": null
}

+ 0
- 3
nova/tests/functional/api_sample_tests/api_samples/os-networks/network-add-req.json.tpl View File

@@ -1,3 +0,0 @@
{
"id": "1"
}

+ 0
- 12
nova/tests/functional/api_sample_tests/api_samples/os-networks/network-create-req.json.tpl View File

@@ -1,12 +0,0 @@
{
"network": {
"label": "new net 111",
"cidr": "10.20.105.0/24",
"mtu": 9000,
"dhcp_server": "10.20.105.2",
"enable_dhcp": false,
"share_address": true,
"allowed_start": "10.20.105.10",
"allowed_end": "10.20.105.200"
}
}

+ 0
- 36
nova/tests/functional/api_sample_tests/api_samples/os-networks/network-create-resp.json.tpl View File

@@ -1,36 +0,0 @@
{
"network": {
"bridge": null,
"vpn_public_port": null,
"dhcp_start": "%(ip)s",
"bridge_interface": null,
"updated_at": null,
"id": "%(id)s",
"cidr_v6": null,
"deleted_at": null,
"gateway": "%(ip)s",
"rxtx_base": null,
"label": "new net 111",
"priority": null,
"project_id": null,
"vpn_private_address": null,
"deleted": null,
"vlan": null,
"broadcast": "%(ip)s",
"netmask": "%(ip)s",
"injected": null,
"cidr": "10.20.105.0/24",
"vpn_public_address": null,
"multi_host": null,
"dns2": null,
"created_at": null,
"host": null,
"gateway_v6": null,
"netmask_v6": null,
"dns1": null,
"mtu": 9000,
"dhcp_server": "10.20.105.2",
"enable_dhcp": false,
"share_address": true
}
}

+ 22
- 22
nova/tests/functional/api_sample_tests/api_samples/os-networks/network-show-resp.json.tpl View File

@@ -1,37 +1,37 @@
{
"network":
{
"bridge": "br100",
"bridge_interface": "eth0",
"broadcast": "%(ip)s",
"cidr": "10.0.0.0/29",
"bridge": null,
"bridge_interface": null,
"broadcast": null,
"cidr": null,
"cidr_v6": null,
"created_at": "%(strtime)s",
"deleted": false,
"created_at": null,
"deleted": null,
"deleted_at": null,
"dhcp_start": "%(ip)s",
"dhcp_start": null,
"dns1": null,
"dns2": null,
"gateway": "%(ip)s",
"gateway": null,
"gateway_v6": null,
"host": "nsokolov-desktop",
"host": null,
"id": "%(id)s",
"injected": false,
"label": "mynet_0",
"multi_host": false,
"netmask": "%(ip)s",
"injected": null,
"label": "private",
"multi_host": null,
"netmask": null,
"netmask_v6": null,
"priority": null,
"project_id": "6133f8b603924f45bc0c9e21f6df12fa",
"project_id": null,
"rxtx_base": null,
"updated_at": "%(strtime)s",
"vlan": 100,
"vpn_private_address": "%(ip)s",
"vpn_public_address": "%(ip)s",
"vpn_public_port": 1000,
"updated_at": null,
"vlan": null,
"vpn_private_address": null,
"vpn_public_address": null,
"vpn_public_port": null,
"mtu": null,
"dhcp_server": "%(ip)s",
"enable_dhcp": true,
"share_address": false
"dhcp_server": null,
"enable_dhcp": null,
"share_address": null
}
}

+ 18
- 52
nova/tests/functional/api_sample_tests/api_samples/os-networks/networks-list-resp.json.tpl View File

@@ -1,72 +1,38 @@
{
"networks": [
{
"bridge": "br100",
"bridge_interface": "eth0",
"broadcast": "%(ip)s",
"cidr": "10.0.0.0/29",
"bridge": null,
"bridge_interface": null,
"broadcast": null,
"cidr": null,
"cidr_v6": null,
"created_at": "%(strtime)s",
"deleted": false,
"created_at": null,
"deleted": null,
"deleted_at": null,
"dhcp_start": "%(ip)s",
"dhcp_start": null,
"dns1": null,
"dns2": null,
"gateway": "%(ip)s",
"gateway_v6": null,
"host": "nsokolov-desktop",
"id": "%(id)s",
"injected": false,
"label": "mynet_0",
"multi_host": false,
"netmask": "%(ip)s",
"netmask_v6": null,
"priority": null,
"project_id": "6133f8b603924f45bc0c9e21f6df12fa",
"rxtx_base": null,
"updated_at": "%(strtime)s",
"vlan": 100,
"vpn_private_address": "%(ip)s",
"vpn_public_address": "%(ip)s",
"vpn_public_port": 1000,
"mtu": null,
"dhcp_server": "%(ip)s",
"enable_dhcp": true,
"share_address": false
},
{
"bridge": "br101",
"bridge_interface": "eth0",
"broadcast": "%(ip)s",
"cidr": "10.0.0.10/29",
"cidr_v6": null,
"created_at": "%(strtime)s",
"deleted": false,
"deleted_at": null,
"dhcp_start": "%(ip)s",
"dns1": null,
"dns2": null,
"gateway": "%(ip)s",
"gateway": null,
"gateway_v6": null,
"host": null,
"id": "%(id)s",
"injected": false,
"label": "mynet_1",
"multi_host": false,
"netmask": "%(ip)s",
"injected": null,
"label": "private",
"multi_host": null,
"netmask": null,
"netmask_v6": null,
"priority": null,
"project_id": null,
"rxtx_base": null,
"updated_at": null,
"vlan": 101,
"vpn_private_address": "%(ip)s",
"vlan": null,
"vpn_private_address": null,
"vpn_public_address": null,
"vpn_public_port": 1001,
"vpn_public_port": null,
"mtu": null,
"dhcp_server": "%(ip)s",
"enable_dhcp": true,
"share_address": false
"dhcp_server": null,
"enable_dhcp": null,
"share_address": null
}
]
}

+ 12
- 65
nova/tests/functional/api_sample_tests/test_networks.py View File

@@ -16,91 +16,38 @@
import mock

from nova import exception
from nova.tests import fixtures as nova_fixtures
from nova.tests.functional.api_sample_tests import api_sample_base
from nova.tests.unit.api.openstack.compute import test_networks


def _fixtures_passthrough(method_name):
# This compensates for how fixtures 3.x handles the signatures of
# MonkeyPatched functions vs fixtures < 3.x. In fixtures 3 if a bound
# method is patched in for a bound method then both objects will be passed
# in when called. This means the patch method should have the signature of
# (self, targetself, *args, **kwargs). However that will not work for
# fixtures < 3. This method captures self from the call point and discards
# it since it's not needed.
fake_network_api = test_networks.FakeNetworkAPI()
method = getattr(fake_network_api, method_name)

def call(self, *args, **kwargs):
# self is the nova.network.api.API object that has been patched
# method is bound to FakeNetworkAPI so that will be passed in as self
return method(*args, **kwargs)

return call


# TODO(stephenfin): Remove the parts of this test that are nova-network only
class NetworksJsonTests(api_sample_base.ApiSampleTestBaseV21):
USE_NEUTRON = False # partially nova-net only
ADMIN_API = True
sample_dir = "os-networks"

def setUp(self):
super(NetworksJsonTests, self).setUp()
self.stub_out("nova.network.api.API.get_all",
_fixtures_passthrough('get_all'))
self.stub_out("nova.network.api.API.get",
_fixtures_passthrough('get'))
self.stub_out("nova.network.api.API.associate",
_fixtures_passthrough('associate'))
self.stub_out("nova.network.api.API.delete",
_fixtures_passthrough('delete'))
self.stub_out("nova.network.api.API.create",
_fixtures_passthrough('create'))
self.stub_out("nova.network.api.API.add_network_to_project",
_fixtures_passthrough('add_network_to_project'))
sample_dir = 'os-networks'

# TODO(stephenfin): Rework this to work with neutron
def test_network_list(self):
response = self._do_get('os-networks')
self._verify_response('networks-list-resp', {}, response, 200)

# TODO(stephenfin): Rework this to work with neutron
def test_network_show(self):
uuid = test_networks.FAKE_NETWORKS[0]['uuid']
uuid = nova_fixtures.NeutronFixture.network_1['id']
response = self._do_get('os-networks/%s' % uuid)
self._verify_response('network-show-resp', {}, response, 200)

# TODO(stephenfin): Rework this to work with neutron
@mock.patch('nova.network.api.API.get', side_effect=exception.Unauthorized)
@mock.patch('nova.network.neutronv2.api.API.get',
side_effect=exception.Unauthorized)
def test_network_show_token_expired(self, mock_get):
uuid = test_networks.FAKE_NETWORKS[0]['uuid']
uuid = nova_fixtures.NeutronFixture.network_1['id']
response = self._do_get('os-networks/%s' % uuid)
self.assertEqual(401, response.status_code)

# TODO(stephenfin): Remove this API since it's nova-network only
@mock.patch('nova.network.api.API.create',
side_effect=exception.Forbidden)
def test_network_create_forbidden(self, mock_create):
response = self._do_post("os-networks",
'network-create-req', {})
self.assertEqual(403, response.status_code)

# TODO(stephenfin): Remove this API since it's nova-network only
def test_network_create(self):
response = self._do_post("os-networks",
'network-create-req', {})
self._verify_response('network-create-resp', {}, response, 200)
self.api.api_post('os-networks', {},
check_response_status=[410])

# TODO(stephenfin): Remove this API since it's nova-network only
def test_network_add(self):
response = self._do_post("os-networks/add",
'network-add-req', {})
self.assertEqual(202, response.status_code)
self.assertEqual("", response.text)
self.api.api_post('os-networks/add', {},
check_response_status=[410])

# TODO(stephenfin): Remove this API since it's nova-network only
def test_network_delete(self):
response = self._do_delete('os-networks/always_delete')
self.assertEqual(202, response.status_code)
self.assertEqual("", response.text)
self.api.api_delete('os-networks/always-delete',
check_response_status=[410])

+ 12
- 35
nova/tests/functional/api_sample_tests/test_networks_associate.py View File

@@ -16,48 +16,25 @@
from nova.tests.functional.api_sample_tests import api_sample_base


# TODO(stephenfin): Remove this API since it's nova-network only
class NetworksAssociateJsonTests(api_sample_base.ApiSampleTestBaseV21):
USE_NEUTRON = False # nova-net only
ADMIN_API = True
sample_dir = "os-networks-associate"

_sentinel = object()

def setUp(self):
super(NetworksAssociateJsonTests, self).setUp()

def fake_associate(self, context, network_id,
host=NetworksAssociateJsonTests._sentinel,
project=NetworksAssociateJsonTests._sentinel):
return True

self.stub_out("nova.network.api.API.associate", fake_associate)

def test_disassociate(self):
response = self._do_post('os-networks/1/action',
'network-disassociate-req',
{})
self.assertEqual(202, response.status_code)
self.assertEqual("", response.text)
self.api.api_post('os-networks/1/action',
{'disassociate': None},
check_response_status=[410])

def test_disassociate_host(self):
response = self._do_post('os-networks/1/action',
'network-disassociate-host-req',
{})
self.assertEqual(202, response.status_code)
self.assertEqual("", response.text)
self.api.api_post('os-networks/1/action',
{'disassociate_host': None},
check_response_status=[410])

def test_disassociate_project(self):
response = self._do_post('os-networks/1/action',
'network-disassociate-project-req',
{})
self.assertEqual(202, response.status_code)
self.assertEqual("", response.text)
self.api.api_post('os-networks/1/action',
{'disassociate_project': None},
check_response_status=[410])

def test_associate_host(self):
response = self._do_post('os-networks/1/action',
'network-associate-host-req',
{"host": "testHost"})
self.assertEqual(202, response.status_code)
self.assertEqual("", response.text)
self.api.api_post('os-networks/1/action',
{'associate_host': 'foo'},
check_response_status=[410])

+ 1
- 512
nova/tests/unit/api/openstack/compute/test_networks.py View File

@@ -16,21 +16,15 @@

import copy
import datetime
import math

import iso8601
import mock
import netaddr
from oslo_config import cfg
from oslo_utils.fixture import uuidsentinel as uuids
import webob

from nova.api.openstack.compute import networks as networks_v21
from nova.api.openstack.compute import networks_associate \
as networks_associate_v21
import nova.context
from nova import exception
from nova.network import manager
from nova.network.neutronv2 import api as neutron
from nova import objects
from nova import test
@@ -121,48 +115,6 @@ class FakeNetworkAPI(object):
def __init__(self):
self.networks = copy.deepcopy(FAKE_NETWORKS)

def delete(self, context, network_id):
if network_id == 'always_delete':
return True
if network_id == -1:
raise exception.NetworkInUse(network_id=network_id)
for i, network in enumerate(self.networks):
if network['id'] == network_id:
del self.networks[0]
return True
raise exception.NetworkNotFoundForUUID(uuid=network_id)

def disassociate(self, context, network_uuid):
for network in self.networks:
if network.get('uuid') == network_uuid:
network['project_id'] = None
return True
raise exception.NetworkNotFound(network_id=network_uuid)

def associate(self, context, network_uuid, host=_sentinel,
project=_sentinel):
for network in self.networks:
if network.get('uuid') == network_uuid:
if host is not FakeNetworkAPI._sentinel:
network['host'] = host
if project is not FakeNetworkAPI._sentinel:
network['project_id'] = project
return True
raise exception.NetworkNotFound(network_id=network_uuid)

def add_network_to_project(self, context,
project_id, network_uuid=None):
if network_uuid:
for network in self.networks:
if network.get('project_id', None) is None:
network['project_id'] = project_id
return
return
for network in self.networks:
if network.get('uuid') == network_uuid:
network['project_id'] = project_id
return

def get_all(self, context):
return self._fake_db_network_get_all(context, project_only=True)

@@ -199,146 +151,13 @@ class FakeNetworkAPI(object):
network)
raise exception.NetworkNotFound(network_id=network_id)

def create(self, context, **kwargs):
subnet_bits = int(math.ceil(math.log(kwargs.get(
'network_size', CONF.network_size), 2)))
fixed_net_v4 = netaddr.IPNetwork(kwargs['cidr'])
prefixlen_v4 = 32 - subnet_bits
subnets_v4 = list(fixed_net_v4.subnet(
prefixlen_v4,
count=kwargs.get('num_networks', CONF.num_networks)))
new_networks = []
new_id = max((net['id'] for net in self.networks))
for index, subnet_v4 in enumerate(subnets_v4):
new_id += 1
net = {'id': new_id, 'uuid': uuids.fake}

net['cidr'] = str(subnet_v4)
net['netmask'] = str(subnet_v4.netmask)
net['gateway'] = kwargs.get('gateway') or str(subnet_v4[1])
net['broadcast'] = str(subnet_v4.broadcast)
net['dhcp_start'] = str(subnet_v4[2])

for key in FAKE_NETWORKS[0]:
net.setdefault(key, kwargs.get(key))
new_networks.append(net)
self.networks += new_networks
return new_networks


# NOTE(vish): tests that network create Exceptions actually return
# the proper error responses
class NetworkCreateExceptionsTestV21(test.TestCase):
validation_error = exception.ValidationError

class PassthroughAPI(object):
def __init__(self):
self.network_manager = manager.FlatDHCPManager()

def create(self, *args, **kwargs):
if kwargs['label'] == 'fail_NetworkNotCreated':
raise exception.NetworkNotCreated(req='fake_fail')
return self.network_manager.create_networks(*args, **kwargs)

def setUp(self):
super(NetworkCreateExceptionsTestV21, self).setUp()
self._setup()
fakes.stub_out_networking(self)
self.new_network = copy.deepcopy(NEW_NETWORK)

def _setup(self):
self.req = fakes.HTTPRequest.blank('')
self.controller = networks_v21.NetworkController(self.PassthroughAPI())

def test_network_create_bad_vlan(self):
self.new_network['network']['vlan_start'] = 'foo'
self.assertRaises(self.validation_error,
self.controller.create, self.req,
body=self.new_network)

def test_network_create_no_cidr(self):
del self.new_network['network']['cidr']
self.assertRaises(self.validation_error,
self.controller.create, self.req,
body=self.new_network)

def test_network_create_no_label(self):
del self.new_network['network']['label']
self.assertRaises(self.validation_error,
self.controller.create, self.req,
body=self.new_network)

def test_network_create_label_too_long(self):
self.new_network['network']['label'] = "x" * 256
self.assertRaises(self.validation_error,
self.controller.create, self.req,
body=self.new_network)

def test_network_create_invalid_fixed_cidr(self):
self.new_network['network']['fixed_cidr'] = 'foo'
self.assertRaises(self.validation_error,
self.controller.create, self.req,
body=self.new_network)

def test_network_create_invalid_start(self):
self.new_network['network']['allowed_start'] = 'foo'
self.assertRaises(self.validation_error,
self.controller.create, self.req,
body=self.new_network)

def test_network_create_bad_cidr(self):
self.new_network['network']['cidr'] = '128.0.0.0/900'
self.assertRaises(self.validation_error,
self.controller.create, self.req,
body=self.new_network)

def test_network_create_handle_network_not_created(self):
self.new_network['network']['label'] = 'fail_NetworkNotCreated'
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.create, self.req,
body=self.new_network)

@mock.patch.object(objects.NetworkList, 'get_all')
def test_network_create_cidr_conflict(self, mock_get_all):
def fake_get_all(context):
ret = objects.NetworkList(context=context, objects=[])
net = objects.Network(cidr='10.0.0.0/23')
ret.objects.append(net)
return ret

mock_get_all.side_effect = fake_get_all

self.new_network['network']['cidr'] = '10.0.0.0/24'
self.assertRaises(webob.exc.HTTPConflict,
self.controller.create, self.req,
body=self.new_network)

def test_network_create_vlan_conflict(self):

@staticmethod
def get_all(context):
ret = objects.NetworkList(context=context, objects=[])
net = objects.Network(cidr='10.0.0.0/24', vlan=100)
ret.objects.append(net)
return ret

def fake_create(context):
raise exception.DuplicateVlan(vlan=100)

self.stub_out('nova.objects.NetworkList.get_all', get_all)
self.stub_out('nova.objects.Network.create', fake_create)

self.new_network['network']['cidr'] = '20.0.0.0/24'
self.assertRaises(webob.exc.HTTPConflict,
self.controller.create, self.req,
body=self.new_network)


class NetworksTestV21(test.NoDBTestCase):
validation_error = exception.ValidationError

def setUp(self):
super(NetworksTestV21, self).setUp()
# TODO(stephenfin): Consider using then NeutronFixture here
self.fake_network_api = FakeNetworkAPI()
self._setup()
fakes.stub_out_networking(self)
@@ -370,18 +189,6 @@ class NetworksTestV21(test.NoDBTestCase):
res_dict = self.controller.index(self.non_admin_req)
self.assertEqual(res_dict, {'networks': []})

project_id = self.req.environ["nova.context"].project_id
cxt = self.req.environ["nova.context"]
uuid = FAKE_NETWORKS[0]['uuid']
self.fake_network_api.associate(context=cxt,
network_uuid=uuid,
project=project_id)
res_dict = self.controller.index(self.non_admin_req)
expected = [copy.deepcopy(FAKE_USER_NETWORKS[0])]
for network in expected:
self.network_uuid_to_id(network)
self.assertEqual({'networks': expected}, res_dict)

def test_network_list_all_as_admin(self):
res_dict = self.controller.index(self.admin_req)
expected = copy.deepcopy(FAKE_NETWORKS)
@@ -389,19 +196,6 @@ class NetworksTestV21(test.NoDBTestCase):
self.network_uuid_to_id(network)
self.assertEqual({'networks': expected}, res_dict)

def test_network_disassociate(self):
uuid = FAKE_NETWORKS[0]['uuid']
disassociate = self.controller._disassociate_host_and_project
res = disassociate(self.req, uuid, {'disassociate': None})
self._check_status(res, disassociate, 202)
self.assertIsNone(self.fake_network_api.networks[0]['project_id'])
self.assertIsNone(self.fake_network_api.networks[0]['host'])

def test_network_disassociate_not_found(self):
self.assertRaises(webob.exc.HTTPNotFound,
self.controller._disassociate_host_and_project,
self.req, 100, {'disassociate': None})

def test_network_get_as_user(self):
uuid = FAKE_USER_NETWORKS[0]['uuid']
res_dict = self.controller.show(self.non_admin_req, uuid)
@@ -420,200 +214,6 @@ class NetworksTestV21(test.NoDBTestCase):
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.show, self.req, 100)

def test_network_delete(self):
delete_method = self.controller.delete
res = delete_method(self.req, 1)
self._check_status(res, delete_method, 202)

def test_network_delete_not_found(self):
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.delete, self.req, 100)

def test_network_delete_in_use(self):
self.assertRaises(webob.exc.HTTPConflict,
self.controller.delete, self.req, -1)

def test_network_add(self):
uuid = FAKE_NETWORKS[1]['uuid']
add = self.controller.add
res = add(self.req, body={'id': uuid})
self._check_status(res, add, 202)
res_dict = self.controller.show(self.admin_req,
uuid)
self.assertEqual(res_dict['network']['project_id'],
fakes.FAKE_PROJECT_ID)

@mock.patch('nova.tests.unit.api.openstack.compute.test_networks.'
'FakeNetworkAPI.add_network_to_project',
side_effect=exception.NoMoreNetworks)
def test_network_add_no_more_networks_fail(self, mock_add):
uuid = FAKE_NETWORKS[1]['uuid']
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.add,
self.req, body={'id': uuid})

@mock.patch('nova.tests.unit.api.openstack.compute.test_networks.'
'FakeNetworkAPI.add_network_to_project',
side_effect=exception.
NetworkNotFoundForUUID(uuid=fakes.FAKE_PROJECT_ID))
def test_network_add_network_not_found_networks_fail(self, mock_add):
uuid = FAKE_NETWORKS[1]['uuid']
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.add,
self.req, body={'id': uuid})

def test_network_add_network_without_body(self):
self.assertRaises(self.validation_error, self.controller.add,
self.req,
body=None)

def test_network_add_network_with_invalid_id(self):
self.assertRaises(exception.ValidationError, self.controller.add,
self.req,
body={'id': 123})

def test_network_add_network_with_extra_arg(self):
uuid = FAKE_NETWORKS[1]['uuid']
self.assertRaises(exception.ValidationError, self.controller.add,
self.req,
body={'id': uuid,
'extra_arg': 123})

def test_network_add_network_with_none_id(self):
add = self.controller.add
res = add(self.req, body={'id': None})
self._check_status(res, add, 202)

def test_network_create(self):
res_dict = self.controller.create(self.req, body=self.new_network)
self.assertIn('network', res_dict)
uuid = res_dict['network']['id']
res_dict = self.controller.show(self.req, uuid)
self.assertTrue(res_dict['network']['label'].
startswith(NEW_NETWORK['network']['label']))

def test_network_create_large(self):
self.new_network['network']['cidr'] = '128.0.0.0/4'
res_dict = self.controller.create(self.req, body=self.new_network)
self.assertEqual(res_dict['network']['cidr'],
self.new_network['network']['cidr'])

def test_network_neutron_disassociate_not_implemented(self):
uuid = FAKE_NETWORKS[1]['uuid']
self.assertRaises(webob.exc.HTTPNotImplemented,
self.neutron_ctrl._disassociate_host_and_project,
self.req, uuid, {'disassociate': None})


class NetworksAssociateTestV21(test.NoDBTestCase):

def setUp(self):
super(NetworksAssociateTestV21, self).setUp()
self.fake_network_api = FakeNetworkAPI()
self._setup()
fakes.stub_out_networking(self)
self.admin_req = fakes.HTTPRequest.blank('', use_admin_context=True)

def _setup(self):
self.controller = networks_v21.NetworkController(self.fake_network_api)
self.associate_controller = networks_associate_v21\
.NetworkAssociateActionController(self.fake_network_api)
self.neutron_assoc_ctrl = (
networks_associate_v21.NetworkAssociateActionController(
neutron.API()))
self.req = fakes.HTTPRequest.blank('')

def _check_status(self, res, method, code):
self.assertEqual(method.wsgi_code, code)

def test_network_disassociate_host_only(self):
uuid = FAKE_NETWORKS[0]['uuid']
disassociate = self.associate_controller._disassociate_host_only
res = disassociate(
self.req, uuid, {'disassociate_host': None})
self._check_status(res,
disassociate,
202)
self.assertIsNotNone(self.fake_network_api.networks[0]['project_id'])
self.assertIsNone(self.fake_network_api.networks[0]['host'])

def test_network_disassociate_project_only(self):
uuid = FAKE_NETWORKS[0]['uuid']
disassociate = self.associate_controller._disassociate_project_only
res = disassociate(self.req, uuid, {'disassociate_project': None})
self._check_status(res, disassociate, 202)
self.assertIsNone(self.fake_network_api.networks[0]['project_id'])
self.assertIsNotNone(self.fake_network_api.networks[0]['host'])

def test_network_disassociate_project_network_delete(self):
uuid = FAKE_NETWORKS[1]['uuid']
disassociate = self.associate_controller._disassociate_project_only
res = disassociate(
self.req, uuid, {'disassociate_project': None})
self._check_status(res, disassociate, 202)
self.assertIsNone(self.fake_network_api.networks[1]['project_id'])
delete = self.controller.delete
res = delete(self.req, 1)

# NOTE: On v2.1 code, delete method doesn't return anything and
# the status code is decorated on wsgi_code of the method.
self.assertIsNone(res)
self.assertEqual(202, delete.wsgi_code)

def test_network_associate_project_delete_fail(self):
uuid = FAKE_NETWORKS[0]['uuid']
req = fakes.HTTPRequest.blank(
'/v2/%s/os-networks/%s/action' % (fakes.FAKE_PROJECT_ID, uuid))
self.assertRaises(webob.exc.HTTPConflict,
self.controller.delete, req, -1)

def test_network_associate_with_host(self):
uuid = FAKE_NETWORKS[1]['uuid']
associate = self.associate_controller._associate_host
res = associate(self.req, uuid, body={'associate_host': "TestHost"})
self._check_status(res, associate, 202)
res_dict = self.controller.show(self.admin_req, uuid)
self.assertEqual(res_dict['network']['host'], 'TestHost')

def test_network_neutron_associate_not_implemented(self):
uuid = FAKE_NETWORKS[1]['uuid']
self.assertRaises(webob.exc.HTTPNotImplemented,
self.neutron_assoc_ctrl._associate_host,
self.req, uuid, body={'associate_host': "TestHost"})

def _test_network_neutron_associate_host_validation_failed(self, body):
uuid = FAKE_NETWORKS[1]['uuid']

self.assertRaises(exception.ValidationError,
self.associate_controller._associate_host,
self.req, uuid, body=body)

def test_network_neutron_associate_host_non_string(self):
self._test_network_neutron_associate_host_validation_failed(
{'associate_host': 123})

def test_network_neutron_associate_host_empty_body(self):
self._test_network_neutron_associate_host_validation_failed({})

def test_network_neutron_associate_bad_associate_host_key(self):
self._test_network_neutron_associate_host_validation_failed(
{'badassociate_host': "TestHost"})

def test_network_neutron_associate_host_extra_arg(self):
self._test_network_neutron_associate_host_validation_failed(
{'associate_host': "TestHost",
'extra_arg': "extra_arg"})

def test_network_neutron_disassociate_project_not_implemented(self):
uuid = FAKE_NETWORKS[1]['uuid']
self.assertRaises(webob.exc.HTTPNotImplemented,
self.neutron_assoc_ctrl._disassociate_project_only,
self.req, uuid, {'disassociate_project': None})

def test_network_neutron_disassociate_host_not_implemented(self):
uuid = FAKE_NETWORKS[1]['uuid']
self.assertRaises(webob.exc.HTTPNotImplemented,
self.neutron_assoc_ctrl._disassociate_host_only,
self.req, uuid, {'disassociate_host': None})


class NetworksEnforcementV21(test.NoDBTestCase):

@@ -642,90 +242,6 @@ class NetworksEnforcementV21(test.NoDBTestCase):
"Policy doesn't allow %s to be performed." % rule_name,
exc.format_message())

def test_create_policy_failed(self):
rule_name = 'os_compute_api:os-networks'
self.policy.set_rules({rule_name: "project:non_fake"})
exc = self.assertRaises(
exception.PolicyNotAuthorized,
self.controller.create, self.req, body=NEW_NETWORK)
self.assertEqual(
"Policy doesn't allow %s to be performed." % rule_name,
exc.format_message())

def test_delete_policy_failed(self):
rule_name = 'os_compute_api:os-networks'
self.policy.set_rules({rule_name: "project:non_fake"})
exc = self.assertRaises(
exception.PolicyNotAuthorized,
self.controller.delete, self.req, fakes.FAKE_UUID)
self.assertEqual(
"Policy doesn't allow %s to be performed." % rule_name,
exc.format_message())

def test_add_policy_failed(self):
rule_name = 'os_compute_api:os-networks'
self.policy.set_rules({rule_name: "project:non_fake"})
exc = self.assertRaises(
exception.PolicyNotAuthorized,
self.controller.add, self.req,
body={'id': fakes.FAKE_UUID})
self.assertEqual(
"Policy doesn't allow %s to be performed." % rule_name,
exc.format_message())

def test_disassociate_policy_failed(self):
rule_name = 'os_compute_api:os-networks'
self.policy.set_rules({rule_name: "project:non_fake"})
exc = self.assertRaises(
exception.PolicyNotAuthorized,
self.controller._disassociate_host_and_project,
self.req, fakes.FAKE_UUID, body={'network': {}})
self.assertEqual(
"Policy doesn't allow %s to be performed." % rule_name,
exc.format_message())


class NetworksAssociateEnforcementV21(test.NoDBTestCase):

def setUp(self):
super(NetworksAssociateEnforcementV21, self).setUp()
self.controller = (networks_associate_v21.
NetworkAssociateActionController())
self.req = fakes.HTTPRequest.blank('')

def test_disassociate_host_policy_failed(self):
rule_name = 'os_compute_api:os-networks-associate'
self.policy.set_rules({rule_name: "project:non_fake"})
exc = self.assertRaises(
exception.PolicyNotAuthorized,
self.controller._disassociate_host_only,
self.req, fakes.FAKE_UUID, body={'disassociate_host': {}})
self.assertEqual(
"Policy doesn't allow %s to be performed." % rule_name,
exc.format_message())

def test_disassociate_project_only_policy_failed(self):
rule_name = 'os_compute_api:os-networks-associate'
self.policy.set_rules({rule_name: "project:non_fake"})
exc = self.assertRaises(
exception.PolicyNotAuthorized,
self.controller._disassociate_project_only,
self.req, fakes.FAKE_UUID, body={'disassociate_project': {}})
self.assertEqual(
"Policy doesn't allow %s to be performed." % rule_name,
exc.format_message())

def test_disassociate_host_only_policy_failed(self):
rule_name = 'os_compute_api:os-networks-associate'
self.policy.set_rules({rule_name: "project:non_fake"})
exc = self.assertRaises(
exception.PolicyNotAuthorized,
self.controller._associate_host,
self.req, fakes.FAKE_UUID, body={'associate_host': 'fake_host'})
self.assertEqual(
"Policy doesn't allow %s to be performed." % rule_name,
exc.format_message())


class NetworksDeprecationTest(test.NoDBTestCase):

@@ -737,32 +253,5 @@ class NetworksDeprecationTest(test.NoDBTestCase):
def test_all_api_return_not_found(self):
self.assertRaises(exception.VersionNotFoundForAPIMethod,
self.controller.show, self.req, fakes.FAKE_UUID)
self.assertRaises(exception.VersionNotFoundForAPIMethod,
self.controller.delete, self.req, fakes.FAKE_UUID)
self.assertRaises(exception.VersionNotFoundForAPIMethod,
self.controller.index, self.req)
self.assertRaises(exception.VersionNotFoundForAPIMethod,
self.controller._disassociate_host_and_project, self.req, {})
self.assertRaises(exception.VersionNotFoundForAPIMethod,
self.controller.add, self.req, {})
self.assertRaises(exception.VersionNotFoundForAPIMethod,
self.controller.create, self.req, {})


class NetworksAssociateDeprecationTest(test.NoDBTestCase):

def setUp(self):
super(NetworksAssociateDeprecationTest, self).setUp()
self.controller = networks_associate_v21\
.NetworkAssociateActionController()
self.req = fakes.HTTPRequest.blank('', version='2.36')

def test_all_api_return_not_found(self):
self.assertRaises(exception.VersionNotFoundForAPIMethod,
self.controller._associate_host, self.req, fakes.FAKE_UUID, {})
self.assertRaises(exception.VersionNotFoundForAPIMethod,
self.controller._disassociate_project_only, self.req,
fakes.FAKE_UUID, {})
self.assertRaises(exception.VersionNotFoundForAPIMethod,
self.controller._disassociate_host_only, self.req,
fakes.FAKE_UUID, {})

+ 0
- 2
nova/tests/unit/fake_policy.py View File

@@ -57,9 +57,7 @@ policy_data = """
"os_compute_api:os-migrate-server:migrate": "",
"os_compute_api:os-migrate-server:migrate_live": "",
"os_compute_api:os-multinic": "",
"os_compute_api:os-networks": "",
"os_compute_api:os-networks:view": "",
"os_compute_api:os-networks-associate": "",
"os_compute_api:os-tenant-networks": "",
"os_compute_api:os-pause-server:pause": "",
"os_compute_api:os-pause-server:unpause": "",

+ 0
- 2
nova/tests/unit/test_policy.py View File

@@ -346,8 +346,6 @@ class RealRolePolicyTestCase(test.NoDBTestCase):
"os_compute_api:os-lock-server:unlock:unlock_override",
"os_compute_api:os-migrate-server:migrate",
"os_compute_api:os-migrate-server:migrate_live",
"os_compute_api:os-networks",
"os_compute_api:os-networks-associate",
"os_compute_api:os-quota-sets:update",
"os_compute_api:os-quota-sets:delete",
"os_compute_api:os-server-diagnostics",

+ 9
- 0
releasenotes/notes/remove-nova-network-c02953ba72a1795d.yaml View File

@@ -10,7 +10,16 @@ upgrade:
* ``POST /os-security-group-default-rules``
* ``GET /os-security-group-default-rules/{id}``
* ``DELETE /os-security-group-default-rules/{id}``
* ``POST /os-networks``
* ``DELETE /os-networks``
* ``POST /os-networks/add``
* ``POST /os-networks/{id} (associate_host)``
* ``POST /os-networks/{id} (disassociate)``
* ``POST /os-networks/{id} (disassociate_host)``
* ``POST /os-networks/{id} (disassociate_project)``

The following policies have also been removed.

* ``os_compute_api:os-security-group-default-rules``
* ``os_compute_api:os-networks``
* ``os_compute_api:os-networks-associate``

Loading…
Cancel
Save