blob: b8242e99929641d5535c9fd679156ae308f7ed7d [file] [log] [blame]
Dmitriy Kruglovd8c76bc2019-09-26 09:30:38 +02001# Copyright 2019 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.
14import json
15import pytest
16
17from devops.helpers import helpers
18
19from tcp_tests import logger
20from tcp_tests import settings
21
22LOG = logger.logger
23
24
25class TestUbuntuSecurityUpdates(object):
26 """Test class for verification of obtaining Ubuntu security updates"""
27
28 ENV_NAME = settings.ENV_NAME
29 UPGRADE_CMD = (
30 'export DEBIAN_FRONTEND=noninteractive && '
31 'apt-get update && '
32 'apt-get -y upgrade && '
33 'apt-get -y -o Dpkg::Options::="--force-confdef" '
34 ' -o Dpkg::Options::="--force-confnew" dist-upgrade'
35 )
36 INST_LINUX_HEADERS_CMD = (
37 "export DEBIAN_FRONTEND=noninteractive && "
38 "apt-get -y install linux-headers-generic"
39 )
40
41 UPDATE_JOB_NAME = "deploy-update-package"
42 UPDATE_JOB_PARAMETERS = {
43 "ASK_CONFIRMATION": False,
44 "TARGET_SERVERS": ''
45 }
46
47 SANITY_JOB_NAME = 'cvp-sanity'
48 SANITY_JOB_PARAMETERS = {
49 'EXTRA_PARAMS': {
50 'envs': ["tests_set=-k 'not test_ceph_health'"]
51 }
52 }
53
54 JENKINS_START_TIMEOUT = 60
55
56 def get_available_pkg_updates(self, nodes, salt):
57 """Collect available package updates for given nodes
58
59 :param nodes: list, nodes to collect available updates for
60 :param salt: SaltManager, tcp-qa Salt manager instance
61 :return: dict, update candidates for nodes
62 """
63 updates = {}
64 for node in nodes:
65 updates[node] = salt.local(
66 node, "pkg.list_upgrades")['return'][0][node]
67 return updates
68
69 def run_cvp_sanity(self, dt):
70 """A wrapper for executing cvp-sanity pipeline
71
72 :param dt: DrivetrainManager, tcp-qa Drivetrain manager instance
73 :return: str, build execution status of cvp-sanity pipeline
74 """
Hanna Arhipova508f6532021-01-27 15:52:45 +020075 job_result, job_description = dt.start_job_on_jenkins(
Dmitriy Kruglovd8c76bc2019-09-26 09:30:38 +020076 job_name=self.SANITY_JOB_NAME,
77 job_parameters=self.SANITY_JOB_PARAMETERS,
78 start_timeout=self.JENKINS_START_TIMEOUT,
79 build_timeout=60 * 15
80 )
Hanna Arhipova508f6532021-01-27 15:52:45 +020081 assert job_result == "SUCCESS", job_description
Dmitriy Kruglovd8c76bc2019-09-26 09:30:38 +020082
83 def reboot_hw_node(self, ssh, salt, node):
84 """Reboot the given node and wait for it to start back
85
86 :param ssh: UnderlaySSHManager, tcp-qa SSH manager instance
87 :param salt: SaltManager, tcp-qa Salt manager instance
88 :param node: str, name of the node to reboot
89 """
90 LOG.info("Sending reboot command to '{}' node.".format(node))
91 remote = ssh.remote(node_name=node)
92 remote.execute_async("/sbin/shutdown -r now")
93
94 # Wait for restarted node to boot and become accessible
95 helpers.wait_pass(
96 lambda: salt.local(node, "test.ping", timeout=5),
97 timeout=60 * 10, interval=5)
98
99 # TODO: finish the test once ASK_CONFIRMATION option is added to
100 # 'deploy-update-package' pipeline
101 @pytest.mark.grab_versions
102 @pytest.mark.ubuntu_security_updates_pipeline
103 def _test_obtaining_ubuntu_security_updates_via_pipeline(
104 self, salt_actions, drivetrain_actions, show_step):
105 """Test obtaining Ubuntu security updates using Jenkins
106
107 Scenario:
108 1. Collect available package upgrades for nodes of the given server
109 role
110 2. Execute deploy-update-package pipeline for the given server role
111 3. Collect available package upgrades for server role nodes again
112 4. Check that there is no candidates for upgrade
113 5. Run cvp-sanity tests
114
115 Duration: ~ min
116 """
117 salt = salt_actions
118 dt = drivetrain_actions
119
120 role = "mon*"
121 nodes = salt.local(role, "test.ping")['return'][0].keys()
122
123 # Collect available package upgrades for nodes
124 show_step(1)
125 updates = self.get_available_pkg_updates(nodes, salt)
126 LOG.info("Packages to be updated on nodes:\n{}".format(
127 json.dumps(updates, indent=4)))
128
129 # Execute 'deploy-update-package' pipeline to upgrade packages on nodes
130 show_step(2)
131 self.UPDATE_JOB_PARAMETERS["TARGET_SERVERS"] = role
Hanna Arhipova508f6532021-01-27 15:52:45 +0200132 job_result, job_description = dt.start_job_on_jenkins(
Dmitriy Kruglovd8c76bc2019-09-26 09:30:38 +0200133 job_name=self.UPDATE_JOB_NAME,
134 job_parameters=self.UPDATE_JOB_PARAMETERS,
135 start_timeout=self.JENKINS_START_TIMEOUT,
136 build_timeout=60 * 15
137 )
Hanna Arhipova508f6532021-01-27 15:52:45 +0200138 assert job_result == 'SUCCESS', (
Dmitriy Kruglovd8c76bc2019-09-26 09:30:38 +0200139 "'{}' job run status is {} after upgrading packages on {} nodes. "
Hanna Arhipova508f6532021-01-27 15:52:45 +0200140 "Please check the build and executed stages {}".format(
141 self.UPDATE_JOB_NAME, job_result, role, job_description)
Dmitriy Kruglovd8c76bc2019-09-26 09:30:38 +0200142 )
143
144 # Collect available package upgrades for nodes again
145 show_step(3)
146 post_upgrade = self.get_available_pkg_updates(nodes, salt)
147
148 # Check that there is no available package upgrades
149 show_step(4)
150 for node in nodes:
151 assert not post_upgrade[node], (
152 "{} node still has upgrade candidates. Please check the "
153 "following packages and the reason why they are not "
154 "updated:\n{}".format(node, post_upgrade[node])
155 )
156
157 # Execute cvp-sanity tests
158 show_step(5)
159 status = self.run_cvp_sanity(dt)
160 assert status == 'SUCCESS', (
161 "'{0}' job run status is {1} after executing CVP-Sanity "
162 "tests".format(
163 self.SANITY_JOB_NAME, status)
164 )
165
166 @pytest.mark.grab_versions
167 @pytest.mark.ubuntu_security_updates_manual_infra_vms
168 def test_obtaining_ubuntu_security_updates_manual_infra_vms(
169 self, salt_actions, drivetrain_actions, show_step):
170 """Test obtaining Ubuntu security updates on virtual infra nodes.
171 Repeat the scenario for 01, 02 and 03 indexes of nodes.
172
173 Scenario:
174 1. Select set of virtual nodes for upgrade
175 2. Collect available package upgrades for the nodes
176 3. Upgrade the nodes
177 4. Collect available package upgrades for the nodes again
178 5. Check that there is no candidates for upgrade on the nodes
179 6. Run cvp-sanity tests
180
181 Duration: ~ 100 min
182 """
183 salt = salt_actions
184 dt = drivetrain_actions
185
186 for index in ('01', '02', '03'):
187 msg = ("# Executing scenario for '{i}' index of nodes #".format(
188 i=index))
189 LOG.info(
190 "\n\n{pad}\n{msg}\n{pad}".format(pad="#" * len(msg), msg=msg))
191
192 # Select set of nodes for current iteration of updates
193 show_step(1)
194 tgt = "*{}* and E@^(?!kvm|cfg|cmp|osd).*$".format(index)
195 nodes = salt.local(tgt, "test.ping")['return'][0].keys()
196 LOG.info("Nodes to be upgraded:\n{}".format(
197 json.dumps(nodes, indent=4)))
198
199 # Collect available package upgrades for the nodes
200 show_step(2)
201 updates = self.get_available_pkg_updates(nodes, salt)
202
203 # Upgrade the selected nodes
204 show_step(3)
205 for node in nodes:
206 LOG.info(
207 "Starting upgrade of '{}' node.\nThe following packages "
208 "will be updated:\n{}".format(
209 node, json.dumps(updates[node], indent=4))
210 )
211 salt.cmd_run(node, self.UPGRADE_CMD)
212
213 # Collect available package upgrades for the nodes again
214 show_step(4)
215 post_upgrade = self.get_available_pkg_updates(nodes, salt)
216
217 # Check that there is no package upgrades candidates on the nodes
218 show_step(5)
219 missed_upd = {
220 node: pkgs for (node, pkgs) in post_upgrade.items() if pkgs}
221 assert not missed_upd, (
222 "{} nodes still have upgrade candidates. Please check the "
223 "nodes and reason why the listed packages are not "
224 "updated:\n{}".format(
225 missed_upd.keys(), json.dumps(missed_upd, indent=4))
226 )
227
228 # Execute cvp-sanity tests
229 show_step(6)
230 status = self.run_cvp_sanity(dt)
231 assert status == 'SUCCESS', (
232 "'{0}' job run status is {1} after executing CVP-Sanity smoke "
233 "tests".format(self.SANITY_JOB_NAME, status))
234
235 @pytest.mark.grab_versions
236 @pytest.mark.ubuntu_security_updates_manual_hw_nodes
237 def test_obtaining_ubuntu_security_updates_manual_hw_nodes(
238 self,
239 salt_actions,
240 underlay_actions,
241 drivetrain_actions,
242 show_step):
243 """Test obtaining Ubuntu security updates on HW nodes.
244 Repeat the scenario for 01, 02 and 03 indexes of nodes.
245
246 Scenario:
247 1. Select set HW nodes for upgrade
248 2. Collect available package upgrades for the nodes
249 3. Upgrade the nodes
250 4. Collect available package upgrades for the nodes again
251 5. Check that there is no candidates for upgrade on the nodes
252 6. Run cvp-sanity tests
253
254 Duration: ~ 70 min
255 """
256 salt = salt_actions
257 ssh = underlay_actions
258 dt = drivetrain_actions
259
260 for index in ('01', '02', '03'):
261 msg = ("# Executing scenario for '{i}' index of nodes #".format(
262 i=index))
263 LOG.info(
264 "\n\n{pad}\n{msg}\n{pad}".format(pad="#" * len(msg), msg=msg))
265
266 # Select set of nodes for current iteration of updates
267 show_step(1)
268 tgt = "E@^(kvm|cmp).?{}.*$".format(index)
269 nodes = salt.local(tgt, "test.ping")['return'][0].keys()
270 LOG.info("Nodes to be upgraded:\n{}".format(
271 json.dumps(nodes, indent=4)))
272
273 # Collect available package upgrades for the nodes
274 show_step(2)
275 updates = self.get_available_pkg_updates(nodes, salt)
276
277 # Upgrade the selected nodes
278 show_step(3)
279 for node in nodes:
280 LOG.info(
281 "Starting upgrade of '{}' node.\nThe following packages "
282 "will be updated:\n{}".format(
283 node, json.dumps(updates[node], indent=4))
284 )
285 salt.cmd_run(node, self.UPGRADE_CMD)
286 # Update Linux headers on compute nodes
287 if "cmp" in node:
288 LOG.info(
289 "Updating linux headers on '{}' node.".format(node))
290 salt.cmd_run(node, self.INST_LINUX_HEADERS_CMD)
291
292 # Reboot the node after upgrade
293 LOG.info("Starting reboot of '{}' node.".format(node))
294 self.reboot_hw_node(ssh, salt, node)
295 LOG.info("'{}' node is back after reboot.".format(node))
296
297 # Collect available package upgrades for the nodes again
298 show_step(4)
299 post_upgrade = self.get_available_pkg_updates(nodes, salt)
300
301 # Check that there is no package upgrades candidates on the nodes
302 show_step(5)
303 missed_upd = {
304 node: pkgs for (node, pkgs) in post_upgrade.items() if pkgs}
305 assert not missed_upd, (
306 "{} nodes still have upgrade candidates. Please check the "
307 "nodes and reason why the listed packages are not "
308 "updated:\n{}".format(
309 missed_upd.keys(), json.dumps(missed_upd, indent=4))
310 )
311
312 # Execute cvp-sanity tests
313 show_step(6)
314 status = self.run_cvp_sanity(dt)
315 assert status == 'SUCCESS', (
316 "'{0}' job run status is {1} after executing CVP-Sanity "
317 "tests".format(self.SANITY_JOB_NAME, status))