Specification for adding an object model that encapsulates the request to launch one or more instances in the cloud. Co-Authored-By: Sylvain Bauza <sbauza@redhat.com> Change-Id: I5d580c98d98d6899ce46b892d64b21c8dd8abe69 Blueprint: request-spec-object
288 lines
9.4 KiB
ReStructuredText
288 lines
9.4 KiB
ReStructuredText
..
|
|
This work is licensed under a Creative Commons Attribution 3.0 Unported
|
|
License.
|
|
|
|
http://creativecommons.org/licenses/by/3.0/legalcode
|
|
|
|
=========================
|
|
Create RequestSpec Object
|
|
=========================
|
|
|
|
https://blueprints.launchpad.net/nova/+spec/request-spec-object
|
|
|
|
Add a structured, documented object that represents a specification for
|
|
launching multiple instances in a cloud.
|
|
|
|
Problem description
|
|
===================
|
|
|
|
The main interface into the scheduler, the `select_destinations()` method,
|
|
accepts a `request_spec` parameter that is a nested dict. This nested dict is
|
|
constructed in `nova.scheduler.utils.build_request_spec()`, however the
|
|
structure of the request spec is not documented anywhere and the filters in the
|
|
scheduler seem to take a laisse faire approach to querying the object during
|
|
scheduling as well as modifying the `request_spec` object during loops of the
|
|
`nova.scheduler.host_manager.HostStateManager.get_filtered_hosts()` method,
|
|
which calls the filter object's `host_passes` object, supplying a
|
|
`filter_properties` parameter, which itself has a key called `request_spec`
|
|
that contains the aforementioned nested dict.
|
|
|
|
This situation makes it very difficult to understand exactly what is going on
|
|
in the scheduler, and cleaning up this parameter in the scheduler interface is
|
|
a pre-requisite to making a properly-versioned and properly-documented
|
|
interface in preparation for a split-out of the scheduler code.
|
|
|
|
|
|
Use Cases
|
|
----------
|
|
|
|
This is a pure refactoring effort for cleaning up all the interfaces in between
|
|
Nova and the scheduler so the scheduler could be split out by the next cycle.
|
|
|
|
Project Priority
|
|
-----------------
|
|
|
|
This blueprint is part of a global effort around the 'scheduler' refactoring
|
|
for helping it to be split out. This has been defined as the 3rd priority for
|
|
this Kilo cycle.
|
|
|
|
|
|
Proposed change
|
|
===============
|
|
|
|
A new class called `RequestSpec` will be created that models a request to
|
|
launch multiple virtual machine instances. The first version of the
|
|
`RequestSpec` object will simply be an objectified version of the current
|
|
dictionary parameter. The scheduler will construct this `RequestSpec` object
|
|
from the `request_spec` dictionary itself.
|
|
|
|
The existing
|
|
`nova.scheduler.utils.build_request_spec` method will be removed in favor of a
|
|
factory method on `nova.objects.request_spec.RequestSpec` that will construct
|
|
a `RequestSpec` from the existing key/value pairs in the `request_spec`
|
|
parameter supplied to `select_destinations`.
|
|
|
|
Alternatives
|
|
------------
|
|
|
|
None.
|
|
|
|
Data model impact
|
|
-----------------
|
|
|
|
This spec is not focusing on persisting the RequestSpec object but another
|
|
blueprint (and a spec) will be proposed with this one as dependency for
|
|
providing a save() method to the RequestSpec object which would allow it to be
|
|
persisted in (probably) instance_extra DB table.
|
|
|
|
REST API impact
|
|
---------------
|
|
|
|
None.
|
|
|
|
Security impact
|
|
---------------
|
|
|
|
None.
|
|
|
|
Notifications impact
|
|
--------------------
|
|
|
|
None.
|
|
|
|
Other end user impact
|
|
---------------------
|
|
|
|
None.
|
|
|
|
Performance Impact
|
|
------------------
|
|
|
|
None.
|
|
|
|
Other deployer impact
|
|
---------------------
|
|
|
|
None.
|
|
|
|
Developer impact
|
|
----------------
|
|
|
|
None, besides making the scheduler call interfaces gradually easier to read
|
|
and understand.
|
|
|
|
|
|
Implementation
|
|
==============
|
|
|
|
The `request_spec` dictionary is currently constructed by the nova-conductor
|
|
when it calls the `nova.scheduler.utils.build_request_spec()` function, which
|
|
looks like this:
|
|
|
|
.. code:: python
|
|
|
|
def build_request_spec(ctxt, image, instances, instance_type=None):
|
|
"""Build a request_spec for the scheduler.
|
|
|
|
The request_spec assumes that all instances to be scheduled are the same
|
|
type.
|
|
"""
|
|
instance = instances[0]
|
|
if isinstance(instance, obj_base.NovaObject):
|
|
instance = obj_base.obj_to_primitive(instance)
|
|
|
|
if instance_type is None:
|
|
instance_type = flavors.extract_flavor(instance)
|
|
# NOTE(comstud): This is a bit ugly, but will get cleaned up when
|
|
# we're passing an InstanceType internal object.
|
|
extra_specs = db.flavor_extra_specs_get(ctxt, instance_type['flavorid'])
|
|
instance_type['extra_specs'] = extra_specs
|
|
request_spec = {
|
|
'image': image or {},
|
|
'instance_properties': instance,
|
|
'instance_type': instance_type,
|
|
'num_instances': len(instances),
|
|
# NOTE(alaski): This should be removed as logic moves from the
|
|
# scheduler to conductor. Provides backwards compatibility now.
|
|
'instance_uuids': [inst['uuid'] for inst in instances]}
|
|
return jsonutils.to_primitive(request_spec)
|
|
|
|
A possible first version of a class interface for the `RequestSpec`
|
|
class would look like this, in order to be as close to a straight conversion
|
|
from the nested dict's keys to object attribute notation:
|
|
|
|
.. code:: python
|
|
|
|
class RequestSpec(base.NovaObject):
|
|
|
|
"""Models the request to launch one or more instances in the cloud."""
|
|
|
|
VERSION = '1.0'
|
|
|
|
fields = {
|
|
'image': fields.DictOfStringsField(nullable=False),
|
|
# instance_properties could eventually be deconstructed into component
|
|
# parts
|
|
'instance_properties': fields.ObjectField('Instance'),
|
|
'instance_type': fields.ObjectField('Flavor', nullable=False),
|
|
'num_instances': fields.IntegerField(default=1),
|
|
}
|
|
|
|
As `request_spec` dictionary is having a deprecated `instance_uuids` field, we
|
|
will not provide this field into the RequestSpec object and instead bump the
|
|
RPC API version and remove it from the dictionary before as a work item.
|
|
|
|
This blueprint does not change the `select_destinations` scheduler RPC API
|
|
method, so we would construct a `nova.objects.request_spec.RequestSpec` object
|
|
*on the nova-scheduler side*, from the `request_spec` dictionary key in the
|
|
`FilterScheduler._schedule()` method, like so:
|
|
|
|
.. code:: python
|
|
|
|
def _schedule(self, context, request_spec, filter_properties):
|
|
"""Returns a list of hosts that meet the required specs,
|
|
ordered by their fitness.
|
|
"""
|
|
elevated = context.elevated()
|
|
request_spec = objects.RequestSpec.from_dict(request_spec)
|
|
instance_type = request_spec.instance_type
|
|
|
|
update_group_hosts = self._setup_instance_group(context,
|
|
filter_properties)
|
|
|
|
config_options = self._get_configuration_options()
|
|
|
|
filter_properties.update({'context': context,
|
|
'request_spec': request_spec,
|
|
'config_options': config_options,
|
|
'instance_type': instance_type})
|
|
|
|
self.populate_filter_properties(request_spec,
|
|
filter_properties)
|
|
|
|
# Find our local list of acceptable hosts by repeatedly
|
|
# filtering and weighing our options. Each time we choose a
|
|
# host, we virtually consume resources on it so subsequent
|
|
# selections can adjust accordingly.
|
|
|
|
# Note: remember, we are using an iterator here. So only
|
|
# traverse this list once. This can bite you if the hosts
|
|
# are being scanned in a filter or weighing function.
|
|
hosts = self._get_all_host_states(elevated)
|
|
|
|
selected_hosts = []
|
|
if instance_uuids:
|
|
num_instances = len(instance_uuids)
|
|
else:
|
|
num_instances = request_spec.num_instances
|
|
for num in xrange(num_instances):
|
|
# Filter local hosts based on requirements ...
|
|
hosts = self.host_manager.get_filtered_hosts(hosts,
|
|
filter_properties, index=num)
|
|
|
|
The final steps of implementing this blueprint would be to change all
|
|
of the scheduler filters to access the original properties via object
|
|
notation instead of dict-notation.
|
|
|
|
As said above in the data model impact section, this blueprint is not targeting
|
|
to persist this object at the moment. We are also not yet removing the
|
|
`filter_properties` dictionary in this blueprint.
|
|
|
|
Assignee(s)
|
|
-----------
|
|
|
|
Primary assignee:
|
|
bauzas
|
|
|
|
Other contributors:
|
|
None
|
|
|
|
Work Items
|
|
----------
|
|
|
|
- Remove `instance_uuids` field from `request_spec` and bump a new version for
|
|
the Scheduler RPC API
|
|
|
|
- Add request spec class to `nova/scheduler/request_spec.py` w/ unit tests
|
|
|
|
- Add a factory classmethod on `nova.scheduler.RequestSpec` that constructs a
|
|
`RequestSpec` object from the *existing* set of instance type extra_specs,
|
|
scheduler_hints, flavor and image objects that are supplied to the
|
|
`nova.scheduler.utils.build_request_spec` function.
|
|
|
|
- Modify `FilterScheduler._schedule()` to construct a `RequestSpec` object
|
|
from the supplied nested `request_spec` dictionary
|
|
|
|
- Convert all filter classes to operate against the `RequestSpec` object
|
|
instead the nested `request_spec` dictionary.
|
|
|
|
- Add developer reference documentation for what the request spec models.
|
|
|
|
Dependencies
|
|
============
|
|
|
|
None.
|
|
|
|
Testing
|
|
=======
|
|
|
|
New unit tests for the request spec objects will be added. The existing unit
|
|
tests of the scheduler filters will be modified to access the `RequestSpec`
|
|
object in the `filter_properties` dictionary.
|
|
|
|
Documentation Impact
|
|
====================
|
|
|
|
Update any developer reference material that might be referencing the old
|
|
dictionary accesses.
|
|
|
|
References
|
|
==========
|
|
|
|
This blueprint is part of an overall effort to clean up, version, and stabilize
|
|
the interfaces between the nova-api, nova-scheduler, nova-conductor and
|
|
nova-compute daemons that involve scheduling and resource decisions.
|
|
|
|
See https://wiki.openstack.org/wiki/Gantt/kilo#Tasks for the list of all
|
|
blueprints targeted for Kilo.
|