Merge "Fix capsule volume attach"
This commit is contained in:
commit
10bec435dd
@ -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:
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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')
|
||||
|
@ -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)
|
||||
|
@ -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(
|
||||
|
Loading…
Reference in New Issue
Block a user