nova/nova/compute/instance_list.py
Chris Dent def4b17934 Use nova.db.api directly
nova/db/__init__.py was importing * from nova.db.api. This meant that
any time any code anywhere within the nova.db package was imported
then nova.db.api was too, leading to a cascade of imports that may
not have been desired. Also, in general, code in __init__.py is a pain.

Therefore, this change adjusts code that so that either:

* nova.db.api is used directly
* nova.db.api is imported as 'db'

In either case, the functionality remains the same.

The primary goal of this change was to make it possible to import the
model files without having to import the db api. Moving the model files
to a different place in the directory hierarchy was considered, but
given that "code in __init__.py is a pain" this mode was chosen.

This looks like a very large change, but it is essentially adjusting
package names, many in mocks.

Change-Id: Ic1fd7c87ceda05eeb96735da2a415ef37060bb1a
2018-07-10 14:56:27 +00:00

127 lines
5.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.
import copy
from nova.compute import multi_cell_list
import nova.conf
from nova import context
from nova.db import api as db
from nova import exception
from nova import objects
from nova.objects import instance as instance_obj
CONF = nova.conf.CONF
class InstanceSortContext(multi_cell_list.RecordSortContext):
def __init__(self, sort_keys, sort_dirs):
if not sort_keys:
sort_keys = ['created_at', 'id']
sort_dirs = ['desc', 'desc']
if 'uuid' not in sort_keys:
# Historically the default sort includes 'id' (see above), which
# should give us a stable ordering. Since we're striping across
# cell databases here, many sort_keys arrangements will yield
# nothing unique across all the databases to give us a stable
# ordering, which can mess up expected client pagination behavior.
# So, throw uuid into the sort_keys at the end if it's not already
# there to keep us repeatable.
sort_keys = copy.copy(sort_keys) + ['uuid']
sort_dirs = copy.copy(sort_dirs) + ['asc']
super(InstanceSortContext, self).__init__(sort_keys, sort_dirs)
class InstanceLister(multi_cell_list.CrossCellLister):
def __init__(self, sort_keys, sort_dirs, cells=None):
super(InstanceLister, self).__init__(
InstanceSortContext(sort_keys, sort_dirs), cells=cells)
@property
def marker_identifier(self):
return 'uuid'
def get_marker_record(self, ctx, marker):
try:
im = objects.InstanceMapping.get_by_instance_uuid(ctx, marker)
except exception.InstanceMappingNotFound:
raise exception.MarkerNotFound(marker=marker)
elevated = ctx.elevated(read_deleted='yes')
with context.target_cell(elevated, im.cell_mapping) as cctx:
try:
# NOTE(danms): We query this with no columns_to_join()
# as we're just getting values for the sort keys from
# it and none of the valid sort keys are on joined
# columns.
db_inst = db.instance_get_by_uuid(cctx, marker,
columns_to_join=[])
except exception.InstanceNotFound:
raise exception.MarkerNotFound(marker=marker)
return db_inst
def get_marker_by_values(self, ctx, values):
return db.instance_get_by_sort_filters(ctx,
self.sort_ctx.sort_keys,
self.sort_ctx.sort_dirs,
values)
def get_by_filters(self, ctx, filters, limit, marker, **kwargs):
return db.instance_get_all_by_filters_sort(
ctx, filters, limit=limit, marker=marker,
sort_keys=self.sort_ctx.sort_keys,
sort_dirs=self.sort_ctx.sort_dirs,
**kwargs)
# NOTE(danms): These methods are here for legacy glue reasons. We should not
# replicate these for every data type we implement.
def get_instances_sorted(ctx, filters, limit, marker, columns_to_join,
sort_keys, sort_dirs, cell_mappings=None):
return InstanceLister(sort_keys, sort_dirs,
cells=cell_mappings).get_records_sorted(
ctx, filters, limit, marker, columns_to_join=columns_to_join)
def get_instance_objects_sorted(ctx, filters, limit, marker, expected_attrs,
sort_keys, sort_dirs):
"""Same as above, but return an InstanceList."""
query_cell_subset = CONF.api.instance_list_per_project_cells
# NOTE(danms): Replicated in part from instance_get_all_by_sort_filters(),
# where if we're not admin we're restricted to our context's project
if query_cell_subset and not ctx.is_admin:
# We are not admin, and configured to only query the subset of cells
# we could possibly have instances in.
cell_mappings = objects.CellMappingList.get_by_project_id(
ctx, ctx.project_id)
else:
# Either we are admin, or configured to always hit all cells,
# so don't limit the list to a subset.
cell_mappings = None
columns_to_join = instance_obj._expected_cols(expected_attrs)
instance_generator = get_instances_sorted(ctx, filters, limit, marker,
columns_to_join, sort_keys,
sort_dirs,
cell_mappings=cell_mappings)
if 'fault' in expected_attrs:
# We join fault above, so we need to make sure we don't ask
# make_instance_list to do it again for us
expected_attrs = copy.copy(expected_attrs)
expected_attrs.remove('fault')
return instance_obj._make_instance_list(ctx, objects.InstanceList(),
instance_generator,
expected_attrs)