diff --git a/octane/handlers/backup_restore/postgres.py b/octane/handlers/backup_restore/postgres.py index 83f9a213..3e153c55 100644 --- a/octane/handlers/backup_restore/postgres.py +++ b/octane/handlers/backup_restore/postgres.py @@ -12,11 +12,13 @@ import json import logging +import os import requests import six import urlparse import yaml +from fuelclient.objects import node from keystoneclient.v2_0 import Client as keystoneclient from octane.handlers.backup_restore import base @@ -88,6 +90,29 @@ class NailgunArchivator(PostgresArchivator): for args in magic_consts.NAILGUN_ARCHIVATOR_PATCHES: docker.apply_patches(*args, revert=True) + def _create_links_on_remote_logs(self): + with open("/etc/fuel/astute.yaml") as astute: + domain = yaml.load(astute)["DNS_DOMAIN"] + dirname = "/var/log/docker-logs/remote/" + pairs = [(n.data["meta"]["system"]["fqdn"], n.data["ip"]) + for n in node.Node.get_all()] + docker.run_in_container("rsyslog", ["service", "rsyslog", "stop"]) + try: + for fqdn, ip_addr in pairs: + if not fqdn.endswith(domain): + continue + ip_addr_path = os.path.join(dirname, ip_addr) + fqdn_path = os.path.join(dirname, fqdn) + if os.path.islink(ip_addr_path): + continue + if os.path.isdir(ip_addr_path): + os.rename(ip_addr_path, fqdn_path) + else: + os.mkdir(fqdn_path) + os.symlink(fqdn, ip_addr_path) + finally: + docker.run_in_container("rsyslog", ["service", "rsyslog", "start"]) + def _post_restore_action(self): data, _ = docker.run_in_container( "nailgun", @@ -112,6 +137,7 @@ class NailgunArchivator(PostgresArchivator): "/etc/puppet/", ], env=self.context.get_credentials_env()) + self._create_links_on_remote_logs() class KeystoneArchivator(PostgresArchivator): diff --git a/octane/tests/test_archivators_restore.py b/octane/tests/test_archivators_restore.py index d8015b49..355f9752 100644 --- a/octane/tests/test_archivators_restore.py +++ b/octane/tests/test_archivators_restore.py @@ -459,6 +459,8 @@ def test_post_restore_action_astute(mocker): ), ]) def test_post_restore_nailgun(mocker, mock_open, dump, calls): + mock_links = mocker.patch.object( + postgres.NailgunArchivator, "_create_links_on_remote_logs") data = yaml.dump(dump) mock_subprocess_call = mocker.patch("octane.util.subprocess.call") mocker.patch("octane.util.docker.run_in_container", @@ -492,6 +494,7 @@ def test_post_restore_nailgun(mocker, mock_open, dump, calls): "fuel", "release", "--sync-deployment-tasks", "--dir", "/etc/puppet/"], env={'KEYSTONE_PASS': 'password', 'KEYSTONE_USER': 'admin'} ) + mock_links.assert_called_once_with() @pytest.mark.parametrize("exc_on_apply", [True, False]) @@ -535,3 +538,78 @@ def test_post_restore_puppet_apply_host(mocker, mock_open, exc_on_apply): "/etc/fuel/astute.yaml") mkstemp_mock.assert_called_once_with( dir="/etc/fuel", prefix=".astute.yaml.octane") + + +@pytest.mark.parametrize("nodes", [ + [("node_1", True), ("node_2", True), ("node_3", True)], + [("node_1", False)], + [("node_1", False), ("node_2", False), ("node_3", False)], + [("node_1", False), ("node_2", True), ("node_3", False)], +]) +@pytest.mark.parametrize("is_dir", [True, False]) +@pytest.mark.parametrize("exception", [True, False]) +def test_create_links_on_remote_logs( + mocker, mock_open, nodes, is_dir, exception): + domain_name = "test_domain" + mocker.patch("yaml.load", return_value={"DNS_DOMAIN": domain_name}) + domain_names = [] + fuel_client_values = [] + is_link_exists = [] + moved_nodes = [] + for idx, node_link_exits in enumerate(nodes): + node, link_exists = node_link_exits + node_domain_name = "{0}.{1}".format(node, domain_name) + domain_names.append(node_domain_name) + ip_addr = "10.21.10.{0}".format(idx + 1) + fuel_client_mock = mocker.Mock() + fuel_client_mock.data = { + "meta": { + "system": { + "fqdn": node_domain_name + } + }, + "ip": ip_addr, + } + fuel_client_values.append(fuel_client_mock) + is_link_exists.append(link_exists) + if not link_exists: + moved_nodes.append((node_domain_name, ip_addr)) + is_link_mock = mocker.patch("os.path.islink", side_effect=is_link_exists) + mocker.patch("os.path.isdir", return_value=is_dir) + mocker.patch("fuelclient.objects.node.Node.get_all", + return_value=fuel_client_values) + run_in_container_mock = mocker.patch( + "octane.util.docker.run_in_container") + rename_mock = mocker.patch("os.rename") + symlink_mock = mocker.patch("os.symlink") + mkdir_mock = mocker.patch("os.mkdir") + archivator = backup_restore.postgres.NailgunArchivator(None) + if not exception: + + class TestException(Exception): + pass + + is_link_mock.side_effect = TestException("test exc") + with pytest.raises(TestException): + archivator._create_links_on_remote_logs() + assert not mkdir_mock.called + assert not rename_mock.called + else: + archivator._create_links_on_remote_logs() + path = "/var/log/docker-logs/remote/" + path_pairs = [(os.path.join(path, d), os.path.join(path, i)) + for d, i in moved_nodes] + sym_calls = [mock.call(d, os.path.join(path, i)) + for d, i in moved_nodes] + if is_dir: + assert [mock.call(i, d) for d, i in path_pairs] == \ + rename_mock.call_args_list + assert not mkdir_mock.called + else: + assert [mock.call(d) for d, _ in path_pairs] == \ + mkdir_mock.call_args_list + assert not rename_mock.called + assert sym_calls == symlink_mock.call_args_list + assert [mock.call("rsyslog", ["service", "rsyslog", "stop"]), + mock.call("rsyslog", ["service", "rsyslog", "start"])] == \ + run_in_container_mock.call_args_list