Add Openstack Undercloud backup

This new option allows to call the Mistral workflow to run an Undercloud full
backup.

Usage: openstack undercloud backup [--add-path ADD_FILES_TO_BACKUP]

The --add-path allows to add additional files or folders to the
Undercloud backup, for example:

openstack undercloud backup --add-path /etc/hosts \
                            --add-path /var/log/

Depends-on: Iebd67568d5e72967e694b88fc8c73361543929a1
Change-Id: Ief10f5313244d2848b6de604e0493a51db1ed30f
Related bp undercloud-backup-restore
This commit is contained in:
Carlos Camacho 2017-05-19 09:24:03 +02:00
parent 11b659aea0
commit eaaf2e8bc5
6 changed files with 244 additions and 1 deletions

View File

@ -0,0 +1,5 @@
---
features:
- Add a new option to the TripleO client in order to create an Undercloud
backup.
Usage, openstack undercloud backup [--add-path ADD_FILES_TO_BACKUP]

View File

@ -93,6 +93,6 @@ openstack.tripleoclient.v1 =
undercloud_deploy = tripleoclient.v1.undercloud_deploy:DeployUndercloud
undercloud_install = tripleoclient.v1.undercloud:InstallUndercloud
undercloud_upgrade = tripleoclient.v1.undercloud:UpgradeUndercloud
undercloud_backup = tripleoclient.v1.undercloud_backup:BackupUndercloud
oslo.config.opts =
undercloud_config = tripleoclient.v1.undercloud_config:list_opts

View File

@ -0,0 +1,60 @@
# Copyright 2018 Red Hat, 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 mock
from osc_lib.tests import utils
from tripleoclient.v1 import undercloud_backup
class TestUndercloudBackup(utils.TestCommand):
def setUp(self):
super(TestUndercloudBackup, self).setUp()
# Get the command object to test
self.cmd = undercloud_backup.BackupUndercloud(self.app, None)
self.app.client_manager.workflow_engine = mock.Mock()
self.workflow = self.app.client_manager.workflow_engine
@mock.patch('tripleoclient.workflows.undercloud_backup.backup',
autospec=True)
def test_undercloud_backup_noargs(self, plan_mock):
arglist = []
verifylist = []
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
plan_mock.assert_called_once_with(
mock.ANY, {'sources_path': '/home/stack/'})
@mock.patch('tripleoclient.workflows.undercloud_backup.backup',
autospec=True)
def test_undercloud_backup_withargs(self, plan_mock):
arglist = [
'--add-path',
'/tmp/foo.yaml',
'--add-path',
'/tmp/bar.yaml'
]
verifylist = []
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
plan_mock.assert_called_once_with(
mock.ANY,
{'sources_path': '/home/stack/,/tmp/bar.yaml,/tmp/foo.yaml'})

View File

@ -0,0 +1,59 @@
# Copyright 2017 Red Hat, 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 mock
from osc_lib.tests import utils
from tripleoclient.workflows import undercloud_backup
class TestUndercloudBackup(utils.TestCommand):
def setUp(self):
super(TestUndercloudBackup, self).setUp()
self.app.client_manager = mock.Mock()
self.app.client_manager.workflow_engine = self.workflow = mock.Mock()
self.tripleoclient = mock.Mock()
self.websocket = mock.Mock()
self.websocket.__enter__ = lambda s: self.websocket
self.websocket.__exit__ = lambda s, *exc: None
self.tripleoclient.messaging_websocket.return_value = self.websocket
self.app.client_manager.tripleoclient = self.tripleoclient
@mock.patch('tripleoclient.workflows.base.wait_for_messages')
@mock.patch('tripleoclient.workflows.base.start_workflow')
def test_run_backup(self, start_wf_mock, messages_mock):
messages_mock.return_value = []
fetch_name = 'tripleo.undercloud_backup.v1.backup'
fetch_input = {
'sources_path': '/home/stack/'
}
undercloud_backup.backup(self.app.client_manager, fetch_input)
start_wf_mock.assert_called_once_with(self.workflow,
fetch_name,
workflow_input=fetch_input)
@mock.patch('tripleoclient.workflows.base.wait_for_messages')
@mock.patch('tripleoclient.workflows.base.start_workflow')
def test_run_backup_with_args(self, start_wf_mock, messages_mock):
messages_mock.return_value = []
fetch_name = 'tripleo.undercloud_backup.v1.backup'
fetch_input = {
'sources_path': '/tmp/file1.txt,/home/stack/'
}
undercloud_backup.backup(self.app.client_manager, fetch_input)
start_wf_mock.assert_called_once_with(self.workflow,
fetch_name,
workflow_input=fetch_input)

View File

@ -0,0 +1,84 @@
# Copyright 2018 Red Hat, 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 argparse
import logging
from openstackclient.i18n import _
from osc_lib.command import command
from tripleoclient.workflows import undercloud_backup
LOG = logging.getLogger(__name__ + ".BackupUndercloud")
class BackupUndercloud(command.Command):
"""Backup the undercloud"""
def get_parser(self, prog_name):
parser = argparse.ArgumentParser(
description=self.get_description(),
prog=prog_name,
add_help=False
)
# Parameter to choose the files to backup
parser.add_argument(
'--add-path',
action='append',
default=['/home/stack/'],
help=_("Add additional files to backup. "
"Defaults to: /home/stack/ "
"i.e. --add-path /this/is/a/folder/ "
" --add-path /this/is/a/texfile.txt")
)
return parser
def _run_backup_undercloud(self, parsed_args):
clients = self.app.client_manager
files_to_backup = ','.join(sorted(list(set(parsed_args.add_path))))
# Define the backup sources_path (files to backup).
# This is a comma separated string.
# I.e. "/this/is/a/folder/,/this/is/a/texfile.txt"
workflow_input = {
"sources_path": files_to_backup
}
LOG.debug('Launch the Undercloud Backup')
try:
output = undercloud_backup.backup(clients, workflow_input)
LOG.info(output)
except Exception as e:
print ("Undercloud backup finished with errors")
print ('Output: {}'.format(e))
LOG.info(e)
def take_action(self, parsed_args):
LOG.info(
'\n'
' #############################################################\n'
' # Disclaimer #\n'
' # Backup verification is the End Users responsibility #\n'
' # Please verify backup integrity before any possible #\n'
' # disruptive actions against the Undercloud. The resulting #\n'
' # backup file path will be shown on a successful execution. #\n'
' # #\n'
' # .-Stay safe and avoid future issues-. #\n'
' #############################################################\n')
self._run_backup_undercloud(parsed_args)

View File

@ -0,0 +1,35 @@
# Copyright 2018 Red Hat, 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 pprint
from tripleoclient.workflows import base
def backup(clients, workflow_input):
workflow_client = clients.workflow_engine
tripleoclients = clients.tripleoclient
with tripleoclients.messaging_websocket() as ws:
execution = base.start_workflow(
workflow_client,
'tripleo.undercloud_backup.v1.backup',
workflow_input=workflow_input
)
for payload in base.wait_for_messages(workflow_client, ws, execution):
if 'message' in payload:
assert payload['status'] == "SUCCESS", pprint.pformat(payload)
print('Undercloud Backup succeed')