81f1c0d739
Mass fix: 1. shadow builtins in locals 2. binary operators on new line 3. import class as lowercase (not readable type of object in namespace) API not changed. Change-Id: Ia171e466b502d95aa96ff4801eb37d528d659b64
464 lines
19 KiB
Python
464 lines
19 KiB
Python
# Copyright 2015 Mirantis, Inc.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
import os
|
|
import time
|
|
import urllib2
|
|
|
|
from proboscis import test
|
|
from proboscis.asserts import assert_is_not_none
|
|
from proboscis.asserts import assert_true
|
|
|
|
from devops.error import TimeoutError
|
|
from devops.helpers.helpers import wait
|
|
from fuelweb_test import logger
|
|
from fuelweb_test import settings
|
|
from fuelweb_test.helpers import patching
|
|
from fuelweb_test.helpers.decorators import log_snapshot_after_test
|
|
from fuelweb_test.helpers.rally import RallyBenchmarkTest
|
|
from fuelweb_test.helpers.rally import RallyResult
|
|
from fuelweb_test.helpers.utils import install_pkg
|
|
from fuelweb_test.tests.base_test_case import TestBasic
|
|
|
|
|
|
@test(groups=["patching"])
|
|
class PatchingTests(TestBasic):
|
|
"""PatchingTests.""" # TODO documentation
|
|
|
|
def __init__(self):
|
|
self.snapshot_name = settings.PATCHING_SNAPSHOT
|
|
self.pkgs = settings.PATCHING_PKGS
|
|
super(PatchingTests, self).__init__()
|
|
|
|
@test(groups=['prepare_patching_environment'])
|
|
def prepare_patching_environment(self):
|
|
"""Prepare environment for patching (OpenStack)
|
|
|
|
Scenario:
|
|
1. Take existing environment created by previous deployment test
|
|
and snapshot it
|
|
2. Revert snapshot and check that environment is alive
|
|
3. Check that deployed environment is affected by the bug and
|
|
verification scenario fails without applied patches
|
|
|
|
Duration: 10m
|
|
"""
|
|
|
|
logger.debug('Creating snapshot of environment deployed for patching.')
|
|
self.env.make_snapshot(snapshot_name=self.snapshot_name,
|
|
is_make=True)
|
|
self.env.revert_snapshot(self.snapshot_name)
|
|
cluster_id = self.fuel_web.get_last_created_cluster()
|
|
assert_is_not_none(cluster_id, 'Environment for patching not found.')
|
|
slaves = self.fuel_web.client.list_cluster_nodes(cluster_id)
|
|
logger.info('Checking that environment is affected '
|
|
'by bug #{0}...'.format(settings.PATCHING_BUG_ID))
|
|
is_environment_affected = False
|
|
try:
|
|
patching.verify_fix(self.env, target='environment', slaves=slaves)
|
|
except AssertionError:
|
|
is_environment_affected = True
|
|
assert_true(is_environment_affected,
|
|
'Deployed environment for testing patches is not affected'
|
|
'by bug #{0} or provided verification scenario is not '
|
|
'correct! Fix verification passed without applying '
|
|
'patches!'.format(settings.PATCHING_BUG_ID))
|
|
|
|
@test(groups=["patching_environment"],
|
|
depends_on_groups=['prepare_patching_environment'])
|
|
@log_snapshot_after_test
|
|
def patching_environment(self):
|
|
"""Apply patches on deployed environment
|
|
|
|
Scenario:
|
|
1. Revert snapshot of deployed environment
|
|
2. Run Rally benchmark tests and store results
|
|
3. Download patched packages on master node and make local repositories
|
|
4. Add new local repositories on slave nodes
|
|
5. Download late artifacts and clean generated images if needed
|
|
6. Perform actions required to apply patches
|
|
7. Verify that fix works
|
|
8. Run OSTF
|
|
9. Run Rally benchmark tests and compare results
|
|
|
|
Duration 15m
|
|
"""
|
|
|
|
# Step #1
|
|
if not self.env.revert_snapshot(self.snapshot_name):
|
|
raise PatchingTestException('Environment revert from snapshot "{0}'
|
|
'" failed.'.format(self.snapshot_name))
|
|
# Check that environment exists and it's ready for patching
|
|
cluster_id = self.fuel_web.get_last_created_cluster()
|
|
assert_is_not_none(cluster_id, 'Environment for patching not found.')
|
|
|
|
# Step #2
|
|
if settings.PATCHING_RUN_RALLY:
|
|
rally_benchmarks = {}
|
|
benchmark_results1 = {}
|
|
for tag in set(settings.RALLY_TAGS):
|
|
rally_benchmarks[tag] = RallyBenchmarkTest(
|
|
container_repo=settings.RALLY_DOCKER_REPO,
|
|
environment=self.env,
|
|
cluster_id=cluster_id,
|
|
test_type=tag
|
|
)
|
|
benchmark_results1[tag] = rally_benchmarks[tag].run()
|
|
logger.debug(benchmark_results1[tag].show())
|
|
|
|
# Step #3
|
|
patching_repos = patching.add_remote_repositories(
|
|
self.env, settings.PATCHING_MIRRORS)
|
|
if settings.PATCHING_MASTER_MIRRORS:
|
|
patching_master_repos = patching.add_remote_repositories(
|
|
self.env, settings.PATCHING_MASTER_MIRRORS,
|
|
prefix_name='custom_master_repo')
|
|
|
|
# Step #4
|
|
slaves = self.fuel_web.client.list_cluster_nodes(cluster_id)
|
|
for repo in patching_repos:
|
|
patching.connect_slaves_to_repo(self.env, slaves, repo)
|
|
if settings.PATCHING_MASTER_MIRRORS:
|
|
with self.env.d_env.get_admin_remote() as remote:
|
|
for repo in patching_master_repos:
|
|
install_pkg(remote, 'yum-utils')
|
|
patching.connect_admin_to_repo(self.env, repo)
|
|
|
|
# Step #5
|
|
if settings.LATE_ARTIFACTS_JOB_URL:
|
|
data = urllib2.urlopen(settings.LATE_ARTIFACTS_JOB_URL +
|
|
"/artifact/artifacts/artifacts.txt")
|
|
for package in data:
|
|
os.system("wget --directory-prefix"
|
|
" {0} {1}".format(settings.UPDATE_FUEL_PATH,
|
|
package))
|
|
self.env.admin_actions.upload_packages(
|
|
local_packages_dir=settings.UPDATE_FUEL_PATH,
|
|
centos_repo_path='/var/www/nailgun/centos/auxiliary',
|
|
ubuntu_repo_path=settings.LOCAL_MIRROR_UBUNTU)
|
|
if settings.REGENERATE_ENV_IMAGE:
|
|
self.env.admin_actions.clean_generated_image(
|
|
settings.OPENSTACK_RELEASE)
|
|
|
|
# Step #6
|
|
logger.info('Applying fix...')
|
|
patching.apply_patches(self.env, target='environment', slaves=slaves)
|
|
|
|
# Step #7
|
|
logger.info('Verifying fix...')
|
|
patching.verify_fix(self.env, target='environment', slaves=slaves)
|
|
|
|
# Step #8
|
|
# If OSTF fails (sometimes services aren't ready after
|
|
# slaves nodes reboot) sleep 5 minutes and try again
|
|
try:
|
|
self.fuel_web.run_ostf(cluster_id=cluster_id)
|
|
except AssertionError:
|
|
time.sleep(300)
|
|
self.fuel_web.run_ostf(cluster_id=cluster_id)
|
|
|
|
# Step #9
|
|
if settings.PATCHING_RUN_RALLY:
|
|
benchmark_results2 = {}
|
|
for tag in set(settings.RALLY_TAGS):
|
|
benchmark_results2[tag] = rally_benchmarks[tag].run()
|
|
logger.debug(benchmark_results2[tag].show())
|
|
|
|
rally_benchmarks_passed = True
|
|
|
|
for tag in set(settings.RALLY_TAGS):
|
|
if not RallyResult.compare(benchmark_results1[tag],
|
|
benchmark_results2[tag],
|
|
deviation=0.2):
|
|
rally_benchmarks_passed = False
|
|
|
|
assert_true(rally_benchmarks_passed,
|
|
"Rally benchmarks show performance degradation "
|
|
"after packages patching.")
|
|
|
|
number_of_nodes = len(self.fuel_web.client.list_cluster_nodes(
|
|
cluster_id))
|
|
|
|
cluster_nodes = self.fuel_web.client.list_cluster_nodes(cluster_id)
|
|
roles_list = [node['roles'] for node in cluster_nodes]
|
|
unique_roles = []
|
|
|
|
for role in roles_list:
|
|
if not [unique_role for unique_role in unique_roles
|
|
if set(role) == set(unique_role)]:
|
|
unique_roles.append(role)
|
|
|
|
self.env.bootstrap_nodes(self.env.d_env.nodes().slaves[
|
|
number_of_nodes:number_of_nodes + 1])
|
|
|
|
for roles in unique_roles:
|
|
if "mongo" in roles:
|
|
continue
|
|
|
|
node = {'slave-0{}'.format(number_of_nodes + 1):
|
|
[role for role in roles]}
|
|
logger.debug("Adding new node to the cluster: {0}".format(node))
|
|
self.fuel_web.update_nodes(
|
|
cluster_id, node)
|
|
self.fuel_web.deploy_cluster_wait(cluster_id,
|
|
check_services=False)
|
|
self.fuel_web.verify_network(cluster_id)
|
|
# sanity set isn't running due to LP1457515
|
|
self.fuel_web.run_ostf(cluster_id=cluster_id,
|
|
test_sets=['smoke', 'ha'])
|
|
|
|
if "ceph-osd" in roles:
|
|
with self.fuel_web.get_ssh_for_node(
|
|
'slave-0{}'.format(number_of_nodes + 1)
|
|
) as remote_ceph:
|
|
self.fuel_web.prepare_ceph_to_delete(remote_ceph)
|
|
|
|
nailgun_node = self.fuel_web.update_nodes(
|
|
cluster_id, node, False, True)
|
|
nodes = filter(
|
|
lambda x: x["pending_deletion"] is True, nailgun_node)
|
|
self.fuel_web.deploy_cluster(cluster_id)
|
|
wait(
|
|
lambda: self.fuel_web.is_node_discovered(nodes[0]),
|
|
timeout=6 * 60)
|
|
# sanity set isn't running due to LP1457515
|
|
self.fuel_web.run_ostf(cluster_id=cluster_id,
|
|
test_sets=['smoke', 'ha'])
|
|
|
|
|
|
@test(groups=["patching_master_tests"])
|
|
class PatchingMasterTests(TestBasic):
|
|
|
|
def __init__(self):
|
|
self.snapshot_name = settings.PATCHING_SNAPSHOT
|
|
self.pkgs = settings.PATCHING_PKGS
|
|
super(PatchingMasterTests, self).__init__()
|
|
|
|
@test(groups=['prepare_patching_master_environment'])
|
|
def prepare_patching_master_environment(self):
|
|
"""Prepare environment for patching (master node)
|
|
|
|
Scenario:
|
|
1. Take existing environment created by previous deployment test
|
|
and snapshot it
|
|
2. Revert snapshot and check that environment is alive
|
|
3. Check that deployed environment is affected by the bug and
|
|
verification scenario fails without applied patches
|
|
|
|
Duration: 10m
|
|
"""
|
|
|
|
logger.debug('Creating snapshot of environment deployed for patching.')
|
|
self.env.make_snapshot(snapshot_name=self.snapshot_name,
|
|
is_make=True)
|
|
self.env.revert_snapshot(self.snapshot_name)
|
|
cluster_id = self.fuel_web.get_last_created_cluster()
|
|
assert_is_not_none(cluster_id, 'Environment for patching not found.')
|
|
slaves = self.fuel_web.client.list_cluster_nodes(cluster_id)
|
|
logger.info('Checking that environment is affected '
|
|
'by bug #{0}...'.format(settings.PATCHING_BUG_ID))
|
|
is_environment_affected = False
|
|
try:
|
|
patching.verify_fix(self.env, target='environment', slaves=slaves)
|
|
except AssertionError:
|
|
is_environment_affected = True
|
|
assert_true(is_environment_affected,
|
|
'Deployed environment for testing patches is not affected'
|
|
'by bug #{0} or provided verification scenario is not '
|
|
'correct! Fix verification passed without applying '
|
|
'patches!'.format(settings.PATCHING_BUG_ID))
|
|
|
|
@test(groups=["patching_test"],
|
|
depends_on_groups=['prepare_patching_master_environment'])
|
|
@log_snapshot_after_test
|
|
def patching_test(self):
|
|
"""Apply patches on deployed master
|
|
|
|
Scenario:
|
|
1. Download patched packages on master node and make local repositories
|
|
2. Download late artifacts and clean generated images if needed
|
|
3. Perform actions required to apply patches
|
|
4. Verify that fix works
|
|
5. Run OSTF
|
|
6. Run network verification
|
|
7. Reset and delete cluster
|
|
8. Bootstrap 3 slaves
|
|
|
|
Duration 30m
|
|
"""
|
|
|
|
if not self.env.revert_snapshot(self.snapshot_name):
|
|
raise PatchingTestException('Environment revert from snapshot "{0}'
|
|
'" failed.'.format(self.snapshot_name))
|
|
|
|
# Step #1
|
|
with self.env.d_env.get_admin_remote() as remote:
|
|
install_pkg(remote, 'yum-utils')
|
|
patching_repos = patching.add_remote_repositories(
|
|
self.env, settings.PATCHING_MASTER_MIRRORS)
|
|
|
|
for repo in patching_repos:
|
|
patching.connect_admin_to_repo(self.env, repo)
|
|
|
|
# Step #2
|
|
if settings.LATE_ARTIFACTS_JOB_URL:
|
|
data = urllib2.urlopen(
|
|
settings.LATE_ARTIFACTS_JOB_URL +
|
|
"/artifact/artifacts/artifacts.txt")
|
|
for package in data:
|
|
os.system("wget --directory-prefix"
|
|
" {0} {1}".format(settings.UPDATE_FUEL_PATH,
|
|
package))
|
|
self.env.admin_actions.upload_packages(
|
|
local_packages_dir=settings.UPDATE_FUEL_PATH,
|
|
centos_repo_path='/var/www/nailgun/centos/auxiliary',
|
|
ubuntu_repo_path=settings.LOCAL_MIRROR_UBUNTU)
|
|
if settings.REGENERATE_ENV_IMAGE:
|
|
self.env.admin_actions.clean_generated_image(
|
|
settings.OPENSTACK_RELEASE)
|
|
|
|
# Step #3
|
|
logger.info('Applying fix...')
|
|
patching.apply_patches(self.env, target='master')
|
|
|
|
# Step #4
|
|
logger.info('Verifying fix...')
|
|
patching.verify_fix(self.env, target='master')
|
|
|
|
# Step #5
|
|
active_nodes = []
|
|
for node in self.env.d_env.nodes().slaves:
|
|
if node.driver.node_active(node):
|
|
active_nodes.append(node)
|
|
logger.debug('active nodes are {}'.format(active_nodes))
|
|
cluster_id = self.fuel_web.get_last_created_cluster()
|
|
if self.fuel_web.get_last_created_cluster():
|
|
number_of_nodes = len(self.fuel_web.client.list_cluster_nodes(
|
|
cluster_id))
|
|
self.fuel_web.run_ostf(cluster_id=cluster_id)
|
|
if number_of_nodes > 1:
|
|
self.fuel_web.verify_network(cluster_id)
|
|
|
|
cluster_nodes = self.fuel_web.client.list_cluster_nodes(cluster_id)
|
|
roles_list = [node['roles'] for node in cluster_nodes]
|
|
unique_roles = []
|
|
|
|
for role in roles_list:
|
|
if not [unique_role for unique_role in unique_roles
|
|
if set(role) == set(unique_role)]:
|
|
unique_roles.append(role)
|
|
|
|
self.env.bootstrap_nodes(self.env.d_env.nodes().slaves[
|
|
number_of_nodes:number_of_nodes + 1])
|
|
|
|
for roles in unique_roles:
|
|
if "mongo" in roles:
|
|
continue
|
|
node = {'slave-0{}'.format(number_of_nodes + 1):
|
|
[role for role in roles]}
|
|
logger.debug("Adding new node to"
|
|
" the cluster: {0}".format(node))
|
|
self.fuel_web.update_nodes(
|
|
cluster_id, node)
|
|
self.fuel_web.deploy_cluster_wait(cluster_id,
|
|
check_services=False)
|
|
self.fuel_web.verify_network(cluster_id)
|
|
# sanity set isn't running due to LP1457515
|
|
self.fuel_web.run_ostf(cluster_id=cluster_id,
|
|
test_sets=['smoke', 'ha'])
|
|
|
|
if "ceph-osd" in roles:
|
|
with self.fuel_web.get_ssh_for_node(
|
|
'slave-0{}'.format(number_of_nodes + 1)
|
|
) as remote:
|
|
self.fuel_web.prepare_ceph_to_delete(remote)
|
|
nailgun_node = self.fuel_web.update_nodes(
|
|
cluster_id, node, False, True)
|
|
nodes = filter(
|
|
lambda x: x["pending_deletion"] is True, nailgun_node)
|
|
self.fuel_web.deploy_cluster(cluster_id)
|
|
wait(
|
|
lambda: self.fuel_web.is_node_discovered(nodes[0]),
|
|
timeout=6 * 60)
|
|
# sanity set isn't running due to LP1457515
|
|
self.fuel_web.run_ostf(cluster_id=cluster_id,
|
|
test_sets=['smoke', 'ha'])
|
|
|
|
active_nodes = []
|
|
for node in self.env.d_env.nodes().slaves:
|
|
if node.driver.node_active(node):
|
|
active_nodes.append(node)
|
|
logger.debug('active nodes are {}'.format(active_nodes))
|
|
|
|
self.fuel_web.stop_reset_env_wait(cluster_id)
|
|
self.fuel_web.wait_nodes_get_online_state(
|
|
active_nodes, timeout=10 * 60)
|
|
self.fuel_web.client.delete_cluster(cluster_id)
|
|
try:
|
|
wait((lambda: len(
|
|
self.fuel_web.client.list_nodes()) == number_of_nodes),
|
|
timeout=5 * 60)
|
|
except TimeoutError:
|
|
assert_true(len(
|
|
self.fuel_web.client.list_nodes()) == number_of_nodes,
|
|
'Nodes are not discovered in timeout 5 *60')
|
|
self.env.bootstrap_nodes(self.env.d_env.nodes().slaves[:3])
|
|
|
|
@test(groups=["patching_master"],
|
|
depends_on_groups=['patching_test'])
|
|
@log_snapshot_after_test
|
|
def patching_master(self):
|
|
"""
|
|
Deploy cluster after master node patching
|
|
|
|
Scenario:
|
|
1. Create cluster
|
|
2. Add 1 node with controller role
|
|
3. Add 2 nodes with compute role
|
|
4. Deploy the cluster
|
|
5. Run network verification
|
|
6. Run OSTF
|
|
|
|
Duration 50m
|
|
"""
|
|
cluster_id = self.fuel_web.create_cluster(
|
|
name=self.__class__.__name__,
|
|
mode=settings.DEPLOYMENT_MODE,
|
|
settings={
|
|
"net_provider": 'neutron',
|
|
"net_segment_type": settings.NEUTRON_SEGMENT_TYPE,
|
|
'tenant': 'patchingMaster',
|
|
'user': 'patchingMaster',
|
|
'password': 'patchingMaster'
|
|
}
|
|
)
|
|
self.fuel_web.update_nodes(
|
|
cluster_id,
|
|
{
|
|
'slave-01': ['controller'],
|
|
'slave-02': ['compute'],
|
|
'slave-03': ['compute']
|
|
}
|
|
)
|
|
self.fuel_web.deploy_cluster_wait(cluster_id)
|
|
|
|
self.fuel_web.verify_network(cluster_id)
|
|
|
|
self.fuel_web.run_ostf(
|
|
cluster_id=cluster_id)
|
|
|
|
|
|
class PatchingTestException(Exception):
|
|
pass
|