diff --git a/config_tempest/constants.py b/config_tempest/constants.py index 5580edbd..1de8f917 100644 --- a/config_tempest/constants.py +++ b/config_tempest/constants.py @@ -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 = { diff --git a/config_tempest/flavors.py b/config_tempest/flavors.py index 658e0ef2..67479b51 100644 --- a/config_tempest/flavors.py +++ b/config_tempest/flavors.py @@ -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] diff --git a/config_tempest/main.py b/config_tempest/main.py index 8a3dcd73..1ee27dd6 100755 --- a/config_tempest/main.py +++ b/config_tempest/main.py @@ -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, diff --git a/config_tempest/tests/test_flavors.py b/config_tempest/tests/test_flavors.py index 31c28bd1..198ff6dd 100644 --- a/config_tempest/tests/test_flavors.py +++ b/config_tempest/tests/test_flavors.py @@ -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 diff --git a/doc/source/admin/admin_usage.rst b/doc/source/admin/admin_usage.rst index 059d744d..d7d00008 100644 --- a/doc/source/admin/admin_usage.rst +++ b/doc/source/admin/admin_usage.rst @@ -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 \ + --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 diff --git a/doc/source/user/usage.rst b/doc/source/user/usage.rst index 9ca91542..140cdad8 100644 --- a/doc/source/user/usage.rst +++ b/doc/source/user/usage.rst @@ -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? `_ 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 = -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. \ No newline at end of file + exception.