blob: 0637abf221f927c83ac1246de83bc20f92b24a38 [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
16from datetime import datetime
17
18from tcp_tests.helpers import ext
19from 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
28def extract_name_from_mark(mark):
29 """Simple function to extract name from mark
30
31 :param mark: pytest.mark.MarkInfo
32 :rtype: string or None
33 """
34 if mark:
35 if len(mark.args) > 0:
36 return mark.args[0]
37 elif 'name' in mark.kwargs:
38 return mark.kwargs['name']
39 return None
40
41
42@pytest.fixture(scope="session")
43def hardware(request, config):
44 """Fixture for manage the hardware layer.
45
46 - start/stop/reboot libvirt/IPMI(/MaaS?) nodes
47 - snapshot/revert libvirt nodes (fuel-devops only)
48 - block/unblock libvirt networks/interfaces (fuel-devops only)
49
50 This fixture should get a hardware configuration from
51 'config' object or create a virtual/baremetal underlay
52 using EnvironmentManager.
53
54 Creates a snapshot 'hardware' with ready-to-use virtual environment
55 (Only for config.hardware.manager='devops'):
56 - just created virtual nodes in power-on state
57 - node volumes filled with necessary content
58 - node network interfaces connected to necessary devices
59
60 config.hardware.manager: one of ('devops', 'maas', None)
61 config.hardware.config: path to the config file for the manager
62 config.hardware.current_snapshot = Latest created or reverted snapshot
63
64 :rtype EnvironmentModel: if config.hardware.manager == 'devops'
65 :rtype EnvironmentManagerEmpty: if config.hardware.manager == 'empty'
66 """
67 env = None
68
69 manager = config.hardware.manager
70
71 if manager == 'empty':
72 # No environment manager is used.
73 # 'config' should contain config.underlay.ssh settings
74 # 'config' should contain config.underlay.current_snapshot setting
75 env = envmanager_empty.EnvironmentManagerEmpty(config=config)
76
77 elif manager == 'devops':
78 # fuel-devops environment manager is used.
79 # config.underlay.ssh settings can be empty or witn SSH to existing env
80 # config.underlay.current_snapshot
81 env = envmanager_devops.EnvironmentManager(config=config)
82 else:
83 raise Exception("Unknown hardware manager: '{}'".format(manager))
84
85 # for devops manager: power on nodes and wait for SSH
86 # for empty manager: do nothing
87 # for maas manager: provision nodes and wait for SSH
Dennis Dmitriev6f59add2016-10-18 13:45:27 +030088 if not env.has_snapshot(ext.SNAPSHOT.hardware):
Dennis Dmitriev75fce1b2016-10-18 15:04:28 +030089 env.start()
Dennis Dmitriev6f59add2016-10-18 13:45:27 +030090 env.create_snapshot(ext.SNAPSHOT.hardware)
91
92 def fin():
93 if settings.SHUTDOWN_ENV_ON_TEARDOWN:
94 LOG.info("Shutdown environment...")
95 env.stop()
96
97 request.addfinalizer(fin)
98 return env
99
100
101@pytest.fixture(scope='function')
102def revert_snapshot(request, hardware):
103 """Revert snapshot for the test case
104
105 Usage:
106 @pytest.mark.revert_snapshot(name='<required_snapshot_name>')
107
108 If the mark 'revert_snapshot' is absend, or <required_snapshot_name>
109 not found, then an initial 'hardware' snapshot will be reverted.
110
111 :rtype string: name of the reverted snapshot or None
112 """
113 revert_snapshot = request.keywords.get('revert_snapshot', None)
114 snapshot_name = extract_name_from_mark(revert_snapshot)
115
116 if snapshot_name and \
117 hardware.has_snapshot(snapshot_name) and \
118 hardware.has_snapshot_config(snapshot_name):
119 hardware.revert_snapshot(snapshot_name)
120 return snapshot_name
121 else:
122 hardware.revert_snapshot(ext.SNAPSHOT.hardware)
123 return None
124
125
126@pytest.fixture(scope='function', autouse=True)
127def snapshot(request, hardware):
128 """Fixture for creating snapshot at the end of test if it's needed
129
130 Marks:
131 snapshot_needed(name=None) - make snapshot if test is passed. If
132 name argument provided, it will be used for creating snapshot,
133 otherwise, test function name will be used
134
135 fail_snapshot - make snapshot if test failed
136
137 :param request: pytest.python.FixtureRequest
138 :param env: envmanager.EnvironmentManager
139 """
140 snapshot_needed = request.keywords.get('snapshot_needed', None)
141 fail_snapshot = request.keywords.get('fail_snapshot', None)
142
143 def test_fin():
144 default_snapshot_name = getattr(request.node.function,
145 '_snapshot_name',
146 request.node.function.__name__)
147 if hasattr(request.node, 'rep_call') and request.node.rep_call.passed \
148 and snapshot_needed:
149 snapshot_name = extract_name_from_mark(snapshot_needed) or \
150 "{}_passed".format(default_snapshot_name)
151 hardware.create_snapshot(snapshot_name)
152
153 elif hasattr(request.node, 'rep_setup') and \
154 request.node.rep_setup.failed and fail_snapshot:
155 snapshot_name = "{0}_prep_failed".format(default_snapshot_name)
156 hardware.create_snapshot(snapshot_name)
157
158 elif hasattr(request.node, 'rep_call') and \
159 request.node.rep_call.failed and fail_snapshot:
160 snapshot_name = "{0}_failed".format(default_snapshot_name)
161 hardware.create_snapshot(snapshot_name)
162
163 request.addfinalizer(test_fin)
164
165
166@pytest.fixture(scope="function")
167def underlay(revert_snapshot, config, hardware):
168 """Fixture that should provide SSH access to underlay objects.
169
170 - Starts the 'hardware' environment and creates 'underlay' with required
171 configuration.
172 - Fills the following object using the 'hardware' fixture:
173 config.underlay.ssh = JSONList of SSH access credentials for nodes.
174 This list will be used for initialization the
175 model UnderlaySSHManager, see it for details.
176
177 :rtype UnderlaySSHManager: Object that encapsulate SSH credentials;
178 - provide list of underlay nodes;
179 - provide SSH access to underlay nodes using
180 node names or node IPs.
181 """
182 # If no snapshot was reverted, then try to revert the snapshot
183 # that belongs to the fixture.
184 # Note: keep fixtures in strict dependences from each other!
185 if not revert_snapshot:
186 if hardware.has_snapshot(ext.SNAPSHOT.underlay) and \
187 hardware.has_snapshot_config(ext.SNAPSHOT.underlay):
188 hardware.revert_snapshot(ext.SNAPSHOT.underlay)
189
190 # Create Underlay
191 if not config.underlay.ssh:
192 # If config.underlay.ssh wasn't provided from external config, then
193 # try to get necessary data from hardware manager (fuel-devops)
194 config.underlay.ssh = hardware.get_ssh_data(
195 roles=config.underlay.roles)
196
197 underlay = underlay_ssh_manager.UnderlaySSHManager(config.underlay.ssh)
198
199 if not config.underlay.lvm:
200 underlay.enable_lvm(hardware.lvm_storages())
201 config.underlay.lvm = underlay.config_lvm
202
203 hardware.create_snapshot(ext.SNAPSHOT.underlay)
204
205 else:
206 # 1. hardware environment created and powered on
207 # 2. config.underlay.ssh contains SSH access to provisioned nodes
208 # (can be passed from external config with TESTS_CONFIGS variable)
209 underlay = underlay_ssh_manager.UnderlaySSHManager(config.underlay.ssh)
210
211 return underlay