use of io.strimzi.api.kafka.model.status.Status in project strimzi by strimzi.
the class OperatorMetricsTest method testPauseReconcile.
@Test
public void testPauseReconcile(VertxTestContext context) {
MetricsProvider metrics = createCleanMetricsProvider();
AbstractWatchableStatusedResourceOperator resourceOperator = resourceOperatorWithExistingPausedResource();
AbstractOperator operator = new AbstractOperator(vertx, "TestResource", resourceOperator, metrics, null) {
@Override
protected Future createOrUpdate(Reconciliation reconciliation, CustomResource resource) {
return Future.succeededFuture();
}
@Override
public Set<Condition> validate(Reconciliation reconciliation, CustomResource resource) {
return new HashSet<>();
}
@Override
protected Future<Boolean> delete(Reconciliation reconciliation) {
return null;
}
@Override
protected Status createStatus() {
return new Status() {
};
}
};
Checkpoint async = context.checkpoint();
operator.reconcile(new Reconciliation("test", "TestResource", "my-namespace", "my-resource")).onComplete(context.succeeding(v -> context.verify(() -> {
MeterRegistry registry = metrics.meterRegistry();
Tag selectorTag = Tag.of("selector", "");
assertThat(registry.get(AbstractOperator.METRICS_PREFIX + "reconciliations").meter().getId().getTags().get(2), is(selectorTag));
assertThat(registry.get(AbstractOperator.METRICS_PREFIX + "reconciliations").tag("kind", "TestResource").counter().count(), is(1.0));
assertThat(registry.get(AbstractOperator.METRICS_PREFIX + "reconciliations.successful").meter().getId().getTags().get(2), is(selectorTag));
assertThat(registry.get(AbstractOperator.METRICS_PREFIX + "reconciliations.successful").tag("kind", "TestResource").counter().count(), is(1.0));
assertThat(registry.get(AbstractOperator.METRICS_PREFIX + "resources.paused").meter().getId().getTags().get(2), is(selectorTag));
assertThat(registry.get(AbstractOperator.METRICS_PREFIX + "resources.paused").tag("kind", "TestResource").gauge().value(), is(1.0));
assertThat(registry.get(AbstractOperator.METRICS_PREFIX + "reconciliations.duration").meter().getId().getTags().get(2), is(selectorTag));
assertThat(registry.get(AbstractOperator.METRICS_PREFIX + "reconciliations.duration").tag("kind", "TestResource").timer().count(), is(1L));
assertThat(registry.get(AbstractOperator.METRICS_PREFIX + "reconciliations.duration").tag("kind", "TestResource").timer().totalTime(TimeUnit.MILLISECONDS), greaterThan(0.0));
assertThat(registry.get(AbstractOperator.METRICS_PREFIX + "resource.state").tag("kind", "TestResource").tag("name", "my-resource").tag("resource-namespace", "my-namespace").gauge().value(), is(1.0));
async.flag();
})));
}
use of io.strimzi.api.kafka.model.status.Status in project strimzi-kafka-operator by strimzi.
the class AbstractConnectOperator method createConnectorWatch.
/**
* Create a watch on {@code KafkaConnector} in the given {@code namespace}.
* The watcher will:
* <ul>
* <li>{@linkplain #reconcileConnectors(Reconciliation, CustomResource, KafkaConnectStatus, boolean, String, OrderedProperties)} on the KafkaConnect
* identified by {@code KafkaConnector.metadata.labels[strimzi.io/cluster]}.</li>
* <li>The {@code KafkaConnector} status is updated with the result.</li>
* </ul>
* @param connectOperator The operator for {@code KafkaConnect}.
* @param watchNamespaceOrWildcard The namespace to watch.
* @param selectorLabels Selector labels for filtering the custom resources
*
* @return A future which completes when the watch has been set up.
*/
public static Future<Watch> createConnectorWatch(AbstractConnectOperator<KubernetesClient, KafkaConnect, KafkaConnectList, Resource<KafkaConnect>, KafkaConnectSpec, KafkaConnectStatus> connectOperator, String watchNamespaceOrWildcard, Labels selectorLabels) {
Optional<LabelSelector> selector = (selectorLabels == null || selectorLabels.toMap().isEmpty()) ? Optional.empty() : Optional.of(new LabelSelector(null, selectorLabels.toMap()));
return Util.async(connectOperator.vertx, () -> {
Watch watch = connectOperator.connectorOperator.watch(watchNamespaceOrWildcard, new Watcher<KafkaConnector>() {
@Override
public void eventReceived(Action action, KafkaConnector kafkaConnector) {
String connectorName = kafkaConnector.getMetadata().getName();
String connectorNamespace = kafkaConnector.getMetadata().getNamespace();
String connectorKind = kafkaConnector.getKind();
String connectName = kafkaConnector.getMetadata().getLabels() == null ? null : kafkaConnector.getMetadata().getLabels().get(Labels.STRIMZI_CLUSTER_LABEL);
String connectNamespace = connectorNamespace;
switch(action) {
case ADDED:
case DELETED:
case MODIFIED:
if (connectName != null) {
// Check whether a KafkaConnect exists
connectOperator.resourceOperator.getAsync(connectNamespace, connectName).compose(connect -> {
KafkaConnectApi apiClient = connectOperator.connectClientProvider.apply(connectOperator.vertx);
if (connect == null) {
Reconciliation r = new Reconciliation("connector-watch", connectOperator.kind(), kafkaConnector.getMetadata().getNamespace(), connectName);
updateStatus(r, noConnectCluster(connectNamespace, connectName), kafkaConnector, connectOperator.connectorOperator);
LOGGER.infoCr(r, "{} {} in namespace {} was {}, but Connect cluster {} does not exist", connectorKind, connectorName, connectorNamespace, action, connectName);
return Future.succeededFuture();
} else {
// grab the lock and call reconcileConnectors()
// (i.e. short circuit doing a whole KafkaConnect reconciliation).
Reconciliation reconciliation = new Reconciliation("connector-watch", connectOperator.kind(), kafkaConnector.getMetadata().getNamespace(), connectName);
if (!Util.matchesSelector(selector, connect)) {
LOGGER.debugCr(reconciliation, "{} {} in namespace {} was {}, but Connect cluster {} does not match label selector {} and will be ignored", connectorKind, connectorName, connectorNamespace, action, connectName, selectorLabels);
return Future.succeededFuture();
} else if (connect.getSpec() != null && connect.getSpec().getReplicas() == 0) {
LOGGER.infoCr(reconciliation, "{} {} in namespace {} was {}, but Connect cluster {} has 0 replicas", connectorKind, connectorName, connectorNamespace, action, connectName);
updateStatus(reconciliation, zeroReplicas(connectNamespace, connectName), kafkaConnector, connectOperator.connectorOperator);
return Future.succeededFuture();
} else {
LOGGER.infoCr(reconciliation, "{} {} in namespace {} was {}", connectorKind, connectorName, connectorNamespace, action);
return connectOperator.withLock(reconciliation, LOCK_TIMEOUT_MS, () -> connectOperator.reconcileConnectorAndHandleResult(reconciliation, KafkaConnectResources.qualifiedServiceName(connectName, connectNamespace), apiClient, isUseResources(connect), kafkaConnector.getMetadata().getName(), action == Action.DELETED ? null : kafkaConnector).compose(reconcileResult -> {
LOGGER.infoCr(reconciliation, "reconciled");
return Future.succeededFuture(reconcileResult);
}));
}
}
});
} else {
updateStatus(new Reconciliation("connector-watch", connectOperator.kind(), kafkaConnector.getMetadata().getNamespace(), null), new InvalidResourceException("Resource lacks label '" + Labels.STRIMZI_CLUSTER_LABEL + "': No connect cluster in which to create this connector."), kafkaConnector, connectOperator.connectorOperator);
}
break;
case ERROR:
LOGGER.errorCr(new Reconciliation("connector-watch", connectorKind, connectName, connectorNamespace), "Failed {} {} in namespace {} ", connectorKind, connectorName, connectorNamespace);
break;
default:
LOGGER.errorCr(new Reconciliation("connector-watch", connectorKind, connectName, connectorNamespace), "Unknown action: {} {} in namespace {}", connectorKind, connectorName, connectorNamespace);
}
}
@Override
public void onClose(WatcherException e) {
if (e != null) {
throw new KubernetesClientException(e.getMessage());
}
}
});
return watch;
});
}
use of io.strimzi.api.kafka.model.status.Status in project strimzi-kafka-operator by strimzi.
the class OperatorMetricsTest method successfulReconcile.
public void successfulReconcile(VertxTestContext context, Labels selectorLabels) {
MetricsProvider metrics = createCleanMetricsProvider();
AbstractWatchableStatusedResourceOperator resourceOperator = resourceOperatorWithExistingResourceWithSelectorLabel(selectorLabels);
AbstractOperator operator = new AbstractOperator(vertx, "TestResource", resourceOperator, metrics, selectorLabels) {
@Override
protected Future createOrUpdate(Reconciliation reconciliation, CustomResource resource) {
return Future.succeededFuture();
}
@Override
public Set<Condition> validate(Reconciliation reconciliation, CustomResource resource) {
return emptySet();
}
@Override
protected Future<Boolean> delete(Reconciliation reconciliation) {
return null;
}
@Override
protected Status createStatus() {
return new Status() {
};
}
};
Checkpoint async = context.checkpoint();
operator.reconcile(new Reconciliation("test", "TestResource", "my-namespace", "my-resource")).onComplete(context.succeeding(v -> context.verify(() -> {
MeterRegistry registry = metrics.meterRegistry();
Tag selectorTag = Tag.of("selector", selectorLabels != null ? selectorLabels.toSelectorString() : "");
assertThat(registry.get(AbstractOperator.METRICS_PREFIX + "reconciliations").meter().getId().getTags().get(2), is(selectorTag));
assertThat(registry.get(AbstractOperator.METRICS_PREFIX + "reconciliations").tag("kind", "TestResource").counter().count(), is(1.0));
assertThat(registry.get(AbstractOperator.METRICS_PREFIX + "reconciliations.successful").meter().getId().getTags().get(2), is(selectorTag));
assertThat(registry.get(AbstractOperator.METRICS_PREFIX + "reconciliations.successful").tag("kind", "TestResource").counter().count(), is(1.0));
assertThat(registry.get(AbstractOperator.METRICS_PREFIX + "reconciliations.duration").meter().getId().getTags().get(2), is(selectorTag));
assertThat(registry.get(AbstractOperator.METRICS_PREFIX + "reconciliations.duration").tag("kind", "TestResource").timer().count(), is(1L));
assertThat(registry.get(AbstractOperator.METRICS_PREFIX + "reconciliations.duration").tag("kind", "TestResource").timer().totalTime(TimeUnit.MILLISECONDS), greaterThan(0.0));
assertThat(registry.get(AbstractOperator.METRICS_PREFIX + "resource.state").tag("kind", "TestResource").tag("name", "my-resource").tag("resource-namespace", "my-namespace").gauge().value(), is(1.0));
async.flag();
})));
}
use of io.strimzi.api.kafka.model.status.Status in project strimzi-kafka-operator by strimzi.
the class ConnectorMockTest method setupMockConnectAPI.
private void setupMockConnectAPI() {
api = mock(KafkaConnectApi.class);
runningConnectors = new HashMap<>();
when(api.list(any(), anyInt())).thenAnswer(i -> {
String host = i.getArgument(0);
String matchingKeyPrefix = host + "##";
return Future.succeededFuture(runningConnectors.keySet().stream().filter(s -> s.startsWith(matchingKeyPrefix)).map(s -> s.substring(matchingKeyPrefix.length())).collect(Collectors.toList()));
});
when(api.listConnectorPlugins(any(), any(), anyInt())).thenAnswer(i -> {
ConnectorPlugin connectorPlugin = new ConnectorPluginBuilder().withConnectorClass("io.strimzi.MyClass").withType("sink").withVersion("1.0.0").build();
return Future.succeededFuture(Collections.singletonList(connectorPlugin));
});
when(api.updateConnectLoggers(any(), anyString(), anyInt(), anyString(), any(OrderedProperties.class))).thenReturn(Future.succeededFuture());
when(api.getConnectorConfig(any(), any(), any(), anyInt(), any())).thenAnswer(invocation -> {
String host = invocation.getArgument(2);
String connectorName = invocation.getArgument(4);
ConnectorState connectorState = runningConnectors.get(key(host, connectorName));
if (connectorState != null) {
Map<String, String> map = new HashMap<>();
map.put("name", connectorName);
for (Map.Entry<String, Object> entry : connectorState.config) {
if (entry.getValue() != null) {
map.put(entry.getKey(), entry.getValue().toString());
}
}
return Future.succeededFuture(map);
} else {
return Future.failedFuture(new ConnectRestException("GET", String.format("/connectors/%s/config", connectorName), 404, "Not Found", ""));
}
});
when(api.getConnector(any(), any(), anyInt(), any())).thenAnswer(invocation -> {
String host = invocation.getArgument(1);
String connectorName = invocation.getArgument(3);
ConnectorState connectorState = runningConnectors.get(key(host, connectorName));
if (connectorState == null) {
return Future.failedFuture(new ConnectRestException("GET", String.format("/connectors/%s", connectorName), 404, "Not Found", ""));
}
return Future.succeededFuture(TestUtils.map("name", connectorName, "config", connectorState.config, "tasks", emptyMap()));
});
when(api.createOrUpdatePutRequest(any(), any(), anyInt(), anyString(), any())).thenAnswer(invocation -> {
LOGGER.info((String) invocation.getArgument(1) + invocation.getArgument(2) + invocation.getArgument(3) + invocation.getArgument(4));
String host = invocation.getArgument(1);
LOGGER.info("###### create " + host);
String connectorName = invocation.getArgument(3);
JsonObject connectorConfig = invocation.getArgument(4);
runningConnectors.putIfAbsent(key(host, connectorName), new ConnectorState(false, connectorConfig));
return Future.succeededFuture();
});
when(api.delete(any(), any(), anyInt(), anyString())).thenAnswer(invocation -> {
String host = invocation.getArgument(1);
LOGGER.info("###### delete " + host);
String connectorName = invocation.getArgument(3);
ConnectorState remove = runningConnectors.remove(key(host, connectorName));
return remove != null ? Future.succeededFuture() : Future.failedFuture("No such connector " + connectorName);
});
when(api.statusWithBackOff(any(), any(), any(), anyInt(), anyString())).thenAnswer(invocation -> {
String host = invocation.getArgument(2);
LOGGER.info("###### status " + host);
String connectorName = invocation.getArgument(4);
return kafkaConnectApiStatusMock(host, connectorName);
});
when(api.status(any(), any(), anyInt(), anyString())).thenAnswer(invocation -> {
String host = invocation.getArgument(1);
LOGGER.info("###### status " + host);
String connectorName = invocation.getArgument(3);
return kafkaConnectApiStatusMock(host, connectorName);
});
when(api.pause(any(), anyInt(), anyString())).thenAnswer(invocation -> {
String host = invocation.getArgument(0);
String connectorName = invocation.getArgument(2);
ConnectorState connectorState = runningConnectors.get(key(host, connectorName));
if (connectorState == null) {
return Future.failedFuture(new ConnectRestException("PUT", "", 404, "Not found", "Connector name " + connectorName));
}
if (!connectorState.paused) {
runningConnectors.put(key(host, connectorName), new ConnectorState(true, connectorState.config));
}
return Future.succeededFuture();
});
when(api.resume(any(), anyInt(), anyString())).thenAnswer(invocation -> {
String host = invocation.getArgument(0);
String connectorName = invocation.getArgument(2);
ConnectorState connectorState = runningConnectors.get(key(host, connectorName));
if (connectorState == null) {
return Future.failedFuture(new ConnectRestException("PUT", "", 404, "Not found", "Connector name " + connectorName));
}
if (connectorState.paused) {
runningConnectors.put(key(host, connectorName), new ConnectorState(false, connectorState.config));
}
return Future.succeededFuture();
});
when(api.restart(any(), anyInt(), anyString())).thenAnswer(invocation -> {
String host = invocation.getArgument(0);
String connectorName = invocation.getArgument(2);
ConnectorState connectorState = runningConnectors.get(key(host, connectorName));
if (connectorState == null) {
return Future.failedFuture(new ConnectRestException("PUT", "", 404, "Not found", "Connector name " + connectorName));
}
return Future.succeededFuture();
});
when(api.restartTask(any(), anyInt(), anyString(), anyInt())).thenAnswer(invocation -> {
String host = invocation.getArgument(0);
String connectorName = invocation.getArgument(2);
ConnectorState connectorState = runningConnectors.get(key(host, connectorName));
if (connectorState == null) {
return Future.failedFuture(new ConnectRestException("PUT", "", 404, "Not found", "Connector name " + connectorName));
}
return Future.succeededFuture();
});
when(api.getConnectorTopics(any(), any(), anyInt(), anyString())).thenAnswer(invocation -> {
String host = invocation.getArgument(1);
String connectorName = invocation.getArgument(3);
ConnectorState connectorState = runningConnectors.get(key(host, connectorName));
if (connectorState == null) {
return Future.failedFuture(new ConnectRestException("GET", String.format("/connectors/%s/topics", connectorName), 404, "Not Found", ""));
}
return Future.succeededFuture(List.of("my-topic"));
});
}
use of io.strimzi.api.kafka.model.status.Status in project strimzi by strimzi.
the class AbstractConnectOperator method createConnectorWatch.
/**
* Create a watch on {@code KafkaConnector} in the given {@code namespace}.
* The watcher will:
* <ul>
* <li>{@linkplain #reconcileConnectors(Reconciliation, CustomResource, KafkaConnectStatus, boolean, String, OrderedProperties)} on the KafkaConnect
* identified by {@code KafkaConnector.metadata.labels[strimzi.io/cluster]}.</li>
* <li>The {@code KafkaConnector} status is updated with the result.</li>
* </ul>
* @param connectOperator The operator for {@code KafkaConnect}.
* @param watchNamespaceOrWildcard The namespace to watch.
* @param selectorLabels Selector labels for filtering the custom resources
*
* @return A future which completes when the watch has been set up.
*/
public static Future<Watch> createConnectorWatch(AbstractConnectOperator<KubernetesClient, KafkaConnect, KafkaConnectList, Resource<KafkaConnect>, KafkaConnectSpec, KafkaConnectStatus> connectOperator, String watchNamespaceOrWildcard, Labels selectorLabels) {
Optional<LabelSelector> selector = (selectorLabels == null || selectorLabels.toMap().isEmpty()) ? Optional.empty() : Optional.of(new LabelSelector(null, selectorLabels.toMap()));
return Util.async(connectOperator.vertx, () -> {
Watch watch = connectOperator.connectorOperator.watch(watchNamespaceOrWildcard, new Watcher<KafkaConnector>() {
@Override
public void eventReceived(Action action, KafkaConnector kafkaConnector) {
String connectorName = kafkaConnector.getMetadata().getName();
String connectorNamespace = kafkaConnector.getMetadata().getNamespace();
String connectorKind = kafkaConnector.getKind();
String connectName = kafkaConnector.getMetadata().getLabels() == null ? null : kafkaConnector.getMetadata().getLabels().get(Labels.STRIMZI_CLUSTER_LABEL);
String connectNamespace = connectorNamespace;
switch(action) {
case ADDED:
case DELETED:
case MODIFIED:
if (connectName != null) {
// Check whether a KafkaConnect exists
connectOperator.resourceOperator.getAsync(connectNamespace, connectName).compose(connect -> {
KafkaConnectApi apiClient = connectOperator.connectClientProvider.apply(connectOperator.vertx);
if (connect == null) {
Reconciliation r = new Reconciliation("connector-watch", connectOperator.kind(), kafkaConnector.getMetadata().getNamespace(), connectName);
updateStatus(r, noConnectCluster(connectNamespace, connectName), kafkaConnector, connectOperator.connectorOperator);
LOGGER.infoCr(r, "{} {} in namespace {} was {}, but Connect cluster {} does not exist", connectorKind, connectorName, connectorNamespace, action, connectName);
return Future.succeededFuture();
} else {
// grab the lock and call reconcileConnectors()
// (i.e. short circuit doing a whole KafkaConnect reconciliation).
Reconciliation reconciliation = new Reconciliation("connector-watch", connectOperator.kind(), kafkaConnector.getMetadata().getNamespace(), connectName);
if (!Util.matchesSelector(selector, connect)) {
LOGGER.debugCr(reconciliation, "{} {} in namespace {} was {}, but Connect cluster {} does not match label selector {} and will be ignored", connectorKind, connectorName, connectorNamespace, action, connectName, selectorLabels);
return Future.succeededFuture();
} else if (connect.getSpec() != null && connect.getSpec().getReplicas() == 0) {
LOGGER.infoCr(reconciliation, "{} {} in namespace {} was {}, but Connect cluster {} has 0 replicas", connectorKind, connectorName, connectorNamespace, action, connectName);
updateStatus(reconciliation, zeroReplicas(connectNamespace, connectName), kafkaConnector, connectOperator.connectorOperator);
return Future.succeededFuture();
} else {
LOGGER.infoCr(reconciliation, "{} {} in namespace {} was {}", connectorKind, connectorName, connectorNamespace, action);
return connectOperator.withLock(reconciliation, LOCK_TIMEOUT_MS, () -> connectOperator.reconcileConnectorAndHandleResult(reconciliation, KafkaConnectResources.qualifiedServiceName(connectName, connectNamespace), apiClient, isUseResources(connect), kafkaConnector.getMetadata().getName(), action == Action.DELETED ? null : kafkaConnector).compose(reconcileResult -> {
LOGGER.infoCr(reconciliation, "reconciled");
return Future.succeededFuture(reconcileResult);
}));
}
}
});
} else {
updateStatus(new Reconciliation("connector-watch", connectOperator.kind(), kafkaConnector.getMetadata().getNamespace(), null), new InvalidResourceException("Resource lacks label '" + Labels.STRIMZI_CLUSTER_LABEL + "': No connect cluster in which to create this connector."), kafkaConnector, connectOperator.connectorOperator);
}
break;
case ERROR:
LOGGER.errorCr(new Reconciliation("connector-watch", connectorKind, connectName, connectorNamespace), "Failed {} {} in namespace {} ", connectorKind, connectorName, connectorNamespace);
break;
default:
LOGGER.errorCr(new Reconciliation("connector-watch", connectorKind, connectName, connectorNamespace), "Unknown action: {} {} in namespace {}", connectorKind, connectorName, connectorNamespace);
}
}
@Override
public void onClose(WatcherException e) {
if (e != null) {
throw new KubernetesClientException(e.getMessage());
}
}
});
return watch;
});
}
Aggregations