summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nova/api/openstack/placement/objects/resource_provider.py50
-rw-r--r--nova/tests/functional/api/openstack/placement/db/test_allocation_candidates.py74
2 files changed, 91 insertions, 33 deletions
diff --git a/nova/api/openstack/placement/objects/resource_provider.py b/nova/api/openstack/placement/objects/resource_provider.py
index bb377bc..aaaa09c 100644
--- a/nova/api/openstack/placement/objects/resource_provider.py
+++ b/nova/api/openstack/placement/objects/resource_provider.py
@@ -733,9 +733,18 @@ def _provider_ids_from_rp_ids(context, rp_ids):
733 me.c.parent_provider_id == parent.c.id) 733 me.c.parent_provider_id == parent.c.id)
734 sel = sa.select(cols).select_from(me_to_parent) 734 sel = sa.select(cols).select_from(me_to_parent)
735 sel = sel.where(me.c.id.in_(rp_ids)) 735 sel = sel.where(me.c.id.in_(rp_ids))
736 return { 736
737 r[0]: ProviderIds(**dict(r)) for r in context.session.execute(sel) 737 ret = {}
738 } 738 for r in context.session.execute(sel):
739 # Use its id/uuid for the root id/uuid if the root id/uuid is None
740 # TODO(tetsuro): Remove this to when we are sure all root_provider_id
741 # values are NOT NULL
742 d = dict(r)
743 if d['root_id'] is None:
744 d['root_id'] = d['id']
745 d['root_uuid'] = d['uuid']
746 ret[d['id']] = ProviderIds(**d)
747 return ret
739 748
740 749
741def _provider_ids_from_uuid(context, uuid): 750def _provider_ids_from_uuid(context, uuid):
@@ -2732,13 +2741,15 @@ def _get_usages_by_provider_tree(ctx, root_ids):
2732 # FROM allocations 2741 # FROM allocations
2733 # JOIN resource_providers 2742 # JOIN resource_providers
2734 # ON allocations.resource_provider_id = resource_providers.id 2743 # ON allocations.resource_provider_id = resource_providers.id
2735 # AND resource_providers.root_provider_id IN($root_ids) 2744 # AND (resource_providers.root_provider_id IN($root_ids)
2745 # OR resource_providers.id IN($root_ids))
2736 # GROUP BY resource_provider_id, resource_class_id 2746 # GROUP BY resource_provider_id, resource_class_id
2737 # ) 2747 # )
2738 # AS usages 2748 # AS usage
2739 # ON inv.resource_provider_id = usage.resource_provider_id 2749 # ON inv.resource_provider_id = usage.resource_provider_id
2740 # AND inv.resource_class_id = usage.resource_class_id 2750 # AND inv.resource_class_id = usage.resource_class_id
2741 # WHERE rp.root_provider_id IN ($root_ids) 2751 # WHERE (rp.root_provider_id IN ($root_ids)
2752 # OR resource_providers.id IN($root_ids))
2742 rpt = sa.alias(_RP_TBL, name="rp") 2753 rpt = sa.alias(_RP_TBL, name="rp")
2743 inv = sa.alias(_INV_TBL, name="inv") 2754 inv = sa.alias(_INV_TBL, name="inv")
2744 # Build our derived table (subquery in the FROM clause) that sums used 2755 # Build our derived table (subquery in the FROM clause) that sums used
@@ -2746,7 +2757,12 @@ def _get_usages_by_provider_tree(ctx, root_ids):
2746 derived_alloc_to_rp = sa.join( 2757 derived_alloc_to_rp = sa.join(
2747 _ALLOC_TBL, _RP_TBL, 2758 _ALLOC_TBL, _RP_TBL,
2748 sa.and_(_ALLOC_TBL.c.resource_provider_id == _RP_TBL.c.id, 2759 sa.and_(_ALLOC_TBL.c.resource_provider_id == _RP_TBL.c.id,
2749 _RP_TBL.c.root_provider_id.in_(root_ids))) 2760 # TODO(tetsuro): Remove this OR condition when all
2761 # root_provider_id values are NOT NULL
2762 sa.or_(_RP_TBL.c.root_provider_id.in_(root_ids),
2763 _RP_TBL.c.id.in_(root_ids))
2764 )
2765 )
2750 usage = sa.alias( 2766 usage = sa.alias(
2751 sa.select([ 2767 sa.select([
2752 _ALLOC_TBL.c.resource_provider_id, 2768 _ALLOC_TBL.c.resource_provider_id,
@@ -2778,7 +2794,14 @@ def _get_usages_by_provider_tree(ctx, root_ids):
2778 inv.c.allocation_ratio, 2794 inv.c.allocation_ratio,
2779 inv.c.max_unit, 2795 inv.c.max_unit,
2780 usage.c.used, 2796 usage.c.used,
2781 ]).select_from(usage_join).where(rpt.c.root_provider_id.in_(root_ids)) 2797 ]).select_from(usage_join).where(
2798 # TODO(tetsuro): Remove this or condition when all
2799 # root_provider_id values are NOT NULL
2800 sa.or_(
2801 rpt.c.root_provider_id.in_(root_ids),
2802 rpt.c.id.in_(root_ids)
2803 )
2804 )
2782 return ctx.session.execute(query).fetchall() 2805 return ctx.session.execute(query).fetchall()
2783 2806
2784 2807
@@ -3052,7 +3075,16 @@ def _get_providers_with_resource(ctx, rc_id, amount):
3052 sel = sel.where(sa.and_(*where_conds)) 3075 sel = sel.where(sa.and_(*where_conds))
3053 res = ctx.session.execute(sel).fetchall() 3076 res = ctx.session.execute(sel).fetchall()
3054 res = set((r[0], r[1]) for r in res) 3077 res = set((r[0], r[1]) for r in res)
3055 return res 3078 # TODO(tetsuro): Bug#1799892: We could have old providers with no root
3079 # provider set and they haven't undergone a data migration yet,
3080 # so we need to set the root_id explicitly here. We remove
3081 # this and when all root_provider_id values are NOT NULL
3082 ret = []
3083 for rp_tuple in res:
3084 rp_id = rp_tuple[0]
3085 root_id = rp_id if rp_tuple[1] is None else rp_tuple[1]
3086 ret.append((rp_id, root_id))
3087 return ret
3056 3088
3057 3089
3058@db_api.placement_context_manager.reader 3090@db_api.placement_context_manager.reader
diff --git a/nova/tests/functional/api/openstack/placement/db/test_allocation_candidates.py b/nova/tests/functional/api/openstack/placement/db/test_allocation_candidates.py
index a33f6d6..8903fed 100644
--- a/nova/tests/functional/api/openstack/placement/db/test_allocation_candidates.py
+++ b/nova/tests/functional/api/openstack/placement/db/test_allocation_candidates.py
@@ -467,6 +467,9 @@ class AllocationCandidatesTestCase(tb.PlacementDbBaseTestCase):
467 ) 467 )
468 conn.execute(ins_rptbl) 468 conn.execute(ins_rptbl)
469 469
470 # This is needed for _validate_allocation_requests() at the end
471 self.rp_uuid_to_name[uuids.rp1] = 'cn1'
472
470 # Add VCPU(resource_class_id=0) inventory to the provider. 473 # Add VCPU(resource_class_id=0) inventory to the provider.
471 ins_invtbl = inv_tbl.insert().values( 474 ins_invtbl = inv_tbl.insert().values(
472 id=1, 475 id=1,
@@ -491,31 +494,38 @@ class AllocationCandidatesTestCase(tb.PlacementDbBaseTestCase):
491 ) 494 )
492 conn.execute(ins_alloctbl) 495 conn.execute(ins_alloctbl)
493 496
494 # TODO(tetsuro): Bug#1799892: Fix this not to raise the KeyError 497 alloc_cands = self._get_allocation_candidates(
495 # alloc_cands = self._get_allocation_candidates( 498 {'': placement_lib.RequestGroup(
496 # {'': placement_lib.RequestGroup( 499 use_same_provider=False,
497 # use_same_provider=False, 500 resources={
498 # resources={ 501 fields.ResourceClass.VCPU: 1
499 # fields.ResourceClass.VCPU: 1 502 }
500 # } 503 )}
501 # )} 504 )
502 # )
503 #
504 # expected = [
505 # [('cn1', fields.ResourceClass.VCPU, 1)]
506 # ]
507 # self._validate_allocation_requests(expected, alloc_cands)
508 #
509 # expected = {
510 # 'cn1': set([
511 # (fields.ResourceClass.VCPU, 8, 4)
512 # ]),
513 # }
514 # self._validate_provider_summary_resources(expected, alloc_cands)
515 505
516 self.assertRaises( 506 expected = [
517 KeyError, 507 [('cn1', fields.ResourceClass.VCPU, 1)]
518 self._get_allocation_candidates, 508 ]
509 self._validate_allocation_requests(expected, alloc_cands)
510
511 expected = {
512 'cn1': set([
513 (fields.ResourceClass.VCPU, 8, 4)
514 ]),
515 }
516 self._validate_provider_summary_resources(expected, alloc_cands)
517
518 # NOTE(tetsuro): Getting allocation candidates goes through a
519 # different path when sharing/nested providers exist, let's test
520 # that case and the path creating a new sharing provider.
521 # We omit the direct database insertion of 'ss1' here since 'cn1',
522 # which has no root id in the database, is the actual target of the
523 # following test.
524 ss1 = self._create_provider('ss1', uuids.agg1)
525 tb.set_traits(ss1, "MISC_SHARES_VIA_AGGREGATE")
526 tb.add_inventory(ss1, fields.ResourceClass.VCPU, 8)
527
528 alloc_cands = self._get_allocation_candidates(
519 {'': placement_lib.RequestGroup( 529 {'': placement_lib.RequestGroup(
520 use_same_provider=False, 530 use_same_provider=False,
521 resources={ 531 resources={
@@ -524,6 +534,22 @@ class AllocationCandidatesTestCase(tb.PlacementDbBaseTestCase):
524 )} 534 )}
525 ) 535 )
526 536
537 expected = [
538 [('cn1', fields.ResourceClass.VCPU, 1)],
539 [('ss1', fields.ResourceClass.VCPU, 1)]
540 ]
541 self._validate_allocation_requests(expected, alloc_cands)
542
543 expected = {
544 'cn1': set([
545 (fields.ResourceClass.VCPU, 8, 4)
546 ]),
547 'ss1': set([
548 (fields.ResourceClass.VCPU, 8, 0)
549 ]),
550 }
551 self._validate_provider_summary_resources(expected, alloc_cands)
552
527 def test_all_local(self): 553 def test_all_local(self):
528 """Create some resource providers that can satisfy the request for 554 """Create some resource providers that can satisfy the request for
529 resources with local (non-shared) resources and verify that the 555 resources with local (non-shared) resources and verify that the