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

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.""" 

16 

17from unittest import mock 

18 

19import ddt 

20 

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 

26 

27 

28@ddt.ddt 

29class DockerExecHelperTestCase(test.TestCase): 

30 """Tests DockerExecHelper""" 

31 

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) 

39 

40 def test_create_container(self): 

41 fake_name = 'fake_container' 

42 self.DockerExecHelper.configuration.container_image_name = 'fake_image' 

43 

44 self.mock_object(self.DockerExecHelper, '_inner_execute', 

45 mock.Mock(return_value=('fake_container_id', ''))) 

46 self.mock_object(self.DockerExecHelper, 'disconnect_network') 

47 

48 self.DockerExecHelper.create_container(fake_name) 

49 

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) 

56 

57 def test_create_container_failure(self): 

58 self.mock_object(self.DockerExecHelper, '_inner_execute', 

59 mock.Mock(side_effect=OSError())) 

60 

61 self.assertRaises(exception.ShareBackendException, 

62 self.DockerExecHelper.create_container) 

63 

64 def test_start_container(self): 

65 fake_name = 'fake_container' 

66 

67 self.mock_object(self.DockerExecHelper, '_inner_execute', mock.Mock()) 

68 

69 self.DockerExecHelper.start_container(fake_name) 

70 

71 self.DockerExecHelper._inner_execute.assert_called_once_with([ 

72 'docker', 'container', 'start', 'fake_container']) 

73 

74 def test_start_container_impossible_failure(self): 

75 self.mock_object(self.DockerExecHelper, "_inner_execute", 

76 mock.Mock(side_effect=OSError())) 

77 

78 self.assertRaises(exception.ShareBackendException, 

79 self.DockerExecHelper.start_container, None) 

80 

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'] 

85 

86 self.DockerExecHelper.stop_container("manila-fake-conainer") 

87 

88 self.DockerExecHelper._inner_execute.assert_called_once_with(expected) 

89 

90 def test_stop_container_oh_noes(self): 

91 self.mock_object(self.DockerExecHelper, "_inner_execute", 

92 mock.Mock(side_effect=OSError)) 

93 

94 self.assertRaises(exception.ShareBackendException, 

95 self.DockerExecHelper.stop_container, 

96 "manila-fake-container") 

97 

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'] 

102 

103 self.DockerExecHelper.execute("fake_container", ["fake_script"]) 

104 

105 self.DockerExecHelper._inner_execute.assert_called_once_with( 

106 expected, ignore_errors=False) 

107 

108 def test_execute_name_not_there(self): 

109 self.assertRaises(exception.ManilaException, 

110 self.DockerExecHelper.execute, 

111 None, ['do', 'stuff']) 

112 

113 def test_execute_command_not_there(self): 

114 self.assertRaises(exception.ManilaException, 

115 self.DockerExecHelper.execute, 

116 'fake-name', None) 

117 

118 def test_execute_bad_command_format(self): 

119 self.assertRaises(exception.ManilaException, 

120 self.DockerExecHelper.execute, 

121 'fake-name', 'do stuff') 

122 

123 def test__inner_execute_ok(self): 

124 self.DockerExecHelper._execute = mock.Mock(return_value='fake') 

125 

126 result = self.DockerExecHelper._inner_execute("fake_command") 

127 

128 self.assertEqual(result, 'fake') 

129 

130 def test__inner_execute_not_ok(self): 

131 self.DockerExecHelper._execute = mock.Mock(side_effect=[OSError()]) 

132 

133 self.assertRaises(OSError, 

134 self.DockerExecHelper._inner_execute, "fake_command") 

135 

136 def test__inner_execute_not_ok_ignore_errors(self): 

137 self.DockerExecHelper._execute = mock.Mock(side_effect=OSError()) 

138 

139 result = self.DockerExecHelper._inner_execute("fake_command", 

140 ignore_errors=True) 

141 

142 self.assertIsNone(result) 

143 

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'] 

149 

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]])) 

155 

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 ) 

169 

170 def test_fetch_container_interfaces(self): 

171 fake_name = 'fake_container' 

172 fake_eths = fakes.FAKE_IP_LINK_SHOW 

173 

174 self.mock_object(self.DockerExecHelper, 'execute', 

175 mock.Mock(return_value=fake_eths)) 

176 

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']) 

182 

183 def test_rename_container(self): 

184 fake_old_name = 'old_name' 

185 fake_new_name = 'new_name' 

186 fake_veth_names = ['fake_veth'] 

187 

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])) 

192 

193 self.DockerExecHelper.rename_container(fake_old_name, fake_new_name) 

194 

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])]) 

201 

202 def test_rename_container_exception_veth(self): 

203 fake_old_name = 'old_name' 

204 fake_new_name = 'new_name' 

205 

206 self.mock_object(self.DockerExecHelper, 'get_container_veths', 

207 mock.Mock(return_value=[])) 

208 

209 self.assertRaises(exception.ManilaException, 

210 self.DockerExecHelper.rename_container, 

211 fake_old_name, fake_new_name) 

212 

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'] 

220 

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)) 

225 

226 self.assertRaises(exception.ShareBackendException, 

227 self.DockerExecHelper.rename_container, 

228 fake_old_name, fake_new_name) 

229 

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])]) 

239 

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): 

245 

246 self.DockerExecHelper._execute = mock.Mock( 

247 return_value=fake_return_value) 

248 

249 result = self.DockerExecHelper.container_exists("fake_name") 

250 

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) 

255 

256 def test_create_network(self): 

257 fake_network_name = 'fake_network_name' 

258 

259 self.mock_object(self.DockerExecHelper, '_inner_execute', 

260 mock.Mock(return_value=('fake_network_id', ''))) 

261 

262 self.DockerExecHelper.create_network(fake_network_name) 

263 

264 self.DockerExecHelper._inner_execute.assert_called_once_with([ 

265 'docker', 'network', 'create', fake_network_name]) 

266 

267 def test_create_network_failure(self): 

268 self.mock_object(self.DockerExecHelper, '_inner_execute', 

269 mock.Mock(side_effect=OSError())) 

270 

271 self.assertRaises(exception.ShareBackendException, 

272 self.DockerExecHelper.create_network, None) 

273 

274 def test_remove_network(self): 

275 fake_network_name = 'fake_network_name' 

276 

277 self.mock_object(self.DockerExecHelper, '_inner_execute', 

278 mock.Mock(return_value=('fake_network_id', ''))) 

279 

280 self.DockerExecHelper.remove_network(fake_network_name) 

281 

282 self.DockerExecHelper._inner_execute.assert_called_once_with([ 

283 'docker', 'network', 'remove', fake_network_name]) 

284 

285 def test_remove_network_failure(self): 

286 self.mock_object(self.DockerExecHelper, '_inner_execute', 

287 mock.Mock(side_effect=OSError())) 

288 

289 self.assertRaises(exception.ShareBackendException, 

290 self.DockerExecHelper.remove_network, None) 

291 

292 def test_connect_network(self): 

293 fake_network_name = 'fake_network_name' 

294 fake_server_id = 'fake_server_id' 

295 

296 self.mock_object(self.DockerExecHelper, '_inner_execute') 

297 

298 self.DockerExecHelper.connect_network(fake_network_name, 

299 fake_server_id) 

300 

301 self.DockerExecHelper._inner_execute.assert_called_once_with([ 

302 'docker', 'network', 'connect', fake_network_name, fake_server_id]) 

303 

304 def test_connect_network_failure(self): 

305 self.mock_object(self.DockerExecHelper, '_inner_execute', 

306 mock.Mock(side_effect=OSError())) 

307 

308 self.assertRaises(exception.ShareBackendException, 

309 self.DockerExecHelper.connect_network, None, None) 

310 

311 def test_disconnect_network(self): 

312 fake_network_name = 'fake_network_name' 

313 fake_server_id = 'fake_server_id' 

314 

315 self.mock_object(self.DockerExecHelper, '_inner_execute') 

316 

317 self.DockerExecHelper.disconnect_network(fake_network_name, 

318 fake_server_id) 

319 

320 self.DockerExecHelper._inner_execute.assert_called_once_with([ 

321 'docker', 'network', 'disconnect', fake_network_name, 

322 fake_server_id]) 

323 

324 def test_disconnect_network_failure(self): 

325 self.mock_object(self.DockerExecHelper, '_inner_execute', 

326 mock.Mock(side_effect=OSError())) 

327 

328 self.assertRaises(exception.ShareBackendException, 

329 self.DockerExecHelper.disconnect_network, None, None) 

330 

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'] 

335 

336 self.mock_object(self.DockerExecHelper, '_inner_execute', 

337 mock.Mock(return_value=fake_docker_inspect_networks)) 

338 

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]) 

345 

346 def test_get_container_networks_failure(self): 

347 self.mock_object(self.DockerExecHelper, '_inner_execute', 

348 mock.Mock(side_effect=OSError())) 

349 

350 self.assertRaises(exception.ShareBackendException, 

351 self.DockerExecHelper.get_container_networks, None) 

352 

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'] 

357 

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], '')])) 

366 

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 ]) 

377 

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] 

382 

383 self.mock_object(self.DockerExecHelper, '_inner_execute', 

384 mock.Mock(return_value=fake_network_id)) 

385 

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 ]) 

392 

393 def test_get_network_bridge_failure(self): 

394 self.mock_object(self.DockerExecHelper, '_inner_execute', 

395 mock.Mock(side_effect=OSError())) 

396 

397 self.assertRaises(exception.ShareBackendException, 

398 self.DockerExecHelper.get_network_bridge, None) 

399 

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' 

404 

405 self.mock_object(self.DockerExecHelper, '_execute', 

406 mock.Mock(return_value=fake_ip_link_show_master)) 

407 

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)