Allow to specify min flavor memory and disk size

python-tempestconf doesn't provide any way how to define a
different flavor memory and disk size but provides an option
for defining a custom image (not cirros which is default).
However, when using custom image the default flavor size is
not enough.
Therefore the review adds two arguments which can be used
for defining flavor minimum memory and minimum disk size.

The review also edits the documentation and fixes a few typos.

Change-Id: Iba14b65ff8e147765e47d223dea6231ab649135f
Story: 2001536
Task: 6341
changes/96/647696/9
Martin Kopec 4 years ago
parent dbb2711c59
commit cdc0266de5
  1. 5
      config_tempest/constants.py
  2. 58
      config_tempest/flavors.py
  3. 10
      config_tempest/main.py
  4. 24
      config_tempest/tests/test_flavors.py
  5. 15
      doc/source/admin/admin_usage.rst
  6. 49
      doc/source/user/usage.rst

@ -27,6 +27,11 @@ DEFAULT_IMAGE = ("http://download.cirros-cloud.net/0.3.5/"
"cirros-0.3.5-x86_64-disk.img")
DEFAULT_IMAGE_FORMAT = 'qcow2'
DEFAULT_FLAVOR_RAM = 64
DEFAULT_FLAVOR_RAM_ALT = 128
DEFAULT_FLAVOR_DISK = 1
DEFAULT_FLAVOR_VCPUS = 1
# The dict holds the credentials, which are not supposed to be printed
# to a tempest.conf when --test-accounts CLI parameter is used.
ALL_CREDENTIALS_KEYS = {

@ -15,11 +15,12 @@
from operator import itemgetter
from config_tempest.constants import LOG
from config_tempest import constants as C
class Flavors(object):
def __init__(self, client, allow_creation, conf, no_rng=False):
def __init__(self, client, allow_creation, conf, min_memory, min_disk,
no_rng=False):
"""Init.
:type client: FlavorsClient object from tempest lib
@ -29,22 +30,31 @@ class Flavors(object):
self.client = client
self.allow_creation = allow_creation
self._conf = conf
self.no_rng = no_rng
self.flavor_list = self.client.list_flavors()['flavors']
min_memory_alt = C.DEFAULT_FLAVOR_RAM_ALT
name = 'm1.nano'
name_alt = 'm1.micro'
if min_memory != C.DEFAULT_FLAVOR_RAM:
min_memory_alt = min_memory + 1
name = 'custom'
name_alt = 'custom_alt'
self._conf.set('volume', 'volume_size', str(min_disk))
self.prefs = [
{'key': 'flavor_ref', 'name': name, 'ram': min_memory,
'disk': min_disk, 'no_rng': no_rng},
{'key': 'flavor_ref_alt', 'name': name_alt,
'ram': min_memory_alt, 'disk': min_disk, 'no_rng': no_rng}
]
def create_tempest_flavors(self):
"""Find or create flavors and set them in conf.
If 'flavor_ref' and 'flavor_ref_alt' are specified in conf, it will
try to find them, if not found, it raises an Exception.
Otherwise it will try finding or creating 'm1.nano' and 'm1.micro'
flavors and set their ids in conf.
Otherwise it will try finding or creating the required base flavors
(m1.nano and m1.micro by default) and set their ids in conf.
"""
prefs = [
{'key': 'flavor_ref', 'name': 'm1.nano', 'ram': 64},
{'key': 'flavor_ref_alt', 'name': 'm1.micro', 'ram': 128}
]
for pref in prefs:
for pref in self.prefs:
flavor_id = None
if self._conf.has_option('compute', pref['key']):
flavor_id = self._conf.get('compute', pref['key'])
@ -53,13 +63,13 @@ class Flavors(object):
raise Exception("%s id '%s' specified by user doesn't"
" exist", pref['key'], flavor_id)
else:
# create m1.nano/m1.micro flavor
flavor_id = self.create_flavor(pref['name'], ram=pref['ram'],
no_rng=self.no_rng)
flavor_id = self.create_flavor(pref['name'], pref['ram'],
C.DEFAULT_FLAVOR_VCPUS,
pref['disk'],
no_rng=pref['no_rng'])
self._conf.set('compute', pref['key'], flavor_id)
def create_flavor(self, flavor_name, ram=64, vcpus=1,
disk=1, no_rng=False):
def create_flavor(self, flavor_name, ram, vcpus, disk, no_rng=False):
"""Create flavors or try to discover two smallest ones available.
:param flavor_name: flavor name to be created (usually m1.nano or
@ -71,10 +81,10 @@ class Flavors(object):
"""
flavor_id = self.find_flavor_by_name(flavor_name)
if flavor_id is not None:
LOG.info("(no change) Found flavor '%s'", flavor_name)
C.LOG.info("(no change) Found flavor '%s'", flavor_name)
return flavor_id
elif self.allow_creation:
LOG.info("Creating flavor '%s'", flavor_name)
C.LOG.info("Creating flavor '%s'", flavor_name)
resp = self.client.create_flavor(name=flavor_name,
ram=ram, vcpus=vcpus,
disk=disk, id=None)
@ -101,8 +111,8 @@ class Flavors(object):
"""
found = [f for f in self.flavor_list if f['id'] == flavor_id]
if found:
LOG.info("Found flavor '%s' by it's id '%s'",
found[0]['name'], flavor_id)
C.LOG.info("Found flavor '%s' by it's id '%s'",
found[0]['name'], flavor_id)
# return flavor's id
return found[0]['id']
return None
@ -127,9 +137,9 @@ class Flavors(object):
smallest flavor found.
:param flavor_name: [m1.nano, m1.micro]
"""
LOG.warning("Flavor '%s' not found and creation is not allowed. "
"Trying to autodetect the smallest flavor available.",
flavor_name)
C.LOG.warning("Flavor '%s' not found and creation is not allowed. "
"Trying to autodetect the smallest flavor available.",
flavor_name)
flavors = []
for flavor in self.flavor_list:
f = self.client.show_flavor(flavor['id'])['flavor']
@ -145,7 +155,7 @@ class Flavors(object):
f = flavors[1]
else:
f = flavors[0]
LOG.warning("Found '%s' flavor (id: '%s', ram: '%s', disk: '%s', "
"vcpus: '%s') ", f[0], f[1], f[2], f[3], f[4])
C.LOG.warning("Found '%s' flavor (id: '%s', ram: '%s', disk: '%s', "
"vcpus: '%s') ", f[0], f[1], f[2], f[3], f[4])
# return flavor's id
return f[1]

@ -306,6 +306,12 @@ def get_arg_parser():
glance if it's not already there. The name of
the image is the leaf name of the path. Default
is '%s'""" % C.DEFAULT_IMAGE)
parser.add_argument('--flavor-min-mem', default=C.DEFAULT_FLAVOR_RAM,
type=int, help="""Specify minimum memory for new
flavours, default is '%s'.""" % C.DEFAULT_FLAVOR_RAM)
parser.add_argument('--flavor-min-disk', default=C.DEFAULT_FLAVOR_DISK,
type=int, help="""Specify minimum disk size for new
flavours, default is '%s'.""" % C.DEFAULT_FLAVOR_DISK)
parser.add_argument('--network-id',
help="""Specify which network with external connectivity
should be used by the tests.""")
@ -513,6 +519,8 @@ def config_tempest(**kwargs):
users = Users(clients.projects, clients.roles, clients.users, conf)
users.create_tempest_users(services.is_service('orchestration'))
flavors = Flavors(clients.flavors, kwargs.get('create', False), conf,
kwargs.get('flavor_min_mem', C.DEFAULT_FLAVOR_RAM),
kwargs.get('flavor_min_disk', C.DEFAULT_FLAVOR_DISK),
no_rng=kwargs.get('no_rng', False))
flavors.create_tempest_flavors()
@ -569,6 +577,8 @@ def main():
create_accounts_file=args.create_accounts_file,
debug=args.debug,
deployer_input=args.deployer_input,
flavor_min_mem=args.flavor_min_mem,
flavor_min_disk=args.flavor_min_disk,
image_disk_format=args.image_disk_format,
image_path=args.image,
network_id=args.network_id,

@ -17,6 +17,7 @@ from fixtures import MonkeyPatch
import logging
import mock
from config_tempest import constants as C
from config_tempest.flavors import Flavors
from config_tempest.tests.base import BaseConfigTempestTest
@ -44,7 +45,7 @@ class TestFlavors(BaseConfigTempestTest):
mock_function = mock.Mock(return_value=return_value)
self.useFixture(MonkeyPatch(self.CLIENT_MOCK + '.list_flavors',
mock_function))
self.Service = Flavors(self.client, True, self.conf)
self.Service = Flavors(self.client, True, self.conf, 64, 1)
def test_create_tempest_flavors(self):
self.Service.flavor_list = []
@ -54,8 +55,8 @@ class TestFlavors(BaseConfigTempestTest):
self.Service.create_tempest_flavors()
self.assertEqual(self.conf.get('compute', 'flavor_ref'), "FakeID")
self.assertEqual(self.conf.get('compute', 'flavor_ref_alt'), "FakeID")
calls = [mock.call('m1.nano', ram=64, no_rng=False),
mock.call('m1.micro', ram=128, no_rng=False)]
calls = [mock.call('m1.nano', 64, 1, 1, no_rng=False),
mock.call('m1.micro', 128, 1, 1, no_rng=False)]
mock_function.assert_has_calls(calls, any_order=True)
def check_call_of_discover_smallest_flavor(self):
@ -65,7 +66,9 @@ class TestFlavors(BaseConfigTempestTest):
func2mock = 'config_tempest.flavors.Flavors.discover_smallest_flavor'
mock_function = mock.Mock()
self.useFixture(MonkeyPatch(func2mock, mock_function))
self.Service.create_flavor('nano')
self.Service.create_flavor('nano', C.DEFAULT_FLAVOR_RAM,
C.DEFAULT_FLAVOR_VCPUS,
C.DEFAULT_FLAVOR_DISK)
calls = [mock.call('nano')]
mock_function.assert_has_calls(calls, any_order=True)
@ -95,7 +98,9 @@ class TestFlavors(BaseConfigTempestTest):
self.Service.allow_creation = False
self.Service.flavor_list = []
try:
self.Service.create_flavor('name')
self.Service.create_flavor('name', C.DEFAULT_FLAVOR_RAM,
C.DEFAULT_FLAVOR_VCPUS,
C.DEFAULT_FLAVOR_DISK)
except Exception:
return
# it should have ended in the except block above
@ -104,7 +109,9 @@ class TestFlavors(BaseConfigTempestTest):
# not enough flavors found
self.Service.flavor_list = [{'id': 'FAKE', 'name': 'fake_name'}]
try:
self.Service.create_flavor('name')
self.Service.create_flavor('name', C.DEFAULT_FLAVOR_RAM,
C.DEFAULT_FLAVOR_VCPUS,
C.DEFAULT_FLAVOR_DISK)
except Exception:
return
# it should have ended in the except block above
@ -119,7 +126,10 @@ class TestFlavors(BaseConfigTempestTest):
mock_function = mock.Mock(return_value={})
self.useFixture(MonkeyPatch(client + '.set_flavor_extra_spec',
mock_function))
resp = self.Service.create_flavor(flavor_name="MyID", no_rng=no_rng)
resp = self.Service.create_flavor("MyID", C.DEFAULT_FLAVOR_RAM,
C.DEFAULT_FLAVOR_VCPUS,
C.DEFAULT_FLAVOR_DISK,
no_rng=no_rng)
self.assertEqual(resp, return_value['flavor']['id'])
return mock_function

@ -39,6 +39,21 @@ resources (`Flavors`_ and `Users`_) if they don't exist already:
--os-cloud devstack-admin \
--create
If a user wants to use a custom image (instead of the default cirros one),
a minimum memory and disk size for new flavors can be defined by
``--flavor-min-mem`` and ``--flavor-min-disk`` arguments.
.. code-block:: shell-session
$ discover-tempest-config \
--image <path/url to custom image> \
--flavor-min-mem 1024 \
--flavor-min-disk 10
In the example above ``python-tempestconf`` will create *custom* flavor with
1024 MB of RAM and 10 GB of disk size and *custom_alt** flavor with 1024 + 1 MB
of RAM and 10 GB of disk size.
``python-tempestconf`` can also create a minimal accounts file when
``--create-accounts-file`` is used. It can be useful when a user doesn't have

@ -14,7 +14,7 @@ of the following:
* use ``clouds.yaml`` file and take advantage of ``os-client-config`` support
and use a named cloud, see `Examples of usage with a named cloud`_
If a user doesn't use ``--create``, no resources, which requires admin
If a user doesn't use ``--create``, no resources, which require admin
credentials, are created. See `Resources`_ section.
@ -66,8 +66,8 @@ generated ``tempest.conf`` from one of the two following reasons:
* ``python-tempestconf`` is able to discover it, but a user wants to set it
differently
Values specified as overrides will be set to tempest.conf no matter what if
they were discovered or not. If a section or a key don't exist, they will be
Values specified as overrides will be set to tempest.conf no matter if they
were discovered or not. If a section or a key don't exist, they will be
created.
In the following example we make the tool to print debugging information, we
@ -110,7 +110,7 @@ A user can define key-value pairs which are not wanted to be written to the
generated ``tempest.conf``. This can be useful in case when
``python-tempestconf`` discovers something which is not wanted by a user to
have in ``tempest.conf``. If the option is used, ``python-tempestconf`` will
make sure, that the defined values are not written to tempest.conf no matter
make sure that the defined values are not written to tempest.conf no matter
if they were discovered or not.
.. code-block:: shell-session
@ -120,9 +120,9 @@ if they were discovered or not.
--remove section2.key2=value \
--remove section3.key3=value1,value2
In the following case **all** api_extensions will be removed and tempest.conf
will **not contain** the api_extensions key under compute-feature-enabled
section.
In the following case **all** api_extensions will be removed and
``tempest.conf`` will **not contain** the api_extensions key under
compute-feature-enabled section.
.. code-block:: shell-session
@ -190,7 +190,7 @@ links:
* `how to generate it? <https://docs.openstack.org/tempest/latest/account_generator.html>`_
When ``--test-accounts`` argument is used, ``python-tempestconf`` will not
write any credentials to generated tempest.conf file, it will add a
write any credentials to generated ``tempest.conf`` file, it will add a
**test_accounts_file** key to **auth** section with value equal to the path
provided by the ``--test-accounts`` argument. Also **use_dynamic_credentials**
under **auth** section will be set to False as
@ -210,7 +210,7 @@ If you already have the file created, you can run
--out etc/tempest.conf \
--test-accounts /path/to/my/accounts.yaml
The generated tempest.conf will look like:
The generated ``tempest.conf`` will look like:
.. code-block:: shell-session
@ -272,8 +272,8 @@ Then if you use ``--os-cloud`` argument you can run
:command:`discover-tempest-config` **without** setting any OS_* environment
variable (for example by sourcing any OpenStack RC file).
``--os-cloud`` defines specifies one of the cloud names located in the
``clouds.yaml`` file.
``--os-cloud`` specifies one of the cloud names located in the ``clouds.yaml``
file.
.. code-block:: shell-session
:emphasize-lines: 3
@ -308,7 +308,7 @@ look like:
Resources
---------
Without specifying ``--create`` argument, no resources which requires admin
Without specifying ``--create`` argument, no resources which require admin
credentials are crated during the ``python-tempestconf`` execution. For the
documentation on how to use ``--create`` argument see `Admin User Guide`_
@ -405,10 +405,25 @@ image.
Flavors
+++++++
``python-tempestconf`` looks for these two flavors:
``python-tempestconf`` looks by default for these two flavors:
* *m1.nano* with 64 MB of RAM, which will be set as **compute.flavor_ref**
* *m1.micro* with 128 MB of RAM, which will be set as
**compute.flavor_alt_ref**
If a user used ``--flavor-min-mem`` argument, ``python-tempestconf`` will look
for these two flavors:
* *custom*
* *custom_alt*
.. note::
* m1.nano with 64 MB of RAM, which will be set as **compute.flavor_ref**
* m1.micro with 128 MB of RAM, which will be set as **compute.flavor_alt_ref**
``python-tempestconf`` looks for flavors by name, so if a user has had
a flavor with name *custom*/*custom_alt* already created, those flavors'
IDs will be set as **compute.flavor_ref**/**compute.flavor_ref_alt**
without checking if theirs RAM size is equal to the one specified by
``--flavor-min-mem``.
If they are not found and ``--create`` argument is not used, the tool will try
to auto discover two smallest flavors available in the system. If at least two
@ -435,7 +450,7 @@ The generated tempest.conf will look like:
flavor_alt_ref = <ID_2>
<omitted some content>
In the following example, a `override`_ option specifies **compute.flavor_ref**
In the following example, an `override`_ option specifies **compute.flavor_ref**
ID, which if it's found, the tool continues with looking for a **m1.micro**
flavor to be set as **compute.flavor_alt_ref** as was explained above.
@ -447,4 +462,4 @@ flavor to be set as **compute.flavor_alt_ref** as was explained above.
.. note::
If the **compute.flavor_ref** ID is not found, the tool ends with an
exception.
exception.

Loading…
Cancel
Save