blob: e1420b5701261fe39f33d341412a2507bb272d27 [file] [log] [blame]
Dennis Dmitriev6f59add2016-10-18 13:45:27 +03001# 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
15import pytest
Dennis Dmitriev6f59add2016-10-18 13:45:27 +030016
17from tcp_tests.helpers import ext
Dennis Dmitriev535869c2016-11-16 22:38:06 +020018from tcp_tests.helpers import utils
Dennis Dmitriev6f59add2016-10-18 13:45:27 +030019from tcp_tests import logger
20from tcp_tests import settings
21from tcp_tests.managers import envmanager_devops
22from tcp_tests.managers import envmanager_empty
23from tcp_tests.managers import underlay_ssh_manager
24
25LOG = logger.logger
26
27
Dennis Dmitriev6f59add2016-10-18 13:45:27 +030028@pytest.fixture(scope="session")
29def hardware(request, config):
30 """Fixture for manage the hardware layer.
31
32 - start/stop/reboot libvirt/IPMI(/MaaS?) nodes
33 - snapshot/revert libvirt nodes (fuel-devops only)
34 - block/unblock libvirt networks/interfaces (fuel-devops only)
35
36 This fixture should get a hardware configuration from
37 'config' object or create a virtual/baremetal underlay
38 using EnvironmentManager.
39
40 Creates a snapshot 'hardware' with ready-to-use virtual environment
41 (Only for config.hardware.manager='devops'):
42 - just created virtual nodes in power-on state
43 - node volumes filled with necessary content
44 - node network interfaces connected to necessary devices
45
46 config.hardware.manager: one of ('devops', 'maas', None)
47 config.hardware.config: path to the config file for the manager
48 config.hardware.current_snapshot = Latest created or reverted snapshot
49
50 :rtype EnvironmentModel: if config.hardware.manager == 'devops'
51 :rtype EnvironmentManagerEmpty: if config.hardware.manager == 'empty'
52 """
53 env = None
54
55 manager = config.hardware.manager
56
57 if manager == 'empty':
58 # No environment manager is used.
59 # 'config' should contain config.underlay.ssh settings
60 # 'config' should contain config.underlay.current_snapshot setting
61 env = envmanager_empty.EnvironmentManagerEmpty(config=config)
62
63 elif manager == 'devops':
64 # fuel-devops environment manager is used.
65 # config.underlay.ssh settings can be empty or witn SSH to existing env
66 # config.underlay.current_snapshot
67 env = envmanager_devops.EnvironmentManager(config=config)
68 else:
69 raise Exception("Unknown hardware manager: '{}'".format(manager))
70
71 # for devops manager: power on nodes and wait for SSH
72 # for empty manager: do nothing
73 # for maas manager: provision nodes and wait for SSH
Dennis Dmitriev6f59add2016-10-18 13:45:27 +030074 if not env.has_snapshot(ext.SNAPSHOT.hardware):
Dennis Dmitriev6f59add2016-10-18 13:45:27 +030075 env.create_snapshot(ext.SNAPSHOT.hardware)
76
77 def fin():
78 if settings.SHUTDOWN_ENV_ON_TEARDOWN:
79 LOG.info("Shutdown environment...")
80 env.stop()
81
82 request.addfinalizer(fin)
83 return env
84
85
86@pytest.fixture(scope='function')
87def revert_snapshot(request, hardware):
88 """Revert snapshot for the test case
89
90 Usage:
91 @pytest.mark.revert_snapshot(name='<required_snapshot_name>')
92
93 If the mark 'revert_snapshot' is absend, or <required_snapshot_name>
94 not found, then an initial 'hardware' snapshot will be reverted.
95
96 :rtype string: name of the reverted snapshot or None
97 """
Dennis Dmitriev535869c2016-11-16 22:38:06 +020098 top_fixtures_snapshots = utils.get_top_fixtures_marks(
99 request, 'revert_snapshot')
Dennis Dmitriev6f59add2016-10-18 13:45:27 +0300100
Dennis Dmitriev535869c2016-11-16 22:38:06 +0200101 # Try to revert the best matches snapshot for the test
102 for snapshot_name in top_fixtures_snapshots:
103 if hardware.has_snapshot(snapshot_name) and \
104 hardware.has_snapshot_config(snapshot_name):
105 hardware.revert_snapshot(snapshot_name)
106 return snapshot_name
107
108 # Fallback to the basic snapshot
109 hardware.revert_snapshot(ext.SNAPSHOT.hardware)
110 return None
Dennis Dmitriev6f59add2016-10-18 13:45:27 +0300111
112
113@pytest.fixture(scope='function', autouse=True)
114def snapshot(request, hardware):
115 """Fixture for creating snapshot at the end of test if it's needed
116
117 Marks:
118 snapshot_needed(name=None) - make snapshot if test is passed. If
119 name argument provided, it will be used for creating snapshot,
120 otherwise, test function name will be used
121
122 fail_snapshot - make snapshot if test failed
123
124 :param request: pytest.python.FixtureRequest
125 :param env: envmanager.EnvironmentManager
126 """
127 snapshot_needed = request.keywords.get('snapshot_needed', None)
128 fail_snapshot = request.keywords.get('fail_snapshot', None)
129
130 def test_fin():
131 default_snapshot_name = getattr(request.node.function,
132 '_snapshot_name',
133 request.node.function.__name__)
134 if hasattr(request.node, 'rep_call') and request.node.rep_call.passed \
135 and snapshot_needed:
Dennis Dmitriev535869c2016-11-16 22:38:06 +0200136 snapshot_name = utils.extract_name_from_mark(snapshot_needed) or \
Dennis Dmitriev6f59add2016-10-18 13:45:27 +0300137 "{}_passed".format(default_snapshot_name)
Dennis Dmitriev411dd102017-09-15 16:04:47 +0300138 hardware.create_snapshot(snapshot_name, force=True)
Dennis Dmitriev6f59add2016-10-18 13:45:27 +0300139
140 elif hasattr(request.node, 'rep_setup') and \
141 request.node.rep_setup.failed and fail_snapshot:
142 snapshot_name = "{0}_prep_failed".format(default_snapshot_name)
Dennis Dmitriev411dd102017-09-15 16:04:47 +0300143 hardware.create_snapshot(snapshot_name, force=True)
Dennis Dmitriev6f59add2016-10-18 13:45:27 +0300144
145 elif hasattr(request.node, 'rep_call') and \
146 request.node.rep_call.failed and fail_snapshot:
147 snapshot_name = "{0}_failed".format(default_snapshot_name)
Dennis Dmitriev411dd102017-09-15 16:04:47 +0300148 hardware.create_snapshot(snapshot_name, force=True)
Dennis Dmitriev6f59add2016-10-18 13:45:27 +0300149
150 request.addfinalizer(test_fin)
151
152
Dennis Dmitriev535869c2016-11-16 22:38:06 +0200153@pytest.mark.revert_snapshot(ext.SNAPSHOT.underlay)
Dennis Dmitriev6f59add2016-10-18 13:45:27 +0300154@pytest.fixture(scope="function")
155def underlay(revert_snapshot, config, hardware):
156 """Fixture that should provide SSH access to underlay objects.
157
158 - Starts the 'hardware' environment and creates 'underlay' with required
159 configuration.
160 - Fills the following object using the 'hardware' fixture:
161 config.underlay.ssh = JSONList of SSH access credentials for nodes.
162 This list will be used for initialization the
163 model UnderlaySSHManager, see it for details.
164
165 :rtype UnderlaySSHManager: Object that encapsulate SSH credentials;
166 - provide list of underlay nodes;
167 - provide SSH access to underlay nodes using
168 node names or node IPs.
169 """
Dennis Dmitriev6f59add2016-10-18 13:45:27 +0300170 # Create Underlay
171 if not config.underlay.ssh:
172 # If config.underlay.ssh wasn't provided from external config, then
173 # try to get necessary data from hardware manager (fuel-devops)
Dennis Dmitriev7b9538f2017-05-15 17:01:34 +0300174
175 # for devops manager: power on nodes and wait for SSH
176 # for empty manager: do nothing
177 # for maas manager: provision nodes and wait for SSH
178 hardware.start(underlay_node_roles=config.underlay.roles,
179 timeout=config.underlay.bootstrap_timeout)
180
Dennis Dmitriev6f59add2016-10-18 13:45:27 +0300181 config.underlay.ssh = hardware.get_ssh_data(
182 roles=config.underlay.roles)
183
Dennis Dmitriev2a13a132016-11-04 00:56:23 +0200184 underlay = underlay_ssh_manager.UnderlaySSHManager(config)
Dennis Dmitriev6f59add2016-10-18 13:45:27 +0300185
186 if not config.underlay.lvm:
187 underlay.enable_lvm(hardware.lvm_storages())
188 config.underlay.lvm = underlay.config_lvm
189
190 hardware.create_snapshot(ext.SNAPSHOT.underlay)
191
192 else:
193 # 1. hardware environment created and powered on
194 # 2. config.underlay.ssh contains SSH access to provisioned nodes
195 # (can be passed from external config with TESTS_CONFIGS variable)
Dennis Dmitriev2a13a132016-11-04 00:56:23 +0200196 underlay = underlay_ssh_manager.UnderlaySSHManager(config)
Dennis Dmitriev6f59add2016-10-18 13:45:27 +0300197
198 return underlay