diff --git a/compose/project.py b/compose/project.py index fa3eace2..f5bb8beb 100644 --- a/compose/project.py +++ b/compose/project.py @@ -235,6 +235,12 @@ class Project(object): def initialize_volumes(self): try: for volume in self.volumes: + if volume.is_user_created: + log.info( + 'Found user-created volume "{0}". No new namespaced ' + 'volume will be created.'.format(volume.name) + ) + continue volume.create() except NotFound: raise ConfigurationError( diff --git a/compose/volume.py b/compose/volume.py index fb8bd580..9bd98fa5 100644 --- a/compose/volume.py +++ b/compose/volume.py @@ -1,6 +1,8 @@ from __future__ import absolute_import from __future__ import unicode_literals +from docker.errors import NotFound + class Volume(object): def __init__(self, client, project, name, driver=None, driver_opts=None): @@ -21,6 +23,15 @@ class Volume(object): def inspect(self): return self.client.inspect_volume(self.full_name) + @property + def is_user_created(self): + try: + self.client.inspect_volume(self.name) + except NotFound: + return False + + return True + @property def full_name(self): return '{0}_{1}'.format(self.project, self.name) diff --git a/tests/integration/project_test.py b/tests/integration/project_test.py index a3e0f33a..d1b1fdf0 100644 --- a/tests/integration/project_test.py +++ b/tests/integration/project_test.py @@ -4,6 +4,7 @@ from __future__ import unicode_literals import random import py +from docker.errors import NotFound from .testcases import DockerClientTestCase from compose.config import config @@ -624,7 +625,7 @@ class ProjectTest(DockerClientTestCase): self.assertEqual(volume_data['Name'], full_vol_name) self.assertEqual(volume_data['Driver'], 'local') - def test_project_up_invalid_volume_driver(self): + def test_initialize_volumes_invalid_volume_driver(self): vol_name = '{0:x}'.format(random.getrandbits(32)) config_data = config.Config( @@ -642,7 +643,7 @@ class ProjectTest(DockerClientTestCase): with self.assertRaises(config.ConfigurationError): project.initialize_volumes() - def test_project_up_updated_driver(self): + def test_initialize_volumes_updated_driver(self): vol_name = '{0:x}'.format(random.getrandbits(32)) full_vol_name = 'composetest_{0}'.format(vol_name) @@ -675,3 +676,24 @@ class ProjectTest(DockerClientTestCase): assert 'Configuration for volume {0} specifies driver smb'.format( vol_name ) in str(e.exception) + + def test_initialize_volumes_user_created_volumes(self): + # Use composetest_ prefix so it gets garbage-collected in tearDown() + vol_name = 'composetest_{0:x}'.format(random.getrandbits(32)) + full_vol_name = 'composetest_{0}'.format(vol_name) + self.client.create_volume(vol_name) + config_data = config.Config( + version=2, services=[{ + 'name': 'web', + 'image': 'busybox:latest', + 'command': 'top' + }], volumes={vol_name: {'driver': 'local'}} + ) + project = Project.from_config( + name='composetest', + config_data=config_data, client=self.client + ) + project.initialize_volumes() + + with self.assertRaises(NotFound): + self.client.inspect_volume(full_vol_name) diff --git a/tests/integration/volume_test.py b/tests/integration/volume_test.py index 8ae35378..8bcce0e1 100644 --- a/tests/integration/volume_test.py +++ b/tests/integration/volume_test.py @@ -54,3 +54,13 @@ class VolumeTest(DockerClientTestCase): vol.remove() volumes = self.client.volumes()['Volumes'] assert len([v for v in volumes if v['Name'] == vol.full_name]) == 0 + + def test_is_user_created(self): + vol = Volume(self.client, 'composetest', 'uservolume01') + try: + self.client.create_volume('uservolume01') + assert vol.is_user_created is True + finally: + self.client.remove_volume('uservolume01') + vol2 = Volume(self.client, 'composetest', 'volume01') + assert vol2.is_user_created is False