use of io.strimzi.operator.common.Reconciliation in project strimzi by strimzi.
the class KafkaReconciler method scaleDown.
/**
* Scales down the Kafka cluster if needed. Kafka scale-down is done in one go.
*
* @return Future which completes when the scale-down is finished
*/
protected Future<Void> scaleDown() {
if (currentReplicas != 0 && currentReplicas > kafka.getReplicas()) {
// The previous (current) number of replicas is bigger than desired => we should scale-down
LOGGER.infoCr(reconciliation, "Scaling Kafka down from {} to {} replicas", currentReplicas, kafka.getReplicas());
if (featureGates.useStrimziPodSetsEnabled()) {
Set<String> desiredPodNames = new HashSet<>(kafka.getReplicas());
for (int i = 0; i < kafka.getReplicas(); i++) {
desiredPodNames.add(kafka.getPodName(i));
}
return strimziPodSetOperator.getAsync(reconciliation.namespace(), kafka.getName()).compose(podSet -> {
if (podSet == null) {
return Future.succeededFuture();
} else {
List<Map<String, Object>> desiredPods = podSet.getSpec().getPods().stream().filter(pod -> desiredPodNames.contains(PodSetUtils.mapToPod(pod).getMetadata().getName())).collect(Collectors.toList());
StrimziPodSet scaledDownPodSet = new StrimziPodSetBuilder(podSet).editSpec().withPods(desiredPods).endSpec().build();
return strimziPodSetOperator.reconcile(reconciliation, reconciliation.namespace(), kafka.getName(), scaledDownPodSet).map((Void) null);
}
});
} else {
return stsOperator.scaleDown(reconciliation, reconciliation.namespace(), kafka.getName(), kafka.getReplicas()).map((Void) null);
}
} else {
// desired replicas => no need to scale-down
return Future.succeededFuture();
}
}
use of io.strimzi.operator.common.Reconciliation in project strimzi by strimzi.
the class ManualPodCleaner method cleanPodPvcAndPodSet.
/**
* Handles the modification of the StrimziPodSet controlling the pod which should be cleaned. In order
* to clean the pod and its PVCs, we first need to remove the pod from the StrimziPodSet. Otherwise, the
* StrimziPodSet will break the process by recreating the pods or PVCs. This method first modifies the StrimziPodSet
* and then calls other method to delete the Pod, PVCs and create the new PVCs. Once this method completes, it
* will update the StrimziPodSet again. The Pod will be then recreated by the StrimziPodSet and this method just
* waits for it to become ready.
*
* The complete flow looks like this
* 1. Remove the deleted pod from the PodSet
* 2. Trigger the Pod and PVC deletion and recreation
* 3. Recreate the original PodSet
* 4. Wait for the Pod to be created and become ready
*
* @param podSetName Name of the StrimziPodSet to which this pod belongs
* @param podName Name of the Pod which should be cleaned / deleted
* @param desiredPvcs The list of desired PVCs which should be created after the old Pod and PVCs are deleted
* @param currentPvcs The list of current PVCs which should be deleted
*
* @return Future indicating the result of the cleanup
*/
private Future<Void> cleanPodPvcAndPodSet(String podSetName, String podName, List<PersistentVolumeClaim> desiredPvcs, List<PersistentVolumeClaim> currentPvcs) {
return strimziPodSetOperator.getAsync(reconciliation.namespace(), podSetName).compose(podSet -> {
List<Map<String, Object>> desiredPods = podSet.getSpec().getPods().stream().filter(pod -> !podName.equals(PodSetUtils.mapToPod(pod).getMetadata().getName())).collect(Collectors.toList());
StrimziPodSet reducedPodSet = new StrimziPodSetBuilder(podSet).editSpec().withPods(desiredPods).endSpec().build();
return strimziPodSetOperator.reconcile(reconciliation, reconciliation.namespace(), podSetName, reducedPodSet).compose(ignore -> cleanPodAndPvc(podName, desiredPvcs, currentPvcs)).compose(ignore -> {
// We recreate the StrimziPodSet in its old configuration => any further changes have to be done by rolling update
// These fields need to be cleared before recreating the StatefulSet
podSet.getMetadata().setResourceVersion(null);
podSet.getMetadata().setSelfLink(null);
podSet.getMetadata().setUid(null);
podSet.setStatus(null);
return strimziPodSetOperator.reconcile(reconciliation, reconciliation.namespace(), podSetName, podSet);
}).compose(ignore -> podOperator.readiness(reconciliation, reconciliation.namespace(), podName, 1_000L, operationTimeoutMs)).map((Void) null);
});
}
use of io.strimzi.operator.common.Reconciliation in project strimzi by strimzi.
the class PvcReconciler method resizeAndReconcilePvcs.
/**
* Resizes and reconciles the PVCs based on the model and list of PVCs passed to it. It will return a future with
* collection containing a list of pods which need restart to complete the filesystem resizing. The PVCs are only
* created or updated. This method does not delete any PVCs. This is done by a separate method which should be
* called separately at the end of the reconciliation.
*
* @param podNameProvider Function to generate a pod name from its index
* @param pvcs List of desired PVC used by this controller
*
* @return Future with list of pod names which should be restarted to complete the filesystem resizing
*/
public Future<Collection<String>> resizeAndReconcilePvcs(Function<Integer, String> podNameProvider, List<PersistentVolumeClaim> pvcs) {
Set<String> podsToRestart = new HashSet<>();
// Has to use Raw type because of the CompositeFuture
@SuppressWarnings({ "rawtypes" }) List<Future> futures = new ArrayList<>(pvcs.size());
for (PersistentVolumeClaim desiredPvc : pvcs) {
Future<Void> perPvcFuture = pvcOperator.getAsync(reconciliation.namespace(), desiredPvc.getMetadata().getName()).compose(currentPvc -> {
if (currentPvc == null || currentPvc.getStatus() == null || !"Bound".equals(currentPvc.getStatus().getPhase())) {
// * The PVC is not Bound, we should reconcile it
return pvcOperator.reconcile(reconciliation, reconciliation.namespace(), desiredPvc.getMetadata().getName(), desiredPvc).map((Void) null);
} else if (currentPvc.getStatus().getConditions().stream().anyMatch(cond -> "Resizing".equals(cond.getType()) && "true".equals(cond.getStatus().toLowerCase(Locale.ENGLISH)))) {
// The PVC is Bound, but it is already resizing => Nothing to do, we should let it resize
LOGGER.debugCr(reconciliation, "The PVC {} is resizing, nothing to do", desiredPvc.getMetadata().getName());
return Future.succeededFuture();
} else if (currentPvc.getStatus().getConditions().stream().anyMatch(cond -> "FileSystemResizePending".equals(cond.getType()) && "true".equals(cond.getStatus().toLowerCase(Locale.ENGLISH)))) {
// The PVC is Bound and resized but waiting for FS resizing => We need to restart the pod which is using it
String podName = podNameProvider.apply(getPodIndexFromPvcName(desiredPvc.getMetadata().getName()));
podsToRestart.add(podName);
LOGGER.infoCr(reconciliation, "The PVC {} is waiting for file system resizing and the pod {} needs to be restarted.", desiredPvc.getMetadata().getName(), podName);
return Future.succeededFuture();
} else {
// The PVC is Bound and resizing is not in progress => We should check if the SC supports resizing and check if size changed
Long currentSize = StorageUtils.convertToMillibytes(currentPvc.getSpec().getResources().getRequests().get("storage"));
Long desiredSize = StorageUtils.convertToMillibytes(desiredPvc.getSpec().getResources().getRequests().get("storage"));
if (!currentSize.equals(desiredSize)) {
// The sizes are different => we should resize (shrinking will be handled in StorageDiff, so we do not need to check that)
return resizePvc(currentPvc, desiredPvc);
} else {
// size didn't change, just reconcile
return pvcOperator.reconcile(reconciliation, reconciliation.namespace(), desiredPvc.getMetadata().getName(), desiredPvc).map((Void) null);
}
}
});
futures.add(perPvcFuture);
}
return CompositeFuture.all(futures).map(podsToRestart);
}
use of io.strimzi.operator.common.Reconciliation in project strimzi by strimzi.
the class EntityOperatorTest method testImagePullSecretsFromCo.
@ParallelTest
public void testImagePullSecretsFromCo() {
LocalObjectReference secret1 = new LocalObjectReference("some-pull-secret");
LocalObjectReference secret2 = new LocalObjectReference("some-other-pull-secret");
List<LocalObjectReference> secrets = new ArrayList<>(2);
secrets.add(secret1);
secrets.add(secret2);
Kafka resource = new KafkaBuilder(ResourceUtils.createKafka(namespace, cluster, replicas, image, healthDelay, healthTimeout)).editSpec().withNewEntityOperator().withTopicOperator(entityTopicOperatorSpec).withUserOperator(entityUserOperatorSpec).endEntityOperator().endSpec().build();
EntityOperator eo = EntityOperator.fromCrd(new Reconciliation("test", resource.getKind(), resource.getMetadata().getNamespace(), resource.getMetadata().getName()), resource, VERSIONS, true);
Deployment dep = eo.generateDeployment(true, null, secrets);
assertThat(dep.getSpec().getTemplate().getSpec().getImagePullSecrets().size(), is(2));
assertThat(dep.getSpec().getTemplate().getSpec().getImagePullSecrets().contains(secret1), is(true));
assertThat(dep.getSpec().getTemplate().getSpec().getImagePullSecrets().contains(secret2), is(true));
}
use of io.strimzi.operator.common.Reconciliation in project strimzi by strimzi.
the class EntityOperatorTest method testFromCrdNoUserOperatorInEntityOperator.
@ParallelTest
public void testFromCrdNoUserOperatorInEntityOperator() {
EntityOperatorSpec entityOperatorSpec = new EntityOperatorSpecBuilder().withNewTopicOperator().endTopicOperator().build();
Kafka resource = new KafkaBuilder(ResourceUtils.createKafka(namespace, cluster, replicas, image, healthDelay, healthTimeout)).editSpec().withEntityOperator(entityOperatorSpec).endSpec().build();
EntityOperator entityOperator = EntityOperator.fromCrd(new Reconciliation("test", resource.getKind(), resource.getMetadata().getNamespace(), resource.getMetadata().getName()), resource, VERSIONS, true);
assertThat(entityOperator.topicOperator(), is(notNullValue()));
assertThat(entityOperator.userOperator(), is(nullValue()));
}
Aggregations