Skip to content

Commit d6b932f

Browse files
committed
Merge remote-tracking branch 'origin/release/2.2' into develop
2 parents dd846f4 + 99d7c8a commit d6b932f

File tree

21 files changed

+1181
-710
lines changed

21 files changed

+1181
-710
lines changed

kafka-plugins-0.10/pom.xml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@
1919
<artifactId>kafka-plugins-common</artifactId>
2020
<version>${project.parent.version}</version>
2121
</dependency>
22+
<dependency>
23+
<groupId>org.apache.avro</groupId>
24+
<artifactId>avro</artifactId>
25+
<version>${avro.version}</version>
26+
</dependency>
2227
<dependency>
2328
<groupId>org.apache.kafka</groupId>
2429
<artifactId>kafka_2.11</artifactId>
@@ -182,8 +187,8 @@
182187
<version>1.1.0</version>
183188
<configuration>
184189
<cdapArtifacts>
185-
<parent>system:cdap-data-pipeline[6.0.0,7.0.0-SNAPSHOT)</parent>
186-
<parent>system:cdap-data-streams[6.0.0,7.0.0-SNAPSHOT)</parent>
190+
<parent>system:cdap-data-pipeline[6.1.0-SNAPSHOT,7.0.0-SNAPSHOT)</parent>
191+
<parent>system:cdap-data-streams[6.1.0-SNAPSHOT,7.0.0-SNAPSHOT)</parent>
187192
</cdapArtifacts>
188193
</configuration>
189194
<executions>

kafka-plugins-0.10/src/main/java/io/cdap/plugin/alertpublisher/KafkaAlertPublisher.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import io.cdap.cdap.etl.api.Alert;
2828
import io.cdap.cdap.etl.api.AlertPublisher;
2929
import io.cdap.cdap.etl.api.AlertPublisherContext;
30+
import io.cdap.cdap.etl.api.FailureCollector;
3031
import io.cdap.cdap.etl.api.PipelineConfigurer;
3132
import io.cdap.plugin.common.KafkaHelpers;
3233
import io.cdap.plugin.common.KeyValueListParser;
@@ -62,13 +63,14 @@ public KafkaAlertPublisher(Config config) {
6263

6364
@Override
6465
public void configurePipeline(PipelineConfigurer pipelineConfigurer) throws IllegalArgumentException {
65-
config.validate();
66+
config.validate(pipelineConfigurer.getStageConfigurer().getFailureCollector());
6667
}
6768

6869
@Override
6970
public void initialize(AlertPublisherContext context) throws Exception {
7071
super.initialize(context);
71-
config.validate();
72+
config.validate(context.getFailureCollector());
73+
context.getFailureCollector().getOrThrowException();
7274
Properties props = new Properties();
7375
// Add client id property with stage name as value.
7476
props.put(ProducerConfig.CLIENT_ID_CONFIG, context.getStageName());
@@ -112,6 +114,7 @@ public void destroy() {
112114
*/
113115
public static class Config extends PluginConfig {
114116

117+
public static final String TOPIC = "topic";
115118
@Name("brokers")
116119
@Description("Specifies the connection string where Producer can find one or more brokers to " +
117120
"determine the leader for each topic.")
@@ -157,7 +160,7 @@ private Map<String, String> getProducerProperties() {
157160
return producerProps;
158161
}
159162

160-
private void validate() {
163+
private void validate(FailureCollector collector) {
161164
// If the topic or brokers are macros they would not be available at config time. So do not perform
162165
// validations yet.
163166
if (Strings.isNullOrEmpty(topic) || Strings.isNullOrEmpty(brokers)) {
@@ -167,11 +170,13 @@ private void validate() {
167170
try {
168171
Topic.validate(topic);
169172
} catch (InvalidTopicException e) {
170-
throw new IllegalArgumentException(String.format("Topic name %s is not a valid kafka topic. Please provide " +
171-
"valid kafka topic name. %s", topic, e.getMessage()));
173+
collector.addFailure(String.format(
174+
"Topic name %s is not a valid kafka topic. Please provide valid kafka topic name. %s", topic,
175+
e.getMessage()), null)
176+
.withConfigProperty(TOPIC);
172177
}
173178

174-
KafkaHelpers.validateKerberosSetting(principal, keytabLocation);
179+
KafkaHelpers.validateKerberosSetting(principal, keytabLocation, collector);
175180
}
176181
}
177182
}

kafka-plugins-0.10/src/main/java/io/cdap/plugin/batch/source/KafkaBatchSource.java

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@
2929
import io.cdap.cdap.api.dataset.lib.KeyValue;
3030
import io.cdap.cdap.common.io.ByteBuffers;
3131
import io.cdap.cdap.etl.api.Emitter;
32+
import io.cdap.cdap.etl.api.FailureCollector;
3233
import io.cdap.cdap.etl.api.PipelineConfigurer;
34+
import io.cdap.cdap.etl.api.StageConfigurer;
3335
import io.cdap.cdap.etl.api.batch.BatchRuntimeContext;
3436
import io.cdap.cdap.etl.api.batch.BatchSource;
3537
import io.cdap.cdap.etl.api.batch.BatchSourceContext;
@@ -53,6 +55,7 @@
5355
import java.util.HashMap;
5456
import java.util.List;
5557
import java.util.Map;
58+
import java.util.Set;
5659
import java.util.stream.Collectors;
5760
import javax.annotation.Nullable;
5861

@@ -122,9 +125,9 @@ public Map<String, String> getKafkaProperties() {
122125
return conf;
123126
}
124127

125-
public void validate() {
126-
super.validate();
127-
KafkaHelpers.validateKerberosSetting(principal, keytabLocation);
128+
public void validate(FailureCollector collector) {
129+
super.validate(collector);
130+
KafkaHelpers.validateKerberosSetting(principal, keytabLocation, collector);
128131
}
129132
}
130133

@@ -134,16 +137,23 @@ public KafkaBatchSource(Kafka10BatchConfig config) {
134137

135138
@Override
136139
public void configurePipeline(PipelineConfigurer pipelineConfigurer) {
137-
config.validate();
138-
pipelineConfigurer.getStageConfigurer().setOutputSchema(config.getSchema());
140+
StageConfigurer stageConfigurer = pipelineConfigurer.getStageConfigurer();
141+
FailureCollector failureCollector = stageConfigurer.getFailureCollector();
142+
config.validate(failureCollector);
143+
stageConfigurer.setOutputSchema(config.getSchema(failureCollector));
144+
failureCollector.getOrThrowException();
139145
}
140146

141147
@Override
142148
public void prepareRun(BatchSourceContext context) throws Exception {
143149
Job job = JobUtils.createInstance();
144150
Configuration conf = job.getConfiguration();
145151

146-
KafkaPartitionOffsets partitionOffsets = config.getInitialPartitionOffsets();
152+
FailureCollector failureCollector = context.getFailureCollector();
153+
KafkaPartitionOffsets partitionOffsets = config.getInitialPartitionOffsets(failureCollector);
154+
Schema schema = config.getSchema(failureCollector);
155+
Set<Integer> partitions = config.getPartitions(failureCollector);
156+
failureCollector.getOrThrowException();
147157

148158
// If the offset directory is provided, try to load the file
149159
if (!context.isPreviewEnabled() && config.getOffsetDir() != null) {
@@ -167,10 +177,11 @@ public void prepareRun(BatchSourceContext context) throws Exception {
167177
KafkaHelpers.setupKerberosLogin(kafkaConf, config.getPrincipal(), config.getKeytabLocation());
168178
kafkaConf.putAll(config.getKafkaProperties());
169179
kafkaRequests = KafkaInputFormat.saveKafkaRequests(conf, config.getTopic(), kafkaConf,
170-
config.getPartitions(), config.getMaxNumberRecords(),
180+
partitions,
181+
config.getMaxNumberRecords(),
171182
partitionOffsets);
172183
LineageRecorder lineageRecorder = new LineageRecorder(context, config.referenceName);
173-
Schema schema = config.getSchema();
184+
174185
if (schema != null) {
175186
lineageRecorder.createExternalDataset(schema);
176187
if (schema.getFields() != null && !schema.getFields().isEmpty()) {
@@ -203,8 +214,11 @@ public void onRunFinish(boolean succeeded, BatchSourceContext context) {
203214
public void initialize(BatchRuntimeContext context) throws Exception {
204215
super.initialize(context);
205216

206-
schema = config.getSchema();
207-
Schema messageSchema = config.getMessageSchema();
217+
schema = config.getSchema(context.getFailureCollector());
218+
Schema messageSchema = config.getMessageSchema(context.getFailureCollector());
219+
if (schema == null || messageSchema == null) {
220+
return;
221+
}
208222
for (Schema.Field field : schema.getFields()) {
209223
String name = field.getName();
210224
if (!name.equals(config.getKeyField()) && !name.equals(config.getPartitionField()) &&

kafka-plugins-0.10/src/main/java/io/cdap/plugin/common/KafkaHelpers.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package io.cdap.plugin.common;
1818

1919
import com.google.common.base.Strings;
20+
import io.cdap.cdap.etl.api.FailureCollector;
2021
import org.apache.kafka.clients.consumer.Consumer;
2122
import org.apache.kafka.common.TopicPartition;
2223
import org.slf4j.Logger;
@@ -33,6 +34,8 @@
3334
public final class KafkaHelpers {
3435
private static final Logger LOG = LoggerFactory.getLogger(KafkaHelpers.class);
3536
public static final String SASL_JAAS_CONFIG = "sasl.jaas.config";
37+
public static final String PRINCIPAL = "principal";
38+
public static final String KEYTAB = "keytab";
3639

3740
// This class cannot be instantiated
3841
private KafkaHelpers() {
@@ -113,11 +116,28 @@ public static void setupKerberosLogin(Map<String, ? super String> conf, @Nullabl
113116
*/
114117
public static void validateKerberosSetting(@Nullable String principal, @Nullable String keytab) {
115118
if (Strings.isNullOrEmpty(principal) != Strings.isNullOrEmpty(keytab)) {
116-
String emptyField = Strings.isNullOrEmpty(principal) ? "principal" : "keytab";
119+
String emptyField = Strings.isNullOrEmpty(principal) ? PRINCIPAL : KEYTAB;
117120
String message = emptyField + " is empty. When Kerberos security is enabled for Kafka, " +
118121
"then both the principal and the keytab have " +
119122
"to be specified. If Kerberos is not enabled, then both should be empty.";
120123
throw new IllegalArgumentException(message);
121124
}
122125
}
126+
127+
/**
128+
* Validates whether the principal and keytab are both set or both of them are null/empty.
129+
* Stores the result in the provided failureCollector.
130+
*
131+
* @param principal Kerberos principal
132+
* @param keytab Kerberos keytab for the principal
133+
* @param collector input failureCollector into which the error will be added if present
134+
*/
135+
public static void validateKerberosSetting(@Nullable String principal, @Nullable String keytab,
136+
FailureCollector collector) {
137+
if (Strings.isNullOrEmpty(principal) != Strings.isNullOrEmpty(keytab)) {
138+
String emptyField = Strings.isNullOrEmpty(principal) ? PRINCIPAL : KEYTAB;
139+
String message = "Field " + emptyField + " must be specified.";
140+
collector.addFailure(message, null).withConfigProperty(emptyField);
141+
}
142+
}
123143
}

kafka-plugins-0.10/src/main/java/io/cdap/plugin/sink/KafkaBatchSink.java

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import io.cdap.cdap.api.data.schema.Schema;
2929
import io.cdap.cdap.api.dataset.lib.KeyValue;
3030
import io.cdap.cdap.etl.api.Emitter;
31+
import io.cdap.cdap.etl.api.FailureCollector;
3132
import io.cdap.cdap.etl.api.PipelineConfigurer;
3233
import io.cdap.cdap.etl.api.batch.BatchSink;
3334
import io.cdap.cdap.etl.api.batch.BatchSinkContext;
@@ -58,6 +59,8 @@
5859
@Description("KafkaSink to write events to kafka")
5960
public class KafkaBatchSink extends ReferenceBatchSink<StructuredRecord, Text, Text> {
6061
private static final Logger LOG = LoggerFactory.getLogger(KafkaBatchSink.class);
62+
private static final String ASYNC = "async";
63+
private static final String TOPIC = "topic";
6164

6265
// Configuration for the plugin.
6366
private final Config producerConfig;
@@ -77,7 +80,8 @@ public KafkaBatchSink(Config producerConfig) {
7780
public void configurePipeline(PipelineConfigurer pipelineConfigurer) {
7881
super.configurePipeline(pipelineConfigurer);
7982

80-
producerConfig.validate();
83+
producerConfig.validate(pipelineConfigurer.getStageConfigurer().getFailureCollector());
84+
pipelineConfigurer.getStageConfigurer().getFailureCollector().getOrThrowException();
8185
}
8286

8387
@Override
@@ -135,35 +139,42 @@ public void destroy() {
135139
*/
136140
public static class Config extends ReferencePluginConfig {
137141

138-
@Name("brokers")
142+
private static final String BROKERS = "brokers";
143+
private static final String KEY = "key";
144+
private static final String TOPIC = KafkaBatchSink.TOPIC;
145+
private static final String FORMAT = "format";
146+
private static final String KAFKA_PROPERTIES = "kafkaProperties";
147+
private static final String COMPRESSION_TYPE = "compressionType";
148+
149+
@Name(BROKERS)
139150
@Description("Specifies the connection string where Producer can find one or more brokers to " +
140151
"determine the leader for each topic")
141152
@Macro
142153
private String brokers;
143154

144-
@Name("async")
155+
@Name(ASYNC)
145156
@Description("Specifies whether an acknowledgment is required from broker that message was received. " +
146157
"Default is FALSE")
147158
@Macro
148159
private String async;
149160

150-
@Name("key")
161+
@Name(KEY)
151162
@Description("Specify the key field to be used in the message. Only String Partitioner is supported.")
152163
@Macro
153164
@Nullable
154165
private String key;
155166

156-
@Name("topic")
167+
@Name(TOPIC)
157168
@Description("Topic to which message needs to be published")
158169
@Macro
159170
private String topic;
160171

161-
@Name("format")
172+
@Name(FORMAT)
162173
@Description("Format a structured record should be converted to")
163174
@Macro
164175
private String format;
165176

166-
@Name("kafkaProperties")
177+
@Name(KAFKA_PROPERTIES)
167178
@Description("Additional kafka producer properties to set")
168179
@Macro
169180
@Nullable
@@ -179,7 +190,7 @@ public static class Config extends ReferencePluginConfig {
179190
@Nullable
180191
private String keytabLocation;
181192

182-
@Name("compressionType")
193+
@Name(COMPRESSION_TYPE)
183194
@Description("Compression type to be applied on message")
184195
@Macro
185196
private String compressionType;
@@ -196,21 +207,23 @@ public Config(String brokers, String async, String key, String topic, String for
196207
this.compressionType = compressionType;
197208
}
198209

199-
private void validate() {
210+
private void validate(FailureCollector collector) {
200211
if (!async.equalsIgnoreCase("true") && !async.equalsIgnoreCase("false")) {
201-
throw new IllegalArgumentException("Async flag has to be either TRUE or FALSE.");
212+
collector.addFailure("Async flag has to be either TRUE or FALSE.", null)
213+
.withConfigProperty(ASYNC);
202214
}
203215

204-
KafkaHelpers.validateKerberosSetting(principal, keytabLocation);
216+
KafkaHelpers.validateKerberosSetting(principal, keytabLocation, collector);
205217
}
206218
}
207219

208220
private static class KafkaOutputFormatProvider implements OutputFormatProvider {
221+
public static final String HAS_KEY = "hasKey";
209222
private final Map<String, String> conf;
210223

211224
KafkaOutputFormatProvider(Config kafkaSinkConfig) {
212225
this.conf = new HashMap<>();
213-
conf.put("topic", kafkaSinkConfig.topic);
226+
conf.put(TOPIC, kafkaSinkConfig.topic);
214227

215228
conf.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaSinkConfig.brokers);
216229
conf.put("compression.type", kafkaSinkConfig.compressionType);
@@ -220,13 +233,13 @@ private static class KafkaOutputFormatProvider implements OutputFormatProvider {
220233
KafkaHelpers.setupKerberosLogin(conf, kafkaSinkConfig.principal, kafkaSinkConfig.keytabLocation);
221234
addKafkaProperties(kafkaSinkConfig.kafkaProperties);
222235

223-
conf.put("async", kafkaSinkConfig.async);
236+
conf.put(ASYNC, kafkaSinkConfig.async);
224237
if (kafkaSinkConfig.async.equalsIgnoreCase("true")) {
225238
conf.put(ACKS_REQUIRED, "1");
226239
}
227240

228241
if (!Strings.isNullOrEmpty(kafkaSinkConfig.key)) {
229-
conf.put("hasKey", kafkaSinkConfig.key);
242+
conf.put(HAS_KEY, kafkaSinkConfig.key);
230243
}
231244
}
232245

0 commit comments

Comments
 (0)