container_test.py 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. import docker
  2. from .. import mock
  3. from .. import unittest
  4. from ..helpers import BUSYBOX_IMAGE_WITH_TAG
  5. from compose.const import LABEL_ONE_OFF
  6. from compose.const import LABEL_SLUG
  7. from compose.container import Container
  8. from compose.container import get_container_name
  9. class ContainerTest(unittest.TestCase):
  10. def setUp(self):
  11. self.container_id = "abcabcabcbabc12345"
  12. self.container_dict = {
  13. "Id": self.container_id,
  14. "Image": BUSYBOX_IMAGE_WITH_TAG,
  15. "Command": "top",
  16. "Created": 1387384730,
  17. "Status": "Up 8 seconds",
  18. "Ports": None,
  19. "SizeRw": 0,
  20. "SizeRootFs": 0,
  21. "Names": ["/composetest_db_1", "/composetest_web_1/db"],
  22. "NetworkSettings": {
  23. "Ports": {},
  24. },
  25. "Config": {
  26. "Labels": {
  27. "com.docker.compose.project": "composetest",
  28. "com.docker.compose.service": "web",
  29. "com.docker.compose.container-number": "7",
  30. },
  31. }
  32. }
  33. def test_from_ps(self):
  34. container = Container.from_ps(None,
  35. self.container_dict,
  36. has_been_inspected=True)
  37. assert container.dictionary == {
  38. "Id": self.container_id,
  39. "Image": BUSYBOX_IMAGE_WITH_TAG,
  40. "Name": "/composetest_db_1",
  41. }
  42. def test_from_ps_prefixed(self):
  43. self.container_dict['Names'] = [
  44. '/swarm-host-1' + n for n in self.container_dict['Names']
  45. ]
  46. container = Container.from_ps(
  47. None,
  48. self.container_dict,
  49. has_been_inspected=True)
  50. assert container.dictionary == {
  51. "Id": self.container_id,
  52. "Image": BUSYBOX_IMAGE_WITH_TAG,
  53. "Name": "/composetest_db_1",
  54. }
  55. def test_environment(self):
  56. container = Container(None, {
  57. 'Id': 'abc',
  58. 'Config': {
  59. 'Env': [
  60. 'FOO=BAR',
  61. 'BAZ=DOGE',
  62. ]
  63. }
  64. }, has_been_inspected=True)
  65. assert container.environment == {
  66. 'FOO': 'BAR',
  67. 'BAZ': 'DOGE',
  68. }
  69. def test_number(self):
  70. container = Container(None, self.container_dict, has_been_inspected=True)
  71. assert container.number == 7
  72. def test_name(self):
  73. container = Container.from_ps(None,
  74. self.container_dict,
  75. has_been_inspected=True)
  76. assert container.name == "composetest_db_1"
  77. def test_name_without_project(self):
  78. self.container_dict['Name'] = "/composetest_web_7"
  79. container = Container(None, self.container_dict, has_been_inspected=True)
  80. assert container.name_without_project == "web_7"
  81. def test_name_without_project_custom_container_name(self):
  82. self.container_dict['Name'] = "/custom_name_of_container"
  83. container = Container(None, self.container_dict, has_been_inspected=True)
  84. assert container.name_without_project == "custom_name_of_container"
  85. def test_name_without_project_one_off(self):
  86. self.container_dict['Name'] = "/composetest_web_092cd63296f"
  87. self.container_dict['Config']['Labels'][LABEL_SLUG] = (
  88. "092cd63296fdc446ad432d3905dd1fcbe12a2ba6b52"
  89. )
  90. self.container_dict['Config']['Labels'][LABEL_ONE_OFF] = 'True'
  91. container = Container(None, self.container_dict, has_been_inspected=True)
  92. assert container.name_without_project == 'web_092cd63296fd'
  93. def test_inspect_if_not_inspected(self):
  94. mock_client = mock.create_autospec(docker.APIClient)
  95. container = Container(mock_client, dict(Id="the_id"))
  96. container.inspect_if_not_inspected()
  97. mock_client.inspect_container.assert_called_once_with("the_id")
  98. assert container.dictionary == mock_client.inspect_container.return_value
  99. assert container.has_been_inspected
  100. container.inspect_if_not_inspected()
  101. assert mock_client.inspect_container.call_count == 1
  102. def test_human_readable_ports_none(self):
  103. container = Container(None, self.container_dict, has_been_inspected=True)
  104. assert container.human_readable_ports == ''
  105. def test_human_readable_ports_public_and_private(self):
  106. self.container_dict['NetworkSettings']['Ports'].update({
  107. "45454/tcp": [{"HostIp": "0.0.0.0", "HostPort": "49197"}],
  108. "45453/tcp": [],
  109. })
  110. container = Container(None, self.container_dict, has_been_inspected=True)
  111. expected = "45453/tcp, 0.0.0.0:49197->45454/tcp"
  112. assert container.human_readable_ports == expected
  113. def test_get_local_port(self):
  114. self.container_dict['NetworkSettings']['Ports'].update({
  115. "45454/tcp": [{"HostIp": "0.0.0.0", "HostPort": "49197"}],
  116. })
  117. container = Container(None, self.container_dict, has_been_inspected=True)
  118. assert container.get_local_port(45454, protocol='tcp') == '0.0.0.0:49197'
  119. def test_human_readable_states_no_health(self):
  120. container = Container(None, {
  121. "State": {
  122. "Status": "running",
  123. "Running": True,
  124. "Paused": False,
  125. "Restarting": False,
  126. "OOMKilled": False,
  127. "Dead": False,
  128. "Pid": 7623,
  129. "ExitCode": 0,
  130. "Error": "",
  131. "StartedAt": "2018-01-29T00:34:25.2052414Z",
  132. "FinishedAt": "0001-01-01T00:00:00Z"
  133. },
  134. }, has_been_inspected=True)
  135. expected = "Up"
  136. assert container.human_readable_state == expected
  137. def test_human_readable_states_starting(self):
  138. container = Container(None, {
  139. "State": {
  140. "Status": "running",
  141. "Running": True,
  142. "Paused": False,
  143. "Restarting": False,
  144. "OOMKilled": False,
  145. "Dead": False,
  146. "Pid": 11744,
  147. "ExitCode": 0,
  148. "Error": "",
  149. "StartedAt": "2018-02-03T07:56:20.3591233Z",
  150. "FinishedAt": "2018-01-31T08:56:11.0505228Z",
  151. "Health": {
  152. "Status": "starting",
  153. "FailingStreak": 0,
  154. "Log": []
  155. }
  156. }
  157. }, has_been_inspected=True)
  158. expected = "Up (health: starting)"
  159. assert container.human_readable_state == expected
  160. def test_human_readable_states_healthy(self):
  161. container = Container(None, {
  162. "State": {
  163. "Status": "running",
  164. "Running": True,
  165. "Paused": False,
  166. "Restarting": False,
  167. "OOMKilled": False,
  168. "Dead": False,
  169. "Pid": 5674,
  170. "ExitCode": 0,
  171. "Error": "",
  172. "StartedAt": "2018-02-03T08:32:05.3281831Z",
  173. "FinishedAt": "2018-02-03T08:11:35.7872706Z",
  174. "Health": {
  175. "Status": "healthy",
  176. "FailingStreak": 0,
  177. "Log": []
  178. }
  179. }
  180. }, has_been_inspected=True)
  181. expected = "Up (healthy)"
  182. assert container.human_readable_state == expected
  183. def test_get(self):
  184. container = Container(None, {
  185. "Status": "Up 8 seconds",
  186. "HostConfig": {
  187. "VolumesFrom": ["volume_id"]
  188. },
  189. }, has_been_inspected=True)
  190. assert container.get('Status') == "Up 8 seconds"
  191. assert container.get('HostConfig.VolumesFrom') == ["volume_id"]
  192. assert container.get('Foo.Bar.DoesNotExist') is None
  193. def test_short_id(self):
  194. container = Container(None, self.container_dict, has_been_inspected=True)
  195. assert container.short_id == self.container_id[:12]
  196. def test_has_api_logs(self):
  197. container_dict = {
  198. 'HostConfig': {
  199. 'LogConfig': {
  200. 'Type': 'json-file'
  201. }
  202. }
  203. }
  204. container = Container(None, container_dict, has_been_inspected=True)
  205. assert container.has_api_logs is True
  206. container_dict['HostConfig']['LogConfig']['Type'] = 'none'
  207. container = Container(None, container_dict, has_been_inspected=True)
  208. assert container.has_api_logs is False
  209. container_dict['HostConfig']['LogConfig']['Type'] = 'syslog'
  210. container = Container(None, container_dict, has_been_inspected=True)
  211. assert container.has_api_logs is False
  212. container_dict['HostConfig']['LogConfig']['Type'] = 'journald'
  213. container = Container(None, container_dict, has_been_inspected=True)
  214. assert container.has_api_logs is True
  215. container_dict['HostConfig']['LogConfig']['Type'] = 'foobar'
  216. container = Container(None, container_dict, has_been_inspected=True)
  217. assert container.has_api_logs is False
  218. class GetContainerNameTestCase(unittest.TestCase):
  219. def test_get_container_name(self):
  220. assert get_container_name({}) is None
  221. assert get_container_name({'Name': 'myproject_db_1'}) == 'myproject_db_1'
  222. assert get_container_name(
  223. {'Names': ['/myproject_db_1', '/myproject_web_1/db']}
  224. ) == 'myproject_db_1'
  225. assert get_container_name({
  226. 'Names': [
  227. '/swarm-host-1/myproject_db_1',
  228. '/swarm-host-1/myproject_web_1/db'
  229. ]
  230. }) == 'myproject_db_1'