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