diff --git a/salt/states/dockerng.py b/salt/states/dockerng.py index bad7913d1d89..bfc045e5d371 100644 --- a/salt/states/dockerng.py +++ b/salt/states/dockerng.py @@ -2091,7 +2091,13 @@ def volume_present(name, driver=None, driver_opts=None): Name of the volume driver - Type of driver for that volume. + Type of driver for that volume. If ``None`` and the volume + does not yet exist, the volume will be created using Docker's + default driver. If ``None`` and the volume does exist, this + function does nothing, even if the existing volume's driver is + not the Docker default driver. (To ensure that an existing + volume's driver matches the Docker default, you must + explicitly name Docker's default driver here.) driver_opts Option for tha volume driver @@ -2145,7 +2151,7 @@ def volume_present(name, driver=None, driver_opts=None): return ret # volume exits, check if driver is the same. volume = volumes[0] - if volume['Driver'] != driver: + if driver is not None and volume['Driver'] != driver: try: ret['changes']['removed'] = __salt__['dockerng.remove_volume'](name) except Exception as exc: diff --git a/tests/unit/states/dockerng_test.py b/tests/unit/states/dockerng_test.py index 94cac83c1ea9..e78e97a2a4d4 100644 --- a/tests/unit/states/dockerng_test.py +++ b/tests/unit/states/dockerng_test.py @@ -506,22 +506,94 @@ def test_volume_present(self): ''' Test dockerng.volume_present ''' - dockerng_create_volume = Mock(return_value='created') + volumes = [] + default_driver = 'dummy_default' + + def create_volume(name, driver=None, driver_opts=None): + for v in volumes: + # volume_present should never try to add a conflicting + # volume + self.assertNotEqual(v['Name'], name) + if driver is None: + driver = default_driver + new = {'Name': name, 'Driver': driver} + volumes.append(new) + return new + + def remove_volume(name): + old_len = len(volumes) + removed = [v for v in volumes if v['Name'] == name] + # volume_present should not have tried to remove a volume + # that didn't exist + self.assertEqual(1, len(removed)) + volumes.remove(removed[0]) + return removed[0] + + dockerng_create_volume = Mock(side_effect=create_volume) __salt__ = {'dockerng.create_volume': dockerng_create_volume, - 'dockerng.volumes': Mock(return_value={'Volumes': []}), + 'dockerng.volumes': Mock(return_value={'Volumes': volumes}), + 'dockerng.remove_volume': Mock(side_effect=remove_volume), } with patch.dict(dockerng_state.__dict__, {'__salt__': __salt__}): ret = dockerng_state.volume_present( 'volume_foo', ) - dockerng_create_volume.assert_called_with('volume_foo', - driver=None, - driver_opts=None) - self.assertEqual(ret, {'name': 'volume_foo', - 'comment': '', - 'changes': {'created': 'created'}, - 'result': True}) + dockerng_create_volume.assert_called_with('volume_foo', + driver=None, + driver_opts=None) + self.assertEqual( + { + 'name': 'volume_foo', + 'comment': '', + 'changes': { + 'created': { + 'Driver': default_driver, + 'Name': 'volume_foo', + }, + }, + 'result': True, + }, + ret) + self.assertEqual(len(volumes), 1) + self.assertEqual(volumes[0]['Name'], 'volume_foo') + self.assertIs(volumes[0]['Driver'], default_driver) + + # run it again with the same arguments + orig_volumes = [volumes[0].copy()] + ret = dockerng_state.volume_present('volume_foo') + self.assertEqual( + { + 'name': 'volume_foo', + 'comment': "Volume 'volume_foo' already exists.", + 'changes': {}, + 'result': True, + }, + ret) + self.assertEqual(orig_volumes, volumes) + + # run it again, except with a different driver + ret = dockerng_state.volume_present('volume_foo', driver='local') + self.assertEqual( + { + 'name': 'volume_foo', + 'comment': "", + 'changes': { + 'removed': { + 'Driver': default_driver, + 'Name': 'volume_foo', + }, + 'created': { + 'Driver': 'local', + 'Name': 'volume_foo', + }, + }, + 'result': True, + }, + ret) + mod_orig_volumes = [orig_volumes[0].copy()] + mod_orig_volumes[0]['Driver'] = 'local' + self.assertEqual(mod_orig_volumes, volumes) def test_volume_present_with_another_driver(self): '''