Fuel CCP - Tests sub-project
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

test_daemonsets.py 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. # Copyright 2016 Mirantis, Inc.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License"); you may
  4. # not use this file except in compliance with the License. You may obtain
  5. # a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  11. # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  12. # License for the specific language governing permissions and limitations
  13. # under the License.
  14. import time
  15. from devops.helpers import helpers
  16. import pytest
  17. from fuel_ccp_tests.helpers import ext
  18. from fuel_ccp_tests import logger
  19. LOG = logger.logger
  20. class TestDaemonsetsUpdates():
  21. """Test class for update DaemonSets"""
  22. from_nginx_image = 'nginx:1.10'
  23. to_nginx_image = 'nginx:1.11'
  24. def get_nginx_spec(self):
  25. """Create specification for DaemonSet with Nginx containers
  26. :return: nested dict
  27. """
  28. return {
  29. 'apiVersion': 'extensions/v1beta1',
  30. 'kind': 'DaemonSet',
  31. 'metadata': {
  32. 'labels': {'app': 'nginx'},
  33. 'name': 'nginx',
  34. },
  35. 'spec': {
  36. 'template': {
  37. 'metadata': {
  38. 'labels': {'app': 'nginx'},
  39. 'name': 'nginx-app'},
  40. 'spec': {
  41. 'containers': [
  42. {'name': 'nginx-app',
  43. 'image': self.from_nginx_image},
  44. ],
  45. },
  46. },
  47. 'updateStrategy': {
  48. 'type': 'RollingUpdate',
  49. },
  50. }
  51. }
  52. def get_nginx_pods(self, k8sclient):
  53. """Return the nginx pods
  54. :param: k8sclient: kubernetes api client
  55. :return: list of pods with nginx containers
  56. """
  57. spec = self.get_nginx_spec()
  58. return [x for x in k8sclient.pods.list()
  59. if spec['metadata']['name'] in x.name]
  60. def get_nginx_ds(self, k8sclient):
  61. """Return the nginx DaemonSets
  62. :param k8sclient: kubernetes api client
  63. :return: list of DaemonSets with pods with nginx containers
  64. """
  65. spec = self.get_nginx_spec()
  66. return [x for x in k8sclient.daemonsets.list()
  67. if spec['metadata']['name'] in x.name]
  68. def wait_nginx_pods_ready(self, k8sclient):
  69. """Wait until the nginx pods are ready
  70. :param: k8sclient: kubernetes api client
  71. :return: None
  72. """
  73. nginx_pods = self.get_nginx_pods(k8sclient)
  74. for pod in nginx_pods:
  75. pod.wait_running(timeout=60)
  76. def delete_nginx_pods(self, k8sclient):
  77. """Delete the nginx pods
  78. :param: k8sclient: kubernetes api client
  79. :return: None
  80. """
  81. nginx_pods = self.get_nginx_pods(k8sclient)
  82. for pod in nginx_pods:
  83. k8sclient.pods.delete(body=pod.spec, name=pod.name)
  84. helpers.wait(lambda: pod.name not in [
  85. x.name for x in self.get_nginx_pods(k8sclient)])
  86. def check_nginx_pods_image(self, k8sclient, nginx_image):
  87. """Check nginx pods image version
  88. :param: k8sclient: kubernetes api client,
  89. :param: nginx_image: version of nginx_image to compare
  90. :return: None
  91. """
  92. nginx_pods = self.get_nginx_pods(k8sclient)
  93. for pod in nginx_pods:
  94. pod_image = pod.status.container_statuses[0].image
  95. assert pod_image == nginx_image, (
  96. "Pod {0} has image {1} while expected {2}"
  97. .format(pod.name, pod_image, nginx_image))
  98. def check_nginx_ds_image(self, k8sclient, nginx_image):
  99. """Check nginx DaemonSets version
  100. :param: k8sclient: kubernetes api client,
  101. :param: nginx_image: version of nginx_image to compare
  102. :return: None
  103. """
  104. nginx_daemonsets = self.get_nginx_ds(k8sclient)
  105. for nginx_ds in nginx_daemonsets:
  106. nginx_ds_image = nginx_ds.spec.template.spec.containers[0].image
  107. assert nginx_ds_image == nginx_image, (
  108. "DaemonSet {0} has image {1} while expected {2}"
  109. .format(nginx_ds.name, nginx_ds_image, nginx_image))
  110. @pytest.mark.revert_snapshot(ext.SNAPSHOT.k8s_deployed)
  111. @pytest.mark.fail_snapshot
  112. @pytest.mark.snapshot_needed
  113. def test_daemonset_rollingupdate_noop(self, k8scluster, show_step):
  114. """Update a daemonset using updateStrategy type: Noop
  115. Scenario:
  116. 1. Deploy k8s using fuel-ccp-installer
  117. 2. Create a DaemonSet for nginx with image version 1_10 and
  118. update strategy Noop
  119. 3. Wait until nginx pods are created and become 'ready'
  120. 4. Check that the image version in the nginx pods is 1_10
  121. Check that the image version in the nginx daemonset is 1_10
  122. 5. Change nginx image version to 1_11 using YAML
  123. 6. Wait for 10 seconds (needs to check that there were
  124. no auto updates of the nginx pods)
  125. 7. Check that the image version in the nginx pods is still 1_10
  126. Check that the image version in the nginx daemonset
  127. is updated to 1_11
  128. 8. Kill all nginx pods that are belong to the nginx daemonset
  129. 9. Wait until nginx pods are created and become 'ready'
  130. 10. Check that the image version in the nginx pods
  131. is updated to 1_11
  132. Duration: 3000 seconds
  133. """
  134. # STEP #1
  135. show_step(1)
  136. k8sclient = k8scluster.api
  137. assert k8sclient.nodes.list() is not None, "Can not get nodes list"
  138. # STEP #2
  139. show_step(2)
  140. nginx_spec = self.get_nginx_spec()
  141. nginx_spec['spec']['updateStrategy']['type'] = 'Noop'
  142. nginx_spec['spec']['template']['spec']['containers'][0][
  143. 'image'] = self.from_nginx_image
  144. k8sclient.daemonsets.create(body=nginx_spec)
  145. # STEP #3
  146. show_step(3)
  147. time.sleep(3)
  148. self.wait_nginx_pods_ready(k8sclient)
  149. # STEP #4
  150. show_step(4)
  151. self.check_nginx_pods_image(k8sclient, self.from_nginx_image)
  152. self.check_nginx_ds_image(k8sclient, self.from_nginx_image)
  153. # STEP #5
  154. show_step(5)
  155. nginx_spec['spec']['template']['spec']['containers'][0][
  156. 'image'] = self.to_nginx_image
  157. k8sclient.daemonsets.update(body=nginx_spec,
  158. name=nginx_spec['metadata']['name'])
  159. # STEP #6
  160. show_step(6)
  161. time.sleep(10)
  162. # STEP #7
  163. show_step(7)
  164. # Pods should still have the old image version
  165. self.check_nginx_pods_image(k8sclient, self.from_nginx_image)
  166. # DaemonSet should have new image version
  167. self.check_nginx_ds_image(k8sclient, self.to_nginx_image)
  168. # STEP #8
  169. show_step(8)
  170. self.delete_nginx_pods(k8sclient)
  171. # STEP #9
  172. show_step(9)
  173. self.wait_nginx_pods_ready(k8sclient)
  174. # STEP #10
  175. show_step(10)
  176. # Pods should have the new image version
  177. self.check_nginx_pods_image(k8sclient, self.to_nginx_image)
  178. @pytest.mark.revert_snapshot(ext.SNAPSHOT.k8s_deployed)
  179. @pytest.mark.fail_snapshot
  180. @pytest.mark.snapshot_needed
  181. def test_daemonset_rollingupdate(self, k8scluster, show_step):
  182. """Update a daemonset using updateStrategy type: RollingUpdate
  183. Scenario:
  184. 1. Deploy k8s using fuel-ccp-installer
  185. 2. Create a DaemonSet for nginx with image version 1_10 and
  186. update strategy RollingUpdate
  187. 3. Wait until nginx pods are created and become 'ready'
  188. 4. Check that the image version in the nginx pods is 1_10
  189. Check that the image version in the nginx daemonset is 1_10
  190. 5. Change nginx image version to 1_11 using YAML
  191. 6. Wait for 10 seconds (needs to check that there were
  192. no auto updates of the nginx pods)
  193. 7. Check that the image version in the nginx daemonset
  194. is updated to 1_11
  195. Wait for ~120 sec that the image version in the nginx pods
  196. is changed to 1_11
  197. Duration: 3000 seconds
  198. """
  199. # STEP #1
  200. show_step(1)
  201. k8sclient = k8scluster.api
  202. assert k8sclient.nodes.list() is not None, "Can not get nodes list"
  203. # STEP #2
  204. show_step(2)
  205. nginx_spec = self.get_nginx_spec()
  206. nginx_spec['spec']['template']['spec']['containers'][0][
  207. 'image'] = self.from_nginx_image
  208. k8sclient.daemonsets.create(body=nginx_spec)
  209. # STEP #3
  210. show_step(3)
  211. time.sleep(3)
  212. self.wait_nginx_pods_ready(k8sclient)
  213. # STEP #4
  214. show_step(4)
  215. self.check_nginx_pods_image(k8sclient, self.from_nginx_image)
  216. self.check_nginx_ds_image(k8sclient, self.from_nginx_image)
  217. # STEP #5
  218. show_step(5)
  219. nginx_spec['spec']['template']['spec']['containers'][0][
  220. 'image'] = self.to_nginx_image
  221. k8sclient.daemonsets.update(body=nginx_spec,
  222. name=nginx_spec['metadata']['name'])
  223. # STEP #6
  224. show_step(6)
  225. time.sleep(10)
  226. # STEP #7
  227. show_step(7)
  228. # DaemonSet should have new image version
  229. self.check_nginx_ds_image(k8sclient, self.to_nginx_image)
  230. # Pods should have new image version
  231. helpers.wait_pass(
  232. lambda: self.check_nginx_pods_image(
  233. k8sclient,
  234. self.to_nginx_image),
  235. timeout=2 * 60)
  236. @pytest.mark.revert_snapshot(ext.SNAPSHOT.k8s_deployed)
  237. @pytest.mark.fail_snapshot
  238. @pytest.mark.snapshot_needed
  239. def test_daemonset_rollout_rollingupdate(self, underlay,
  240. k8scluster, config, show_step):
  241. """Rollback a daemonset using updateStrategy type: RollingUpdate
  242. Scenario:
  243. 1. Deploy k8s using fuel-ccp-installer
  244. 2. Create a DaemonSet for nginx with image version 1_10 and
  245. update strategy RollingUpdate
  246. 3. Wait until nginx pods are created and become 'ready'
  247. 4. Check that the image version in the nginx pods is 1_10
  248. Check that the image version in the nginx daemonset is 1_10
  249. 5. Change nginx image version to 1_11 using YAML
  250. 6. Wait for 10 seconds (needs to check that there were
  251. no auto updates of the nginx pods)
  252. 7. Check that the image version in the nginx daemonset
  253. is updated to 1_11
  254. Wait for ~120 sec that the image version
  255. in the nginx pods is changed to 1_11
  256. 8. Rollback the nginx daemonset:
  257. kubectl rollout undo daemonset/nginx
  258. 9. Check that the image version in the nginx daemonset is
  259. downgraded to 1_10
  260. Wait for ~120 sec that the image version
  261. in the nginx pods is downgraded to 1_10
  262. Duration: 3000 seconds
  263. """
  264. self.test_daemonset_rollingupdate(k8scluster, show_step)
  265. k8sclient = k8scluster.api
  266. show_step(8)
  267. cmd = "kubectl rollout undo daemonset/nginx"
  268. underlay.check_call(cmd,
  269. host=config.k8s.kube_host)
  270. # STEP #9
  271. show_step(9)
  272. self.check_nginx_ds_image(k8sclient, self.from_nginx_image)
  273. # Pods should have new image version
  274. helpers.wait_pass(
  275. lambda: self.check_nginx_pods_image(
  276. k8sclient,
  277. self.from_nginx_image),
  278. timeout=2 * 60
  279. )