From d37b19f8b4f749a42f63e4bc19974d259f82d2e3 Mon Sep 17 00:00:00 2001 From: Alexandr Kostrikov Date: Tue, 23 Aug 2016 15:22:15 +0300 Subject: [PATCH] Implement configdb cli coverage There are new handlers in fuel cli which are intented to utilize CRUD operations of ConfigDB. Work with values(levels and overrides) is verified Change-Id: I531733b296765b0d472644fbe3739e03c0475fca Closes-bug: #1616047 (cherry picked from commit 20fa6bfa5ca873327b5cf9c132d692cd0014a19d) --- core/_tests/models/test_value_objects.py | 86 +++ core/models/value_objects.py | 182 ++++++ doc/base_tests.rst | 4 + fuelweb_test/helpers/utils.py | 71 ++- .../tests/tests_configdb/test_configdb_api.py | 2 +- .../tests/tests_configdb/test_configdb_cli.py | 580 ++++++++++++++++++ 6 files changed, 903 insertions(+), 22 deletions(-) create mode 100644 core/_tests/models/test_value_objects.py create mode 100644 core/models/value_objects.py create mode 100644 fuelweb_test/tests/tests_configdb/test_configdb_cli.py diff --git a/core/_tests/models/test_value_objects.py b/core/_tests/models/test_value_objects.py new file mode 100644 index 000000000..69692eed3 --- /dev/null +++ b/core/_tests/models/test_value_objects.py @@ -0,0 +1,86 @@ +from copy import deepcopy +import unittest + +from core.models.value_objects import FuelAccessParams + +EXAMPLE_YAML_DICT = { + 'OS_USERNAME': 'root', + 'OS_TENANT_NAME': 'project', + 'OS_PASSWORD': 'password', + 'SERVER_ADDRESS': '127.0.0.1', + 'SERVER_PORT': '8000', + 'KEYSTONE_PORT': '5000' +} + +EXPECTED_OPENRC_CONTENT = 'export OS_USERNAME="root"\n' \ + 'export OS_PASSWORD="root"\n' \ + 'export OS_TENANT_NAME="project"\n' \ + 'export SERVICE_URL="https://127.0.0.1:8000"\n' \ + 'export OS_AUTH_URL="https://127.0.0.1:5000"\n' + + +class TestFuelAccessParams(unittest.TestCase): + def test_simple_init(self): + fuel_access = FuelAccessParams() + + fuel_access.username = 'root' + self.assertEqual(fuel_access.username, 'root') + + fuel_access.password = 'password' + self.assertEqual(fuel_access.password, 'password') + + fuel_access.project = 'tenant' + self.assertEqual(fuel_access.project, 'tenant') + + fuel_access.service_address = '127.0.0.1' + self.assertEqual(fuel_access.service_address, '127.0.0.1') + + fuel_access.service_port = '777' + self.assertEqual(fuel_access.service_port, '777') + + fuel_access.keystone_address = '127.0.0.1' + self.assertEqual(fuel_access.keystone_address, '127.0.0.1') + + fuel_access.keystone_port = '5000' + self.assertEqual(fuel_access.keystone_port, '5000') + + def test_tls_init(self): + fuel_access = FuelAccessParams(tls_keystone_enabled=True, + tls_service_enabled=False) + fuel_access.service_address = '127.0.0.1' + fuel_access.service_port = '777' + + fuel_access.keystone_address = '127.0.0.1' + fuel_access.keystone_port = '5000' + + self.assertEqual(fuel_access.service_url, 'http://127.0.0.1:777') + self.assertEqual(fuel_access.os_auth_url, 'https://127.0.0.1:5000') + + def test_init_from_yaml_content(self): + fuel_access = FuelAccessParams.from_yaml_params(EXAMPLE_YAML_DICT) + self.assertEqual(fuel_access.service_address, '127.0.0.1') + self.assertEqual(fuel_access.os_auth_url, 'http://127.0.0.1:5000') + + def test_init_from_yaml_content_with_tls(self): + fuel_access = FuelAccessParams.from_yaml_params( + EXAMPLE_YAML_DICT, + tls_service_enabled=True, + tls_keystone_enabled=True + ) + self.assertEqual(fuel_access.service_address, '127.0.0.1') + self.assertEqual(fuel_access.os_auth_url, 'https://127.0.0.1:5000') + self.assertEqual(fuel_access.service_url, 'https://127.0.0.1:8000') + + def test_failed_from_yaml_content_when_key_absents(self): + yaml_from_content = deepcopy(EXAMPLE_YAML_DICT) + yaml_from_content.pop('OS_PASSWORD', None) + with self.assertRaises(KeyError): + FuelAccessParams.from_yaml_params(yaml_from_content) + + def test_export_to_openrc(self): + openrc_content = FuelAccessParams.from_yaml_params( + EXAMPLE_YAML_DICT, + tls_service_enabled=True, + tls_keystone_enabled=True + ).to_openrc_content() + self.assertEqual(EXPECTED_OPENRC_CONTENT, openrc_content) diff --git a/core/models/value_objects.py b/core/models/value_objects.py new file mode 100644 index 000000000..cb26838ca --- /dev/null +++ b/core/models/value_objects.py @@ -0,0 +1,182 @@ +# pylint: disable=too-many-instance-attributes +class FuelAccessParams(object): + """Value object to represent and map yaml file values of fuel master node + access to openrc file. + Should not use any api.""" + + def __init__(self, + tls_service_enabled=False, + tls_keystone_enabled=False): + self.__username = None # type: str + self.__password = None # type: str + self.__project = None # type: str + self.__service_address = None # type: str + self.__service_port = None # type: str + self.__keystone_address = None # type: str + self.__keystone_port = None # type: str + self.__tls_service_enabled = tls_service_enabled # type: bool + self.__tls_keystone_enabled = tls_keystone_enabled # type: bool + + @property + def username(self): + return self.__username + + @username.setter + def username(self, value): + """Set up username + + :type value: str + """ + self.__username = value + + @property + def password(self): + return self.__password + + @password.setter + def password(self, value): + """Set up password + + :type value: str + """ + self.__password = value + + @property + def project(self): + return self.__project + + @project.setter + def project(self, value): + """Set up project + + :type value: str + """ + self.__project = value + + @property + def service_address(self): + return self.__service_address + + @service_address.setter + def service_address(self, value): + """Set up service address + + :type value: str + """ + self.__service_address = value + + @property + def service_port(self): + return self.__service_port + + @service_port.setter + def service_port(self, value): + """Set up service port + + :type value: str + """ + self.__service_port = value + + @property + def keystone_address(self): + address = self.service_address + if self.__keystone_address: + address = self.__keystone_address + return address + + @keystone_address.setter + def keystone_address(self, value): + """Set up keystone address + + :type value: str + """ + self.__keystone_address = value + + @property + def keystone_port(self): + return self.__keystone_port + + @keystone_port.setter + def keystone_port(self, value): + """Set up keystone port + + :type value: str + """ + self.__keystone_port = value + + @property + def os_auth_url(self): + """Get url of authentication endpoint + + :rtype: str + :return: The url of os auth endpoint + """ + protocol = 'https' if self.__tls_keystone_enabled else 'http' + + return "{protocol}://{keystone_address}:{keystone_port}".format( + protocol=protocol, + keystone_address=self.keystone_address, + keystone_port=self.keystone_port + ) + + @property + def service_url(self): + """Get url of nailgun service endpoint + + :rtype: str + :return: The url of nailgun endpoint + """ + protocol = 'https' if self.__tls_service_enabled else 'http' + + return "{protocol}://{service_address}:{service_port}".format( + protocol=protocol, + service_address=self.service_address, + service_port=self.service_port + ) + + def to_openrc_content(self): + """Method to represent access credentials in openrc format. + + :rtype: str + :return: string content for openrc file + """ + env_template = ('export OS_USERNAME="{username}"\n' + 'export OS_PASSWORD="{password}"\n' + 'export OS_TENANT_NAME="{project}"\n' + 'export SERVICE_URL="{service_url}"\n' + 'export OS_AUTH_URL="{os_auth_url}"\n') + + return env_template.format( + username=self.username, + password=self.username, + project=self.project, + service_url=self.service_url, + os_auth_url=self.os_auth_url, + ) + + @classmethod + def from_yaml_params(cls, + yaml_content, + tls_service_enabled=False, + tls_keystone_enabled=False): + """The method to initialize value object from parsed yaml from + master node. + + :type yaml_content: dict[str] + :type tls_service_enabled: boolean + :type tls_keystone_enabled: boolean + :rtype: FuelAccessParams + :return: instance, which can be used + """ + access_params = cls( + tls_service_enabled=tls_service_enabled, + tls_keystone_enabled=tls_keystone_enabled) + access_params.username = yaml_content['OS_USERNAME'] + access_params.password = yaml_content['OS_PASSWORD'] + access_params.project = yaml_content['OS_TENANT_NAME'] + access_params.service_address = yaml_content['SERVER_ADDRESS'] + access_params.service_port = yaml_content['SERVER_PORT'] + access_params.keystone_port = yaml_content['KEYSTONE_PORT'] + + return access_params +# pylint: enable=too-many-instance-attributes diff --git a/doc/base_tests.rst b/doc/base_tests.rst index 9a59e0015..64280083b 100644 --- a/doc/base_tests.rst +++ b/doc/base_tests.rst @@ -756,6 +756,10 @@ Tests for configDB api Tests for cinder block device driver ------------------------------------ .. automodule:: fuelweb_test.tests.test_bdd + +Tests for configDB cli +---------------------- +.. automodule:: fuelweb_test.tests.tests_configdb.test_configdb_cli :members: Test for tracking /etc dir by etckeeper plugin diff --git a/fuelweb_test/helpers/utils.py b/fuelweb_test/helpers/utils.py index bcebe243b..639030310 100644 --- a/fuelweb_test/helpers/utils.py +++ b/fuelweb_test/helpers/utils.py @@ -46,7 +46,7 @@ from six.moves import xrange import yaml from core.helpers.log_helpers import logwrap - +from core.models.value_objects import FuelAccessParams from fuelweb_test import logger from fuelweb_test import settings from fuelweb_test.helpers.ssh_manager import SSHManager @@ -1108,33 +1108,62 @@ def dict_merge(a, b): @logwrap -def install_configdb(master_node_ip): +def get_access_config_file(): + """Get path to file on master node, which contains access parameters. + That can be changed in fuel library/fuel main. + + :return: string with path to file + """ + ssh_manager = SSHManager() + return ssh_manager.check_call( + ssh_manager.admin_ip, + 'ls -1 $HOME/.config/fuel/fuel_client.yaml')['stdout_str'] + + +@logwrap +def install_configdb(): """ Install ConfigDB extension on master node - :param master_node_ip: string with fuel master ip address :return: None """ - ip = master_node_ip + # TODO(akostrikov) There is a space for improvement. + if not settings.PERESTROIKA_REPO: + raise exceptions.FuelQAVariableNotSet( + 'PERESTROIKA_REPO', + 'http://perestroika-repo-tst.infra.site.net/mos-repos/centos/') ssh_manager = SSHManager() - asserts.assert_is_not_none( - settings.PERESTROIKA_REPO, - message='PERESTROIKA_REPO is empty, please set it to correct path' - ) - cmds = ['yum-config-manager --add-repo ' - '{}'.format(settings.PERESTROIKA_REPO), + admin_ip = ssh_manager.admin_ip + fuel_config_file = get_access_config_file() + openrc_content = FuelAccessParams.from_yaml_params( + YamlEditor(fuel_config_file, + ip=admin_ip).get_content() + ).to_openrc_content() - 'yum-config-manager --add-repo {}'.format( - settings.PACKAGES_CENTOS), + openrc_path = '/root/.openrc' + with ssh_manager.open_on_remote(admin_ip, openrc_path, 'w') as openrc_file: + openrc_file.write(openrc_content) - 'rpm --import {}'.format(settings.MASTER_CENTOS_GPG), - - 'yum install -y tuning-box', - 'nailgun_syncdb', - "sudo -u postgres psql -c '\dt' nailgun | grep tuning_box", - 'service nailgun restart' - ] - for cmd in cmds: - ssh_manager.execute_on_remote(ip=ip, cmd=cmd) + commands = [ + 'yum-config-manager --add-repo ' + '{}'.format(settings.PERESTROIKA_REPO), + 'yum-config-manager --add-repo {}'.format(settings.PACKAGES_CENTOS), + 'rpm --import {}'.format(settings.MASTER_CENTOS_GPG), + # TODO(akostrikov) Temporary hack to be on the edge. + 'yum install -y tuning-box git', + 'yum remove -y tuning-box', + 'git clone http://github.com/openstack/tuning-box', + 'cd tuning-box/ && python setup.py install', + # TODO(akostrikov) Hack end + 'nailgun_syncdb', + "sudo -u postgres psql -c '\dt' nailgun | grep tuning_box", + 'service nailgun restart', + '. .openrc; openstack service create --name tuning-box config', + ('. .openrc; openstack endpoint create' + ' --publicurl $SERVICE_URL/api/config' + ' --region RegionOne tuning-box;') + ] + for install_command in commands: + ssh_manager.check_call(admin_ip, install_command) # pylint: disable=eval-used diff --git a/fuelweb_test/tests/tests_configdb/test_configdb_api.py b/fuelweb_test/tests/tests_configdb/test_configdb_api.py index faf19151d..0d69882b1 100644 --- a/fuelweb_test/tests/tests_configdb/test_configdb_api.py +++ b/fuelweb_test/tests/tests_configdb/test_configdb_api.py @@ -55,7 +55,7 @@ class TestsConfigDBAPI(TestBasic): self.show_step(1) self.env.revert_snapshot('empty') self.show_step(2) - install_configdb(master_node_ip=self.ssh_manager.admin_ip) + install_configdb() logger.debug('Waiting for ConfigDB') wait_pass(lambda: self.fuel_web.client.get_components(), diff --git a/fuelweb_test/tests/tests_configdb/test_configdb_cli.py b/fuelweb_test/tests/tests_configdb/test_configdb_cli.py new file mode 100644 index 000000000..993a2a91a --- /dev/null +++ b/fuelweb_test/tests/tests_configdb/test_configdb_cli.py @@ -0,0 +1,580 @@ +# 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. +import json +import operator +import functools + +from proboscis import test +from proboscis.asserts import assert_equal +from proboscis.asserts import assert_true + +from fuelweb_test.helpers.decorators import log_snapshot_after_test +from fuelweb_test.tests.base_test_case import TestBasic + + +RESOURCE_NAME_1 = 'resource1' +SLASHED_RESOURCE = 'slashed/resource' +ENV_FILE_PARAMS_PATH = '/tmp/configdb_env' +ROOT_PARAMS_FILE = '/root/.config/fuel/fuel_client.yaml' +EXPECTED_RES_DEF = { + u'content': {u'var': 1}, + u'name': u'res1' +} + + +@test(groups=["tests_configdb_api"]) +class TestsConfigDBAPI(TestBasic): + """Tests to cover cli interface of communication with + configdb(tuningbox)""" + + @test(depends_on_groups=['create_component_and_env_configdb'], + groups=['configdb_cli_interface']) + def validate_creation_of_component(self): + """Validate CRUD operations on components and resource definitions + + Scenario: + 1. Revert snapshot create_component_and_env_configdb + 2. Create empty component + 3. Verify empty component contents + 4. Verify failure of duplicate creation + 5. Create component to store resource definitions + 6. Verify component rename + 7. Add resources to component + 8. Verify resources of the component + 9. Make snapshot + + Duration: 5 min + Snapshot: configdb_component_tests + """ + self.show_step(1) # Revert snapshot + self.env.revert_snapshot('create_component_and_env_configdb') + admin_ip = self.ssh_manager.admin_ip + + self.show_step(2) # Create empty component + create_component_cmd = 'fuel2 config comp create --name empty' + self.ssh_manager.check_call(self.ssh_manager.admin_ip, + create_component_cmd) + + self.show_step(3) # Verify empty component contents + list_component_cmd = 'fuel2 config comp list --format json' + list_cmd_out = self.ssh_manager.check_call( + self.ssh_manager.admin_ip, + list_component_cmd)['stdout_str'] + actual_component = [c for c in json.loads(list_cmd_out) if + c['name'] == u'empty'][0] + assert_equal(actual_component['resource_definitions'], []) + assert_equal(actual_component['name'], 'empty') + + self.show_step(4) # Verify failure of duplicate creation + create_duplicate = 'fuel2 config comp create --name empty' + # TODO(akostrikov) return ec!=0 + # TODO(akostrikov) stderr? + stdout = self.ssh_manager.check_call( + self.ssh_manager.admin_ip, + create_duplicate, + raise_on_err=False)['stdout_str'] + assert_true('duplicate key value violates unique constraint' in stdout) + + # TODO(akostrikov) create comp cmd help more productive + # TODO(akostrikov) create component with resource definitions! + # TODO(akostrikov) component show by name + self.show_step(5) # Create component to store resource definitions + create_with_resources = 'fuel2 config comp create --name res' + self.ssh_manager.check_call(admin_ip, create_with_resources) + list_component_cmd = 'fuel2 config comp list --format json' + list_cmd_out = self.ssh_manager.check_call( + admin_ip, + list_component_cmd)['stdout_str'] + res_comp = [c for c in json.loads(list_cmd_out) if + c['name'] == 'res'][0] + assert_equal(res_comp['resource_definitions'], []) + res_id = res_comp['id'] + + self.show_step(6) # Verify component rename + update_comp_cmd = 'fuel2 config comp update -n res_updated ' \ + '{id}'.format(id=res_id) + self.ssh_manager.check_call(admin_ip, update_comp_cmd) + + self.show_step(7) # Add resources to component + create_res_cmd = 'fuel2 config def create --name res1 -i {id} ' \ + '--content \'{{"var": 1}}\' -t json'.format(id=res_id) + self.ssh_manager.check_call(admin_ip, create_res_cmd) + + # TODO(akostrikov) Add more resources to the component + self.show_step(8) # Verify resources of the component + show_comp_cmd = 'fuel2 config comp show {id} --format json'.format( + id=res_id) + show_comp_out = self.ssh_manager.check_call( + self.ssh_manager.admin_ip, + show_comp_cmd)['stdout_str'] + component = json.loads(show_comp_out) + res_def = component['resource_definitions'][0] + assert_equal(res_def['content'], + EXPECTED_RES_DEF['content']) + assert_equal(res_def['component_id'], + res_id) + assert_equal(res_def['name'], + EXPECTED_RES_DEF['name']) + + self.show_step(9) # Make snapshot + self.env.make_snapshot('configdb_component_tests') + + @test(depends_on_groups=['create_component_and_env_configdb'], + groups=['configdb_cli_interface']) + @log_snapshot_after_test + def validate_creation_of_env(self): + """Validate creation of configdb environment + + Scenario: + 1. Revert snapshot create_component_and_env_configdb + 2. Create environment with level + 3. Verify environment fields + 4. Create component for environment + 5. Create environment with component + 6. Verify environment with component + 7. Create environment with component and level + 8. Verify environment with component and level + 9. Create environment with component and two levels + 10. Verify environment with component and two levels + 11. Make snapshot + + Duration: 5 min + Snapshot: configdb_env_tests + """ + self.show_step(1) # Revert snapshot + self.env.revert_snapshot('create_component_and_env_configdb') + admin_ip = self.ssh_manager.admin_ip + + self.show_step(2) # Create environment with level + create_env_cmd = 'fuel2 config env create -l servers' + self.ssh_manager.check_call(self.ssh_manager.admin_ip, create_env_cmd) + list_env_cmd = 'fuel2 config env list' + list_cmd_out = self.ssh_manager.check_call(self.ssh_manager.admin_ip, + list_env_cmd)['stdout_str'] + + self.show_step(3) # Verify environment fields + # TODO(akostrikov) parse stdout of create to find id! + # TODO(akostrikov) bug for name in env to find by uniq name + actual_env = [e for e in json.loads(list_cmd_out) if + e['hierarchy_levels'] == ['servers']][0] + assert_equal(actual_env['hierarchy_levels'], ['servers']) + assert_equal(actual_env['components'], []) + + self.show_step(4) # Create component for environment + create_with_resources = 'fuel2 config comp create --name res' + self.ssh_manager.check_call(admin_ip, create_with_resources) + list_component_cmd = 'fuel2 config comp list --format json' + list_cmd_out = self.ssh_manager.check_call( + admin_ip, + list_component_cmd)['stdout_str'] + + res_comp = [c for c in json.loads(list_cmd_out) if + c['name'] == 'res'][0] + assert_equal(res_comp['resource_definitions'], []) + res_id = res_comp['id'] + + self.show_step(5) # Create environment with component + create_with_comp = 'fuel2 config env create -c {id}'.format(id=res_id) + self.ssh_manager.check_call(admin_ip, create_with_comp) + + self.show_step(6) # Verify environment with component + find_comp_env = 'fuel2 config env list' + env_list = self.ssh_manager.check_call(admin_ip, + find_comp_env)['stdout_str'] + env_comp = [e for e in json.loads(env_list) + if e['components'] == [res_id]][0] + assert_equal(env_comp['hierarchy_levels'], []) + + self.show_step(7) # Create environment with component and level + create_lvl_comp = 'fuel2 config env create -c {id} -l nodes'.format( + id=res_id) + out_lvl_comp = self.ssh_manager.check_call( + admin_ip, create_lvl_comp)['stdout_str'] + + self.show_step(8) # Verify environment with component and level + env_lvl_comp = json.loads(out_lvl_comp) + assert_equal(env_lvl_comp['components'], [res_id]) + assert_equal(env_lvl_comp['hierarchy_levels'], ['nodes']) + + self.show_step(9) # Create environment with component and two levels + create_new_comp = 'fuel2 config comp create -n another_comp -f json' + comp_res = self.ssh_manager.check_call( + admin_ip, create_new_comp)['stdout_str'] + comp_id = json.loads(comp_res)['id'] + create_mult_env_cmd = 'fuel2 config env create ' \ + '-l nodes,servers ' \ + '-c{id1},{id2}'.format(id1=comp_id, id2=res_id) + env_res = self.ssh_manager.check_call( + admin_ip, create_mult_env_cmd)['stdout_str'] + + self.show_step(10) # Verify environment with component and two levels + env_obj = json.loads(env_res) + + levels = env_obj['hierarchy_levels'] + levels_contained = functools.reduce(operator.and_, + ['nodes' in levels, + 'servers' in levels], True) + assert_true(levels_contained) + + components = env_obj['components'] + levels_contained = functools.reduce(operator.and_, + [res_id in components, + comp_id in components], True) + assert_true(levels_contained) + + self.show_step(11) # Make snapshot + self.env.make_snapshot('configdb_env_tests') + + @test(depends_on_groups=['create_component_and_env_configdb'], + groups=['configdb_cli_interface']) + def resource_value_without_level(self): + """Getting and setting resources without level with cli + + Scenario: + 1. Revert snapshot create_component_and_env_configdb + 2. Create component for environment + 3. Create environment with component + 4. Get default resource value + 5. Update resource value + 6. Verify updated resource value + 7. Make snapshot + + Duration: 5 min + Snapshot: configdb_resource_tests + """ + self.show_step(1) # Revert snapshot + self.env.revert_snapshot('create_component_and_env_configdb') + admin_ip = self.ssh_manager.admin_ip + + self.show_step(2) # Create component with resource for environment + create_new_comp = 'fuel2 config comp create -n another_comp -f json' + comp_res = self.ssh_manager.check_call( + admin_ip, create_new_comp)['stdout_str'] + comp_id = json.loads(comp_res)['id'] + create_res_cmd = 'fuel2 config def create --name res1 -i {id} ' \ + '--content \'{{"var": 1}}\' ' \ + '-t json -f json'.format(id=comp_id) + create_res_out = self.ssh_manager.check_call( + admin_ip, create_res_cmd)['stdout_str'] + create_res_obj = json.loads(create_res_out) + res_id = create_res_obj['id'] + + self.show_step(3) # Create environment with component + create_mult_env_cmd = 'fuel2 config env create ' \ + '-c{cid}'.format(cid=comp_id) + env_res = self.ssh_manager.check_call( + admin_ip, create_mult_env_cmd)['stdout_str'] + env_obj = json.loads(env_res) + env_id = env_obj['id'] + + self.show_step(4) # Get default resource value + get_resource_cmd = 'fuel2 config get --env {env_id} ' \ + '--resource {res_id} ' \ + '-f json'.format(env_id=env_id, res_id=res_id) + admin_ip = self.ssh_manager.admin_ip + res = self.ssh_manager.execute_on_remote( + ip=admin_ip, cmd=get_resource_cmd)['stdout_str'] + res_obj = json.loads(res) + assert_equal(res_obj, {}) + + self.show_step(5) # Update resource value + set_resource_cmd = 'fuel2 config set --env {env_id} --resource ' \ + '{res_id} --value \'{{"a": 1, "b": null}}\' ' \ + '--key key --type json' + set_resource_cmd = set_resource_cmd.format(env_id=env_id, + res_id=res_id) + self.ssh_manager.execute_on_remote( + ip=admin_ip, cmd=set_resource_cmd) + + self.show_step(6) # Verify updated resource value + get_resource_cmd = 'fuel2 config get --env {env_id} ' \ + '--resource {res_id} ' \ + '-f json'.format(env_id=env_id, res_id=res_id) + admin_ip = self.ssh_manager.admin_ip + res = self.ssh_manager.execute_on_remote( + ip=admin_ip, cmd=get_resource_cmd)['stdout_str'] + res_obj = json.loads(res) + assert_equal(res_obj['key'], {'a': 1, 'b': None}) + + self.show_step(7) # Make snapshot + self.env.make_snapshot('configdb_resource_tests') + + @test(depends_on_groups=['create_component_and_env_configdb'], + groups=['configdb_cli_interface']) + def resource_value_with_level(self): + """Getting and setting resources without level with cli + + Scenario: + 1. Revert snapshot create_component_and_env_configdb + 2. Create component for environment + 3. Create environment with component and levels + 4. Get default resource value by level + 5. Update resource value with level + 6. Verify updated resource value with level + 7. Verify level value does not leak + 8. Make snapshot + + Duration: 5 min + Snapshot: configdb_resource_tests_lvl + """ + self.show_step(1) # Revert snapshot + self.env.revert_snapshot('create_component_and_env_configdb') + admin_ip = self.ssh_manager.admin_ip + + self.show_step(2) # Create component for environment + create_new_comp = 'fuel2 config comp create -n another_comp -f json' + comp_res = self.ssh_manager.check_call( + admin_ip, create_new_comp)['stdout_str'] + comp_id = json.loads(comp_res)['id'] + create_res_cmd = 'fuel2 config def create --name res1 -i {id} ' \ + '--content \'{{"var": 1}}\' ' \ + '-t json -f json'.format(id=comp_id) + create_res_out = self.ssh_manager.check_call( + admin_ip, create_res_cmd)['stdout_str'] + create_res_obj = json.loads(create_res_out) + res_id = create_res_obj['id'] + + self.show_step(3) # Create environment with component and levels + create_mult_env_cmd = 'fuel2 config env create -l nodes ' \ + '-c{cid}'.format(cid=comp_id) + env_res = self.ssh_manager.check_call( + admin_ip, create_mult_env_cmd)['stdout_str'] + env_obj = json.loads(env_res) + env_id = env_obj['id'] + get_resource_cmd = 'fuel2 config get --env {env_id} ' \ + '--resource {res_id} ' \ + '-f json'.format(env_id=env_id, res_id=res_id) + admin_ip = self.ssh_manager.admin_ip + res = self.ssh_manager.check_call( + admin_ip, + get_resource_cmd)['stdout_str'] + res_obj = json.loads(res) + assert_equal(res_obj, {}) + + self.show_step(4) # Get default resource value by level + get_lvl_res_cmd = 'fuel2 config get --env {env_id} ' \ + '--resource {res_id} ' \ + '--format json --level nodes=1'.format(env_id=env_id, + res_id=res_id) + lvl_res = self.ssh_manager.check_call( + admin_ip, get_lvl_res_cmd)['stdout_str'] + lvl_obj = json.loads(lvl_res) + assert_equal(lvl_obj, {}) + + self.show_step(5) # Update resource value with level + set_lvl_res_cmd = 'fuel2 config set --env {env_id} --resource ' \ + '{res_id} --value \'{{"a": 1, "b": null}}\' ' \ + '--key key --type ' \ + 'json --level nodes=1'.format(env_id=env_id, + res_id=res_id) + self.ssh_manager.check_call( + admin_ip, set_lvl_res_cmd) + + self.show_step(6) # Verify updated resource value with level + get_lvl_res_cmd = 'fuel2 config get --env {env_id} ' \ + '--resource {res_id} ' \ + '--format json --level nodes=1'.format(env_id=env_id, + res_id=res_id) + lvl_res = self.ssh_manager.check_call( + admin_ip, get_lvl_res_cmd)['stdout_str'] + lvl_obj = json.loads(lvl_res) + assert_equal(lvl_obj['key']['a'], 1) + assert_equal(lvl_obj['key']['b'], None) + + self.show_step(7) # Verify level value does not leak + get_lvl_res_cmd = 'fuel2 config get --env {env_id} ' \ + '--resource {res_id} ' \ + '--format json'.format(env_id=env_id, + res_id=res_id) + lvl_res = self.ssh_manager.check_call( + admin_ip, get_lvl_res_cmd)['stdout_str'] + lvl_obj = json.loads(lvl_res) + assert_equal(lvl_obj, {}) + + self.show_step(8) # Make snapshot + self.env.make_snapshot('configdb_resource_tests_lvl') + + @test(depends_on_groups=['create_component_and_env_configdb'], + groups=['configdb_cli_interface']) + def merge_overrides_without_level(self): + """Test overrides behaviour without levels + + Scenario: + 1. Revert snapshot create_component_and_env_configdb + 2. Create component for environment + 3. Create environment for overrides + 4. Update resource value + 5. Update resource override + 6. Check effective value + 7. Make snapshot + + Duration: 5 min + Snapshot: configdb_resource_tests_overrides + """ + self.show_step(1) # Revert snapshot + self.env.revert_snapshot('create_component_and_env_configdb') + admin_ip = self.ssh_manager.admin_ip + + self.show_step(2) # Create component for environment + create_new_comp = 'fuel2 config comp create -n another_comp -f json' + comp_res = self.ssh_manager.check_call( + admin_ip, create_new_comp)['stdout_str'] + comp_id = json.loads(comp_res)['id'] + create_res_cmd = 'fuel2 config def create --name res1 -i {id} ' \ + '--content \'{{"var": 1}}\' ' \ + '-t json -f json'.format(id=comp_id) + create_res_out = self.ssh_manager.check_call( + admin_ip, create_res_cmd)['stdout_str'] + create_res_obj = json.loads(create_res_out) + res_id = create_res_obj['id'] + + self.show_step(3) # Create environment for overrides + create_mult_env_cmd = 'fuel2 config env create ' \ + '-c{cid}'.format(cid=comp_id) + env_res = self.ssh_manager.check_call( + admin_ip, create_mult_env_cmd)['stdout_str'] + env_obj = json.loads(env_res) + env_id = env_obj['id'] + + self.show_step(4) # Update resource value + # TODO(akostrikov) operations on resource by resource name + set_res_cmd = 'fuel2 config set --env {env_id} --resource ' \ + '{res_id} --value \'{{"a": 1, "b": null}}\' ' \ + '--key key --type ' \ + 'json --level nodes=1'.format(env_id=env_id, + res_id=res_id) + self.ssh_manager.check_call( + admin_ip, set_res_cmd) + + self.show_step(5) # Update resource override + set_override_cmd = 'fuel2 config override --env {env_id} --resource ' \ + '{res_id} --value \'{{"a": 3, "b": null}}\' ' \ + '--key key --type ' \ + 'json --level nodes=1'.format(env_id=env_id, + res_id=res_id) + self.ssh_manager.check_call( + admin_ip, set_override_cmd) + + self.show_step(6) # Check effective value + get_resource_cmd = 'fuel2 config get --env {env_id} ' \ + '--resource {res_id} ' \ + '-f json'.format(env_id=env_id, res_id=res_id) + admin_ip = self.ssh_manager.admin_ip + res = self.ssh_manager.check_call( + admin_ip, get_resource_cmd)['stdout_str'] + res_obj = json.loads(res) + assert_equal(res_obj['key']['a'], 3) + assert_equal(res_obj['key']['b'], None) + + self.show_step(7) # Make snapshot + self.env.make_snapshot('configdb_resource_tests_overrides') + + @test(depends_on_groups=['create_component_and_env_configdb'], + groups=['configdb_cli_interface']) + def merge_overrides_with_level(self): + """Test overrides behaviour with levels + + Scenario: + 1. Revert snapshot create_component_and_env_configdb + 2. Create component for environment + 3. Create environment with level for overrides + 4. Update resource value with level + 5. Update resource override with level + 6. Check effective value with level + 7. Check effective value with level + 8. Make snapshot + + Duration: 5 min + Snapshot: configdb_resource_tests_lvl_overrides + """ + self.show_step(1) # Revert snapshot + self.env.revert_snapshot('create_component_and_env_configdb') + admin_ip = self.ssh_manager.admin_ip + + self.show_step(2) # Create component for environment + create_new_comp = 'fuel2 config comp create -n another_comp -f json' + comp_res = self.ssh_manager.check_call( + admin_ip, create_new_comp)['stdout_str'] + comp_id = json.loads(comp_res)['id'] + create_res_cmd = 'fuel2 config def create --name res1 -i {id} ' \ + '--content \'{{"var": 1}}\' ' \ + '-t json -f json'.format(id=comp_id) + create_res_out = self.ssh_manager.check_call( + admin_ip, create_res_cmd)['stdout_str'] + create_res_obj = json.loads(create_res_out) + res_id = create_res_obj['id'] + + self.show_step(3) # Create environment for overrides + create_mult_env_cmd = 'fuel2 config env create ' \ + '-c{cid}'.format(cid=comp_id) + env_res = self.ssh_manager.check_call( + admin_ip, create_mult_env_cmd)['stdout_str'] + env_obj = json.loads(env_res) + env_id = env_obj['id'] + + self.show_step(4) # Update resource value with level + set_res_cmd = 'fuel2 config set --env {env_id} --resource ' \ + '{res_id} --value \'{{"a": 1, "b": null}}\' ' \ + '--key key --type json ' \ + '--level nodes=1'.format(env_id=env_id, + res_id=res_id) + self.ssh_manager.check_call( + admin_ip, set_res_cmd) + + self.show_step(5) # Update resource override with level + set_override_cmd = 'fuel2 config override --env {env_id} --resource ' \ + '{res_id} --value \'{{"a": 3, "b": null}}\' ' \ + '--key key --type json ' \ + '--level nodes=1'.format(env_id=env_id, + res_id=res_id) + self.ssh_manager.check_call( + admin_ip, set_override_cmd) + + self.show_step(6) # Check effective value with level + get_resource_cmd = 'fuel2 config get --env {env_id} ' \ + '--resource {res_id} --level nodes=1 ' \ + '-f json'.format(env_id=env_id, res_id=res_id) + res = self.ssh_manager.check_call( + admin_ip, get_resource_cmd)['stdout_str'] + res_obj = json.loads(res) + assert_equal(res_obj['key']['a'], 3) + assert_equal(res_obj['key']['b'], None) + + self.show_step(7) # Check effective value without level + get_resource_cmd = 'fuel2 config get --env {env_id} ' \ + '--resource {res_id} ' \ + '-f json'.format(env_id=env_id, res_id=res_id) + + res = self.ssh_manager.check_call( + admin_ip, get_resource_cmd)['stdout_str'] + res_obj = json.loads(res) + # TODO(akostrikov) https://bugs.launchpad.net/fuel/+bug/1619264 + assert_equal(res_obj, {}) + + # TODO(akostrikov) multiple levels + self.show_step(8) # Make snapshot + self.env.make_snapshot('configdb_resource_tests_lvl_overrides') + + @test(depends_on_groups=['create_component_and_env_configdb'], + groups=['configdb_cli_interface']) + def update_via_key_path(self): + # TODO(akostrikov) Update_key_by_path + pass + + @test(depends_on_groups=['create_component_and_env_configdb'], + groups=['configdb_cli_interface']) + def key_deletion_via_path(self): + # TODO(akostrikov) Wipe key by path + # TODO(akostrikov) Delete key by path + pass