def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) self.obj.handle_ipabaserid(entry_attrs, options) self.obj.handle_iparangetype(entry_attrs, options) self.add_message( messages.ServiceRestartRequired( service=services.knownservices['sssd'].systemd_name, server=keys[0])) return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) self.obj.get_enabled_roles(entry_attrs) if 'ipalocation_location' in options: ipalocation = entry_attrs.get('ipalocation') if ipalocation: ipalocation = ipalocation[0]['idnsname'] else: ipalocation = u'' try: self.api.Command.dnsserver_mod( keys[0], setattr=[ u'idnsSubstitutionVariable;ipalocation={loc}'.format( loc=ipalocation) ]) except errors.EmptyModlist: pass except errors.NotFound: # server is not DNS server pass if 'ipalocation_location' or 'ipaserviceweight' in options: self.add_message( messages.ServiceRestartRequired( service=services.service('named', api).systemd_name, server=keys[0], )) result = self.api.Command.dns_update_system_records() if not result.get('value'): self.add_message(messages.AutomaticDNSRecordsUpdateFailed()) self.obj.convert_location(entry_attrs, **options) ipalocation = entry_attrs.get('ipalocation_location', [None])[0] if ipalocation: servers_in_loc = self.api.Command.server_find( in_location=ipalocation, no_members=False)['result'] dns_server_in_loc = False for server in servers_in_loc: if 'DNS server' in server.get('enabled_role_servrole', ()): dns_server_in_loc = True break if not dns_server_in_loc: self.add_message( messages.LocationWithoutDNSServer(location=ipalocation)) return dn
class test_range(Declarative): mockldap = None @pytest.fixture(autouse=True, scope="class") def range_setup(self, request, declarative_setup): cls = request.cls def fin(): cls.mockldap = MockLDAP() cls.mockldap.del_entry(domain2_dn) cls.mockldap.del_entry(domain3_dn) cls.mockldap.del_entry(domain4_dn) cls.mockldap.del_entry(domain5_dn) cls.mockldap.del_entry(domain6_dn) cls.mockldap.del_entry(domain7_dn) cls.mockldap.del_entry(domain1range1_dn) cls.mockldap.del_entry(domain2range1_dn) cls.mockldap.del_entry(domain2range2_dn) cls.mockldap.del_entry(domain3range1_dn) cls.mockldap.del_entry(domain3range2_dn) cls.mockldap.del_entry(domain4range1_dn) cls.mockldap.del_entry(domain5range1_dn) cls.mockldap.del_entry(domain5range2_dn) cls.mockldap.del_entry(domain6range1_dn) cls.mockldap.del_entry(domain7range1_dn) cls.mockldap.del_entry(trust_container_dn) cls.mockldap.del_entry(trust_local_dn) cls.mockldap.del_entry(smb_cont_dn) cls.mockldap.unbind() fin() cls.mockldap = MockLDAP() cls.mockldap.add_entry(trust_container_dn, trust_container_add) cls.mockldap.add_entry(smb_cont_dn, smb_cont_add) cls.mockldap.add_entry(trust_local_dn, trust_local_add) cls.mockldap.add_entry(domain2_dn, domain2_add) cls.mockldap.add_entry(domain3_dn, domain3_add) cls.mockldap.add_entry(domain4_dn, domain4_add) cls.mockldap.add_entry(domain5_dn, domain5_add) cls.mockldap.add_entry(domain6_dn, domain6_add) cls.mockldap.add_entry(domain7_dn, domain7_add) cls.mockldap.add_entry(domain1range1_dn, domain1range1_add) cls.mockldap.add_entry(domain2range1_dn, domain2range1_add) cls.mockldap.add_entry(domain2range2_dn, domain2range2_add) cls.mockldap.add_entry(domain3range1_dn, domain3range1_add) cls.mockldap.add_entry(domain3range2_dn, domain3range2_add) cls.mockldap.add_entry(domain4range1_dn, domain4range1_add) cls.mockldap.add_entry(domain5range1_dn, domain5range1_add) cls.mockldap.add_entry(domain5range2_dn, domain5range2_add) cls.mockldap.add_entry(domain6range1_dn, domain6range1_add) cls.mockldap.unbind() request.addfinalizer(fin) cleanup_commands = [ ('idrange_del', [ testrange1, testrange2, testrange3, testrange4, testrange5, testrange6, testrange7, testrange8, testrange9 ], { 'continue': True }), ('user_del', [user1], {}), ('group_del', [group1], {}), ] # Basic tests. tests = [ dict( desc='Create ID range %r' % (testrange1), command=('idrange_add', [testrange1], dict(ipabaseid=testrange1_base_id, ipaidrangesize=testrange1_size, ipabaserid=testrange1_base_rid, ipasecondarybaserid=testrange1_secondary_base_rid)), expected=dict( result=dict( dn=DN(('cn', testrange1), ('cn', 'ranges'), ('cn', 'etc'), api.env.basedn), cn=[testrange1], objectclass=[u'ipaIDrange', u'ipadomainidrange'], ipabaseid=[unicode(testrange1_base_id)], ipabaserid=[unicode(testrange1_base_rid)], ipasecondarybaserid=[ unicode(testrange1_secondary_base_rid) ], ipaidrangesize=[unicode(testrange1_size)], iparangetyperaw=[u'ipa-local'], iparangetype=[u'local domain range'], ), value=testrange1, summary=u'Added ID range "%s"' % (testrange1), ), ), dict( desc='Retrieve ID range %r' % (testrange1), command=('idrange_show', [testrange1], dict()), expected=dict( result=dict( dn=DN(('cn', testrange1), ('cn', 'ranges'), ('cn', 'etc'), api.env.basedn), cn=[testrange1], ipabaseid=[unicode(testrange1_base_id)], ipabaserid=[unicode(testrange1_base_rid)], ipasecondarybaserid=[ unicode(testrange1_secondary_base_rid) ], ipaidrangesize=[unicode(testrange1_size)], iparangetyperaw=[u'ipa-local'], iparangetype=[u'local domain range'], ), value=testrange1, summary=None, ), ), # Checks for modifications leaving objects outside of the range. dict( desc='Create user %r in ID range %r' % (user1, testrange1), command=('user_add', [user1], dict(givenname=u'Test', sn=u'User1', uidnumber=user1_uid)), expected=dict( value=user1, summary=u'Added user "%s"' % user1, result=get_user_result( user1, u'Test', u'User1', 'add', uidnumber=[unicode(user1_uid)], gidnumber=[unicode(user1_uid)], ), ), ), dict( desc='Create group %r in ID range %r' % (group1, testrange1), command=('group_add', [group1], dict(description=u'Test desc 1', gidnumber=group1_gid)), expected=dict( value=group1, summary=u'Added group "%s"' % group1, result=dict( cn=[group1], description=[u'Test desc 1'], gidnumber=[unicode(group1_gid)], objectclass=objectclasses.group + [u'posixgroup'], ipauniqueid=[fuzzy_uuid], dn=DN(('cn', group1), ('cn', 'groups'), ('cn', 'accounts'), api.env.basedn), ), ), ), dict( desc='Try to modify ID range %r to get out bounds object #1' % (testrange1), command=('idrange_mod', [testrange1], dict(ipabaseid=user1_uid + 1)), expected=errors.ExecutionError(message=IPA_LOCAL_RANGE_MOD_ERR), ), dict( desc='Try to modify ID range %r to get out bounds object #2' % (testrange1), command=('idrange_mod', [testrange1], dict(ipaidrangesize=100)), expected=errors.ExecutionError(message=IPA_LOCAL_RANGE_MOD_ERR), ), dict( desc='Try to modify ID range %r to get out bounds object #3' % (testrange1), command=('idrange_mod', [testrange1], dict(ipabaseid=100, ipaidrangesize=100)), expected=errors.ExecutionError(message=IPA_LOCAL_RANGE_MOD_ERR), ), dict(desc='Modify ID range %r' % (testrange1), command=('idrange_mod', [testrange1], dict(ipaidrangesize=90000)), expected=errors.ExecutionError(message=IPA_LOCAL_RANGE_MOD_ERR)), dict( desc='Try to delete ID range %r with active IDs inside it' % testrange1, command=('idrange_del', [testrange1], {}), expected=errors.ValidationError( name='ipabaseid,ipaidrangesize', error=u'range modification leaving objects with ID out of the' u' defined range is not allowed'), ), dict( desc='Delete user %r' % user1, command=('user_del', [user1], {}), expected=dict( result=dict(failed=[]), value=[user1], summary=u'Deleted user "%s"' % user1, ), ), dict( desc='Delete group %r' % group1, command=('group_del', [group1], {}), expected=dict( result=dict(failed=[]), value=[group1], summary=u'Deleted group "%s"' % group1, ), ), # Framework validation: mod local idrange with auto-private-groups # is prohibited dict(desc=('Try to modify local range %r with --auto-private-groups' % (testrange1)), command=('idrange_mod', [testrange1], dict(ipaautoprivategroups='true')), expected=errors.ExecutionError(message=IPA_LOCAL_RANGE_MOD_ERR)), dict( desc='Delete ID range %r' % testrange1, command=('idrange_del', [testrange1], {}), expected=dict( result=dict(failed=[]), value=[testrange1], summary=u'Deleted ID range "%s"' % testrange1, ), ), # Tests for overlapping local ranges. dict( desc='Create ID range %r' % (testrange2), command=('idrange_add', [testrange2], dict(ipabaseid=testrange2_base_id, ipaidrangesize=testrange2_size, ipabaserid=testrange2_base_rid, ipasecondarybaserid=testrange2_secondary_base_rid)), expected=dict( result=dict( dn=DN(('cn', testrange2), ('cn', 'ranges'), ('cn', 'etc'), api.env.basedn), cn=[testrange2], objectclass=[u'ipaIDrange', u'ipadomainidrange'], ipabaseid=[unicode(testrange2_base_id)], ipabaserid=[unicode(testrange2_base_rid)], ipasecondarybaserid=[ unicode(testrange2_secondary_base_rid) ], ipaidrangesize=[unicode(testrange2_size)], iparangetyperaw=[u'ipa-local'], iparangetype=[u'local domain range'], ), value=testrange2, summary=u'Added ID range "%s"' % (testrange2), ), ), dict( desc= 'Try to modify ID range %r so that its rid ranges are overlapping themselves' % (testrange2), command=('idrange_mod', [testrange2], dict(ipabaserid=(testrange2_secondary_base_rid))), expected=errors.ExecutionError(message=IPA_LOCAL_RANGE_MOD_ERR), ), dict( desc='Try to create ID range %r with overlapping rid range' % (testrange3), command=('idrange_add', [testrange3], dict(ipabaseid=testrange3_base_id, ipaidrangesize=testrange3_size, ipabaserid=testrange3_base_rid, ipasecondarybaserid=testrange3_secondary_base_rid)), expected=errors.DatabaseError( desc='Constraint violation', info= 'New primary rid range overlaps with existing primary rid range.' ), ), dict( desc= 'Try to create ID range %r with overlapping secondary rid range' % (testrange4), command=('idrange_add', [testrange4], dict(ipabaseid=testrange4_base_id, ipaidrangesize=testrange4_size, ipabaserid=testrange4_base_rid, ipasecondarybaserid=testrange4_secondary_base_rid)), expected=errors.DatabaseError( desc='Constraint violation', info= 'New secondary rid range overlaps with existing secondary rid range.' ), ), dict( desc= 'Try to create ID range %r with primary range overlapping secondary rid range' % (testrange5), command=('idrange_add', [testrange5], dict(ipabaseid=testrange5_base_id, ipaidrangesize=testrange5_size, ipabaserid=testrange5_base_rid, ipasecondarybaserid=testrange5_secondary_base_rid)), expected=errors.DatabaseError( desc='Constraint violation', info= 'New primary rid range overlaps with existing secondary rid range.' ), ), dict( desc='Try to create ID range %r with overlapping id range' % (testrange6), command=('idrange_add', [testrange6], dict(ipabaseid=testrange6_base_id, ipaidrangesize=testrange6_size, ipabaserid=testrange6_base_rid, ipasecondarybaserid=testrange6_secondary_base_rid)), expected=errors.DatabaseError( desc='Constraint violation', info='New base range overlaps with existing base range.'), ), dict( desc= 'Try to create ID range %r with rid ranges overlapping themselves' % (testrange7), command=('idrange_add', [testrange7], dict(ipabaseid=testrange7_base_id, ipaidrangesize=testrange7_size, ipabaserid=testrange7_base_rid, ipasecondarybaserid=testrange7_secondary_base_rid)), expected=errors.ValidationError( name='ID Range setup', error='Primary RID range and secondary RID range cannot overlap' ), ), dict( desc='Delete ID range %r' % testrange2, command=('idrange_del', [testrange2], {}), expected=dict( result=dict(failed=[]), value=[testrange2], summary=u'Deleted ID range "%s"' % testrange2, ), ), # Testing framework validation: --dom-sid/--dom-name and secondary RID # base cannot be used together dict( desc='Create ID range %r' % (testrange8), command=('idrange_add', [testrange8], dict(ipabaseid=testrange8_base_id, ipaidrangesize=testrange8_size, ipabaserid=testrange8_base_rid, ipasecondarybaserid=testrange8_secondary_base_rid, ipanttrusteddomainsid=domain1_sid)), expected=errors.ValidationError( name='ID Range setup', error='Options dom-sid/dom-name and ' 'secondary-rid-base cannot be used together'), ), # Testing framework validation: --auto-private-groups is prohibited # with ipa-local range dict( desc='Local ID range %r with auto-private-groups' % (testrange8), command=('idrange_add', [testrange8], dict(ipabaseid=testrange8_base_id, ipaidrangesize=testrange8_size, ipaautoprivategroups='true')), expected=errors.ValidationError( name='ID Range setup', error='IPA Range type must be one of ipa-ad-trust ' 'or ipa-ad-trust-posix when ' 'auto-private-groups is specified'), ), # Testing framework validation: --rid-base is prohibited with ipa-ad-posix dict( desc='Try to create ipa-ad-trust-posix ID range %r with base RID' % (domain7range1), command=('idrange_add', [domain7range1], dict(ipabaseid=domain7range1_base_id, ipaidrangesize=domain7range1_size, ipabaserid=domain7range1_base_rid, iparangetype=domain7range1_type, ipanttrusteddomainsid=domain7_sid)), expected=errors.ValidationError( name='ID Range setup', error='Option rid-base must not be used when IPA range ' 'type is ipa-ad-trust-posix'), ), # Testing framework validation: --auto-private-groups can only be # one of true, false, hybrid dict( desc=('Create ID range %r with bogus --auto-private-groups' % (domain7range1)), command=('idrange_add', [domain7range1], dict(ipabaseid=domain7range1_base_id, ipaidrangesize=domain7range1_size, iparangetype=domain7range1_type, ipanttrusteddomainsid=domain7_sid, ipaautoprivategroups='bogus')), expected=errors.ValidationError( name='auto_private_groups', error="must be one of 'true', 'false', 'hybrid'"), ), dict( desc='Create ID range %r' % (domain7range1), command=('idrange_add', [domain7range1], dict(ipabaseid=domain7range1_base_id, ipaidrangesize=domain7range1_size, iparangetype=domain7range1_type, ipanttrusteddomainsid=domain7_sid)), expected=dict( result=dict( dn=unicode(domain7range1_dn), cn=[domain7range1], objectclass=[u'ipaIDrange', u'ipatrustedaddomainrange'], ipabaseid=[unicode(domain7range1_base_id)], ipaidrangesize=[unicode(domain7range1_size)], ipanttrusteddomainsid=[unicode(domain7_sid)], iparangetyperaw=[u'ipa-ad-trust-posix'], iparangetype=[ u'Active Directory trust range with POSIX attributes' ], ), value=unicode(domain7range1), summary=u'Added ID range "%s"' % (domain7range1), ), ), dict( desc='Try to modify ipa-ad-trust-posix ID range %r with base RID' % (domain7range1), command=('idrange_mod', [domain7range1], dict(ipabaserid=domain7range1_base_rid)), expected=errors.ValidationError( name='ID Range setup', error='Option rid-base must not be used when IPA range ' 'type is ipa-ad-trust-posix'), ), # Testing prohibition of deletion of ranges belonging to active # trusted domains. dict( desc='Delete non-active AD trusted range %r' % domain1range1, command=('idrange_del', [domain1range1], {}), expected=dict( result=dict(failed=[]), value=[domain1range1], summary=u'Deleted ID range "%s"' % domain1range1, ), ), dict( desc='Try to delete active AD trusted range %r' % domain2range1, command=('idrange_del', [domain2range1], {}), expected=errors.DependentEntry(label='Active Trust domain', key=domain2range1, dependent=domain2), ), # Testing base range overlaps for ranges of different types and # different domains # - Base range overlaps # 1. ipa-ad-trust-posix type ranges from the same forest can overlap # on base ranges, use domain3range1 and domain3range2 dict( desc=('Modify ipa-ad-trust-posix range %r to overlap on base range' ' with posix range from the same domain' % (domain3range2)), command=('idrange_mod', [domain3range2], dict(ipabaseid=domain3range1_base_id)), expected=dict( messages=(messages.ServiceRestartRequired( service=services.knownservices['sssd'].systemd_name, server=domain3range2).to_dict(), ), result=dict( cn=[domain3range2], ipabaseid=[unicode(domain3range1_base_id)], ipaidrangesize=[unicode(domain3range2_size)], ipanttrusteddomainsid=[unicode(domain3_sid)], iparangetyperaw=[u'ipa-ad-trust-posix'], iparangetype=[ u'Active Directory trust range with POSIX ' 'attributes' ], ), value=domain3range2, summary=u'Modified ID range "%s"' % (domain3range2), ), ), # 2. ipa-ad-trust-posix type ranges from different forests cannot # overlap on base ranges, use domain3range1 and domain4range1 dict( desc=('Modify ipa-ad-trust-posix range %r to overlap on base range' ' with posix range from different domain' % (domain3range1)), command=('idrange_mod', [domain3range1], dict(ipabaseid=domain4range1_base_id)), expected=errors.DatabaseError( desc='Constraint violation', info='New base range overlaps with existing base range.'), ), # 3. ipa-ad-trust ranges from same forest cannot overlap on base ranges, # use domain5range1 and domain5range2 dict( desc=('Modify ipa-ad-trust range %r to overlap on base range' ' with posix range from the same domain' % (domain5range1)), command=('idrange_mod', [domain5range1], dict(ipabaseid=domain5range2_base_id)), expected=errors.DatabaseError( desc='Constraint violation', info='New base range overlaps with existing base range.'), ), # 4. ipa-ad-trust ranges from different forests cannot overlap on base # ranges, use domain5range1 and domain6range1 dict( desc=('Modify ipa-ad-trust range %r to overlap on base range' ' with posix range from different domain' % (domain5range1)), command=('idrange_mod', [domain5range1], dict(ipabaseid=domain6range1_base_id)), expected=errors.DatabaseError( desc='Constraint violation', info='New base range overlaps with existing base range.'), ), # - RID range overlaps # 1. Overlaps on base RID ranges are allowed for ranges from different # domains, use domain2range1 and domain5range1 dict( desc=('Modify ipa-ad-trust range %r to overlap on base RID' ' range with nonposix range from different domain' % (domain2range1)), command=('idrange_mod', [domain2range1], dict(ipabaserid=domain5range1_base_rid)), expected=dict( messages=(messages.ServiceRestartRequired( service=services.knownservices['sssd'].systemd_name, server=domain2range1).to_dict(), ), result=dict( cn=[domain2range1], ipabaseid=[unicode(domain2range1_base_id)], ipabaserid=[unicode(domain5range1_base_rid)], ipaidrangesize=[unicode(domain2range1_size)], ipanttrusteddomainsid=[unicode(domain2_sid)], iparangetyperaw=[u'ipa-ad-trust'], iparangetype=[u'Active Directory domain range'], ), value=domain2range1, summary=u'Modified ID range "%s"' % (domain2range1), ), ), # 2. ipa-ad-trust ranges from the same forest cannot overlap on base # RID ranges, use domain5range1 and domain5range2 dict( desc=('Modify ipa-ad-trust range %r to overlap on base RID range' ' with range from the same domain' % (domain2range1)), command=('idrange_mod', [domain2range1], dict(ipabaserid=domain2range2_base_rid)), expected=errors.DatabaseError( desc='Constraint violation', info='New primary rid range overlaps with existing primary rid ' 'range.'), ), dict( desc=('Modify ipa-ad-trust range %r with --auto-private-groups=' 'true' % (domain2range1)), command=('idrange_mod', [domain2range1], dict(ipaautoprivategroups='true')), expected=dict( messages=(messages.ServiceRestartRequired( service=services.knownservices['sssd'].systemd_name, server=domain2range1).to_dict(), ), result=dict( cn=[domain2range1], ipabaseid=[unicode(domain2range1_base_id)], ipabaserid=[unicode(domain5range1_base_rid)], ipaidrangesize=[unicode(domain2range1_size)], ipanttrusteddomainsid=[unicode(domain2_sid)], iparangetyperaw=[u'ipa-ad-trust'], ipaautoprivategroups=[u'true'], iparangetype=[u'Active Directory domain range'], ), value=domain2range1, summary=u'Modified ID range "%s"' % (domain2range1), ), ), dict( desc=('Modify ipa-ad-trust range %r with --auto-private-groups=' 'false' % (domain2range1)), command=('idrange_mod', [domain2range1], dict(ipaautoprivategroups='false')), expected=dict( messages=(messages.ServiceRestartRequired( service=services.knownservices['sssd'].systemd_name, server=domain2range1).to_dict(), ), result=dict( cn=[domain2range1], ipabaseid=[unicode(domain2range1_base_id)], ipabaserid=[unicode(domain5range1_base_rid)], ipaidrangesize=[unicode(domain2range1_size)], ipanttrusteddomainsid=[unicode(domain2_sid)], iparangetyperaw=[u'ipa-ad-trust'], ipaautoprivategroups=[u'false'], iparangetype=[u'Active Directory domain range'], ), value=domain2range1, summary=u'Modified ID range "%s"' % (domain2range1), ), ), dict( desc=('Modify ipa-ad-trust range %r with --auto-private-groups=' 'hybrid' % (domain2range1)), command=('idrange_mod', [domain2range1], dict(ipaautoprivategroups='hybrid')), expected=dict( messages=(messages.ServiceRestartRequired( service=services.knownservices['sssd'].systemd_name, server=domain2range1).to_dict(), ), result=dict( cn=[domain2range1], ipabaseid=[unicode(domain2range1_base_id)], ipabaserid=[unicode(domain5range1_base_rid)], ipaidrangesize=[unicode(domain2range1_size)], ipanttrusteddomainsid=[unicode(domain2_sid)], iparangetyperaw=[u'ipa-ad-trust'], ipaautoprivategroups=[u'hybrid'], iparangetype=[u'Active Directory domain range'], ), value=domain2range1, summary=u'Modified ID range "%s"' % (domain2range1), ), ), dict( desc=('Modify ipa-ad-trust range %r with --auto-private-groups=' '<empty>' % (domain2range1)), command=('idrange_mod', [domain2range1], dict(ipaautoprivategroups='')), expected=dict( messages=(messages.ServiceRestartRequired( service=services.knownservices['sssd'].systemd_name, server=domain2range1).to_dict(), ), result=dict( cn=[domain2range1], ipabaseid=[unicode(domain2range1_base_id)], ipabaserid=[unicode(domain5range1_base_rid)], ipaidrangesize=[unicode(domain2range1_size)], ipanttrusteddomainsid=[unicode(domain2_sid)], iparangetyperaw=[u'ipa-ad-trust'], iparangetype=[u'Active Directory domain range'], ), value=domain2range1, summary=u'Modified ID range "%s"' % (domain2range1), ), ), # Test for bug 6404 # if dom-name is empty, add should not fail dict( desc='Create ID range %r' % (testrange9), command=('idrange_add', [testrange9], dict(ipanttrusteddomainname=None, ipabaseid=testrange9_base_id, ipaidrangesize=testrange9_size, ipabaserid=testrange9_base_rid, ipasecondarybaserid=testrange9_secondary_base_rid)), expected=dict( result=dict( dn=DN(('cn', testrange9), ('cn', 'ranges'), ('cn', 'etc'), api.env.basedn), cn=[testrange9], objectclass=[u'ipaIDrange', u'ipadomainidrange'], ipabaseid=[unicode(testrange9_base_id)], ipabaserid=[unicode(testrange9_base_rid)], ipasecondarybaserid=[ unicode(testrange9_secondary_base_rid) ], ipaidrangesize=[unicode(testrange9_size)], iparangetyperaw=[u'ipa-local'], iparangetype=[u'local domain range'], ), value=testrange9, summary=u'Added ID range "%s"' % (testrange9), ), ), dict( desc='Delete ID range %r' % testrange9, command=('idrange_del', [testrange9], {}), expected=dict( result=dict(failed=[]), value=[testrange9], summary=u'Deleted ID range "%s"' % testrange9, ), ), ]