rally-openstack/rally_openstack/contexts/nova/flavors.py

135 lines
4.5 KiB
Python

# Copyright 2014: Mirantis 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 rally.common import logging
from rally.common import utils as rutils
from rally.common import validation
from rally.task import context
from rally_openstack.cleanup import manager as resource_manager
from rally_openstack import consts
from rally_openstack import osclients
LOG = logging.getLogger(__name__)
@validation.add("required_platform", platform="openstack", admin=True)
@context.configure(name="flavors", platform="openstack", order=340)
class FlavorsGenerator(context.Context):
"""Context creates a list of flavors."""
CONFIG_SCHEMA = {
"type": "array",
"$schema": consts.JSON_SCHEMA,
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
},
"ram": {
"type": "integer",
"minimum": 1
},
"vcpus": {
"type": "integer",
"minimum": 1
},
"disk": {
"type": "integer",
"minimum": 0
},
"swap": {
"type": "integer",
"minimum": 0
},
"ephemeral": {
"type": "integer",
"minimum": 0
},
"extra_specs": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"additionalProperties": False,
"required": ["name", "ram"]
}
}
def setup(self):
"""Create list of flavors."""
from novaclient import exceptions as nova_exceptions
self.context["flavors"] = {}
clients = osclients.Clients(self.context["admin"]["credential"])
for flavor_config in self.config:
extra_specs = flavor_config.get("extra_specs")
flavor_config = FlavorConfig(**flavor_config)
try:
flavor = clients.nova().flavors.create(**flavor_config)
except nova_exceptions.Conflict:
msg = "Using existing flavor %s" % flavor_config["name"]
if logging.is_debug():
LOG.exception(msg)
else:
LOG.warning(msg)
continue
if extra_specs:
flavor.set_keys(extra_specs)
self.context["flavors"][flavor_config["name"]] = flavor.to_dict()
LOG.debug("Created flavor with id '%s'" % flavor.id)
def cleanup(self):
"""Delete created flavors."""
mather = rutils.make_name_matcher(*[f["name"] for f in self.config])
resource_manager.cleanup(
names=["nova.flavors"],
admin=self.context["admin"],
superclass=mather,
task_id=self.get_owner_id())
class FlavorConfig(dict):
def __init__(self, name, ram, vcpus=1, disk=0, swap=0, ephemeral=0,
extra_specs=None):
"""Flavor configuration for context and flavor & image validation code.
Context code uses this code to provide default values for flavor
creation. Validation code uses this class as a Flavor instance to
check image validity against a flavor that is to be created by
the context.
:param name: name of the newly created flavor
:param ram: RAM amount for the flavor (MBs)
:param vcpus: VCPUs amount for the flavor
:param disk: disk amount for the flavor (GBs)
:param swap: swap amount for the flavor (MBs)
:param ephemeral: ephemeral disk amount for the flavor (GBs)
:param extra_specs: is ignored
"""
super(FlavorConfig, self).__init__(
name=name, ram=ram, vcpus=vcpus, disk=disk,
swap=swap, ephemeral=ephemeral)
self.__dict__.update(self)