70516d4ff9
This makes us store the compute_id of the destination node in the Migration object. Since resize/cold-migration changes the node affiliation of an instance *to* the destination node *from* the source node, we need a positive record of the node id to be used. The destination node set this to its own node when creating the migration, and it is used by the source node when the switchover happens. Because the migration may be backleveled for an older node involved in that process and thus saved or passed without this field, this adds a compatibility routine that falls back to looking up the node by host/nodename. Related to blueprint compute-object-ids Change-Id: I362a40403d1094be36412f5f7afba00da8af8301
192 lines
8.5 KiB
Python
192 lines
8.5 KiB
Python
# 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 oslo_utils import timeutils
|
|
from webob import exc
|
|
|
|
from nova.api.openstack import api_version_request
|
|
from nova.api.openstack import common
|
|
from nova.api.openstack.compute.schemas import migrations as schema_migrations
|
|
from nova.api.openstack.compute.views import migrations as migrations_view
|
|
from nova.api.openstack import wsgi
|
|
from nova.api import validation
|
|
from nova.compute import api as compute
|
|
from nova import exception
|
|
from nova.i18n import _
|
|
from nova.objects import base as obj_base
|
|
from nova.objects import fields
|
|
from nova.policies import migrations as migrations_policies
|
|
|
|
|
|
class MigrationsController(wsgi.Controller):
|
|
"""Controller for accessing migrations in OpenStack API."""
|
|
|
|
_view_builder_class = migrations_view.ViewBuilder
|
|
_collection_name = "servers/%s/migrations"
|
|
|
|
def __init__(self):
|
|
super(MigrationsController, self).__init__()
|
|
self.compute_api = compute.API()
|
|
|
|
def _output(self, req, migrations_obj, add_link=False,
|
|
add_uuid=False, add_user_project=False):
|
|
"""Returns the desired output of the API from an object.
|
|
|
|
From a MigrationsList's object this method returns a list of
|
|
primitive objects with the only necessary fields.
|
|
"""
|
|
detail_keys = ['memory_total', 'memory_processed', 'memory_remaining',
|
|
'disk_total', 'disk_processed', 'disk_remaining']
|
|
|
|
# TODO(Shaohe Feng) we should share the in-progress list.
|
|
live_migration_in_progress = ['queued', 'preparing',
|
|
'running', 'post-migrating']
|
|
|
|
# Note(Shaohe Feng): We need to leverage the oslo.versionedobjects.
|
|
# Then we can pass the target version to it's obj_to_primitive.
|
|
objects = obj_base.obj_to_primitive(migrations_obj)
|
|
objects = [x for x in objects if not x['hidden']]
|
|
for obj in objects:
|
|
del obj['deleted']
|
|
del obj['deleted_at']
|
|
del obj['hidden']
|
|
del obj['cross_cell_move']
|
|
del obj['dest_compute_id']
|
|
if not add_uuid:
|
|
del obj['uuid']
|
|
if 'memory_total' in obj:
|
|
for key in detail_keys:
|
|
del obj[key]
|
|
if not add_user_project:
|
|
if 'user_id' in obj:
|
|
del obj['user_id']
|
|
if 'project_id' in obj:
|
|
del obj['project_id']
|
|
# NOTE(Shaohe Feng) above version 2.23, add migration_type for all
|
|
# kinds of migration, but we only add links just for in-progress
|
|
# live-migration.
|
|
if (add_link and
|
|
obj['migration_type'] ==
|
|
fields.MigrationType.LIVE_MIGRATION and
|
|
obj["status"] in live_migration_in_progress):
|
|
obj["links"] = self._view_builder._get_links(
|
|
req, obj["id"],
|
|
self._collection_name % obj['instance_uuid'])
|
|
elif add_link is False:
|
|
del obj['migration_type']
|
|
|
|
return objects
|
|
|
|
def _index(self, req, add_link=False, next_link=False, add_uuid=False,
|
|
sort_dirs=None, sort_keys=None, limit=None, marker=None,
|
|
allow_changes_since=False, allow_changes_before=False):
|
|
context = req.environ['nova.context']
|
|
context.can(migrations_policies.POLICY_ROOT % 'index')
|
|
search_opts = {}
|
|
search_opts.update(req.GET)
|
|
if 'changes-since' in search_opts:
|
|
if allow_changes_since:
|
|
search_opts['changes-since'] = timeutils.parse_isotime(
|
|
search_opts['changes-since'])
|
|
else:
|
|
# Before microversion 2.59, the changes-since filter was not
|
|
# supported in the DB API. However, the schema allowed
|
|
# additionalProperties=True, so a user could pass it before
|
|
# 2.59 and filter by the updated_at field if we don't remove
|
|
# it from search_opts.
|
|
del search_opts['changes-since']
|
|
|
|
if 'changes-before' in search_opts:
|
|
if allow_changes_before:
|
|
search_opts['changes-before'] = timeutils.parse_isotime(
|
|
search_opts['changes-before'])
|
|
changes_since = search_opts.get('changes-since')
|
|
if (changes_since and search_opts['changes-before'] <
|
|
search_opts['changes-since']):
|
|
msg = _('The value of changes-since must be less than '
|
|
'or equal to changes-before.')
|
|
raise exc.HTTPBadRequest(explanation=msg)
|
|
else:
|
|
# Before microversion 2.59 the schema allowed
|
|
# additionalProperties=True, so a user could pass
|
|
# changes-before before 2.59 and filter by the updated_at
|
|
# field if we don't remove it from search_opts.
|
|
del search_opts['changes-before']
|
|
|
|
if sort_keys:
|
|
try:
|
|
migrations = self.compute_api.get_migrations_sorted(
|
|
context, search_opts,
|
|
sort_dirs=sort_dirs, sort_keys=sort_keys,
|
|
limit=limit, marker=marker)
|
|
except exception.MarkerNotFound as e:
|
|
raise exc.HTTPBadRequest(explanation=e.format_message())
|
|
else:
|
|
migrations = self.compute_api.get_migrations(
|
|
context, search_opts)
|
|
|
|
add_user_project = api_version_request.is_supported(req, '2.80')
|
|
migrations = self._output(req, migrations, add_link,
|
|
add_uuid, add_user_project)
|
|
migrations_dict = {'migrations': migrations}
|
|
|
|
if next_link:
|
|
migrations_links = self._view_builder.get_links(req, migrations)
|
|
if migrations_links:
|
|
migrations_dict['migrations_links'] = migrations_links
|
|
return migrations_dict
|
|
|
|
@wsgi.Controller.api_version("2.1", "2.22") # noqa
|
|
@wsgi.expected_errors(())
|
|
@validation.query_schema(schema_migrations.list_query_schema_v20,
|
|
"2.0", "2.22")
|
|
def index(self, req):
|
|
"""Return all migrations using the query parameters as filters."""
|
|
return self._index(req)
|
|
|
|
@wsgi.Controller.api_version("2.23", "2.58") # noqa
|
|
@wsgi.expected_errors(())
|
|
@validation.query_schema(schema_migrations.list_query_schema_v20,
|
|
"2.23", "2.58")
|
|
def index(self, req): # noqa
|
|
"""Return all migrations using the query parameters as filters."""
|
|
return self._index(req, add_link=True)
|
|
|
|
@wsgi.Controller.api_version("2.59", "2.65") # noqa
|
|
@wsgi.expected_errors(400)
|
|
@validation.query_schema(schema_migrations.list_query_params_v259,
|
|
"2.59", "2.65")
|
|
def index(self, req): # noqa
|
|
"""Return all migrations using the query parameters as filters."""
|
|
limit, marker = common.get_limit_and_marker(req)
|
|
return self._index(req, add_link=True, next_link=True, add_uuid=True,
|
|
sort_keys=['created_at', 'id'],
|
|
sort_dirs=['desc', 'desc'],
|
|
limit=limit, marker=marker,
|
|
allow_changes_since=True)
|
|
|
|
@wsgi.Controller.api_version("2.66") # noqa
|
|
@wsgi.expected_errors(400)
|
|
@validation.query_schema(schema_migrations.list_query_params_v266,
|
|
"2.66", "2.79")
|
|
@validation.query_schema(schema_migrations.list_query_params_v280,
|
|
"2.80")
|
|
def index(self, req): # noqa
|
|
"""Return all migrations using the query parameters as filters."""
|
|
limit, marker = common.get_limit_and_marker(req)
|
|
return self._index(req, add_link=True, next_link=True, add_uuid=True,
|
|
sort_keys=['created_at', 'id'],
|
|
sort_dirs=['desc', 'desc'],
|
|
limit=limit, marker=marker,
|
|
allow_changes_since=True,
|
|
allow_changes_before=True)
|