io.cdap.plugin.kafka.common.KafkaHelpers Maven / Gradle / Ivy
The newest version!
/*
* Copyright © 2018 Cask Data, Inc.
*
* 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.
*/
package io.cdap.plugin.kafka.common;
import com.google.common.base.Strings;
import io.cdap.cdap.etl.api.FailureCollector;
import org.apache.kafka.clients.consumer.Consumer;
import org.apache.kafka.common.TopicPartition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nullable;
/**
* Utility class for Kafka operations
*/
public final class KafkaHelpers {
private static final Logger LOG = LoggerFactory.getLogger(KafkaHelpers.class);
public static final String SASL_JAAS_CONFIG = "sasl.jaas.config";
public static final String PRINCIPAL = "principal";
public static final String KEYTAB = "keytab";
// This class cannot be instantiated
private KafkaHelpers() {
}
/**
* Fetch the latest offsets for the given topic-partitions
*
* @param consumer The Kafka consumer
* @param topicAndPartitions topic-partitions to fetch the offsets for
* @return Mapping of topic-partiton to its latest offset
*/
public static Map getLatestOffsets(Consumer consumer,
Collection topicAndPartitions) {
if (topicAndPartitions.isEmpty()) {
return Collections.emptyMap();
}
consumer.assign(topicAndPartitions);
consumer.seekToEnd(topicAndPartitions);
Map offsets = new HashMap<>();
for (TopicPartition topicAndPartition : topicAndPartitions) {
long offset = consumer.position(topicAndPartition);
offsets.put(topicAndPartition, offset);
}
return offsets;
}
/**
* Fetch the earliest offsets for the given topic-partitions
*
* @param consumer The Kafka consumer
* @param topicAndPartitions topic-partitions to fetch the offsets for
* @return Mapping of topic-partiton to its earliest offset
*/
public static Map getEarliestOffsets(Consumer consumer,
Collection topicAndPartitions) {
if (topicAndPartitions.isEmpty()) {
return Collections.emptyMap();
}
consumer.assign(topicAndPartitions);
consumer.seekToBeginning(topicAndPartitions);
Map offsets = new HashMap<>();
for (TopicPartition topicAndPartition : topicAndPartitions) {
long offset = consumer.position(topicAndPartition);
offsets.put(topicAndPartition, offset);
}
return offsets;
}
/**
* Adds the JAAS conf to the Kafka configuration object for Kafka client login, if needed.
* The JAAS conf is not added if either the principal or the keytab is null.
*
* @param conf Kafka configuration object to add the JAAS conf to
* @param principal Kerberos principal
* @param keytabLocation Kerberos keytab for the principal
*/
public static void setupKerberosLogin(Map conf, @Nullable String principal,
@Nullable String keytabLocation) {
if (principal != null && keytabLocation != null) {
LOG.debug("Adding Kerberos login conf to Kafka for principal {} and keytab {}",
principal, keytabLocation);
conf.put(SASL_JAAS_CONFIG, String.format("com.sun.security.auth.module.Krb5LoginModule required \n" +
" useKeyTab=true \n" +
" storeKey=true \n" +
" useTicketCache=false \n" +
" renewTicket=true \n" +
" keyTab=\"%s\" \n" +
" principal=\"%s\";",
keytabLocation, principal));
} else {
LOG.debug("Not adding Kerberos login conf to Kafka since either the principal {} or the keytab {} is null",
principal, keytabLocation);
}
}
/**
* Validates whether the principal and keytab are both set or both of them are null/empty
*
* @param principal Kerberos principal
* @param keytab Kerberos keytab for the principal
*/
public static void validateKerberosSetting(@Nullable String principal, @Nullable String keytab) {
if (Strings.isNullOrEmpty(principal) != Strings.isNullOrEmpty(keytab)) {
String emptyField = Strings.isNullOrEmpty(principal) ? PRINCIPAL : KEYTAB;
String message = emptyField + " is empty. When Kerberos security is enabled for Kafka, " +
"then both the principal and the keytab have " +
"to be specified. If Kerberos is not enabled, then both should be empty.";
throw new IllegalArgumentException(message);
}
}
/**
* Validates whether the principal and keytab are both set or both of them are null/empty.
* Stores the result in the provided failureCollector.
*
* @param principal Kerberos principal
* @param keytab Kerberos keytab for the principal
* @param collector input failureCollector into which the error will be added if present
*/
public static void validateKerberosSetting(@Nullable String principal, @Nullable String keytab,
FailureCollector collector) {
if (Strings.isNullOrEmpty(principal) != Strings.isNullOrEmpty(keytab)) {
String emptyField = Strings.isNullOrEmpty(principal) ? PRINCIPAL : KEYTAB;
String message = "Field " + emptyField + " must be specified.";
collector.addFailure(message, null).withConfigProperty(emptyField);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy