Coverage for manila/tests/share/drivers/container/test_container_helper.py: 100%
183 statements
« prev ^ index » next coverage.py v7.11.0, created at 2026-02-18 22:19 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2026-02-18 22:19 +0000
1# Copyright (c) 2016 Mirantis, Inc.
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15"""Unit tests for the Container helper module."""
17from unittest import mock
19import ddt
21from manila import exception
22from manila.share import configuration
23from manila.share.drivers.container import container_helper
24from manila import test
25from manila.tests.share.drivers.container import fakes
28@ddt.ddt
29class DockerExecHelperTestCase(test.TestCase):
30 """Tests DockerExecHelper"""
32 def setUp(self):
33 super(DockerExecHelperTestCase, self).setUp()
34 self.fake_conf = configuration.Configuration(None)
35 self.fake_conf.container_image_name = "fake_image"
36 self.fake_conf.container_volume_mount_path = "/tmp/shares"
37 self.DockerExecHelper = container_helper.DockerExecHelper(
38 configuration=self.fake_conf)
40 def test_create_container(self):
41 fake_name = 'fake_container'
42 self.DockerExecHelper.configuration.container_image_name = 'fake_image'
44 self.mock_object(self.DockerExecHelper, '_inner_execute',
45 mock.Mock(return_value=('fake_container_id', '')))
46 self.mock_object(self.DockerExecHelper, 'disconnect_network')
48 self.DockerExecHelper.create_container(fake_name)
50 self.DockerExecHelper._inner_execute.assert_called_once_with([
51 'docker', 'container', 'create', '--name=%s' % fake_name,
52 '--privileged', '-v', '/dev:/dev', '-v', '/tmp/shares:/shares',
53 'fake_image'])
54 self.DockerExecHelper.disconnect_network.assert_called_once_with(
55 'bridge', fake_name)
57 def test_create_container_failure(self):
58 self.mock_object(self.DockerExecHelper, '_inner_execute',
59 mock.Mock(side_effect=OSError()))
61 self.assertRaises(exception.ShareBackendException,
62 self.DockerExecHelper.create_container)
64 def test_start_container(self):
65 fake_name = 'fake_container'
67 self.mock_object(self.DockerExecHelper, '_inner_execute', mock.Mock())
69 self.DockerExecHelper.start_container(fake_name)
71 self.DockerExecHelper._inner_execute.assert_called_once_with([
72 'docker', 'container', 'start', 'fake_container'])
74 def test_start_container_impossible_failure(self):
75 self.mock_object(self.DockerExecHelper, "_inner_execute",
76 mock.Mock(side_effect=OSError()))
78 self.assertRaises(exception.ShareBackendException,
79 self.DockerExecHelper.start_container, None)
81 def test_stop_container(self):
82 self.mock_object(self.DockerExecHelper, "_inner_execute",
83 mock.Mock(return_value=['fake_output', None]))
84 expected = ['docker', 'stop', 'manila-fake-conainer']
86 self.DockerExecHelper.stop_container("manila-fake-conainer")
88 self.DockerExecHelper._inner_execute.assert_called_once_with(expected)
90 def test_stop_container_oh_noes(self):
91 self.mock_object(self.DockerExecHelper, "_inner_execute",
92 mock.Mock(side_effect=OSError))
94 self.assertRaises(exception.ShareBackendException,
95 self.DockerExecHelper.stop_container,
96 "manila-fake-container")
98 def test_execute(self):
99 self.mock_object(self.DockerExecHelper, "_inner_execute",
100 mock.Mock(return_value='fake_output'))
101 expected = ['docker', 'exec', '-i', 'fake_container', 'fake_script']
103 self.DockerExecHelper.execute("fake_container", ["fake_script"])
105 self.DockerExecHelper._inner_execute.assert_called_once_with(
106 expected, ignore_errors=False)
108 def test_execute_name_not_there(self):
109 self.assertRaises(exception.ManilaException,
110 self.DockerExecHelper.execute,
111 None, ['do', 'stuff'])
113 def test_execute_command_not_there(self):
114 self.assertRaises(exception.ManilaException,
115 self.DockerExecHelper.execute,
116 'fake-name', None)
118 def test_execute_bad_command_format(self):
119 self.assertRaises(exception.ManilaException,
120 self.DockerExecHelper.execute,
121 'fake-name', 'do stuff')
123 def test__inner_execute_ok(self):
124 self.DockerExecHelper._execute = mock.Mock(return_value='fake')
126 result = self.DockerExecHelper._inner_execute("fake_command")
128 self.assertEqual(result, 'fake')
130 def test__inner_execute_not_ok(self):
131 self.DockerExecHelper._execute = mock.Mock(side_effect=[OSError()])
133 self.assertRaises(OSError,
134 self.DockerExecHelper._inner_execute, "fake_command")
136 def test__inner_execute_not_ok_ignore_errors(self):
137 self.DockerExecHelper._execute = mock.Mock(side_effect=OSError())
139 result = self.DockerExecHelper._inner_execute("fake_command",
140 ignore_errors=True)
142 self.assertIsNone(result)
144 def test_fetch_container_addresses(self):
145 fake_name = 'fake_container'
146 fake_addresses = ['192.168.144.19', '10.0.0.131']
147 fake_ip_addr_show = fakes.FAKE_IP_ADDR_SHOW
148 fake_interfaces = ['eth0', 'eth1']
150 self.mock_object(self.DockerExecHelper, 'fetch_container_interfaces',
151 mock.Mock(return_value=fake_interfaces))
152 self.mock_object(self.DockerExecHelper, 'execute',
153 mock.Mock(side_effect=[fake_ip_addr_show[0],
154 fake_ip_addr_show[1]]))
156 self.assertEqual(fake_addresses,
157 self.DockerExecHelper.fetch_container_addresses(
158 fake_name, 'inet'))
159 (self.DockerExecHelper.fetch_container_interfaces
160 .assert_called_once_with(fake_name))
161 self.DockerExecHelper.execute.assert_any_call(
162 fake_name, ['ip', '-oneline', '-family', 'inet', 'address',
163 'show', 'scope', 'global', 'dev', 'eth0']
164 )
165 self.DockerExecHelper.execute.assert_any_call(
166 fake_name, ['ip', '-oneline', '-family', 'inet', 'address',
167 'show', 'scope', 'global', 'dev', 'eth1']
168 )
170 def test_fetch_container_interfaces(self):
171 fake_name = 'fake_container'
172 fake_eths = fakes.FAKE_IP_LINK_SHOW
174 self.mock_object(self.DockerExecHelper, 'execute',
175 mock.Mock(return_value=fake_eths))
177 self.assertEqual(
178 ['eth0', 'eth1'],
179 self.DockerExecHelper.fetch_container_interfaces(fake_name))
180 self.DockerExecHelper.execute.assert_called_once_with(
181 fake_name, ['ip', '-o', 'link', 'show'])
183 def test_rename_container(self):
184 fake_old_name = 'old_name'
185 fake_new_name = 'new_name'
186 fake_veth_names = ['fake_veth']
188 self.mock_object(self.DockerExecHelper, 'get_container_veths',
189 mock.Mock(return_value=fake_veth_names))
190 self.mock_object(self.DockerExecHelper, '_inner_execute',
191 mock.Mock(side_effect=[None, None]))
193 self.DockerExecHelper.rename_container(fake_old_name, fake_new_name)
195 self.DockerExecHelper.get_container_veths.assert_called_once_with(
196 fake_old_name)
197 self.DockerExecHelper._inner_execute.assert_has_calls([
198 mock.call(['docker', 'rename', fake_old_name, fake_new_name]),
199 mock.call(['ovs-vsctl', 'set', 'interface', fake_veth_names[0],
200 'external-ids:manila-container=%s' % fake_new_name])])
202 def test_rename_container_exception_veth(self):
203 fake_old_name = 'old_name'
204 fake_new_name = 'new_name'
206 self.mock_object(self.DockerExecHelper, 'get_container_veths',
207 mock.Mock(return_value=[]))
209 self.assertRaises(exception.ManilaException,
210 self.DockerExecHelper.rename_container,
211 fake_old_name, fake_new_name)
213 @ddt.data([['fake', ''], OSError, ['fake', '']],
214 [['fake', ''], OSError, OSError],
215 [OSError])
216 def test_rename_container_exception_cmds(self, side_effect):
217 fake_old_name = 'old_name'
218 fake_new_name = 'new_name'
219 fake_veth_names = ['fake_veth']
221 self.mock_object(self.DockerExecHelper, 'get_container_veths',
222 mock.Mock(return_value=fake_veth_names))
223 self.mock_object(self.DockerExecHelper, '_inner_execute',
224 mock.Mock(side_effect=side_effect))
226 self.assertRaises(exception.ShareBackendException,
227 self.DockerExecHelper.rename_container,
228 fake_old_name, fake_new_name)
230 if len(side_effect) > 1:
231 self.DockerExecHelper._inner_execute.assert_has_calls([
232 mock.call(['docker', 'rename', fake_old_name, fake_new_name]),
233 mock.call(['ovs-vsctl', 'set', 'interface', fake_veth_names[0],
234 'external-ids:manila-container=%s' % fake_new_name])
235 ])
236 else:
237 self.DockerExecHelper._inner_execute.assert_has_calls([
238 mock.call(['docker', 'rename', fake_old_name, fake_new_name])])
240 @ddt.data((["wrong_name\nfake\nfake_container\nfake_name'"], True),
241 (["wrong_name\nfake_container\nfake'"], False),
242 ("\n", False))
243 @ddt.unpack
244 def test_container_exists(self, fake_return_value, expected_result):
246 self.DockerExecHelper._execute = mock.Mock(
247 return_value=fake_return_value)
249 result = self.DockerExecHelper.container_exists("fake_name")
251 self.DockerExecHelper._execute.assert_called_once_with(
252 "docker", "ps", "--no-trunc", "--format='{{.Names}}'",
253 run_as_root=True)
254 self.assertEqual(expected_result, result)
256 def test_create_network(self):
257 fake_network_name = 'fake_network_name'
259 self.mock_object(self.DockerExecHelper, '_inner_execute',
260 mock.Mock(return_value=('fake_network_id', '')))
262 self.DockerExecHelper.create_network(fake_network_name)
264 self.DockerExecHelper._inner_execute.assert_called_once_with([
265 'docker', 'network', 'create', fake_network_name])
267 def test_create_network_failure(self):
268 self.mock_object(self.DockerExecHelper, '_inner_execute',
269 mock.Mock(side_effect=OSError()))
271 self.assertRaises(exception.ShareBackendException,
272 self.DockerExecHelper.create_network, None)
274 def test_remove_network(self):
275 fake_network_name = 'fake_network_name'
277 self.mock_object(self.DockerExecHelper, '_inner_execute',
278 mock.Mock(return_value=('fake_network_id', '')))
280 self.DockerExecHelper.remove_network(fake_network_name)
282 self.DockerExecHelper._inner_execute.assert_called_once_with([
283 'docker', 'network', 'remove', fake_network_name])
285 def test_remove_network_failure(self):
286 self.mock_object(self.DockerExecHelper, '_inner_execute',
287 mock.Mock(side_effect=OSError()))
289 self.assertRaises(exception.ShareBackendException,
290 self.DockerExecHelper.remove_network, None)
292 def test_connect_network(self):
293 fake_network_name = 'fake_network_name'
294 fake_server_id = 'fake_server_id'
296 self.mock_object(self.DockerExecHelper, '_inner_execute')
298 self.DockerExecHelper.connect_network(fake_network_name,
299 fake_server_id)
301 self.DockerExecHelper._inner_execute.assert_called_once_with([
302 'docker', 'network', 'connect', fake_network_name, fake_server_id])
304 def test_connect_network_failure(self):
305 self.mock_object(self.DockerExecHelper, '_inner_execute',
306 mock.Mock(side_effect=OSError()))
308 self.assertRaises(exception.ShareBackendException,
309 self.DockerExecHelper.connect_network, None, None)
311 def test_disconnect_network(self):
312 fake_network_name = 'fake_network_name'
313 fake_server_id = 'fake_server_id'
315 self.mock_object(self.DockerExecHelper, '_inner_execute')
317 self.DockerExecHelper.disconnect_network(fake_network_name,
318 fake_server_id)
320 self.DockerExecHelper._inner_execute.assert_called_once_with([
321 'docker', 'network', 'disconnect', fake_network_name,
322 fake_server_id])
324 def test_disconnect_network_failure(self):
325 self.mock_object(self.DockerExecHelper, '_inner_execute',
326 mock.Mock(side_effect=OSError()))
328 self.assertRaises(exception.ShareBackendException,
329 self.DockerExecHelper.disconnect_network, None, None)
331 def test_get_container_networks(self):
332 fake_container_name = 'fake_container_name'
333 fake_docker_inspect_networks = fakes.FAKE_DOCKER_INSPECT_NETWORKS
334 fake_networks = ['fake_docker_network_0', 'fake_docker_network_1']
336 self.mock_object(self.DockerExecHelper, '_inner_execute',
337 mock.Mock(return_value=fake_docker_inspect_networks))
339 self.assertEqual(
340 fake_networks,
341 self.DockerExecHelper.get_container_networks(fake_container_name))
342 self.DockerExecHelper._inner_execute.assert_called_once_with([
343 'docker', 'container', 'inspect', '-f',
344 '\'{{json .NetworkSettings.Networks}}\'', fake_container_name])
346 def test_get_container_networks_failure(self):
347 self.mock_object(self.DockerExecHelper, '_inner_execute',
348 mock.Mock(side_effect=OSError()))
350 self.assertRaises(exception.ShareBackendException,
351 self.DockerExecHelper.get_container_networks, None)
353 def test_get_container_veths(self):
354 fake_container_name = 'fake_container_name'
355 fake_eths_iflinks = ('10\n11\n', '')
356 fake_veths = ['fake_veth_0', 'fake_veth_1']
358 self.mock_object(self.DockerExecHelper, 'execute',
359 mock.Mock(return_value=fake_eths_iflinks))
360 self.mock_object(
361 self.DockerExecHelper, '_execute',
362 mock.Mock(side_effect=[('/sys/class/net/%s/ifindex'
363 % fake_veths[0], ''),
364 ('/sys/class/net/%s/ifindex'
365 % fake_veths[1], '')]))
367 self.assertEqual(
368 fake_veths,
369 self.DockerExecHelper.get_container_veths(fake_container_name))
370 self.DockerExecHelper.execute.assert_called_once_with(
371 fake_container_name,
372 ['bash', '-c', 'cat /sys/class/net/eth*/iflink'])
373 self.DockerExecHelper._execute.assert_has_calls([
374 mock.call('bash', '-c', 'grep -l 10 /sys/class/net/veth*/ifindex'),
375 mock.call('bash', '-c', 'grep -l 11 /sys/class/net/veth*/ifindex')
376 ])
378 def test_get_network_bridge(self):
379 fake_network_name = 'fake_network_name'
380 fake_network_id = ('012345abcdef', '')
381 fake_bridge = 'br-' + fake_network_id[0]
383 self.mock_object(self.DockerExecHelper, '_inner_execute',
384 mock.Mock(return_value=fake_network_id))
386 self.assertEqual(
387 fake_bridge,
388 self.DockerExecHelper.get_network_bridge(fake_network_name))
389 self.DockerExecHelper._inner_execute.assert_called_once_with([
390 'docker', 'network', 'inspect', '-f', '{{.Id}}', fake_network_name
391 ])
393 def test_get_network_bridge_failure(self):
394 self.mock_object(self.DockerExecHelper, '_inner_execute',
395 mock.Mock(side_effect=OSError()))
397 self.assertRaises(exception.ShareBackendException,
398 self.DockerExecHelper.get_network_bridge, None)
400 def test_get_veth_from_bridge(self):
401 fake_bridge = 'br-012345abcdef'
402 fake_ip_link_show_master = fakes.FAKE_IP_LINK_SHOW_MASTER
403 fake_veth = 'fake_veth'
405 self.mock_object(self.DockerExecHelper, '_execute',
406 mock.Mock(return_value=fake_ip_link_show_master))
408 self.assertEqual(
409 fake_veth, self.DockerExecHelper.get_veth_from_bridge(fake_bridge))
410 self.DockerExecHelper._execute.assert_called_once_with('ip', 'link',
411 'show',
412 'master',
413 fake_bridge)