Search in sources :

Example 6 with ClientQuotaEntity

use of org.apache.kafka.common.quota.ClientQuotaEntity in project kafka by apache.

the class ClientQuotaControlManager method alterClientQuotaEntity.

private void alterClientQuotaEntity(ClientQuotaEntity entity, Map<String, Double> newQuotaConfigs, List<ApiMessageAndVersion> outputRecords, Map<ClientQuotaEntity, ApiError> outputResults) {
    // Check entity types and sanitize the names
    Map<String, String> validatedEntityMap = new HashMap<>(3);
    ApiError error = validateEntity(entity, validatedEntityMap);
    if (error.isFailure()) {
        outputResults.put(entity, error);
        return;
    }
    // Check the combination of entity types and get the config keys
    Map<String, ConfigDef.ConfigKey> configKeys = new HashMap<>(4);
    error = configKeysForEntityType(validatedEntityMap, configKeys);
    if (error.isFailure()) {
        outputResults.put(entity, error);
        return;
    }
    // Don't share objects between different records
    Supplier<List<EntityData>> recordEntitySupplier = () -> validatedEntityMap.entrySet().stream().map(mapEntry -> new EntityData().setEntityType(mapEntry.getKey()).setEntityName(mapEntry.getValue())).collect(Collectors.toList());
    List<ApiMessageAndVersion> newRecords = new ArrayList<>(newQuotaConfigs.size());
    Map<String, Double> currentQuotas = clientQuotaData.containsKey(entity) ? clientQuotaData.get(entity) : Collections.emptyMap();
    for (Map.Entry<String, Double> entry : newQuotaConfigs.entrySet()) {
        String key = entry.getKey();
        Double newValue = entry.getValue();
        if (newValue == null) {
            if (currentQuotas.containsKey(key)) {
                // Null value indicates removal
                newRecords.add(new ApiMessageAndVersion(new ClientQuotaRecord().setEntity(recordEntitySupplier.get()).setKey(key).setRemove(true), CLIENT_QUOTA_RECORD.highestSupportedVersion()));
            }
        } else {
            ApiError validationError = validateQuotaKeyValue(configKeys, key, newValue);
            if (validationError.isFailure()) {
                outputResults.put(entity, validationError);
                return;
            } else {
                final Double currentValue = currentQuotas.get(key);
                if (!Objects.equals(currentValue, newValue)) {
                    // Only record the new value if it has changed
                    newRecords.add(new ApiMessageAndVersion(new ClientQuotaRecord().setEntity(recordEntitySupplier.get()).setKey(key).setValue(newValue), CLIENT_QUOTA_RECORD.highestSupportedVersion()));
                }
            }
        }
    }
    outputRecords.addAll(newRecords);
    outputResults.put(entity, ApiError.NONE);
}
Also used : TimelineHashMap(org.apache.kafka.timeline.TimelineHashMap) HashMap(java.util.HashMap) Supplier(java.util.function.Supplier) ApiError(org.apache.kafka.common.requests.ApiError) ArrayList(java.util.ArrayList) InetAddress(java.net.InetAddress) ClientQuotaRecord(org.apache.kafka.common.metadata.ClientQuotaRecord) ClientQuotaEntity(org.apache.kafka.common.quota.ClientQuotaEntity) Map(java.util.Map) ApiMessageAndVersion(org.apache.kafka.server.common.ApiMessageAndVersion) NoSuchElementException(java.util.NoSuchElementException) QuotaConfigs(org.apache.kafka.common.config.internals.QuotaConfigs) ConfigDef(org.apache.kafka.common.config.ConfigDef) ClientQuotaAlteration(org.apache.kafka.common.quota.ClientQuotaAlteration) Iterator(java.util.Iterator) EntityData(org.apache.kafka.common.metadata.ClientQuotaRecord.EntityData) Collection(java.util.Collection) UnknownHostException(java.net.UnknownHostException) Collectors(java.util.stream.Collectors) SnapshotRegistry(org.apache.kafka.timeline.SnapshotRegistry) Objects(java.util.Objects) List(java.util.List) CLIENT_QUOTA_RECORD(org.apache.kafka.common.metadata.MetadataRecordType.CLIENT_QUOTA_RECORD) Entry(java.util.Map.Entry) Errors(org.apache.kafka.common.protocol.Errors) InvalidRequestException(org.apache.kafka.common.errors.InvalidRequestException) Collections(java.util.Collections) TimelineHashMap(org.apache.kafka.timeline.TimelineHashMap) HashMap(java.util.HashMap) EntityData(org.apache.kafka.common.metadata.ClientQuotaRecord.EntityData) ArrayList(java.util.ArrayList) ClientQuotaRecord(org.apache.kafka.common.metadata.ClientQuotaRecord) ApiMessageAndVersion(org.apache.kafka.server.common.ApiMessageAndVersion) ArrayList(java.util.ArrayList) List(java.util.List) ApiError(org.apache.kafka.common.requests.ApiError) TimelineHashMap(org.apache.kafka.timeline.TimelineHashMap) HashMap(java.util.HashMap) Map(java.util.Map)

Example 7 with ClientQuotaEntity

use of org.apache.kafka.common.quota.ClientQuotaEntity in project kafka by apache.

the class ClientQuotaControlManager method replay.

/**
 * Apply a quota record to the in-memory state.
 *
 * @param record    A ClientQuotaRecord instance.
 */
public void replay(ClientQuotaRecord record) {
    Map<String, String> entityMap = new HashMap<>(2);
    record.entity().forEach(entityData -> entityMap.put(entityData.entityType(), entityData.entityName()));
    ClientQuotaEntity entity = new ClientQuotaEntity(entityMap);
    TimelineHashMap<String, Double> quotas = clientQuotaData.get(entity);
    if (quotas == null) {
        quotas = new TimelineHashMap<>(snapshotRegistry, 0);
        clientQuotaData.put(entity, quotas);
    }
    if (record.remove()) {
        quotas.remove(record.key());
        if (quotas.size() == 0) {
            clientQuotaData.remove(entity);
        }
    } else {
        quotas.put(record.key(), record.value());
    }
}
Also used : TimelineHashMap(org.apache.kafka.timeline.TimelineHashMap) HashMap(java.util.HashMap) ClientQuotaEntity(org.apache.kafka.common.quota.ClientQuotaEntity)

Example 8 with ClientQuotaEntity

use of org.apache.kafka.common.quota.ClientQuotaEntity in project kafka by apache.

the class ClientQuotaControlManagerTest method testAlterAndRemove.

@Test
public void testAlterAndRemove() {
    SnapshotRegistry snapshotRegistry = new SnapshotRegistry(new LogContext());
    ClientQuotaControlManager manager = new ClientQuotaControlManager(snapshotRegistry);
    ClientQuotaEntity userEntity = userEntity("user-1");
    List<ClientQuotaAlteration> alters = new ArrayList<>();
    // Add one quota
    entityQuotaToAlterations(userEntity, quotas(QuotaConfigs.PRODUCER_BYTE_RATE_OVERRIDE_CONFIG, 10000.0), alters::add);
    alterQuotas(alters, manager);
    assertEquals(1, manager.clientQuotaData.get(userEntity).size());
    assertEquals(10000.0, manager.clientQuotaData.get(userEntity).get(QuotaConfigs.PRODUCER_BYTE_RATE_OVERRIDE_CONFIG), 1e-6);
    // Replace it and add another
    alters.clear();
    entityQuotaToAlterations(userEntity, quotas(QuotaConfigs.PRODUCER_BYTE_RATE_OVERRIDE_CONFIG, 10001.0, QuotaConfigs.CONSUMER_BYTE_RATE_OVERRIDE_CONFIG, 20000.0), alters::add);
    alterQuotas(alters, manager);
    assertEquals(2, manager.clientQuotaData.get(userEntity).size());
    assertEquals(10001.0, manager.clientQuotaData.get(userEntity).get(QuotaConfigs.PRODUCER_BYTE_RATE_OVERRIDE_CONFIG), 1e-6);
    assertEquals(20000.0, manager.clientQuotaData.get(userEntity).get(QuotaConfigs.CONSUMER_BYTE_RATE_OVERRIDE_CONFIG), 1e-6);
    // Remove one of the quotas, the other remains
    alters.clear();
    entityQuotaToAlterations(userEntity, quotas(QuotaConfigs.PRODUCER_BYTE_RATE_OVERRIDE_CONFIG, null), alters::add);
    alterQuotas(alters, manager);
    assertEquals(1, manager.clientQuotaData.get(userEntity).size());
    assertEquals(20000.0, manager.clientQuotaData.get(userEntity).get(QuotaConfigs.CONSUMER_BYTE_RATE_OVERRIDE_CONFIG), 1e-6);
    // Remove non-existent quota, no change
    alters.clear();
    entityQuotaToAlterations(userEntity, quotas(QuotaConfigs.REQUEST_PERCENTAGE_OVERRIDE_CONFIG, null), alters::add);
    alterQuotas(alters, manager);
    assertEquals(1, manager.clientQuotaData.get(userEntity).size());
    assertEquals(20000.0, manager.clientQuotaData.get(userEntity).get(QuotaConfigs.CONSUMER_BYTE_RATE_OVERRIDE_CONFIG), 1e-6);
    // All quotas removed, we should cleanup the map
    alters.clear();
    entityQuotaToAlterations(userEntity, quotas(QuotaConfigs.CONSUMER_BYTE_RATE_OVERRIDE_CONFIG, null), alters::add);
    alterQuotas(alters, manager);
    assertFalse(manager.clientQuotaData.containsKey(userEntity));
    // Remove non-existent quota, again no change
    alters.clear();
    entityQuotaToAlterations(userEntity, quotas(QuotaConfigs.CONSUMER_BYTE_RATE_OVERRIDE_CONFIG, null), alters::add);
    alterQuotas(alters, manager);
    assertFalse(manager.clientQuotaData.containsKey(userEntity));
    // Mixed update
    alters.clear();
    Map<String, Double> quotas = new HashMap<>(4);
    quotas.put(QuotaConfigs.REQUEST_PERCENTAGE_OVERRIDE_CONFIG, 99.0);
    quotas.put(QuotaConfigs.CONTROLLER_MUTATION_RATE_OVERRIDE_CONFIG, null);
    quotas.put(QuotaConfigs.PRODUCER_BYTE_RATE_OVERRIDE_CONFIG, 10002.0);
    quotas.put(QuotaConfigs.CONSUMER_BYTE_RATE_OVERRIDE_CONFIG, 20001.0);
    entityQuotaToAlterations(userEntity, quotas, alters::add);
    alterQuotas(alters, manager);
    assertEquals(3, manager.clientQuotaData.get(userEntity).size());
    assertEquals(20001.0, manager.clientQuotaData.get(userEntity).get(QuotaConfigs.CONSUMER_BYTE_RATE_OVERRIDE_CONFIG), 1e-6);
    assertEquals(10002.0, manager.clientQuotaData.get(userEntity).get(QuotaConfigs.PRODUCER_BYTE_RATE_OVERRIDE_CONFIG), 1e-6);
    assertEquals(99.0, manager.clientQuotaData.get(userEntity).get(QuotaConfigs.REQUEST_PERCENTAGE_OVERRIDE_CONFIG), 1e-6);
}
Also used : ClientQuotaAlteration(org.apache.kafka.common.quota.ClientQuotaAlteration) SnapshotRegistry(org.apache.kafka.timeline.SnapshotRegistry) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) LogContext(org.apache.kafka.common.utils.LogContext) ClientQuotaEntity(org.apache.kafka.common.quota.ClientQuotaEntity) Test(org.junit.jupiter.api.Test)

Example 9 with ClientQuotaEntity

use of org.apache.kafka.common.quota.ClientQuotaEntity in project kafka by apache.

the class ClientQuotaControlManagerTest method entityQuotaToAlterations.

static void entityQuotaToAlterations(ClientQuotaEntity entity, Map<String, Double> quota, Consumer<ClientQuotaAlteration> acceptor) {
    Collection<ClientQuotaAlteration.Op> ops = quota.entrySet().stream().map(quotaEntry -> new ClientQuotaAlteration.Op(quotaEntry.getKey(), quotaEntry.getValue())).collect(Collectors.toList());
    acceptor.accept(new ClientQuotaAlteration(entity, ops));
}
Also used : Arrays(java.util.Arrays) HashMap(java.util.HashMap) ApiError(org.apache.kafka.common.requests.ApiError) ArrayList(java.util.ArrayList) ClientQuotaRecord(org.apache.kafka.common.metadata.ClientQuotaRecord) Assertions.assertFalse(org.junit.jupiter.api.Assertions.assertFalse) ClientQuotaEntity(org.apache.kafka.common.quota.ClientQuotaEntity) LogContext(org.apache.kafka.common.utils.LogContext) Map(java.util.Map) ApiMessageAndVersion(org.apache.kafka.server.common.ApiMessageAndVersion) Assertions.assertEquals(org.junit.jupiter.api.Assertions.assertEquals) QuotaConfigs(org.apache.kafka.common.config.internals.QuotaConfigs) ClientQuotaAlteration(org.apache.kafka.common.quota.ClientQuotaAlteration) EntityData(org.apache.kafka.common.metadata.ClientQuotaRecord.EntityData) Collection(java.util.Collection) Collectors(java.util.stream.Collectors) SnapshotRegistry(org.apache.kafka.timeline.SnapshotRegistry) Test(org.junit.jupiter.api.Test) Consumer(java.util.function.Consumer) List(java.util.List) RecordTestUtils(org.apache.kafka.metadata.RecordTestUtils) Assertions.assertTrue(org.junit.jupiter.api.Assertions.assertTrue) Errors(org.apache.kafka.common.protocol.Errors) Timeout(org.junit.jupiter.api.Timeout) Collections(java.util.Collections) ClientQuotaAlteration(org.apache.kafka.common.quota.ClientQuotaAlteration)

Example 10 with ClientQuotaEntity

use of org.apache.kafka.common.quota.ClientQuotaEntity in project kafka by apache.

the class ClientQuotaControlManagerTest method testEntityTypes.

@Test
public void testEntityTypes() throws Exception {
    SnapshotRegistry snapshotRegistry = new SnapshotRegistry(new LogContext());
    ClientQuotaControlManager manager = new ClientQuotaControlManager(snapshotRegistry);
    Map<ClientQuotaEntity, Map<String, Double>> quotasToTest = new HashMap<>();
    quotasToTest.put(userClientEntity("user-1", "client-id-1"), quotas(QuotaConfigs.REQUEST_PERCENTAGE_OVERRIDE_CONFIG, 50.50));
    quotasToTest.put(userClientEntity("user-2", "client-id-1"), quotas(QuotaConfigs.REQUEST_PERCENTAGE_OVERRIDE_CONFIG, 51.51));
    quotasToTest.put(userClientEntity("user-3", "client-id-2"), quotas(QuotaConfigs.REQUEST_PERCENTAGE_OVERRIDE_CONFIG, 52.52));
    quotasToTest.put(userClientEntity(null, "client-id-1"), quotas(QuotaConfigs.REQUEST_PERCENTAGE_OVERRIDE_CONFIG, 53.53));
    quotasToTest.put(userClientEntity("user-1", null), quotas(QuotaConfigs.REQUEST_PERCENTAGE_OVERRIDE_CONFIG, 54.54));
    quotasToTest.put(userClientEntity("user-3", null), quotas(QuotaConfigs.REQUEST_PERCENTAGE_OVERRIDE_CONFIG, 55.55));
    quotasToTest.put(userEntity("user-1"), quotas(QuotaConfigs.REQUEST_PERCENTAGE_OVERRIDE_CONFIG, 56.56));
    quotasToTest.put(userEntity("user-2"), quotas(QuotaConfigs.REQUEST_PERCENTAGE_OVERRIDE_CONFIG, 57.57));
    quotasToTest.put(userEntity("user-3"), quotas(QuotaConfigs.REQUEST_PERCENTAGE_OVERRIDE_CONFIG, 58.58));
    quotasToTest.put(userEntity(null), quotas(QuotaConfigs.REQUEST_PERCENTAGE_OVERRIDE_CONFIG, 59.59));
    quotasToTest.put(clientEntity("client-id-2"), quotas(QuotaConfigs.REQUEST_PERCENTAGE_OVERRIDE_CONFIG, 60.60));
    List<ClientQuotaAlteration> alters = new ArrayList<>();
    quotasToTest.forEach((entity, quota) -> entityQuotaToAlterations(entity, quota, alters::add));
    alterQuotas(alters, manager);
    RecordTestUtils.assertBatchIteratorContains(Arrays.asList(Arrays.asList(new ApiMessageAndVersion(new ClientQuotaRecord().setEntity(Arrays.asList(new EntityData().setEntityType("user").setEntityName("user-1"), new EntityData().setEntityType("client-id").setEntityName("client-id-1"))).setKey("request_percentage").setValue(50.5).setRemove(false), (short) 0)), Arrays.asList(new ApiMessageAndVersion(new ClientQuotaRecord().setEntity(Arrays.asList(new EntityData().setEntityType("user").setEntityName("user-2"), new EntityData().setEntityType("client-id").setEntityName("client-id-1"))).setKey("request_percentage").setValue(51.51).setRemove(false), (short) 0)), Arrays.asList(new ApiMessageAndVersion(new ClientQuotaRecord().setEntity(Arrays.asList(new EntityData().setEntityType("user").setEntityName("user-3"), new EntityData().setEntityType("client-id").setEntityName("client-id-2"))).setKey("request_percentage").setValue(52.52).setRemove(false), (short) 0)), Arrays.asList(new ApiMessageAndVersion(new ClientQuotaRecord().setEntity(Arrays.asList(new EntityData().setEntityType("user").setEntityName(null), new EntityData().setEntityType("client-id").setEntityName("client-id-1"))).setKey("request_percentage").setValue(53.53).setRemove(false), (short) 0)), Arrays.asList(new ApiMessageAndVersion(new ClientQuotaRecord().setEntity(Arrays.asList(new EntityData().setEntityType("user").setEntityName("user-1"), new EntityData().setEntityType("client-id").setEntityName(null))).setKey("request_percentage").setValue(54.54).setRemove(false), (short) 0)), Arrays.asList(new ApiMessageAndVersion(new ClientQuotaRecord().setEntity(Arrays.asList(new EntityData().setEntityType("user").setEntityName("user-3"), new EntityData().setEntityType("client-id").setEntityName(null))).setKey("request_percentage").setValue(55.55).setRemove(false), (short) 0)), Arrays.asList(new ApiMessageAndVersion(new ClientQuotaRecord().setEntity(Arrays.asList(new EntityData().setEntityType("user").setEntityName("user-1"))).setKey("request_percentage").setValue(56.56).setRemove(false), (short) 0)), Arrays.asList(new ApiMessageAndVersion(new ClientQuotaRecord().setEntity(Arrays.asList(new EntityData().setEntityType("user").setEntityName("user-2"))).setKey("request_percentage").setValue(57.57).setRemove(false), (short) 0)), Arrays.asList(new ApiMessageAndVersion(new ClientQuotaRecord().setEntity(Arrays.asList(new EntityData().setEntityType("user").setEntityName("user-3"))).setKey("request_percentage").setValue(58.58).setRemove(false), (short) 0)), Arrays.asList(new ApiMessageAndVersion(new ClientQuotaRecord().setEntity(Arrays.asList(new EntityData().setEntityType("user").setEntityName(null))).setKey("request_percentage").setValue(59.59).setRemove(false), (short) 0)), Arrays.asList(new ApiMessageAndVersion(new ClientQuotaRecord().setEntity(Arrays.asList(new EntityData().setEntityType("client-id").setEntityName("client-id-2"))).setKey("request_percentage").setValue(60.60).setRemove(false), (short) 0))), manager.iterator(Long.MAX_VALUE));
}
Also used : ClientQuotaAlteration(org.apache.kafka.common.quota.ClientQuotaAlteration) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) EntityData(org.apache.kafka.common.metadata.ClientQuotaRecord.EntityData) LogContext(org.apache.kafka.common.utils.LogContext) ClientQuotaRecord(org.apache.kafka.common.metadata.ClientQuotaRecord) SnapshotRegistry(org.apache.kafka.timeline.SnapshotRegistry) ApiMessageAndVersion(org.apache.kafka.server.common.ApiMessageAndVersion) ClientQuotaEntity(org.apache.kafka.common.quota.ClientQuotaEntity) HashMap(java.util.HashMap) Map(java.util.Map) Test(org.junit.jupiter.api.Test)

Aggregations

ClientQuotaEntity (org.apache.kafka.common.quota.ClientQuotaEntity)22 HashMap (java.util.HashMap)15 ClientQuotaAlteration (org.apache.kafka.common.quota.ClientQuotaAlteration)9 ArrayList (java.util.ArrayList)8 Map (java.util.Map)7 Test (org.junit.jupiter.api.Test)7 SnapshotRegistry (org.apache.kafka.timeline.SnapshotRegistry)6 LogContext (org.apache.kafka.common.utils.LogContext)5 Errors (org.apache.kafka.common.protocol.Errors)4 ClientQuotaRecord (org.apache.kafka.common.metadata.ClientQuotaRecord)3 EntityData (org.apache.kafka.common.metadata.ClientQuotaRecord.EntityData)3 ApiError (org.apache.kafka.common.requests.ApiError)3 ApiMessageAndVersion (org.apache.kafka.server.common.ApiMessageAndVersion)3 Collection (java.util.Collection)2 Collections (java.util.Collections)2 List (java.util.List)2 Collectors (java.util.stream.Collectors)2 QuotaConfigs (org.apache.kafka.common.config.internals.QuotaConfigs)2 InvalidRequestException (org.apache.kafka.common.errors.InvalidRequestException)2 EntryData (org.apache.kafka.common.message.AlterClientQuotasResponseData.EntryData)2