Merge "Fix capsule volume attach"

This commit is contained in:
Zuul 2019-03-26 03:41:04 +00:00 committed by Gerrit Code Review
commit 10bec435dd
7 changed files with 72 additions and 43 deletions

View File

@ -243,11 +243,6 @@ class CapsuleController(base.Controller):
container_dict['memory'] = str(allocation['memory'])
container_dict.pop('resources')
if container_dict.get('volumeMounts'):
for volume in container_dict['volumeMounts']:
volume['container_name'] = name
container_volume_requests.append(volume)
container_dict['status'] = consts.CREATING
container_dict['interactive'] = True
container_dict['capsule_id'] = new_capsule.id
@ -266,6 +261,11 @@ class CapsuleController(base.Controller):
**container_dict)
new_container.create(context)
if container_dict.get('volumeMounts'):
for volume in container_dict['volumeMounts']:
volume['container_uuid'] = new_container.uuid
container_volume_requests.append(volume)
# Deal with the volume support
requested_volumes = \
self._build_requested_volumes(context,
@ -358,7 +358,7 @@ class CapsuleController(base.Controller):
# volume.
cinder_api = cinder.CinderAPI(context)
volume_driver = "cinder"
requested_volumes = []
requested_volumes = {}
volume_created = []
try:
for mount in volume_spec:
@ -377,7 +377,7 @@ class CapsuleController(base.Controller):
auto_remove = True
mount_destination = None
container_name = None
container_uuid = None
volume_object = objects.Volume(
context,
@ -391,16 +391,17 @@ class CapsuleController(base.Controller):
for item in volume_mounts:
if item['name'] == mount['name']:
mount_destination = item['mountPath']
container_name = item['container_name']
container_uuid = item['container_uuid']
volmapp = objects.VolumeMapping(
context,
container_path=mount_destination,
user_id=context.user_id,
project_id=context.project_id,
volume_id=volume_object.id)
requested_volumes.append({container_name: volmapp})
requested_volumes.setdefault(container_uuid, [])
requested_volumes[container_uuid].append(volmapp)
if not mount_destination or not container_name:
if not mount_destination or not container_uuid:
msg = _("volume mount parameters is invalid.")
raise exception.Invalid(msg)
except Exception as e:

View File

@ -373,8 +373,6 @@ class ContainersController(base.Controller):
if mounts:
api_utils.version_check('mounts', '1.11')
requested_volumes = self._build_requested_volumes(context, mounts)
cpu_policy = container_dict.pop('cpu_policy', None)
container_dict['cpu_policy'] = cpu_policy
@ -431,7 +429,8 @@ class ContainersController(base.Controller):
kwargs = {}
kwargs['extra_spec'] = extra_spec
kwargs['requested_networks'] = requested_networks
kwargs['requested_volumes'] = requested_volumes
kwargs['requested_volumes'] = (
self._build_requested_volumes(context, new_container, mounts))
if pci_req.requests:
kwargs['pci_requests'] = pci_req
kwargs['run'] = run
@ -567,9 +566,9 @@ class ContainersController(base.Controller):
phynet_name = net.get('provider:physical_network')
return phynet_name
def _build_requested_volumes(self, context, mounts):
def _build_requested_volumes(self, context, container, mounts):
cinder_api = cinder.CinderAPI(context)
requested_volumes = []
requested_volumes = {container.uuid: []}
for mount in mounts:
volume_dict = {
'cinder_volume_id': None,
@ -600,7 +599,7 @@ class ContainersController(base.Controller):
volume_dict['volume_provider'] = 'local'
volmapp = objects.VolumeMapping(context, **volume_dict)
requested_volumes.append(volmapp)
requested_volumes[container.uuid].append(volmapp)
return requested_volumes

View File

@ -12,7 +12,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import copy
import itertools
import math
@ -152,12 +151,11 @@ class Manager(periodic_task.PeriodicTasks):
container.host = None
container.save(context)
def _wait_for_volumes_available(self, context, volmaps, container,
timeout=60, poll_interval=1):
def _wait_for_volumes_available(self, context, requested_volumes,
container, timeout=60, poll_interval=1):
start_time = time.time()
request_volumes = copy.deepcopy(volmaps)
try:
volmaps = itertools.chain(volmaps)
volmaps = itertools.chain.from_iterable(requested_volumes.values())
volmap = next(volmaps)
while time.time() - start_time < timeout:
is_available, is_error = self.driver.is_volume_available(
@ -169,7 +167,8 @@ class Manager(periodic_task.PeriodicTasks):
time.sleep(poll_interval)
except StopIteration:
return
for volmap in request_volumes:
volmaps = itertools.chain.from_iterable(requested_volumes.values())
for volmap in volmaps:
if volmap.auto_remove:
try:
self.driver.delete_volume(context, volmap)
@ -344,14 +343,27 @@ class Manager(periodic_task.PeriodicTasks):
self._fail_container(context, container, six.text_type(e),
unset_host=True)
def _attach_volumes(self, context, container, volmaps):
def _attach_volumes_for_capsule(self, context, capsule, requested_volumes):
for c in (capsule.init_containers or []):
self._attach_volumes(context, c, requested_volumes)
for c in (capsule.containers or []):
self._attach_volumes(context, c, requested_volumes)
def _attach_volumes(self, context, container, requested_volumes):
if isinstance(container, objects.Capsule):
self._attach_volumes_for_capsule(context, container,
requested_volumes)
return
try:
volmaps = requested_volumes.get(container.uuid, [])
for volmap in volmaps:
volmap.container_uuid = container.uuid
volmap.host = self.host
volmap.create(context)
if (isinstance(container, objects.Capsule) and
volmap.connection_info):
if (volmap.connection_info and
(isinstance(container, objects.CapsuleContainer) or
isinstance(container, objects.CapsuleInitContainer))):
# NOTE(hongbin): In this case, the volume is already
# attached to this host so we don't need to do it again.
# This will happen only if there are multiple containers

View File

@ -254,7 +254,8 @@ class DockerDriver(driver.ContainerDriver):
LOG.debug('Creating container with image %(image)s name %(name)s',
{'image': image['image'], 'name': name})
self._provision_network(context, network_api, requested_networks)
binds = self._get_binds(context, requested_volumes)
volmaps = requested_volumes.get(container.uuid, [])
binds = self._get_binds(context, volmaps)
kwargs = {
'name': self.get_container_name(container),
'command': container.command,
@ -1220,7 +1221,8 @@ class DockerDriver(driver.ContainerDriver):
name = container.name
LOG.debug('Creating container with image %(image)s name %(name)s',
{'image': image['image'], 'name': name})
binds = self._get_binds(context, requested_volumes)
volmaps = requested_volumes.get(container.uuid, [])
binds = self._get_binds(context, volmaps)
kwargs = {
'name': self.get_container_name(container),
'command': container.command,

View File

@ -16,6 +16,7 @@ from webtest.app import AppError
from neutronclient.common import exceptions as n_exc
from oslo_utils import uuidutils
import six
from zun.common import exception
from zun import objects
@ -329,7 +330,9 @@ class TestContainerController(api_base.FunctionalTest):
requested_volumes = \
mock_container_create.call_args[1]['requested_volumes']
self.assertEqual(1, len(requested_volumes))
self.assertEqual(fake_volume_id, requested_volumes[0].cinder_volume_id)
self.assertEqual(
fake_volume_id,
six.next(six.itervalues(requested_volumes))[0].cinder_volume_id)
exposed_ports = mock_container_create.call_args[0][1].exposed_ports
self.assertEqual(2, len(exposed_ports))
self.assertIn("80/tcp", exposed_ports)
@ -711,7 +714,9 @@ class TestContainerController(api_base.FunctionalTest):
requested_volumes = \
mock_container_create.call_args[1]['requested_volumes']
self.assertEqual(1, len(requested_volumes))
self.assertEqual(fake_volume_id, requested_volumes[0].cinder_volume_id)
self.assertEqual(
fake_volume_id,
requested_volumes[container.uuid][0].cinder_volume_id)
@patch('zun.network.neutron.NeutronAPI.get_available_network')
@patch('zun.compute.api.API.container_show')
@ -758,8 +763,10 @@ class TestContainerController(api_base.FunctionalTest):
requested_volumes = \
mock_container_create.call_args[1]['requested_volumes']
self.assertEqual(1, len(requested_volumes))
self.assertIsNone(requested_volumes[0].cinder_volume_id)
self.assertEqual('local', requested_volumes[0].volume_provider)
self.assertIsNone(
requested_volumes[container.uuid][0].cinder_volume_id)
self.assertEqual(
'local', requested_volumes[container.uuid][0].volume_provider)
@patch('zun.network.neutron.NeutronAPI.get_available_network')
@patch('zun.compute.api.API.container_show')

View File

@ -346,7 +346,8 @@ class TestManager(base.TestCase):
container.status = 'Stopped'
self.compute_manager._resource_tracker = FakeResourceTracker()
networks = []
volumes = [FakeVolumeMapping()]
FakeVolumeMapping.container_uuid = container.uuid
volumes = {container.uuid: [FakeVolumeMapping()]}
self.compute_manager.container_create(
self.context,
requested_networks=networks,
@ -391,6 +392,7 @@ class TestManager(base.TestCase):
mock_is_volume_available.return_value = True, False
mock_attach_volume.side_effect = [None, base.TestingException("fake")]
container = Container(self.context, **utils.get_test_container())
FakeVolumeMapping.container_uuid = container.uuid
vol = FakeVolumeMapping()
vol.auto_remove = True
vol2 = FakeVolumeMapping()
@ -402,7 +404,7 @@ class TestManager(base.TestCase):
container.status = 'Stopped'
self.compute_manager._resource_tracker = FakeResourceTracker()
networks = []
volumes = [vol, vol2]
volumes = {container.uuid: [vol, vol2]}
self.assertRaises(
base.TestingException,
self.compute_manager.container_create,
@ -450,7 +452,8 @@ class TestManager(base.TestCase):
message="Image Not Found")
mock_spawn_n.side_effect = lambda f, *x, **y: f(*x, **y)
networks = []
volumes = [FakeVolumeMapping()]
FakeVolumeMapping.container_uuid = container.uuid
volumes = {container.uuid: [FakeVolumeMapping()]}
self.assertRaises(
exception.ImageNotFound,
self.compute_manager.container_create,
@ -499,7 +502,8 @@ class TestManager(base.TestCase):
message="Image Not Found")
mock_spawn_n.side_effect = lambda f, *x, **y: f(*x, **y)
networks = []
volumes = [FakeVolumeMapping()]
FakeVolumeMapping.container_uuid = container.uuid
volumes = {container.uuid: [FakeVolumeMapping()]}
self.assertRaises(
exception.ZunException,
self.compute_manager.container_create,
@ -548,7 +552,8 @@ class TestManager(base.TestCase):
message="Docker Error occurred")
mock_spawn_n.side_effect = lambda f, *x, **y: f(*x, **y)
networks = []
volumes = [FakeVolumeMapping()]
FakeVolumeMapping.container_uuid = container.uuid
volumes = {container.uuid: [FakeVolumeMapping()]}
self.assertRaises(
exception.DockerError,
self.compute_manager.container_create,
@ -599,7 +604,8 @@ class TestManager(base.TestCase):
mock_spawn_n.side_effect = lambda f, *x, **y: f(*x, **y)
self.compute_manager._resource_tracker = FakeResourceTracker()
networks = []
volumes = [FakeVolumeMapping()]
FakeVolumeMapping.container_uuid = container.uuid
volumes = {container.uuid: [FakeVolumeMapping()]}
self.assertRaises(
exception.DockerError,
self.compute_manager.container_create,
@ -1309,7 +1315,8 @@ class TestManager(base.TestCase):
mock_is_volume_available):
mock_is_volume_available.return_value = True, False
container = Container(self.context, **utils.get_test_container())
volumes = [FakeVolumeMapping()]
FakeVolumeMapping.container_uuid = container.uuid
volumes = {container.uuid: [FakeVolumeMapping()]}
self.compute_manager._wait_for_volumes_available(self.context,
volumes,
container)
@ -1324,9 +1331,10 @@ class TestManager(base.TestCase):
mock_delete_volume):
mock_is_volume_available.return_value = False, True
container = Container(self.context, **utils.get_test_container())
FakeVolumeMapping.container_uuid = container.uuid
volume = FakeVolumeMapping()
volume.auto_remove = True
volumes = [volume]
volumes = {container.uuid: [volume]}
self.assertRaises(exception.Conflict,
self.compute_manager._wait_for_volumes_available,
self.context, volumes, container, timeout=2)

View File

@ -126,7 +126,7 @@ class TestDockerDriver(base.DriverTestCase):
mock_container.status = 'Creating'
mock_container.healthcheck = {}
networks = [{'network': 'fake-network'}]
volumes = []
volumes = {}
fake_port = {'mac_address': 'fake_mac'}
mock_create_or_update_port.return_value = ([], fake_port)
mock_create_security_group.return_value = {
@ -199,7 +199,7 @@ class TestDockerDriver(base.DriverTestCase):
mock_container.status = 'Creating'
mock_container.healthcheck = {}
networks = [{'network': 'fake-network'}]
volumes = []
volumes = {}
fake_port = {'mac_address': 'fake_mac'}
mock_create_or_update_port.return_value = ([], fake_port)
mock_create_security_group.return_value = {
@ -275,7 +275,7 @@ class TestDockerDriver(base.DriverTestCase):
mock_container.healthcheck = {}
mock_container.runtime = None
networks = [{'network': 'fake-network'}]
volumes = []
volumes = {}
fake_port = {'mac_address': 'fake_mac'}
mock_create_or_update_port.return_value = ([], fake_port)
mock_create_security_group.return_value = {
@ -342,7 +342,7 @@ class TestDockerDriver(base.DriverTestCase):
mock_container.status = 'Creating'
mock_container.runtime = 'runc'
networks = [{'network': 'fake-network'}]
volumes = []
volumes = {}
fake_port = {'mac_address': 'fake_mac'}
mock_create_or_update_port.return_value = ([], fake_port)
with self.assertRaisesRegex(