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
This commit is contained in:
parent
dbb2711c59
commit
cdc0266de5
@ -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**
|
||||
* *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::
|
||||
|
||||
``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…
Reference in New Issue
Block a user