Set fuel access password from console params

Set fuel access passowrd from console params in fuel-restore command.
It used for extra args in fuel console commands as extra args and as
password for nailgun api authorization.

Set up password over argument --admin-password.

    octane fuel-restore --admin-password *****

Change-Id: I7ecc57838c2fcba79f181c942945176d5ed859e9
Closes-bug: 1555145
(cherry picked from commit 61cdc15a72)
This commit is contained in:
Sergey Abramov 2016-03-09 16:42:47 +03:00
parent 742abfdf98
commit 3febaf4e87
8 changed files with 140 additions and 26 deletions

View File

@ -22,9 +22,9 @@ from octane.handlers import backup_restore
LOG = logging.getLogger(__name__)
def restore_data(path_to_backup, archivators):
def restore_data(path_to_backup, archivators, context):
with contextlib.closing(tarfile.open(path_to_backup)) as archive:
archivators = [cls(archive) for cls in archivators]
archivators = [cls(archive, context) for cls in archivators]
for archivator in archivators:
archivator.pre_restore_check()
for archivator in archivators:
@ -50,13 +50,36 @@ class BaseRestoreCommand(command.Command):
assert self.archivators
if not os.path.isfile(parsed_args.path):
raise ValueError("Invalid path to backup file")
restore_data(parsed_args.path, self.archivators)
restore_data(
parsed_args.path,
self.archivators,
self.get_context(parsed_args))
def get_context(self, parsed_args):
return None
class RestoreCommand(BaseRestoreCommand):
archivators = backup_restore.ARCHIVATORS
def get_parser(self, *args, **kwargs):
parser = super(RestoreCommand, self).get_parser(*args, **kwargs)
parser.add_argument(
"--admin-password",
type=str,
action="store",
dest="admin_password",
required=True,
help="Fuel admin password")
return parser
def get_context(self, parsed_args):
return backup_restore.NailgunCredentialsContext(
password=parsed_args.admin_password,
user="admin"
)
class RestoreRepoCommand(BaseRestoreCommand):

View File

@ -10,6 +10,8 @@
# License for the specific language governing permissions and limitations
# under the License.
import collections
from octane.handlers.backup_restore import astute
from octane.handlers.backup_restore import cobbler
from octane.handlers.backup_restore import fuel_keys
@ -43,3 +45,6 @@ REPO_ARCHIVATORS = [
mirrors.MirrorsBackup,
mirrors.RepoBackup,
]
NailgunCredentialsContext = collections.namedtuple(
"NailgunCredentialsContext", ["password", "user"])

View File

@ -19,8 +19,9 @@ from octane.util import subprocess
class Base(object):
def __init__(self, archive):
def __init__(self, archive, context=None):
self.archive = archive
self.context = context
def backup(self):
raise NotImplemented

View File

@ -32,4 +32,12 @@ class NailgunPluginsArchivator(base.PathArchivator):
def restore(self):
super(NailgunPluginsArchivator, self).restore()
if os.path.exists(self.path):
subprocess.call(["fuel", "plugins", "--sync"])
subprocess.call([
"fuel",
"plugins",
"--sync",
"--user",
self.context.user,
"--password",
self.context.password
])

View File

@ -83,10 +83,6 @@ class NailgunArchivator(PostgresArchivator):
self._post_restore_action()
def _post_restore_action(self):
with open("/etc/fuel/astute.yaml") as astute_conf:
data_dict = yaml.load(astute_conf.read())["FUEL_ACCESS"]
user = data_dict["user"]
password = data_dict["password"]
data, _ = docker.run_in_container(
"nailgun",
["cat", magic_consts.OPENSTACK_FIXTURES],
@ -97,13 +93,20 @@ class NailgunArchivator(PostgresArchivator):
release = helpers.merge_dicts(
base_release_fields, fixture['fields'])
self.__post_data_to_nailgun(
"/api/v1/releases/", release, user, password)
"/api/v1/releases/",
release,
self.context.user,
self.context.password)
subprocess.call([
"fuel",
"release",
"--sync-deployment-tasks",
"--dir",
"/etc/puppet/",
"--user",
self.context.user,
"--password",
self.context.password
])

View File

@ -10,6 +10,10 @@
# License for the specific language governing permissions and limitations
# under the License.
import shutil
import tempfile
import yaml
from octane.handlers.backup_restore import base
from octane.util import puppet
@ -25,4 +29,16 @@ class PuppetApplyHost(base.Base):
pass
def restore(self):
puppet.apply_host()
_, tmp_file_name = tempfile.mkstemp(
dir="/etc/fuel",
prefix=".astute.yaml.octane")
shutil.copy("/etc/fuel/astute.yaml", tmp_file_name)
try:
with open("/etc/fuel/astute.yaml") as current:
data = yaml.load(current)
data["FUEL_ACCESS"]["password"] = self.context.password
with open("/etc/fuel/astute.yaml", "w") as current:
yaml.safe_dump(data, current, default_flow_style=False)
puppet.apply_host()
finally:
shutil.move(tmp_file_name, "/etc/fuel/astute.yaml")

View File

@ -16,6 +16,7 @@ import yaml
from keystoneclient.v2_0 import Client as keystoneclient
from octane.handlers import backup_restore
from octane.handlers.backup_restore import astute
from octane.handlers.backup_restore import cobbler
from octane.handlers.backup_restore import fuel_keys
@ -437,8 +438,6 @@ def test_post_restore_action_astute(mocker):
])
def test_post_restore_nailgun(mocker, mock_open, dump, calls):
data = yaml.dump(dump)
mock_open.return_value.read.return_value = yaml.dump(
{"FUEL_ACCESS": {"user": "admin", "password": "admin"}})
mock_subprocess_call = mocker.patch("octane.util.subprocess.call")
mocker.patch("octane.util.docker.run_in_container",
return_value=(data, None))
@ -450,7 +449,11 @@ def test_post_restore_nailgun(mocker, mock_open, dump, calls):
mocker.patch.object(keystoneclient, "__init__", mock_init)
post_data = mocker.patch("requests.post")
postgres.NailgunArchivator(None)._post_restore_action()
postgres.NailgunArchivator(
None,
backup_restore.NailgunCredentialsContext(
user="admin", password="password")
)._post_restore_action()
headers = {
"X-Auth-Token": token,
@ -463,10 +466,56 @@ def test_post_restore_nailgun(mocker, mock_open, dump, calls):
json_mock.assert_has_calls([mock.call(d) for d in calls], any_order=True)
assert json_mock.call_count == 2
mock_subprocess_call.assert_called_once_with([
"fuel", "release", "--sync-deployment-tasks", "--dir", "/etc/puppet/"])
"fuel",
"release",
"--sync-deployment-tasks",
"--dir",
"/etc/puppet/",
"--user",
"admin",
"--password",
"password",
])
def test_post_restore_puppet_apply_host(mocker):
mock_apply = mocker.patch("octane.util.puppet.apply_host")
puppet.PuppetApplyHost(None).restore()
@pytest.mark.parametrize("exc_on_apply", [True, False])
def test_post_restore_puppet_apply_host(mocker, mock_open, exc_on_apply):
class TestException(Exception):
pass
mkstemp_mock = mocker.patch(
"tempfile.mkstemp",
return_value=(1, "/etc/fuel/.astute.yaml.bac"))
mock_copy = mocker.patch("shutil.copy")
mock_move = mocker.patch("shutil.move")
yaml_load = mocker.patch(
"yaml.load", return_value={"FUEL_ACCESS": {"password": "dump_pswd"}})
yaml_dump = mocker.patch("yaml.safe_dump")
context = backup_restore.NailgunCredentialsContext(
user="admin", password="user_pswd")
archivator = puppet.PuppetApplyHost(None, context)
if exc_on_apply:
mock_apply = mocker.patch(
"octane.util.puppet.apply_host",
side_effect=TestException("test exception"))
pytest.raises(TestException, archivator.restore)
else:
mock_apply = mocker.patch("octane.util.puppet.apply_host")
archivator.restore()
assert mock_apply.called
assert mock_open.call_args_list == [
mock.call("/etc/fuel/astute.yaml"),
mock.call("/etc/fuel/astute.yaml", "w"),
]
yaml_load.assert_called_once_with(mock_open.return_value)
yaml_dump.asswer_called_once_with(
{'FUEL_ACCESS': {'password': 'user_pswd'}},
mock_open.return_value,
default_flow_style=False)
mock_copy.assert_called_once_with("/etc/fuel/astute.yaml",
"/etc/fuel/.astute.yaml.bac")
mock_move.assert_called_once_with("/etc/fuel/.astute.yaml.bac",
"/etc/fuel/astute.yaml")
mkstemp_mock.assert_called_once_with(
dir="/etc/fuel", prefix=".astute.yaml.octane")

View File

@ -22,26 +22,35 @@ from octane.handlers import backup_restore
("path", False),
("path", True),
])
@pytest.mark.parametrize("command, archivators", [
("fuel-restore", backup_restore.ARCHIVATORS),
("fuel-repo-restore", backup_restore.REPO_ARCHIVATORS),
@pytest.mark.parametrize("command, archivators, password_required", [
("fuel-restore", backup_restore.ARCHIVATORS, True),
("fuel-repo-restore", backup_restore.REPO_ARCHIVATORS, False),
])
def test_parser(mocker, octane_app, path, is_file, command, archivators):
@pytest.mark.parametrize("password", [None, "password"])
def test_parser(
mocker, octane_app, path, is_file, command, archivators,
password, password_required):
restore_mock = mocker.patch('octane.commands.restore.restore_data')
mocker.patch("os.path.isfile", return_value=is_file)
params = [command]
if path:
params += ["--from", path]
if password and password_required:
params += ["--admin-password", password]
try:
octane_app.run(params)
except AssertionError: # parse error, app returns 2
assert not restore_mock.called
assert path is None
assert not password or path is None
except ValueError: # Invalid path to backup file
assert not restore_mock.called
assert not is_file
else:
restore_mock.assert_called_once_with(path, archivators)
context = None
if password and password_required:
context = backup_restore.NailgunCredentialsContext(
user="admin", password=password)
restore_mock.assert_called_once_with(path, archivators, context)
assert path is not None
assert is_file
@ -51,10 +60,10 @@ def test_restore_data(mocker):
archivator_mock_1 = mocker.Mock()
archivator_mock_2 = mocker.Mock()
path = "path"
restore.restore_data(path, [archivator_mock_1, archivator_mock_2])
restore.restore_data(path, [archivator_mock_1, archivator_mock_2], None)
tar_mock.assert_called_once_with(path)
for arch_mock in [archivator_mock_1, archivator_mock_2]:
arch_mock.assert_has_calls([
mock.call(tar_mock.return_value),
mock.call(tar_mock.return_value, None),
mock.call().pre_restore_check(),
mock.call().restore()])