From 52ea061cb6f4088b90327125d125010d2f4cf332 Mon Sep 17 00:00:00 2001 From: zatserklyany Date: Tue, 20 Sep 2016 16:12:39 +0300 Subject: [PATCH] Add updated node to environment without master update This testgroup should be run with this parameter: export FORCE_DISABLE_UPDATES=True Change-Id: I725ba867571d69e53e4d51b6a135ddb3ef9e3b71 Closes-Bug: #1627611 --- doc/base_tests.rst | 7 +- fuelweb_test/helpers/fuel_actions.py | 60 ++++ fuelweb_test/settings.py | 3 + .../test_add_upgraded_node_to_cluster.py | 294 ++++++++++++++++++ 4 files changed, 363 insertions(+), 1 deletion(-) create mode 100644 fuelweb_test/tests/tests_upgrade/test_add_upgraded_node_to_cluster.py diff --git a/doc/base_tests.rst b/doc/base_tests.rst index 929b9a309..eeec374c2 100644 --- a/doc/base_tests.rst +++ b/doc/base_tests.rst @@ -797,4 +797,9 @@ Test SR-IOV Test graph extension ------------------------------------------------------ .. automodule:: fuelweb_test.tests.test_graph_extension - :members: \ No newline at end of file + :members: + +Test for mixed cluster +---------------------- +.. automodule:: fuelweb_test.tests.tests_upgrade.test_add_upgraded_node_to_cluster + :members: diff --git a/fuelweb_test/helpers/fuel_actions.py b/fuelweb_test/helpers/fuel_actions.py index 47ea449cf..c9995b2fd 100644 --- a/fuelweb_test/helpers/fuel_actions.py +++ b/fuelweb_test/helpers/fuel_actions.py @@ -233,6 +233,66 @@ class AdminActions(BaseActions): data = self.ssh_manager.execute_on_remote(self.admin_ip, cmd) return yaml.load(cStringIO(''.join(data['stdout']))) + @logwrap + def create_mirror(self, pattern_name, repo_groups, input_file=None): + """Creates a new local mirrors + :param pattern_name: the builtin input file name + :param repo_groups: the name of repository groups + :param input_file: the path to file with input data + """ + cmd = 'fuel-mirror create -P {0} -G {1}'.format(pattern_name, + repo_groups) + if input_file: + cmd = '{0} -I {1}'.format(cmd, input_file) + self.ssh_manager.check_call(self.admin_ip, cmd) + + @logwrap + def apply_mirror(self, pattern_name, repo_groups, input_file=None, + set_default=False, replace_default=False, + environment_id=None): + """Applies local mirrors for FUEL-environments + :param pattern_name: the builtin input file name + :param repo_groups: the name of repository groups + :param input_file: the path to file with input data + :param set_default: set as default repository + :param replace_default: replace default repository with generated + mirrors + :param environment_id: FUEL environment ID to update, by default + applies for all environments + """ + cmd = 'fuel-mirror apply -G {1}'.format(repo_groups) + if pattern_name: + cmd = '{0} -P {1}'.format(cmd, pattern_name) + elif input_file: + cmd = '{0} -I {1}'.format(cmd, input_file) + if set_default: + cmd = '{0} --default'.format(cmd) + if replace_default: + cmd = '{0} --replace'.format(cmd) + if environment_id: + cmd = '{0} --env {1}'.format(cmd, environment_id) + self.ssh_manager.check_call(self.admin_ip, cmd) + + @staticmethod + def create_mos_repo(name, uri, priority=1050, version='9.0'): + suite = (('{}-'.format(version)).join(name.split('-')) + if len(name.split('-')) > 1 + else '{}9.0'.format(name)) + return { + 'name': name, + 'section': 'main restricted', + 'uri': uri, + 'priority': priority, + 'suite': suite, + 'type': 'deb'} + + @staticmethod + def add_cluster_repo(attributes, repo): + repos = attributes['editable']['repo_setup']['repos'] + if repo['name'] not in [value['name'] for value in repos['value']]: + repos['value'].append(repo) + return repos + class NailgunActions(BaseActions): """NailgunActions.""" # TODO documentation diff --git a/fuelweb_test/settings.py b/fuelweb_test/settings.py index ad858575d..54304af5f 100644 --- a/fuelweb_test/settings.py +++ b/fuelweb_test/settings.py @@ -465,6 +465,9 @@ UPGRADE_BACKUP_FILES_REMOTE_DIR = os.environ.get( SNAPSHOT = os.environ.get('SNAPSHOT', '') +MIRROR_HOST = os.environ.get('MIRROR_HOST', 'mirror.fuel-infra.org') +MOS_UBUNTU_MIRROR_ID = os.environ.get('MOS_UBUNTU_MIRROR_ID', None) + # Repos paths and files MOS_REPOS = os.environ.get('MOS_REPOS', 'http://mirror.fuel-infra.org/mos-repos/') diff --git a/fuelweb_test/tests/tests_upgrade/test_add_upgraded_node_to_cluster.py b/fuelweb_test/tests/tests_upgrade/test_add_upgraded_node_to_cluster.py new file mode 100644 index 000000000..3a32f6ac2 --- /dev/null +++ b/fuelweb_test/tests/tests_upgrade/test_add_upgraded_node_to_cluster.py @@ -0,0 +1,294 @@ +# Copyright 2016 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. + +from copy import deepcopy + +from proboscis import test + +from fuelweb_test import logger +from fuelweb_test.helpers import os_actions +from fuelweb_test.helpers.decorators import log_snapshot_after_test +from fuelweb_test.settings import DEPLOYMENT_MODE_HA +from fuelweb_test.settings import NEUTRON_SEGMENT +from fuelweb_test.settings import MIRROR_HOST +from fuelweb_test.settings import MOS_REPOS +from fuelweb_test.settings import MOS_UBUNTU_MIRROR_ID +from fuelweb_test.settings import PATCHING_WEB_DIR +from fuelweb_test.tests.base_test_case import SetupEnvironment +from fuelweb_test.tests.base_test_case import TestBasic + + +@test +class TestAddUpdatedNodeToCluster(TestBasic): + """Add updated node to environment without master update + to validate that the "mixed" environment is operational + Required variable: + * FORCE_DISABLE_UPDATES=True + """ + + def __init__(self): + super(TestAddUpdatedNodeToCluster, self).__init__() + self.admin_ip = self.ssh_manager.admin_ip + self.local_mirrors_dir = 'mirrors/mos-repos/ubuntu/9.0' + + self.update_repos = [ + 'mos-updates', + 'mos-security', + 'mos-holdback'] + + self.base_nodes_dict = { + 'slave-01': ['controller'], + 'slave-02': ['controller'], + 'slave-03': ['controller'], + 'slave-04': ['compute'] + } + self.updated_node = 'slave-05' + + def add_mos_repos(self, attributes): + for name in self.update_repos: + repo = self.env.admin_actions.create_mos_repo(name, '') + self.env.admin_actions.add_cluster_repo(attributes, repo) + + def download_latest_snapshot(self): + if not MOS_UBUNTU_MIRROR_ID: + result = self.ssh_manager.check_call( + self.admin_ip, + ('curl {}/ubuntu/snapshots/9.0-latest.target.txt ' + '| head -1').format(MOS_REPOS) + ) + latest = result['stdout_str'] + else: + latest = MOS_UBUNTU_MIRROR_ID + logger.info("Latest snapsot: {}".format(latest)) + snapshot_dir = '{}/snapshot'.format(PATCHING_WEB_DIR) + self.ssh_manager.check_call( + self.admin_ip, + '(rsync -az ' + '{0}::mirror/mos-repos/ubuntu/snapshots/{1}/ ' + '{2})'.format(MIRROR_HOST, latest, snapshot_dir) + ) + cmd_list = [ + 'chown -R root:root {}'.format(snapshot_dir), + 'chmod -R 755 {}'.format(snapshot_dir) + ] + self.ssh_manager.check_call(self.admin_ip, ' && '.join(cmd_list)) + + def apply_local_repos(self, cluster_id, repos_list, repos_dir, + change_mos_updates=False): + attributes = self.fuel_web.client.get_cluster_attributes(cluster_id) + old_repos = attributes['editable']['repo_setup']['repos']['value'] + repos = deepcopy(old_repos) + for repo in repos: + if repo['name'] in repos_list: + repo['uri'] = 'http://{0}:8080/{1}'.format( + self.admin_ip, repos_dir) + if change_mos_updates: + if repo['name'] == 'mos-updates': + repo['suite'] = 'mos9.0-proposed' + repo['priority'] = 1150 + attributes['editable']['repo_setup']['repos']['value'] = deepcopy( + repos) + self.fuel_web.client.update_cluster_attributes(cluster_id, attributes) + + def create_delete_instance(self, cluster_id, compute_node): + os_conn = os_actions.OpenStackActions( + self.fuel_web.get_public_vip(cluster_id)) + hypervisors = os_conn.get_hypervisors() + hypervisor_name = (compute_node if compute_node + else hypervisors[0].hypervisor_hostname) + net_name = self.fuel_web.get_cluster_predefined_networks_name( + cluster_id)['private_net'] + instance = os_conn.create_server_for_migration( + label=net_name, + availability_zone="nova:{0}".format(hypervisor_name)) + logger.info("New instance {0} created on {1}" + .format(instance.id, hypervisor_name)) + os_conn.delete_instance(instance) + + def add_neutron_extention(self, node_ip): + """ + Explicitly enable neutron extension 'dns' on updated controller node + :param node_ip: IP address of updated controller node + """ + s = 'extension_drivers' + f = '/etc/neutron/plugins/ml2/ml2_conf.ini' + egrep = ("egrep '^{0}' {1} | grep -v dns &>/dev/null" + "|| echo False").format(s, f) + ret = self.ssh_manager.check_call(node_ip, egrep) + logger.info('ret = {}'.format(ret['stdout_str'])) + if 'False' not in ret['stdout_str']: + cmd_list = [ + "sed -ir 's/^{s} = /{s} = dns,/' {f}".format(s=s, f=f), + "service neutron-server restart"] + self.ssh_manager.check_call(node_ip, ' && '.join(cmd_list)) + + @test(depends_on=[SetupEnvironment.prepare_slaves_5], + groups=["base_deploy_3_ctrl_1_cmp"]) + @log_snapshot_after_test + def base_deploy_3_ctrl_1_cmp(self): + """Create base environment 3 controllers and 1 compute, create local + mirror and latest snapshot + + Scenario: + 1. Revert snapshot "ready_with_5_slaves" + 2. Create environment with neutron networking + 3. Add 3 nodes with controller role and 1 node with compute role + 4. Create local mirror + 5. Set local mirror mos as default for environment + 6. Download latest snapshot + 7. Run network verification + 8. Deploy the environment + 9. Run OSTF + 10. Create snapshot + + Duration 90m + Snapshot base_deploy_3_ctrl_1_cmp + """ + snapshotname = 'base_deploy_3_ctrl_1_cmp' + self.check_run(snapshotname) + + self.show_step(1) + self.env.revert_snapshot("ready_with_5_slaves") + + self.show_step(2) + cluster_id = self.fuel_web.create_cluster( + name=self.__class__.__name__, + mode=DEPLOYMENT_MODE_HA, + settings={ + 'net_provider': 'neutron', + 'net_segment_type': NEUTRON_SEGMENT['vlan'] + } + ) + + self.show_step(3) + self.fuel_web.update_nodes(cluster_id, self.base_nodes_dict) + + self.show_step(4) + self.env.admin_actions.create_mirror('ubuntu', 'mos') + + self.show_step(5) + attributes = self.fuel_web.client.get_cluster_attributes(cluster_id) + self.add_mos_repos(attributes) + self.fuel_web.client.update_cluster_attributes(cluster_id, attributes) + self.apply_local_repos(cluster_id, + self.update_repos, + self.local_mirrors_dir) + + self.show_step(6) + self.download_latest_snapshot() + + self.show_step(7) + self.fuel_web.verify_network(cluster_id) + + self.show_step(8) + self.fuel_web.deploy_cluster_wait(cluster_id) + + self.show_step(9) + self.fuel_web.run_ostf( + cluster_id, + test_sets=['smoke', 'sanity']) + + self.show_step(10) + self.env.make_snapshot(snapshotname, is_make=True) + + def add_updated_node_to_environment(self, role): + """Add updated node to environment without master update + :param role: node role + """ + snapshot_name = "add_updated_{}_to_environment".format(role) + + self.show_step(1) + self.env.revert_snapshot("base_deploy_3_ctrl_1_cmp") + cluster_id = self.fuel_web.get_last_created_cluster() + + self.show_step(2) + self.apply_local_repos(cluster_id, + self.update_repos, + 'snapshot', + change_mos_updates=True) + + self.show_step(3) + logger.info('Add 1 node with {} role'.format(role)) + self.fuel_web.update_nodes( + cluster_id, + {self.updated_node: [role]}) + node = self.fuel_web.get_nailgun_node_by_name(self.updated_node) + logger.info("Updated node: {0}\nhostname: {1}\nip: {2}".format( + self.updated_node, node['hostname'], node['ip'])) + + self.show_step(4) + self.fuel_web.verify_network(cluster_id) + + self.show_step(5) + self.fuel_web.deploy_cluster_changes_wait(cluster_id) + + if role == 'controller': + logger.warning( + "Temporary: add neutron extention 'dns' until bug LP#1628540") + self.add_neutron_extention(node['ip']) + + self.show_step(6) + compute_node = (node['fqdn'] if role == 'compute' else None) + for _ in range(5): + self.create_delete_instance(cluster_id, compute_node) + + self.show_step(7) + self.fuel_web.run_ostf(cluster_id, test_sets=['smoke', 'sanity']) + + self.show_step(8) + self.env.make_snapshot(snapshot_name) + + @test(depends_on=[base_deploy_3_ctrl_1_cmp], + groups=["add_updated_node_to_environment", + "add_updated_compute_to_environment"]) + @log_snapshot_after_test + def add_updated_compute_to_environment(self): + """Add updated compute to environment without master update + + Scenario: + 1. Revert snapshot 'base_deploy_3_ctrl_1_cmp' + 2. Set local snapshot repo as default for environment + 3. Add 1 node with compute role + 4. Run network verification + 5. Deploy changes + 6. Create-delete instance + 7. Run OSTF + 8. Create snapshot + + Duration 60m + Snapshot add_updated_compute_to_environment + """ + self.add_updated_node_to_environment('compute') + + @test(depends_on=[base_deploy_3_ctrl_1_cmp], + groups=["add_updated_node_to_environment", + "add_updated_controller_to_environment"]) + @log_snapshot_after_test + def add_updated_controller_to_environment(self): + """Add updated controller to environment without master update + + Scenario: + 1. Revert snapshot 'base_deploy_3_ctrl_1_cmp' + 2. Set local snapshot repo as default for environment + 3. Add 1 node with controller role + 4. Run network verification + 5. Deploy changes + 6. Create-delete instance + 7. Run OSTF + 8. Create snapshot + + Duration 60m + Snapshot add_updated_controller_to_environment + """ + self.add_updated_node_to_environment('controller')