From 2bc2234cad71b31253d8d17e59a1abb3be590f56 Mon Sep 17 00:00:00 2001 From: Chris MacNaughton Date: Thu, 16 Apr 2020 11:53:35 +0200 Subject: [PATCH] Update to migrate bits out to Zaza --- ..._zaza_utilities_parallel_series_upgrade.py | 33 ++------ .../utilities/parallel_series_upgrade.py | 84 ++----------------- 2 files changed, 18 insertions(+), 99 deletions(-) diff --git a/unit_tests/utilities/test_zaza_utilities_parallel_series_upgrade.py b/unit_tests/utilities/test_zaza_utilities_parallel_series_upgrade.py index 616c590..aefa00b 100644 --- a/unit_tests/utilities/test_zaza_utilities_parallel_series_upgrade.py +++ b/unit_tests/utilities/test_zaza_utilities_parallel_series_upgrade.py @@ -179,6 +179,9 @@ class TestParallelSeriesUpgrade(AioTestCase): self.async_block_until = mock.AsyncMock() self.model.async_block_until = self.async_block_until + self.model.async_wait_for_unit_idle = mock.AsyncMock() + self.async_run_on_machine = mock.AsyncMock() + self.model.async_run_on_machine = self.async_run_on_machine @mock.patch.object(upgrade_utils.cl_utils, 'get_class') async def test_run_post_application_upgrade_functions( @@ -520,13 +523,12 @@ class TestParallelSeriesUpgrade(AioTestCase): pause_non_leader_primary=False) self.async_run_action.assert_not_called() - @mock.patch.object(upgrade_utils, 'run_on_machine') - async def test_async_do_release_upgrade(self, mock_run_on_machine): + async def test_async_do_release_upgrade(self): await upgrade_utils.async_do_release_upgrade('1') do_release_upgrade_cmd = ( 'yes | sudo DEBIAN_FRONTEND=noninteractive ' 'do-release-upgrade -f DistUpgradeViewNonInteractive') - mock_run_on_machine.assert_called_once_with( + self.async_run_on_machine.assert_called_once_with( '1', do_release_upgrade_cmd, timeout='120m' ) @@ -538,37 +540,20 @@ class TestParallelSeriesUpgrade(AioTestCase): '1', to_series='xenial' ) - @mock.patch.object(upgrade_utils, 'run_on_machine') - async def test_reboot(self, mock_run_on_machine): + async def test_reboot(self): await upgrade_utils.reboot('1') - mock_run_on_machine.assert_called_once_with( + self.async_run_on_machine.assert_called_once_with( '1', 'sudo init 6 & exit' ) - async def test_run_on_machine(self): - await upgrade_utils.run_on_machine('1', 'test') - self.check_call.assert_called_once_with( - ['juju', 'run', '--machine=1', 'test']) - - async def test_run_on_machine_with_timeout(self): - await upgrade_utils.run_on_machine('1', 'test', timeout='20m') - self.check_call.assert_called_once_with( - ['juju', 'run', '--machine=1', '--timeout=20m', 'test']) - - async def test_run_on_machine_with_model(self): - await upgrade_utils.run_on_machine('1', 'test', model_name='test') - self.check_call.assert_called_once_with( - ['juju', 'run', '--machine=1', '--model=test', 'test']) - - @mock.patch.object(upgrade_utils, 'run_on_machine') - async def test_async_dist_upgrade(self, mock_run_on_machine): + async def test_async_dist_upgrade(self): await upgrade_utils.async_dist_upgrade('1') apt_update_command = ( """yes | sudo DEBIAN_FRONTEND=noninteractive """ """apt-get --assume-yes """ """-o "Dpkg::Options::=--force-confdef" """ """-o "Dpkg::Options::=--force-confold" dist-upgrade""") - mock_run_on_machine.assert_has_calls([ + self.async_run_on_machine.assert_has_calls([ mock.call('1', 'sudo apt-get update'), mock.call('1', apt_update_command), ]) diff --git a/zaza/openstack/utilities/parallel_series_upgrade.py b/zaza/openstack/utilities/parallel_series_upgrade.py index 980f556..eea2edb 100755 --- a/zaza/openstack/utilities/parallel_series_upgrade.py +++ b/zaza/openstack/utilities/parallel_series_upgrade.py @@ -18,7 +18,6 @@ import asyncio -import concurrent import collections import copy import logging @@ -208,7 +207,7 @@ async def parallel_series_upgrade( await series_upgrade_utils.async_set_series( application, to_series=to_series) app_idle = [ - wait_for_unit_idle(unit) for unit in status["units"] + model.async_wait_for_unit_idle(unit) for unit in status["units"] ] await asyncio.gather(*app_idle) prepare_group = [ @@ -309,7 +308,7 @@ async def serial_series_upgrade( await series_upgrade_utils.async_set_series( application, to_series=to_series) if not follower_first and leader_machine not in completed_machines: - await wait_for_unit_idle(leader) + await model.async_wait_for_unit_idle(leader) await prepare_series_upgrade(leader_machine, to_series=to_series) logging.info("About to upgrade leader of {}: {}" .format(application, leader_machine)) @@ -326,7 +325,7 @@ async def serial_series_upgrade( machine = unit['machine'] if machine in completed_machines: continue - await wait_for_unit_idle(unit_name) + await model.async_wait_for_unit_idle(unit_name) await prepare_series_upgrade(machine, to_series=to_series) logging.info("About to upgrade follower of {}: {}" .format(application, machine)) @@ -339,7 +338,7 @@ async def serial_series_upgrade( completed_machines.append(machine) if follower_first and leader_machine not in completed_machines: - await wait_for_unit_idle(leader) + await model.async_wait_for_unit_idle(leader) await prepare_series_upgrade(leader_machine, to_series=to_series) logging.info("About to upgrade leader of {}: {}" .format(application, leader_machine)) @@ -530,37 +529,13 @@ async def reboot(machine): :rtype: None """ try: - await run_on_machine(machine, 'sudo init 6 & exit') + await model.async_run_on_machine(machine, 'sudo init 6 & exit') # await run_on_machine(unit, "sudo reboot && exit") except subprocess.CalledProcessError as e: logging.warn("Error doing reboot: {}".format(e)) pass -async def run_on_machine(machine, command, model_name=None, timeout=None): - """Juju run on unit. - - :param model_name: Name of model unit is in - :type model_name: str - :param unit_name: Name of unit to match - :type unit: str - :param command: Command to execute - :type command: str - :param timeout: How long in seconds to wait for command to complete - :type timeout: int - :returns: action.data['results'] {'Code': '', 'Stderr': '', 'Stdout': ''} - :rtype: dict - """ - cmd = ['juju', 'run', '--machine={}'.format(machine)] - if model_name: - cmd.append('--model={}'.format(model_name)) - if timeout: - cmd.append('--timeout={}'.format(timeout)) - cmd.append(command) - logging.info("About to call '{}'".format(cmd)) - await os_utils.check_call(cmd) - - async def async_dist_upgrade(machine): """Run dist-upgrade on unit after update package db. @@ -571,14 +546,14 @@ async def async_dist_upgrade(machine): """ logging.info('Updating package db ' + machine) update_cmd = 'sudo apt-get update' - await run_on_machine(machine, update_cmd) + await model.async_run_on_machine(machine, update_cmd) logging.info('Updating existing packages ' + machine) dist_upgrade_cmd = ( """yes | sudo DEBIAN_FRONTEND=noninteractive apt-get --assume-yes """ """-o "Dpkg::Options::=--force-confdef" """ """-o "Dpkg::Options::=--force-confold" dist-upgrade""") - await run_on_machine(machine, dist_upgrade_cmd) + await model.async_run_on_machine(machine, dist_upgrade_cmd) async def async_do_release_upgrade(machine): @@ -594,46 +569,5 @@ async def async_do_release_upgrade(machine): 'yes | sudo DEBIAN_FRONTEND=noninteractive ' 'do-release-upgrade -f DistUpgradeViewNonInteractive') - await run_on_machine(machine, do_release_upgrade_cmd, timeout="120m") - - -# TODO: Move these functions into zaza.model -async def wait_for_unit_idle(unit_name, timeout=600): - """Wait until the unit's agent is idle. - - :param unit_name: The unit name of the application, ex: mysql/0 - :type unit_name: str - :param timeout: How long to wait before timing out - :type timeout: int - :returns: None - :rtype: None - """ - app = unit_name.split('/')[0] - try: - await model.async_block_until( - _unit_idle(app, unit_name), - timeout=timeout) - except concurrent.futures._base.TimeoutError: - raise model.ModelTimeout("Zaza has timed out waiting on {} to " - "reach idle state.".format(unit_name)) - - -def _unit_idle(app, unit_name): - async def f(): - x = await get_agent_status(app, unit_name) - return x == "idle" - return f - - -async def get_agent_status(app, unit_name): - """Get the current status of the specified unit. - - :param app: The name of the Juju application, ex: mysql - :type app: str - :param unit_name: The unit name of the application, ex: mysql/0 - :type unit_name: str - :returns: The agent status, either active / idle, returned by Juju - :rtype: str - """ - return (await model.async_get_status()). \ - applications[app]['units'][unit_name]['agent-status']['status'] + await model.async_run_on_machine( + machine, do_release_upgrade_cmd, timeout="120m")