diff --git a/releasenotes/notes/overcloud-deploy-history-4a54b53ac10e6542.yaml b/releasenotes/notes/overcloud-deploy-history-4a54b53ac10e6542.yaml new file mode 100644 index 000000000..91c9cb935 --- /dev/null +++ b/releasenotes/notes/overcloud-deploy-history-4a54b53ac10e6542.yaml @@ -0,0 +1,7 @@ +--- +fixes: + - Each deploy command run by a user is now track in an history file under + $HOME/.tripleo directory. It allow to retrieve all the previous calls from + the openstack overcloud deploy command, the environment files used and the + templates directories used, for analysis, debugging or tracking. See + https://bugs.launchpad.net/tripleo/+bug/1673700 diff --git a/tripleoclient/tests/test_utils.py b/tripleoclient/tests/test_utils.py index 6d558c4dc..d04dda0da 100644 --- a/tripleoclient/tests/test_utils.py +++ b/tripleoclient/tests/test_utils.py @@ -15,9 +15,12 @@ from uuid import uuid4 +import argparse import mock +from mock import call import os.path import tempfile + from unittest import TestCase import yaml @@ -712,3 +715,45 @@ class TestBracketIPV6(TestCase): def test_already_bracketed(self): result = utils.bracket_ipv6('[::1]') self.assertEqual('[::1]', result) + + +class TestStoreCliParam(TestCase): + + def setUp(self): + self.args = argparse.ArgumentParser() + + @mock.patch('os.mkdir') + @mock.patch('os.path.exists') + def test_fail_to_create_file(self, mock_exists, mock_mkdir): + mock_exists.return_value = False + mock_mkdir.side_effect = OSError() + self.assertRaises(OSError, utils.store_cli_param, self.args) + + @mock.patch('os.path.isdir') + @mock.patch('os.path.exists') + def test_exists_but_not_dir(self, mock_exists, mock_isdir): + mock_exists.return_value = True + mock_isdir.return_value = False + self.assertRaises(exceptions.InvalidConfiguration, + utils.store_cli_param, + self.args) + + @mock.patch('six.moves.builtins.open') + @mock.patch('os.path.isdir') + @mock.patch('os.path.exists') + def test_write_cli_param(self, mock_exists, mock_isdir, mock_open): + history_path = os.path.join(os.path.expanduser("~"), '.tripleo') + mock_exists.return_value = True + mock_isdir.return_value = True + utils.store_cli_param(self.args) + expected_call = [call("%s/history" % history_path, 'a')] + mock_open.assert_has_calls(expected_call) + + @mock.patch('six.moves.builtins.open') + @mock.patch('os.path.isdir') + @mock.patch('os.path.exists') + def test_fail_to_write_data(self, mock_exists, mock_isdir, mock_open): + mock_exists.return_value = True + mock_isdir.return_value = True + mock_open.side_effect = IOError() + self.assertRaises(IOError, utils.store_cli_param, self.args) diff --git a/tripleoclient/utils.py b/tripleoclient/utils.py index ff31dc895..1f5bc47c5 100644 --- a/tripleoclient/utils.py +++ b/tripleoclient/utils.py @@ -15,6 +15,7 @@ from __future__ import print_function import csv +import datetime import hashlib import json import logging @@ -77,6 +78,35 @@ def write_overcloudrc(stack_name, overcloudrcs, config_directory='.'): os.chmod(rcv3path, 0o600) +def store_cli_param(parsed_args): + """write the cli parameters into an history file""" + + history_path = os.path.join(os.path.expanduser("~"), '.tripleo') + if not os.path.exists(history_path): + try: + os.mkdir(history_path) + except OSError as e: + messages = "Unable to create TripleO history directory: " + "{0}, {1}".format(history_path, e) + raise OSError(messages) + if os.path.isdir(history_path): + try: + with open(os.path.join(history_path, + 'history'), 'a') as history: + args = parsed_args.__dict__.copy() + used_args = ', '.join('%s=%s' % (key, value) + for key, value in args.items()) + history.write(' '.join([str(datetime.datetime.now()), + used_args])) + except IOError as e: + messages = "Unable to write into TripleO history file: " + "{0}, {1}".format(history_path, e) + raise IOError(messages) + else: + raise exceptions.InvalidConfiguration("Target path %s is not a " + "directory" % history_path) + + def create_tempest_deployer_input(config_name='tempest-deployer-input.conf'): config = configparser.ConfigParser() diff --git a/tripleoclient/v1/overcloud_deploy.py b/tripleoclient/v1/overcloud_deploy.py index e4f93155d..6abb14ef2 100644 --- a/tripleoclient/v1/overcloud_deploy.py +++ b/tripleoclient/v1/overcloud_deploy.py @@ -812,6 +812,7 @@ class DeployOvercloud(command.Command): sc_logger.setLevel(logging.CRITICAL) self._validate_args(parsed_args) + utils.store_cli_param(parsed_args) stack = utils.get_stack(self.orchestration_client, parsed_args.stack)