James Parker 071426c223 Test resize with mem_page_size in flavor
These tests are meant to address issue [1]. It adds three new testcases:

 * test_hugepage_resize_keyword_large_to_small
 * test_hugepage_resize_explicit_pagesize_to_small
 * test_hugepage_resize_explicit_size_to_size

All three tests follow the same basic procedure, spawn a guest with a
flavor using hw:mem_page_size:<size_a>, resize the guest to a flavor
with a different size hw:mem_page_size:<size_b>, and then resize the
guest back to the original flavor. Throughout the tests XML checks are
conducted to ensure the page size is accurate for the present flavor.

Instead of trying to dynamically determine the hugepage sizes configured
on the computes, a new config parameter was added to define what
hugepage sizes are available on the host. To avoid dynamic ram
calculation sizes for the guest based on available hugepages, a guest
ram parameter was also added so users may define the size to use when
spawning guests.

We also need a new job that has multiple hugepage sizes configured. We
cannot use our existing whitebox-devstack-multinode job because that
one runs tests that dynamically turn on file backed memory, which is
incompatible with hugepages. This commit adds tasks into job setup
that allows for the setup of hugepages.

In our devstack plugin.sh, we set track_instance_changes to True
(devstack defaults it to False) to make sure the scheduler has the
latest information about available huge pages, and avoid a race
whereing instances failed to schedule because our lone 1G page
still appeared used by an instance that had actually beed fully
deleted.

[1] https://bugs.launchpad.net/nova/+bug/1831269

Change-Id: I5282df3b20c24a909f3b7bb97214206bc07e5b91
2024-04-18 08:18:56 +02:00

197 lines
8.6 KiB
Python

# Copyright 2022 Red Hat Inc.
# All Rights Reserved.
#
# 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 tempest import config
import testtools
from whitebox_tempest_plugin.api.compute import base
from oslo_log import log as logging
CONF = config.CONF
LOG = logging.getLogger(__name__)
class HugePageResize(base.BaseWhiteboxComputeTest):
@classmethod
def skip_checks(cls):
super(HugePageResize, cls).skip_checks()
if len(getattr(CONF.whitebox_hardware,
'configured_hugepage_sizes')) == 0:
msg = "configured_hugepage_sizes in whitebox-hardware is not " \
"present"
raise cls.skipException(msg)
def _get_xml_hugepage_size(self, server_id):
"""Analyze the hugepage xml element(s) from a provided instance. Expect
to find only one hugepage element in the domain. Return boolean result
comparing if the found page size is equal to the expected page size.
"""
huge_pages_list = self._get_hugepage_xml_element(server_id)
self.assertEqual(1, len(huge_pages_list), "Expected to find 1 "
"hugepage XML element on server %s but found %s"
% (server_id, len(huge_pages_list)))
huge_page_xml = huge_pages_list[0]
return int(huge_page_xml.attrib['size'])
def test_hugepage_resize_large_to_small(self):
"""Resize a guest with large hugepages to small hugepages and back
Create a guest using a flavor with hw:mem_page_size:large, resize it
to a flavor with hw:mem_page_size:small, and then resize it back to
the original flavor
"""
flavor_a = self.create_flavor(
ram=str(CONF.whitebox.hugepage_guest_ram_size),
extra_specs={'hw:mem_page_size': 'large'})
server = self.create_test_server(flavor=flavor_a['id'],
wait_until='ACTIVE')
# Cannot assume the exact pagesize of the guest, verify the backing
# memory element is present on the guest and the found size is greater
# than or equal to the smallest potential size configured in the
# environment
large_page_size = self._get_xml_hugepage_size(server['id'])
minimum_pagesize_threshold = \
min(CONF.whitebox_hardware.configured_hugepage_sizes)
self.assertTrue(
large_page_size >= minimum_pagesize_threshold,
"Pagesize found %s should be greater than or equal to pagesize "
"of %s for server %s" %
(large_page_size, minimum_pagesize_threshold, server['id'])
)
# Resize the guest using a flavor with hw:mem_page_size:small,
# memory backing element should not be present on guest currently so
# no need for XML verification
flavor_b = self.create_flavor(
ram=str(CONF.whitebox.hugepage_guest_ram_size),
extra_specs={'hw:mem_page_size': 'small'})
self.resize_server(server['id'], flavor_b['id'])
# Resize instance back to staring flavor size and repeat XML check of
# the guest
self.resize_server(server['id'], flavor_a['id'])
large_page_size = self._get_xml_hugepage_size(server['id'])
self.assertTrue(
large_page_size >= minimum_pagesize_threshold,
"After resizing back to original flavor, pagesize found %s should "
"be greater than or equal to pagesize of %s for server %s" %
(large_page_size, minimum_pagesize_threshold, server['id'])
)
def test_hugepage_resize_size_to_small(self):
"""Resize a guest with a specified hugepage size to small hugepages
Create a guest using a flavor with using an explicit hugepage size(s),
based on what is configured in whitebox_hardware. Resize the guest to a
flavor with hw:mem_page_size:small, and then resize it back to the
original flavor. Repeat this process for every hugepage size configured
in in whitebox_hardware.configured_hugepage_sizes
"""
flavor_small = self.create_flavor(
ram=str(CONF.whitebox.hugepage_guest_ram_size),
extra_specs={'hw:mem_page_size': 'small'})
# Create a flavor and launch an instance based on every configured
# hugepage size in the deployment.
for page_size in CONF.whitebox_hardware.configured_hugepage_sizes:
flavor_a = self.create_flavor(
ram=str(CONF.whitebox.hugepage_guest_ram_size),
extra_specs={'hw:mem_page_size': str(page_size)})
server = self.create_test_server(flavor=flavor_a['id'],
wait_until='ACTIVE')
size_found = self._get_xml_hugepage_size(server['id'])
self.assertTrue(
page_size == size_found,
"Expected pagesize of %s not found on server %s instead "
"found %s" % (page_size, server['id'], size_found)
)
# Resize the guest using a flavor with hw:mem_page_size:small,
# memory backing will not be present in with guest so follow up
# XML verification is not necessary
self.resize_server(server['id'], flavor_small['id'])
# Resize back to its original size and confirm memory backing
# element is present and has the correct size
self.resize_server(server['id'], flavor_a['id'])
size_found = self._get_xml_hugepage_size(server['id'])
self.assertTrue(
page_size == size_found,
"Expected pagesize of %s not found on server %s after "
"resizing back to original flavor size, instead found %s" %
(page_size, server['id'], size_found)
)
self.delete_server(server['id'])
@testtools.skipUnless(
len(CONF.whitebox_hardware.configured_hugepage_sizes) > 1,
'Need at least 2 configured hugepage sizes to execute test')
def test_hugepage_resize_size_to_size(self):
"""Resize a guest with a specified hugepage size to another size
Create two flavors based on the two provided hugepage sizes. The
flavors created use explicit sizes Create a
server using the first flavor, resize the guest to the second flavor,
and resize back to the original spec
"""
start_size, target_size = \
CONF.whitebox_hardware.configured_hugepage_sizes
flavor_a = self.create_flavor(
ram=str(CONF.whitebox.hugepage_guest_ram_size),
extra_specs={'hw:mem_page_size': str(start_size)})
server = self.create_test_server(flavor=flavor_a['id'],
wait_until='ACTIVE')
size_found = self._get_xml_hugepage_size(server['id'])
self.assertTrue(
start_size == size_found,
"Expected pagesize of %s not found on server %s instead "
"found %s" % (start_size, server['id'], size_found)
)
flavor_b = self.create_flavor(
ram=str(CONF.whitebox.hugepage_guest_ram_size),
extra_specs={'hw:mem_page_size': str(target_size)})
# Resize to the target size and confirm memory backing element is
# present and has the correct size
self.resize_server(server['id'], flavor_b['id'])
size_found = self._get_xml_hugepage_size(server['id'])
self.assertTrue(
target_size == size_found,
"Expected pagesize of %s not found on server %s after resize "
"instead found %s" % (target_size, server['id'], size_found)
)
# Resize back to its original size and confirm memory backing
# element is present and has the correct size
self.resize_server(server['id'], flavor_a['id'])
size_found = self._get_xml_hugepage_size(server['id'])
self.assertTrue(
start_size == size_found,
"Expected pagesize of %s not found on server %s after resizing "
"back to original flavor size, instead found %s" %
(start_size, server['id'], size_found)
)