Update/upgrade commands for services with external installers

New `openstack overcloud external-update run` and `openstack overcloud
external-upgrade run` commands are defined. These are meant to perform
updates and upgrades for services deployed via
external_deploy_tasks. A separate command is used because external
installers don't fit well within the --nodes and --roles selection
pattern we've established for the normal `update run` and `upgrade
run` commands.

Partial-Bug: #1783949
Depends-On: Ib2474e8f69711cd6610a78884d5032ffd19ad249
Depends-On: I982032a0eadfbfb7f1eadee9cae26c8cd5fcdbba
Change-Id: Ib2f32ae8ac234b0c25b0e1ff1f8f8d8e041185e0
This commit is contained in:
Jiri Stransky 2018-07-12 17:38:49 +02:00
parent f6cb7d86ba
commit 457ffd753f
16 changed files with 465 additions and 3 deletions

View File

@ -0,0 +1,10 @@
---
upgrade:
- |
New `openstack overcloud external-update run` and `openstack
overcloud external-upgrade run` commands are defined. These are
meant to perform updates and upgrades for services deployed via
external_deploy_tasks. A separate command is used because external
installers don't fit well within the --nodes and --roles selection
pattern we've established for the normal `update run` and `upgrade
run` commands.

View File

@ -90,6 +90,8 @@ openstack.tripleoclient.v1 =
overcloud_upgrade_prepare = tripleoclient.v1.overcloud_upgrade:UpgradePrepare
overcloud_upgrade_run = tripleoclient.v1.overcloud_upgrade:UpgradeRun
overcloud_upgrade_converge = tripleoclient.v1.overcloud_upgrade:UpgradeConvergeOvercloud
overcloud_external-update_run = tripleoclient.v1.overcloud_external_update:ExternalUpdateRun
overcloud_external-upgrade_run = tripleoclient.v1.overcloud_external_upgrade:ExternalUpgradeRun
overcloud_ceph-upgrade_run = tripleoclient.v1.overcloud_ceph_upgrade:CephUpgrade
overcloud_ffwd-upgrade_prepare = tripleoclient.v1.overcloud_ffwd_upgrade:FFWDUpgradePrepare
overcloud_ffwd-upgrade_run = tripleoclient.v1.overcloud_ffwd_upgrade:FFWDUpgradeRun

View File

@ -44,6 +44,8 @@ UPDATE_QUEUE = 'update'
UPGRADE_QUEUE = 'upgrade'
FFWD_UPGRADE_QUEUE = 'ffwdupgrade'
CEPH_UPGRADE_QUEUE = 'cephupgrade'
EXTERNAL_UPDATE_QUEUE = 'externalupdate'
EXTERNAL_UPGRADE_QUEUE = 'externalupgrade'
STACK_TIMEOUT = 240
@ -56,6 +58,8 @@ MAJOR_UPGRADE_PLAYBOOKS = ["upgrade_steps_playbook.yaml",
"deploy_steps_playbook.yaml",
"post_upgrade_steps_playbook.yaml"]
MAJOR_UPGRADE_SKIP_TAGS = ['validation', 'pre-upgrade']
EXTERNAL_UPDATE_PLAYBOOKS = ['external_update_steps_playbook.yaml']
EXTERNAL_UPGRADE_PLAYBOOKS = ['external_upgrade_steps_playbook.yaml']
# upgrade environment files expected by the client in the --templates
# tripleo-heat-templates default above $TRIPLEO_HEAT_TEMPLATES
UPDATE_PREPARE_ENV = "environments/lifecycle/update-prepare.yaml"

View File

@ -0,0 +1,49 @@
# 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.tests import fakes
class FakeClientWrapper(object):
def __init__(self):
self._instance = mock.Mock()
self.object_store = FakeObjectClient()
def messaging_websocket(self):
return fakes.FakeWebSocket()
class FakeObjectClient(object):
def __init__(self):
self._instance = mock.Mock()
self.put_object = mock.Mock()
def get_object(self, *args):
return
class TestOvercloudExternalUpdateRun(utils.TestCommand):
def setUp(self):
super(TestOvercloudExternalUpdateRun, self).setUp()
self.app.client_manager.auth_ref = mock.Mock(auth_token="TOKEN")
self.app.client_manager.tripleoclient = FakeClientWrapper()
self.app.client_manager.workflow_engine = mock.Mock()

View File

@ -0,0 +1,66 @@
# 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 tripleoclient import constants
from tripleoclient.tests.v1.overcloud_external_update import fakes
from tripleoclient.v1 import overcloud_external_update
class TestOvercloudExternalUpdateRun(fakes.TestOvercloudExternalUpdateRun):
def setUp(self):
super(TestOvercloudExternalUpdateRun, self).setUp()
# Get the command object to test
app_args = mock.Mock()
app_args.verbose_level = 1
self.cmd = overcloud_external_update.ExternalUpdateRun(
self.app, app_args)
uuid4_patcher = mock.patch('uuid.uuid4', return_value="UUID4")
self.mock_uuid4 = uuid4_patcher.start()
self.addCleanup(self.mock_uuid4.stop)
@mock.patch('tripleoclient.workflows.package_update.update_ansible',
autospec=True)
@mock.patch('os.path.expanduser')
@mock.patch('oslo_concurrency.processutils.execute')
@mock.patch('six.moves.builtins.open')
def test_update_with_user_and_tags(self, mock_open, mock_execute,
mock_expanduser, update_ansible):
mock_expanduser.return_value = '/home/fake/'
argslist = ['--ssh-user', 'tripleo-admin',
'--tags', 'ceph']
verifylist = [
('ssh_user', 'tripleo-admin'),
('tags', 'ceph'),
]
parsed_args = self.check_parser(self.cmd, argslist, verifylist)
with mock.patch('os.path.exists') as mock_exists:
mock_exists.return_value = True
self.cmd.take_action(parsed_args)
update_ansible.assert_called_once_with(
self.app.client_manager,
nodes='all',
inventory_file=mock_open().read(),
playbook='external_update_steps_playbook.yaml',
ansible_queue_name=constants.EXTERNAL_UPDATE_QUEUE,
node_user='tripleo-admin',
tags='ceph',
skip_tags='',
)

View File

@ -0,0 +1,49 @@
# 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.tests import fakes
class FakeClientWrapper(object):
def __init__(self):
self._instance = mock.Mock()
self.object_store = FakeObjectClient()
def messaging_websocket(self):
return fakes.FakeWebSocket()
class FakeObjectClient(object):
def __init__(self):
self._instance = mock.Mock()
self.put_object = mock.Mock()
def get_object(self, *args):
return
class TestOvercloudExternalUpgradeRun(utils.TestCommand):
def setUp(self):
super(TestOvercloudExternalUpgradeRun, self).setUp()
self.app.client_manager.auth_ref = mock.Mock(auth_token="TOKEN")
self.app.client_manager.tripleoclient = FakeClientWrapper()
self.app.client_manager.workflow_engine = mock.Mock()

View File

@ -0,0 +1,66 @@
# 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 tripleoclient import constants
from tripleoclient.tests.v1.overcloud_external_upgrade import fakes
from tripleoclient.v1 import overcloud_external_upgrade
class TestOvercloudExternalUpgradeRun(fakes.TestOvercloudExternalUpgradeRun):
def setUp(self):
super(TestOvercloudExternalUpgradeRun, self).setUp()
# Get the command object to test
app_args = mock.Mock()
app_args.verbose_level = 1
self.cmd = overcloud_external_upgrade.ExternalUpgradeRun(
self.app, app_args)
uuid4_patcher = mock.patch('uuid.uuid4', return_value="UUID4")
self.mock_uuid4 = uuid4_patcher.start()
self.addCleanup(self.mock_uuid4.stop)
@mock.patch('tripleoclient.workflows.package_update.update_ansible',
autospec=True)
@mock.patch('os.path.expanduser')
@mock.patch('oslo_concurrency.processutils.execute')
@mock.patch('six.moves.builtins.open')
def test_upgrade_with_user_and_tags(self, mock_open, mock_execute,
mock_expanduser, update_ansible):
mock_expanduser.return_value = '/home/fake/'
argslist = ['--ssh-user', 'tripleo-admin',
'--tags', 'ceph']
verifylist = [
('ssh_user', 'tripleo-admin'),
('tags', 'ceph'),
]
parsed_args = self.check_parser(self.cmd, argslist, verifylist)
with mock.patch('os.path.exists') as mock_exists:
mock_exists.return_value = True
self.cmd.take_action(parsed_args)
update_ansible.assert_called_once_with(
self.app.client_manager,
nodes='all',
inventory_file=mock_open().read(),
playbook='external_upgrade_steps_playbook.yaml',
ansible_queue_name=constants.EXTERNAL_UPGRADE_QUEUE,
node_user='tripleo-admin',
tags='ceph',
skip_tags='',
)

View File

@ -163,6 +163,7 @@ class TestFFWDUpgradeRun(fakes.TestFFWDUpgradeRun):
nodes='',
playbook=constants.FFWD_UPGRADE_PLAYBOOK,
node_user='heat-admin',
tags='',
skip_tags=''
)
@ -188,6 +189,7 @@ class TestFFWDUpgradeRun(fakes.TestFFWDUpgradeRun):
nodes='',
playbook=constants.FFWD_UPGRADE_PLAYBOOK,
node_user='my-user',
tags='',
skip_tags=''
)

View File

@ -152,6 +152,7 @@ class TestOvercloudUpdateRun(fakes.TestOvercloudUpdateRun):
playbook='fake-playbook.yaml',
ansible_queue_name=constants.UPDATE_QUEUE,
node_user='tripleo-admin',
tags='',
skip_tags=''
)
@ -182,6 +183,7 @@ class TestOvercloudUpdateRun(fakes.TestOvercloudUpdateRun):
playbook=book,
ansible_queue_name=constants.UPDATE_QUEUE,
node_user='heat-admin',
tags='',
skip_tags=''
)
@ -211,6 +213,7 @@ class TestOvercloudUpdateRun(fakes.TestOvercloudUpdateRun):
playbook=book,
ansible_queue_name=constants.UPDATE_QUEUE,
node_user='heat-admin',
tags='',
skip_tags=''
)

View File

@ -170,6 +170,7 @@ class TestOvercloudUpgradeRun(fakes.TestOvercloudUpgradeRun):
playbook='fake-playbook.yaml',
ansible_queue_name=constants.UPGRADE_QUEUE,
node_user='tripleo-admin',
tags='',
skip_tags=''
)
@ -202,6 +203,7 @@ class TestOvercloudUpgradeRun(fakes.TestOvercloudUpgradeRun):
playbook=book,
ansible_queue_name=constants.UPGRADE_QUEUE,
node_user='heat-admin',
tags='',
skip_tags='validation'
)
@ -232,6 +234,7 @@ class TestOvercloudUpgradeRun(fakes.TestOvercloudUpgradeRun):
playbook='fake-playbook.yaml',
ansible_queue_name=constants.UPGRADE_QUEUE,
node_user='heat-admin',
tags='',
skip_tags=''
)
@ -262,6 +265,7 @@ class TestOvercloudUpgradeRun(fakes.TestOvercloudUpgradeRun):
playbook=book,
ansible_queue_name=constants.UPGRADE_QUEUE,
node_user='heat-admin',
tags='',
skip_tags=''
)
@ -294,6 +298,7 @@ class TestOvercloudUpgradeRun(fakes.TestOvercloudUpgradeRun):
playbook=book,
ansible_queue_name=constants.UPGRADE_QUEUE,
node_user='heat-admin',
tags='',
skip_tags='pre-upgrade,validation'
)

View File

@ -948,7 +948,7 @@ def process_multiple_environments(created_env_files, tht_root,
def run_update_ansible_action(log, clients, nodes, inventory, playbook,
queue, all_playbooks, action, ssh_user,
skip_tags=''):
tags='', skip_tags=''):
playbooks = [playbook]
if playbook == "all":
playbooks = all_playbooks
@ -956,7 +956,8 @@ def run_update_ansible_action(log, clients, nodes, inventory, playbook,
log.debug("Running ansible playbook %s " % book)
action.update_ansible(clients, nodes=nodes, inventory_file=inventory,
playbook=book, ansible_queue_name=queue,
node_user=ssh_user, skip_tags=skip_tags)
node_user=ssh_user, tags=tags,
skip_tags=skip_tags)
def prepend_environment(environment_files, templates_dir, environment):

View File

@ -0,0 +1,102 @@
# 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.
#
from oslo_config import cfg
from oslo_log import log as logging
from osc_lib.i18n import _
from osc_lib import utils
from tripleoclient import command
from tripleoclient import constants
from tripleoclient import utils as oooutils
from tripleoclient.workflows import package_update
CONF = cfg.CONF
logging.register_options(CONF)
logging.setup(CONF, '')
class ExternalUpdateRun(command.Command):
"""Run external minor update Ansible playbook
This will run the external minor update Ansible playbook,
executing tasks from the undercloud. The update playbooks are
made available after completion of the 'overcloud update
prepare' command.
"""
log = logging.getLogger(__name__ + ".ExternalUpdateRun")
def get_parser(self, prog_name):
parser = super(ExternalUpdateRun, self).get_parser(prog_name)
parser.add_argument('--static-inventory',
dest='static_inventory',
action="store",
default=None,
help=_('Path to an existing ansible inventory to '
'use. If not specified, one will be '
'generated in '
'~/tripleo-ansible-inventory.yaml')
)
parser.add_argument("--ssh-user",
dest="ssh_user",
action="store",
default="heat-admin",
help=_("The ssh user name for connecting to "
"the overcloud nodes.")
)
parser.add_argument('--tags',
dest='tags',
action="store",
default="",
help=_('A string specifying the tag or comma '
'separated list of tags to be passed '
'as --tags to ansible-playbook. ')
)
parser.add_argument('--skip-tags',
dest='skip_tags',
action="store",
default="",
help=_('A string specifying the tag or comma '
'separated list of tags to be passed '
'as --skip-tags to ansible-playbook. ')
)
parser.add_argument('--stack', dest='stack',
help=_('Name or ID of heat stack '
'(default=Env: OVERCLOUD_STACK_NAME)'),
default=utils.env('OVERCLOUD_STACK_NAME',
default='overcloud'))
return parser
def take_action(self, parsed_args):
self.log.debug("take_action(%s)" % parsed_args)
clients = self.app.client_manager
stack = parsed_args.stack
# Run ansible:
inventory = oooutils.get_tripleo_ansible_inventory(
parsed_args.static_inventory, parsed_args.ssh_user, stack)
limit_hosts = 'all'
playbook = 'all'
oooutils.run_update_ansible_action(
self.log, clients, limit_hosts, inventory, playbook,
constants.EXTERNAL_UPDATE_QUEUE,
constants.EXTERNAL_UPDATE_PLAYBOOKS,
package_update, parsed_args.ssh_user,
tags=parsed_args.tags, skip_tags=parsed_args.skip_tags)
self.log.info("Completed Overcloud External Update Run.")

View File

@ -0,0 +1,102 @@
# 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.
#
from oslo_config import cfg
from oslo_log import log as logging
from osc_lib.i18n import _
from osc_lib import utils
from tripleoclient import command
from tripleoclient import constants
from tripleoclient import utils as oooutils
from tripleoclient.workflows import package_update
CONF = cfg.CONF
logging.register_options(CONF)
logging.setup(CONF, '')
class ExternalUpgradeRun(command.Command):
"""Run external major upgrade Ansible playbook
This will run the external major upgrade Ansible playbook,
executing tasks from the undercloud. The upgrade playbooks are
made available after completion of the 'overcloud upgrade
prepare' command.
"""
log = logging.getLogger(__name__ + ".ExternalUpgradeRun")
def get_parser(self, prog_name):
parser = super(ExternalUpgradeRun, self).get_parser(prog_name)
parser.add_argument('--static-inventory',
dest='static_inventory',
action="store",
default=None,
help=_('Path to an existing ansible inventory to '
'use. If not specified, one will be '
'generated in '
'~/tripleo-ansible-inventory.yaml')
)
parser.add_argument("--ssh-user",
dest="ssh_user",
action="store",
default="heat-admin",
help=_("The ssh user name for connecting to "
"the overcloud nodes.")
)
parser.add_argument('--tags',
dest='tags',
action="store",
default="",
help=_('A string specifying the tag or comma '
'separated list of tags to be passed '
'as --tags to ansible-playbook. ')
)
parser.add_argument('--skip-tags',
dest='skip_tags',
action="store",
default="",
help=_('A string specifying the tag or comma '
'separated list of tags to be passed '
'as --skip-tags to ansible-playbook. ')
)
parser.add_argument('--stack', dest='stack',
help=_('Name or ID of heat stack '
'(default=Env: OVERCLOUD_STACK_NAME)'),
default=utils.env('OVERCLOUD_STACK_NAME',
default='overcloud'))
return parser
def take_action(self, parsed_args):
self.log.debug("take_action(%s)" % parsed_args)
clients = self.app.client_manager
stack = parsed_args.stack
# Run ansible:
inventory = oooutils.get_tripleo_ansible_inventory(
parsed_args.static_inventory, parsed_args.ssh_user, stack)
limit_hosts = 'all'
playbook = 'all'
oooutils.run_update_ansible_action(
self.log, clients, limit_hosts, inventory, playbook,
constants.EXTERNAL_UPGRADE_QUEUE,
constants.EXTERNAL_UPGRADE_PLAYBOOKS,
package_update, parsed_args.ssh_user,
tags=parsed_args.tags, skip_tags=parsed_args.skip_tags)
self.log.info("Completed Overcloud External Upgrade Run.")

View File

@ -219,7 +219,8 @@ class UpgradeRun(command.Command):
constants.UPGRADE_QUEUE,
constants.MAJOR_UPGRADE_PLAYBOOKS,
package_update,
parsed_args.ssh_user, skip_tags)
parsed_args.ssh_user,
skip_tags=skip_tags)
playbooks = (constants.MAJOR_UPGRADE_PLAYBOOKS
if playbook == 'all' else playbook)