Merge "Prevent race condition on creating network"
This commit is contained in:
commit
fa48dbe10a
|
@ -21,7 +21,6 @@ from zun.api import utils as api_utils
|
|||
from zun.api import validation
|
||||
from zun.common import exception
|
||||
from zun.common import policy
|
||||
from zun import objects
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
@ -61,11 +60,7 @@ class NetworkController(base.Controller):
|
|||
:param network_dict: a network within the request body.
|
||||
"""
|
||||
context = pecan.request.context
|
||||
policy.enforce(context, "network:create",
|
||||
action="network:create")
|
||||
network_dict['project_id'] = context.project_id
|
||||
network_dict['user_id'] = context.user_id
|
||||
new_network = objects.Network(context, **network_dict)
|
||||
new_network.create(context)
|
||||
pecan.request.compute_api.network_create(context, new_network)
|
||||
policy.enforce(context, "network:create", action="network:create")
|
||||
new_network = pecan.request.compute_api.network_create(
|
||||
context, network_dict['neutron_net_id'])
|
||||
return view.format_network(pecan.request.host_url, new_network)
|
||||
|
|
|
@ -234,8 +234,8 @@ class API(object):
|
|||
container_actions.NETWORK_ATTACH)
|
||||
return self.rpcapi.network_attach(context, container, *args)
|
||||
|
||||
def network_create(self, context, network):
|
||||
return self.rpcapi.network_create(context, network)
|
||||
def network_create(self, context, *args):
|
||||
return self.rpcapi.network_create(context, *args)
|
||||
|
||||
def resize_container(self, context, container, *args):
|
||||
return self.rpcapi.resize_container(context, container, *args)
|
||||
|
|
|
@ -1254,11 +1254,9 @@ class Manager(periodic_task.PeriodicTasks):
|
|||
self.driver.network_attach(context, container, requested_network)
|
||||
self._update_task_state(context, container, None)
|
||||
|
||||
def network_create(self, context, network):
|
||||
def network_create(self, context, neutron_net_id):
|
||||
LOG.debug('Create network')
|
||||
docker_network = self.driver.create_network(context, network)
|
||||
network.network_id = docker_network['Id']
|
||||
network.save()
|
||||
return self.driver.create_network(context, neutron_net_id)
|
||||
|
||||
def resize_container(self, context, container, patch):
|
||||
@utils.synchronized(container.uuid)
|
||||
|
|
|
@ -203,6 +203,7 @@ class API(rpc_service.API):
|
|||
container=container,
|
||||
requested_network=requested_network)
|
||||
|
||||
def network_create(self, context, new_network):
|
||||
def network_create(self, context, neutron_net_id):
|
||||
host = None
|
||||
return self._call(host, 'network_create', network=new_network)
|
||||
return self._call(host, 'network_create',
|
||||
neutron_net_id=neutron_net_id)
|
||||
|
|
|
@ -1214,13 +1214,12 @@ class DockerDriver(driver.ContainerDriver):
|
|||
container.addresses = addresses
|
||||
container.save(context)
|
||||
|
||||
def create_network(self, context, network):
|
||||
def create_network(self, context, neutron_net_id):
|
||||
with docker_utils.docker_client() as docker:
|
||||
network_api = zun_network.api(context,
|
||||
docker_api=docker)
|
||||
docker_net_name = self._get_docker_network_name(
|
||||
context, network.neutron_net_id)
|
||||
docker_network = network_api.create_network(
|
||||
neutron_net_id=network.neutron_net_id,
|
||||
context, neutron_net_id)
|
||||
return network_api.create_network(
|
||||
neutron_net_id=neutron_net_id,
|
||||
name=docker_net_name)
|
||||
return docker_network
|
||||
|
|
|
@ -1032,6 +1032,16 @@ def update_network(context, uuid, values):
|
|||
context, uuid, values)
|
||||
|
||||
|
||||
@profiler.trace("db")
|
||||
def destroy_network(context, network_uuid):
|
||||
"""Destroy a network.
|
||||
|
||||
:param context: Request context
|
||||
:param network_uuid: The uuid of a network.
|
||||
"""
|
||||
return _get_dbdriver_instance().destroy_network(context, network_uuid)
|
||||
|
||||
|
||||
@profiler.trace("db")
|
||||
def create_exec_instance(context, values):
|
||||
"""Create a new exec instance.
|
||||
|
|
|
@ -1228,6 +1228,15 @@ class Connection(object):
|
|||
except NoResultFound:
|
||||
raise exception.NetworkNotFound(network=network_uuid)
|
||||
|
||||
def destroy_network(self, context, network_uuid):
|
||||
session = get_session()
|
||||
with session.begin():
|
||||
query = model_query(models.Network, session=session)
|
||||
query = add_identity_filter(query, network_uuid)
|
||||
count = query.delete()
|
||||
if count != 1:
|
||||
raise exception.NetworkNotFound(network=network_uuid)
|
||||
|
||||
def list_exec_instances(self, context, filters=None, limit=None,
|
||||
marker=None, sort_key=None, sort_dir=None):
|
||||
query = model_query(models.ExecInstance)
|
||||
|
|
|
@ -25,6 +25,7 @@ from zun.common.i18n import _
|
|||
import zun.conf
|
||||
from zun.network import network
|
||||
from zun.network import neutron
|
||||
from zun import objects
|
||||
from zun.objects import fields as obj_fields
|
||||
from zun.pci import manager as pci_manager
|
||||
from zun.pci import utils as pci_utils
|
||||
|
@ -113,16 +114,34 @@ class KuryrNetwork(network.Network):
|
|||
options['neutron.pool.v6.uuid'] = v6_subnet.get('subnetpool_id')
|
||||
options['neutron.subnet.v6.uuid'] = v6_subnet.get('id')
|
||||
|
||||
network_dict = {}
|
||||
network_dict['project_id'] = self.context.project_id
|
||||
network_dict['user_id'] = self.context.user_id
|
||||
network_dict['name'] = name
|
||||
network_dict['neutron_net_id'] = neutron_net_id
|
||||
network = objects.Network(self.context, **network_dict)
|
||||
# The DB model has unique constraint on 'neutron_net_id' field
|
||||
# which will guarantee only one request can create the network in here
|
||||
# (and call docker.create_network later) if there are concurrent
|
||||
# requests on creating networks for the same neutron net.
|
||||
network.create(self.context)
|
||||
|
||||
LOG.debug("Calling docker.create_network to create network %s, "
|
||||
"ipam_options %s, options %s", name, ipam_options, options)
|
||||
docker_network = self.docker.create_network(
|
||||
name=name,
|
||||
driver=CONF.network.driver_name,
|
||||
enable_ipv6=True if v6_subnet else False,
|
||||
options=options,
|
||||
ipam=ipam_options)
|
||||
try:
|
||||
docker_network = self.docker.create_network(
|
||||
name=name,
|
||||
driver=CONF.network.driver_name,
|
||||
enable_ipv6=True if v6_subnet else False,
|
||||
options=options,
|
||||
ipam=ipam_options)
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
network.destroy()
|
||||
|
||||
return docker_network
|
||||
network.network_id = docker_network['Id']
|
||||
network.save()
|
||||
return network
|
||||
|
||||
def _check_valid_subnetpool(self, neutron_api,
|
||||
subnetpool_id, subnet_cidr):
|
||||
|
|
|
@ -19,7 +19,8 @@ from zun.objects import base
|
|||
@base.ZunObjectRegistry.register
|
||||
class Network(base.ZunPersistentObject, base.ZunObject):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
# Version 1.1: Add destroy method
|
||||
VERSION = '1.1'
|
||||
|
||||
fields = {
|
||||
'id': fields.IntegerField(),
|
||||
|
@ -92,3 +93,8 @@ class Network(base.ZunPersistentObject, base.ZunObject):
|
|||
dbapi.update_network(context, self.uuid, updates)
|
||||
|
||||
self.obj_reset_changes()
|
||||
|
||||
@base.remotable
|
||||
def destroy(self, context=None):
|
||||
dbapi.destroy_network(context, self.uuid)
|
||||
self.obj_reset_changes()
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
from mock import patch
|
||||
from zun.tests.unit.api import base as api_base
|
||||
from zun.tests.unit.db import utils
|
||||
|
||||
|
||||
class TestNetworkController(api_base.FunctionalTest):
|
||||
|
@ -19,7 +20,8 @@ class TestNetworkController(api_base.FunctionalTest):
|
|||
@patch('zun.compute.api.API.network_create')
|
||||
def test_network_create(self, mock_network_create, mock_policy):
|
||||
mock_policy.return_value = True
|
||||
mock_network_create.side_effect = lambda x, y: y
|
||||
test_object = utils.create_test_network(context=self.context)
|
||||
mock_network_create.return_value = test_object
|
||||
params = ('{"name": "network-test", "neutron_net_id": "test-id"}')
|
||||
response = self.post('/v1/networks/',
|
||||
params=params,
|
||||
|
|
|
@ -1364,12 +1364,10 @@ class TestManager(base.TestCase):
|
|||
self.assertTrue(mock_fail.called)
|
||||
self.assertTrue(mock_delete_volume.called)
|
||||
|
||||
@mock.patch.object(Network, 'save')
|
||||
@mock.patch.object(fake_driver, 'create_network')
|
||||
def test_network_create(self, mock_create, mock_save):
|
||||
def test_network_create(self, mock_create):
|
||||
network = Network(self.context, **utils.get_test_network())
|
||||
ret = ({'Id': '0eeftestnetwork'})
|
||||
mock_create.return_value = ret
|
||||
self.compute_manager.network_create(self.context, network)
|
||||
mock_create.assert_any_call(self.context, network)
|
||||
mock_save.assert_called_once()
|
||||
|
|
|
@ -20,6 +20,7 @@ from neutronclient.common import exceptions as n_exc
|
|||
from zun.common import exception
|
||||
from zun.network import kuryr_network
|
||||
from zun.objects.container import Container
|
||||
from zun.objects.network import Network
|
||||
from zun.tests import base
|
||||
from zun.tests.unit.db import utils
|
||||
|
||||
|
@ -142,19 +143,20 @@ class KuryrNetworkTestCase(base.TestCase):
|
|||
self.network_api.init(self.context, self.docker_api)
|
||||
self.network_api.neutron_api = FakeNeutronClient()
|
||||
|
||||
@mock.patch.object(Network, 'create')
|
||||
@mock.patch.object(Network, 'save')
|
||||
@mock.patch('zun.network.neutron.NeutronAPI')
|
||||
def test_create_network_without_subnetpool(self,
|
||||
mock_neutron_api_cls):
|
||||
def test_create_network_without_subnetpool(
|
||||
self, mock_neutron_api_cls, mock_save, mock_create):
|
||||
self.network_api.neutron_api.subnets[0].pop('subnetpool_id')
|
||||
mock_neutron_api_cls.return_value = self.network_api.neutron_api
|
||||
name = 'test_kuryr_network'
|
||||
neutron_net_id = 'fake-net-id'
|
||||
with mock.patch.object(self.network_api.docker, 'create_network',
|
||||
return_value='docker-net'
|
||||
return_value={'Id': 'docker-net'}
|
||||
) as mock_create_network:
|
||||
docker_network = self.network_api.create_network(name,
|
||||
neutron_net_id)
|
||||
self.assertEqual('docker-net', docker_network)
|
||||
network = self.network_api.create_network(name, neutron_net_id)
|
||||
self.assertEqual('docker-net', network.network_id)
|
||||
mock_create_network.assert_called_once_with(
|
||||
name=name,
|
||||
driver='kuryr',
|
||||
|
@ -169,18 +171,19 @@ class KuryrNetworkTestCase(base.TestCase):
|
|||
'neutron.subnet.uuid': 'fake-subnet-id',
|
||||
'neutron.pool.uuid': None})
|
||||
|
||||
@mock.patch.object(Network, 'create')
|
||||
@mock.patch.object(Network, 'save')
|
||||
@mock.patch('zun.network.neutron.NeutronAPI')
|
||||
def test_create_network_with_subnetpool(self,
|
||||
mock_neutron_api_cls):
|
||||
def test_create_network_with_subnetpool(
|
||||
self, mock_neutron_api_cls, mock_save, mock_create):
|
||||
mock_neutron_api_cls.return_value = self.network_api.neutron_api
|
||||
name = 'test_kuryr_network'
|
||||
neutron_net_id = 'fake-net-id'
|
||||
with mock.patch.object(self.network_api.docker, 'create_network',
|
||||
return_value='docker-net'
|
||||
return_value={'Id': 'docker-net'}
|
||||
) as mock_create_network:
|
||||
docker_network = self.network_api.create_network(name,
|
||||
neutron_net_id)
|
||||
self.assertEqual('docker-net', docker_network)
|
||||
network = self.network_api.create_network(name, neutron_net_id)
|
||||
self.assertEqual('docker-net', network.network_id)
|
||||
mock_create_network.assert_called_once_with(
|
||||
name=name,
|
||||
driver='kuryr',
|
||||
|
|
|
@ -364,7 +364,7 @@ object_data = {
|
|||
'ContainerPCIRequests': '1.0-7b8f7f044661fe4e24e6949c035af2c4',
|
||||
'ContainerAction': '1.1-b0c721f9e10c6c0d1e41e512c49eb877',
|
||||
'ContainerActionEvent': '1.0-2974d0a6f5d4821fd4e223a88c10181a',
|
||||
'Network': '1.0-235ba13359282107f27c251af9aaffcd',
|
||||
'Network': '1.1-f57547d39a95cf36f2b026aa4a863879',
|
||||
'ExecInstance': '1.0-59464e7b96db847c0abb1e96d3cec30a',
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue