def test_obj_make_compatible(self): obj = objects.InstanceGroup(self.context, **_INST_GROUP_OBJ_VALS) data = lambda x: x['nova_object.data'] obj_primitive = data(obj.obj_to_primitive()) self.assertNotIn('metadetails', obj_primitive) obj.obj_make_compatible(obj_primitive, '1.6') self.assertEqual({}, obj_primitive['metadetails'])
def test_rules_helper(self): obj = objects.InstanceGroup() self.assertEqual({}, obj.rules) self.assertNotIn('_rules', obj) obj._rules = {} self.assertEqual({}, obj.rules) self.assertIn('_rules', obj)
def test_get_by_instance_uuid(self, mock_get_ig, get_by_uuid): fake_spec = fake_request_spec.fake_db_spec() get_by_uuid.return_value = fake_spec mock_get_ig.return_value = objects.InstanceGroup(name='fresh') req_obj = request_spec.RequestSpec.get_by_instance_uuid( self.context, fake_spec['instance_uuid']) self.assertEqual(1, req_obj.num_instances) self.assertEqual(['host2', 'host4'], req_obj.ignore_hosts) self.assertEqual('fake', req_obj.project_id) self.assertEqual({'hint': ['over-there']}, req_obj.scheduler_hints) self.assertEqual(['host1', 'host3'], req_obj.force_hosts) self.assertIsNone(req_obj.availability_zone) self.assertEqual(['node1', 'node2'], req_obj.force_nodes) self.assertIsInstance(req_obj.image, objects.ImageMeta) self.assertIsInstance(req_obj.numa_topology, objects.InstanceNUMATopology) self.assertIsInstance(req_obj.pci_requests, objects.InstancePCIRequests) self.assertIsInstance(req_obj.flavor, objects.Flavor) self.assertIsInstance(req_obj.retry, objects.SchedulerRetries) self.assertIsInstance(req_obj.limits, objects.SchedulerLimits) self.assertIsInstance(req_obj.instance_group, objects.InstanceGroup) self.assertEqual('fresh', req_obj.instance_group.name)
def _create_instance_group(self, context, members): ig = objects.InstanceGroup(name='fake_name', user_id='fake_user', project_id='fake', members=members) ig.create(context) return ig.uuid
def create(self, req, body): """Creates a new server group.""" context = _authorize_context(req) quotas = objects.Quotas(context=context) try: quotas.reserve(project_id=context.project_id, user_id=context.user_id, server_groups=1) except nova.exception.OverQuota: msg = _("Quota exceeded, too many server groups.") raise exc.HTTPForbidden(explanation=msg) vals = body['server_group'] sg = objects.InstanceGroup(context) sg.project_id = context.project_id sg.user_id = context.user_id try: sg.name = vals.get('name') sg.policies = vals.get('policies') sg.create() except ValueError as e: quotas.rollback() raise exc.HTTPBadRequest(explanation=e) quotas.commit() return {'server_group': self._format_server_group(context, sg, req)}
def _get_group_details_with_filter_not_configured(self, policy): wrong_filter = { 'affinity': 'ServerGroupAntiAffinityFilter', 'anti-affinity': 'ServerGroupAffinityFilter', } self.flags(scheduler_default_filters=[wrong_filter[policy]]) instance = fake_instance.fake_instance_obj(self.context, params={'host': 'hostA'}) group = objects.InstanceGroup() group.uuid = str(uuid.uuid4()) group.members = [instance.uuid] group.policies = [policy] with contextlib.nested( mock.patch.object(objects.InstanceGroup, 'get_by_instance_uuid', return_value=group), mock.patch.object(objects.InstanceGroup, 'get_hosts', return_value=['hostA']), ) as (get_group, get_hosts): scheduler_utils._SUPPORTS_ANTI_AFFINITY = None scheduler_utils._SUPPORTS_AFFINITY = None self.assertRaises(exception.UnsupportedPolicyException, scheduler_utils._get_group_details, self.context, 'fake-uuid')
def fake_spec_obj(remove_id=False): ctxt = context.RequestContext('fake', 'fake') req_obj = objects.RequestSpec(ctxt) if not remove_id: req_obj.id = 42 req_obj.instance_uuid = uuidutils.generate_uuid() req_obj.image = IMAGE_META req_obj.numa_topology = INSTANCE_NUMA_TOPOLOGY req_obj.pci_requests = PCI_REQUESTS req_obj.flavor = fake_flavor.fake_flavor_obj(ctxt) req_obj.retry = objects.SchedulerRetries() req_obj.limits = objects.SchedulerLimits() req_obj.instance_group = objects.InstanceGroup(uuid=uuids.instgroup) req_obj.project_id = 'fake' req_obj.user_id = 'fake-user' req_obj.num_instances = 1 req_obj.availability_zone = None req_obj.ignore_hosts = ['host2', 'host4'] req_obj.force_hosts = ['host1', 'host3'] req_obj.force_nodes = ['node1', 'node2'] req_obj.scheduler_hints = {'hint': ['over-there']} req_obj.requested_destination = None # This should never be a changed field req_obj.obj_reset_changes(['id']) return req_obj
def setup_instance_group(context, request_spec): """Add group_hosts and group_policies fields to filter_properties dict based on instance uuids provided in request_spec, if those instances are belonging to a group. :param request_spec: Request spec """ if request_spec.instance_group and request_spec.instance_group.hosts: group_hosts = request_spec.instance_group.hosts else: group_hosts = None instance_uuid = request_spec.instance_uuid group_info = _get_group_details(context, instance_uuid, request_spec, user_group_hosts=group_hosts) if group_info is not None: if request_spec.instance_group is None: # WRS: create instance_group if it doesn't exist request_spec.instance_group = objects.InstanceGroup( policies=group_info.policies, hosts=list(group_info.hosts), members=group_info.members, name=group_info.name, metadetails=group_info.metadetails) else: request_spec.instance_group.hosts = list(group_info.hosts) request_spec.instance_group.policies = group_info.policies request_spec.instance_group.members = group_info.members # WRS:extension -- metadetails, name request_spec.instance_group.metadetails = group_info.metadetails request_spec.instance_group.name = group_info.name
def test_destroy(self, mock_db_delete, mock_notify): obj = objects.InstanceGroup(context=self.context) obj.uuid = _DB_UUID obj.destroy() mock_db_delete.assert_called_once_with(self.context, _DB_UUID) mock_notify.assert_called_once_with(self.context, "delete", {'server_group_id': _DB_UUID})
def _test_group_anti_affinity_filter_fails(self, filt_cls, policy): inst1 = objects.Instance(uuid=uuids.inst1) # We already have an inst1 on host1 host = fakes.FakeHostState('host1', 'node1', {}, instances=[inst1]) spec_obj = objects.RequestSpec(instance_group=objects.InstanceGroup( policy=policy, hosts=['host1'], members=[uuids.inst1], rules={}), instance_uuid=uuids.fake) self.assertFalse(filt_cls.host_passes(host, spec_obj))
def _test_group_affinity_filter_fails(self, filt_cls, policy): host = fakes.FakeHostState('host1', 'node1', {}) spec_obj = objects.RequestSpec( instance_group=objects.InstanceGroup(policies=[policy], hosts=['host2'], members=['fake-uuid1'], metadetails={})) self.assertFalse(filt_cls.host_passes(host, spec_obj))
def test_destroy_main(self): db_group = self._main_group() create_group = objects.InstanceGroup._from_db_object( self.context, objects.InstanceGroup(), db_group) create_group.destroy() self.assertRaises(exception.InstanceGroupNotFound, db_api.instance_group_get, self.context, create_group.uuid)
def test_setup_instance_group_with_filter_not_configured(self, mock_ggd): mock_ggd.side_effect = exception.NoValidHost(reason='whatever') spec = {'instance_properties': {'uuid': uuids.instance}} spec = objects.RequestSpec(instance_uuid=uuids.instance) spec.instance_group = objects.InstanceGroup(hosts=['hostC']) self.assertRaises(exception.NoValidHost, scheduler_utils.setup_instance_group, self.context, spec)
def test_add_members_main(self): db_group = self._main_group() create_group = objects.InstanceGroup._from_db_object( self.context, objects.InstanceGroup(), db_group) new_member = ['memberbar'] objects.InstanceGroup.add_members(self.context, create_group.uuid, new_member) db_group = db_api.instance_group_get(self.context, create_group.uuid) self.assertEqual(create_group.members + new_member, db_group.members)
def test_load_hosts(self, mock_get_by_filt): mock_get_by_filt.return_value = [objects.Instance(host='host1'), objects.Instance(host='host2')] obj = objects.InstanceGroup(self.context, members=['uuid1']) self.assertEqual(2, len(obj.hosts)) self.assertIn('host1', obj.hosts) self.assertIn('host2', obj.hosts) self.assertNotIn('hosts', obj.obj_what_changed())
def _create_groups_and_instances_with_metadata(self, ctx, metadetails): instances = [self._create_instance(ctx, cell=None), self._create_instance(ctx, cell=None)] members = [instance.uuid for instance in instances] ig = objects.InstanceGroup(context=ctx, name='fake_name', user_id='fake_user', project_id='fake', members=members, metadetails=metadetails) ig.create() return ig.uuid
def _get_weighed_host(self, hosts, policy): request_spec = objects.RequestSpec( instance_group=objects.InstanceGroup( policies=[policy], members=[ 'member1', 'member2', 'member3', 'member4', 'member5', 'member6', 'member7' ])) return self.weight_handler.get_weighed_objects(self.weighers, hosts, request_spec)[0]
def _create_server_group(self, policy='anti-affinity'): instance = fake_instance.fake_instance_obj(self.context, params={'host': 'hostA'}) group = objects.InstanceGroup() group.name = 'pele' group.uuid = str(uuid.uuid4()) group.members = [instance.uuid] group.policies = [policy] return group
def test_save_main(self, _mock_notify): db_group = self._main_group() create_group = objects.InstanceGroup._from_db_object( self.context, objects.InstanceGroup(), db_group) create_group.policies = ['bar1', 'bar2'] create_group.members = ['memberbar1', 'memberbar2'] create_group.name = 'anewname' create_group.save() db_group = db_api.instance_group_get(self.context, create_group.uuid) ovo_fixture.compare_obj(self, create_group, db_group)
def test_group_anti_affinity_filter_allows_instance_to_same_host(self): fake_uuid = uuids.fake mock_instance = objects.Instance(uuid=fake_uuid) host_state = fakes.FakeHostState('host1', 'node1', {}, instances=[mock_instance]) spec_obj = objects.RequestSpec(instance_group=objects.InstanceGroup( policy='anti-affinity', hosts=['host1', 'host2'], members=[]), instance_uuid=mock_instance.uuid) self.assertTrue(affinity_filter.ServerGroupAntiAffinityFilter(). host_passes(host_state, spec_obj))
def _api_group(self, **values): group = objects.InstanceGroup(context=self.context, user_id=self.context.user_id, project_id=self.context.project_id, name='foogroup', policies=['foo1'], members=['memberfoo']) group.update(values) group.create() return group
def test_create(self, mock_db_create, mock_notify, mock_notify_action): obj = objects.InstanceGroup(context=self.context) obj.uuid = _DB_UUID obj.name = _INST_GROUP_DB['name'] obj.user_id = _INST_GROUP_DB['user_id'] obj.project_id = _INST_GROUP_DB['project_id'] obj.members = _INST_GROUP_DB['members'] obj.policies = [_INST_GROUP_DB['policy']['policy']] obj.updated_at = _TS_NOW obj.created_at = _TS_NOW obj.create() mock_db_create.assert_called_once_with( self.context, { 'uuid': _DB_UUID, 'name': _INST_GROUP_DB['name'], 'user_id': _INST_GROUP_DB['user_id'], 'project_id': _INST_GROUP_DB['project_id'], 'created_at': _TS_NOW, 'updated_at': _TS_NOW, }, members=_INST_GROUP_DB['members'], policies=[_INST_GROUP_DB['policy']['policy']], policy=None, rules=None) mock_notify.assert_called_once_with( self.context, "create", { 'uuid': _DB_UUID, 'name': _INST_GROUP_DB['name'], 'user_id': _INST_GROUP_DB['user_id'], 'project_id': _INST_GROUP_DB['project_id'], 'created_at': _TS_NOW, 'updated_at': _TS_NOW, 'members': _INST_GROUP_DB['members'], 'policies': [_INST_GROUP_DB['policy']['policy']], 'server_group_id': _DB_UUID }) def _group_matcher(group): """Custom mock call matcher method.""" return (group.uuid == _DB_UUID and group.name == _INST_GROUP_DB['name'] and group.user_id == _INST_GROUP_DB['user_id'] and group.project_id == _INST_GROUP_DB['project_id'] and group.created_at == _TS_NOW and group.updated_at == _TS_NOW and group.members == _INST_GROUP_DB['members'] and group.policies == [_INST_GROUP_DB['policy']['policy']] and group.id == 1) group_matcher = test_utils.CustomMockCallMatcher(_group_matcher) self.assertRaises(exception.ObjectActionError, obj.create) mock_notify_action.assert_called_once_with(context=self.context, group=group_matcher, action='create')
def _api_group(self, **values): group = objects.InstanceGroup(context=self.context, user_id=self.context.user_id, project_id=self.context.project_id, name='foogroup', policy='anti-affinity', rules={'max_server_per_host': 1}, members=['memberfoo']) group.update(values) group.create() return group
def test_save_without_hosts(self, mock_db_get, mock_notify): mock_db_get.return_value = _INST_GROUP_DB obj = objects.InstanceGroup(self.context, **_INST_GROUP_DB) obj.obj_reset_changes() obj.hosts = ['fake-host1'] self.assertRaises(exception.InstanceGroupSaveException, obj.save) # make sure that we can save by removing hosts from what is updated obj.obj_reset_changes(['hosts']) obj.save() # since hosts was the only update, there is no actual call self.assertFalse(mock_notify.called)
def test_setup_instance_group_with_no_group(self, mock_ggd): mock_ggd.return_value = None spec = objects.RequestSpec(instance_uuid=uuids.instance) spec.instance_group = objects.InstanceGroup(hosts=['hostC']) scheduler_utils.setup_instance_group(self.context, spec) mock_ggd.assert_called_once_with(self.context, uuids.instance, ['hostC']) # Make sure the field isn't touched by the caller. self.assertFalse(spec.instance_group.obj_attr_is_set('policies')) self.assertEqual(['hostC'], spec.instance_group.hosts)
def _get_weighed_host(self, hosts, policy, group='default'): if group == 'default': members = [ 'member1', 'member2', 'member3', 'member4', 'member5', 'member6', 'member7' ] else: members = ['othermember1', 'othermember2'] request_spec = objects.RequestSpec( instance_group=objects.InstanceGroup(policy=policy, members=members)) return self.weight_handler.get_weighed_objects(self.weighers, hosts, request_spec)[0]
def test_destroy(self, mock_db_delete, mock_notify, mock_notify_action): obj = objects.InstanceGroup(context=self.context) obj.uuid = _DB_UUID obj.destroy() group_matcher = test_utils.CustomMockCallMatcher( lambda group: group.uuid == _DB_UUID) mock_notify_action.assert_called_once_with(context=obj._context, group=group_matcher, action='delete') mock_db_delete.assert_called_once_with(self.context, _DB_UUID) mock_notify.assert_called_once_with(self.context, "delete", {'server_group_id': _DB_UUID})
def _test_group_anti_affinity_filter_with_rules(self, rules, members): filt_cls = affinity_filter.ServerGroupAntiAffinityFilter() inst1 = objects.Instance(uuid=uuids.inst1) inst2 = objects.Instance(uuid=uuids.inst2) spec_obj = objects.RequestSpec( instance_group=objects.InstanceGroup(policy='anti-affinity', hosts=['host1'], members=members, rules=rules), instance_uuid=uuids.fake) # 2 instances on same host host_wit_2_inst = fakes.FakeHostState( 'host1', 'node1', {}, instances=[inst1, inst2]) return filt_cls.host_passes(host_wit_2_inst, spec_obj)
def test_schedule_instance_group(self, mock_get_hosts, mock_get_all_states): """Test that since the request spec object contains an instance group object, that upon choosing a host in the primary schedule loop, that we update the request spec's instance group information """ num_instances = 2 ig = objects.InstanceGroup(hosts=[]) spec_obj = objects.RequestSpec( num_instances=num_instances, flavor=objects.Flavor(memory_mb=512, root_gb=512, ephemeral_gb=0, swap=0, vcpus=1), project_id=uuids.project_id, instance_group=ig) hs1 = mock.Mock(spec=host_manager.HostState, host='host1') hs2 = mock.Mock(spec=host_manager.HostState, host='host2') all_host_states = [hs1, hs2] mock_get_all_states.return_value = all_host_states # Simulate host 1 and host 2 being randomly returned first by # _get_sorted_hosts() in the two iterations for each instance in # num_instances mock_get_hosts.side_effect = ([hs2, hs1], [hs1, hs2]) instance_uuids = [ getattr(uuids, 'instance%d' % x) for x in range(num_instances) ] ctx = mock.Mock() self.driver._schedule(ctx, spec_obj, instance_uuids, mock.sentinel.alloc_reqs_by_rp_uuid, mock.sentinel.provider_summaries) # Check that _get_sorted_hosts() is called twice and that the # second time, we pass it the hosts that were returned from # _get_sorted_hosts() the first time sorted_host_calls = [ mock.call(spec_obj, all_host_states, 0), mock.call(spec_obj, [hs2, hs1], 1), ] mock_get_hosts.assert_has_calls(sorted_host_calls) # The instance group object should have both host1 and host2 in its # instance group hosts list and there should not be any "changes" to # save in the instance group object self.assertEqual(['host2', 'host1'], ig.hosts) self.assertEqual({}, ig.obj_get_changes())
def _populate_group_info(self, filter_properties): if filter_properties.get('instance_group'): # New-style group information as a NovaObject, we can directly set # the field self.instance_group = filter_properties.get('instance_group') elif filter_properties.get('group_updated') is True: # Old-style group information having ugly dict keys containing sets # NOTE(sbauza): Can be dropped once select_destinations is removed policies = list(filter_properties.get('group_policies')) members = list(filter_properties.get('group_hosts')) self.instance_group = objects.InstanceGroup(policies=policies, members=members) else: # Set the value anyway to avoid any call to obj_attr_is_set for it self.instance_group = None