Pass images list to prestage playbook if uploaded

Previously the uploaded images list is not passed to prestage playbook
if the prestage source is local. This commit ensures the images list
is passed to the prestage playbook regardless of the prestage source.

Test Plan:
  - Verify that the images specified in the uploaded list are
    prestaged for both previous and current release.
  - Verify that images prestage is skipped if the images list file
    has not been uploaded and the subcloud is running a different
    release than the prestage release (i.e. prestage source is
    remote).
  - Verify that images are prestaged if the subcloud is running
    the same release as the prestage release (i.e. prestage source
    is local) regardless of the existence of the prestage images list.

Story: 2010798
Task: 48392

Signed-off-by: Tee Ngo <tee.ngo@windriver.com>
Change-Id: Ide6a5c449cf94325f34eb367c704e5ad72423fa5
This commit is contained in:
Tee Ngo 2023-07-14 13:08:05 -04:00
parent 0cd5c53933
commit 8fd60fe186
2 changed files with 124 additions and 53 deletions

View File

@ -378,58 +378,57 @@ def prestage_packages(context, subcloud, payload):
def prestage_images(context, subcloud, payload):
"""Run the prestage images ansible script.
Approach:
If the prestage images file has been uploaded, include the fully
qualified path name in the extra vars before invoking the prestage_images.yml
playbook.
If the prestage images file has been uploaded for the target software
version then pass the image_list_file to the prestage_images.yml playbook
If the images file does not exist and the prestage source is remote,
skip calling prestage_images.yml playbook.
If the prestage images file has not been uploaded, only proceed
with images prestage if the prestage source is local.
Ensure the final state is either prestage-failed or prestage-complete
regardless of whether prestage_images.yml playbook is executed or skipped.
"""
prestage_software_version = payload.get(
consts.PRESTAGE_REQUEST_RELEASE, SW_VERSION)
local = is_local(subcloud.software_version, prestage_software_version)
extra_vars_str = "software_version=%s" % prestage_software_version
image_list_file = None
image_list_filename = None
deploy_dir = os.path.join(DEPLOY_BASE_DIR, prestage_software_version)
if not local:
image_list_filename = None
if os.path.isdir(deploy_dir):
image_list_filename = utils.get_filename_by_prefix(deploy_dir,
'prestage_images')
if image_list_filename:
image_list_file = os.path.join(deploy_dir, image_list_filename)
# include this file in the ansible args:
extra_vars_str += (" image_list_file=%s" % image_list_file)
LOG.debug("prestage images list file: %s", image_list_file)
else:
LOG.debug("prestage images list file does not exist")
# There are only two scenarios where we want to run ansible
# for prestaging images:
# 1. local
# 2. remote, with supplied image list
if local or ((not local) and image_list_file):
# Ansible inventory filename for the specified subcloud
ansible_subcloud_inventory_file = \
utils.get_ansible_filename(subcloud.name,
ANSIBLE_PRESTAGE_INVENTORY_SUFFIX)
_run_ansible(context,
["ansible-playbook",
ANSIBLE_PRESTAGE_SUBCLOUD_IMAGES_PLAYBOOK,
"--inventory", ansible_subcloud_inventory_file,
"--extra-vars", extra_vars_str],
"images",
subcloud,
consts.PRESTAGE_STATE_IMAGES,
payload['sysadmin_password'],
payload['oam_floating_ip'],
prestage_software_version,
ansible_subcloud_inventory_file,
timeout_seconds=CONF.playbook_timeout * 2)
if os.path.isdir(deploy_dir):
image_list_filename = utils.get_filename_by_prefix(deploy_dir,
'prestage_images')
if image_list_filename:
image_list_file = os.path.join(deploy_dir, image_list_filename)
# include this file in the ansible args:
extra_vars_str += (" image_list_file=%s" % image_list_file)
LOG.debug("prestage images list file: %s", image_list_file)
else:
LOG.info("Skipping ansible prestage images step, is_local: %s,"
" image_list_file: %s", local, image_list_file)
LOG.debug("prestage images list file does not exist")
if prestage_software_version != subcloud.software_version:
# Prestage source is remote but there is no images list file so
# skip the images prestage.
LOG.info("Images prestage is skipped for %s as the prestage images "
"list for release %s has not been uploaded and the "
"subcloud is running a different load than %s."
% (subcloud.name, prestage_software_version,
prestage_software_version))
return
# Ansible inventory filename for the specified subcloud
ansible_subcloud_inventory_file = \
utils.get_ansible_filename(subcloud.name,
ANSIBLE_PRESTAGE_INVENTORY_SUFFIX)
_run_ansible(context,
["ansible-playbook",
ANSIBLE_PRESTAGE_SUBCLOUD_IMAGES_PLAYBOOK,
"--inventory", ansible_subcloud_inventory_file,
"--extra-vars", extra_vars_str],
"images",
subcloud,
consts.PRESTAGE_STATE_IMAGES,
payload['sysadmin_password'],
payload['oam_floating_ip'],
prestage_software_version,
ansible_subcloud_inventory_file,
timeout_seconds=CONF.playbook_timeout * 2)

View File

@ -2211,13 +2211,11 @@ class TestSubcloudManager(base.DCManagerTestCase):
in str(e))
@mock.patch.object(os_path, 'isdir')
@mock.patch.object(os_path, 'exists')
@mock.patch.object(cutils, 'get_filename_by_prefix')
@mock.patch.object(prestage, '_run_ansible')
def test_prestage_remote_pass(self, mock_run_ansible,
mock_get_filename_by_prefix,
mock_file_exists,
mock_isdir):
def test_prestage_remote_pass_with_img_list(self, mock_run_ansible,
mock_get_filename_by_prefix,
mock_isdir):
values = copy.copy(FAKE_PRESTAGE_PAYLOAD)
subcloud = self.create_subcloud_static(self.ctx,
@ -2225,11 +2223,10 @@ class TestSubcloudManager(base.DCManagerTestCase):
deploy_status=consts.DEPLOY_STATE_NONE,
software_version=FAKE_SUBCLOUD_SW_VERSION)
prestage._prestage_standalone_thread(self.ctx, subcloud, payload=values)
mock_run_ansible.return_value = None
mock_get_filename_by_prefix.return_value = 'prestage_images_list.txt'
mock_file_exists.return_value = True
mock_isdir.return_value = True
prestage._prestage_standalone_thread(self.ctx, subcloud, payload=values)
# Verify that subcloud has the correct deploy status
updated_subcloud = db_api.subcloud_get_by_name(self.ctx, subcloud.name)
@ -2248,8 +2245,42 @@ class TestSubcloudManager(base.DCManagerTestCase):
self.assertTrue(
FAKE_PRESTAGE_RELEASE in mock_run_ansible.call_args_list[1].args[1][5])
@mock.patch.object(os_path, 'isdir')
@mock.patch.object(cutils, 'get_filename_by_prefix')
@mock.patch.object(prestage, '_run_ansible')
def test_prestage_local_pass(self, mock_run_ansible):
def test_prestage_remote_pass_without_img_list(self, mock_run_ansible,
mock_get_filename_by_prefix,
mock_isdir):
values = copy.copy(FAKE_PRESTAGE_PAYLOAD)
subcloud = self.create_subcloud_static(self.ctx,
name='subcloud1',
deploy_status=consts.DEPLOY_STATE_NONE,
software_version=FAKE_SUBCLOUD_SW_VERSION)
mock_run_ansible.return_value = None
mock_get_filename_by_prefix.return_value = None
mock_isdir.return_value = True
prestage._prestage_standalone_thread(self.ctx, subcloud, payload=values)
# Verify that subcloud has the correct deploy status
updated_subcloud = db_api.subcloud_get_by_name(self.ctx, subcloud.name)
self.assertEqual(consts.PRESTAGE_STATE_COMPLETE,
updated_subcloud.deploy_status)
# Verify that only prestage package playbook is called
self.assertEqual(mock_run_ansible.call_count, 1)
# Verify the prestage request release was passed to the playbooks
self.assertTrue(
FAKE_PRESTAGE_RELEASE in mock_run_ansible.call_args_list[0].args[1][5])
@mock.patch.object(os_path, 'isdir')
@mock.patch.object(cutils, 'get_filename_by_prefix')
@mock.patch.object(prestage, '_run_ansible')
def test_prestage_local_pass_with_img_list(self, mock_run_ansible,
mock_get_filename_by_prefix,
mock_isdir):
values = copy.copy(FAKE_PRESTAGE_PAYLOAD)
subcloud = self.create_subcloud_static(self.ctx,
@ -2257,8 +2288,10 @@ class TestSubcloudManager(base.DCManagerTestCase):
deploy_status=consts.DEPLOY_STATE_NONE,
software_version=FAKE_PRESTAGE_RELEASE)
prestage._prestage_standalone_thread(self.ctx, subcloud, payload=values)
mock_run_ansible.return_value = None
mock_get_filename_by_prefix.return_value = 'prestage_images_list.txt'
mock_isdir.return_value = True
prestage._prestage_standalone_thread(self.ctx, subcloud, payload=values)
# Verify that subcloud has the correct deploy status
updated_subcloud = db_api.subcloud_get_by_name(self.ctx, subcloud.name)
@ -2267,6 +2300,45 @@ class TestSubcloudManager(base.DCManagerTestCase):
# Verify both of prestage package and image ansible playbooks were called
self.assertEqual(mock_run_ansible.call_count, 2)
# Verify the "image_list_file" was passed to the prestage image playbook
# for the local prestage
self.assertTrue(
'image_list_file' in mock_run_ansible.call_args_list[1].args[1][5])
# Verify the prestage request release was passed to the playbooks
self.assertTrue(
FAKE_PRESTAGE_RELEASE in mock_run_ansible.call_args_list[0].args[1][5])
self.assertTrue(
FAKE_PRESTAGE_RELEASE in mock_run_ansible.call_args_list[1].args[1][5])
@mock.patch.object(os_path, 'isdir')
@mock.patch.object(cutils, 'get_filename_by_prefix')
@mock.patch.object(prestage, '_run_ansible')
def test_prestage_local_pass_without_img_list(self, mock_run_ansible,
mock_get_filename_by_prefix,
mock_isdir):
values = copy.copy(FAKE_PRESTAGE_PAYLOAD)
subcloud = self.create_subcloud_static(self.ctx,
name='subcloud1',
deploy_status=consts.DEPLOY_STATE_NONE,
software_version=FAKE_PRESTAGE_RELEASE)
mock_run_ansible.return_value = None
mock_get_filename_by_prefix.return_value = None
mock_isdir.return_value = True
prestage._prestage_standalone_thread(self.ctx, subcloud, payload=values)
# Verify that subcloud has the correct deploy status
updated_subcloud = db_api.subcloud_get_by_name(self.ctx, subcloud.name)
self.assertEqual(consts.PRESTAGE_STATE_COMPLETE,
updated_subcloud.deploy_status)
# Verify both of prestage package and image ansible playbooks were called
self.assertEqual(mock_run_ansible.call_count, 2)
# Verify the "image_list_file" was not passed to the prestage image playbook
# for the local prestage
self.assertTrue(
'image_list_file' not in mock_run_ansible.call_args_list[1].args[1][5])
# Verify the prestage request release was passed to the playbooks
self.assertTrue(
FAKE_PRESTAGE_RELEASE in mock_run_ansible.call_args_list[0].args[1][5])