Skip to content

refactor: rename "bulk" to more accurate "dynamically created" #1538

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ protected AbstractDependentResource() {
creator = creatable ? (Creator<R, P>) this : null;
updater = updatable ? (Updater<R, P>) this : null;

dependentResourceReconciler = this instanceof BulkDependentResource
? new BulkDependentResourceReconciler<>((BulkDependentResource<R, P>) this)
dependentResourceReconciler = this instanceof DynamicallyCreatedDependentResource
? new DynamicallyCreatedDependentResourceReconciler<>(
(DynamicallyCreatedDependentResource<R, P>) this)
: new SingleDependentResourceReconciler<>(this);
}

Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@
import io.javaoperatorsdk.operator.processing.dependent.Matcher.Result;

/**
* Manages dynamic number of resources created for a primary resource. Since the point of a bulk
* dependent resource is to manage the number of secondary resources dynamically it implement
* {@link Creator} and {@link Deleter} interfaces out of the box. A concrete dependent resource can
* implement additionally also {@link Updater}.
* Manages dynamic number of resources created for a primary resource. Since the point of a
* dynamically-created dependent resource is to manage secondary resources dynamically depending on
* the state of the primary resource, it implements {@link Creator} and {@link Deleter} interfaces
* out of the box. A concrete dynamically-created dependent resource could also additionally
* implement {@link Updater}.
*/
public interface BulkDependentResource<R, P extends HasMetadata>
public interface DynamicallyCreatedDependentResource<R, P extends HasMetadata>
extends Creator<R, P>, Deleter<P> {

/**
Expand Down Expand Up @@ -41,19 +42,19 @@ public interface BulkDependentResource<R, P extends HasMetadata>
Map<String, R> getSecondaryResources(P primary, Context<P> context);

/**
* Used to delete resource if the desired count is lower than the actual count of a resource.
* Deletes the actual resource if it's not in the set of desired secondary resources for the
* specified primary.
*
* @param primary resource
* @param resource actual resource from the cache for the index
* @param key key of the resource
* @param primary the primary resource for which we want to remove now undesired secondary
* resources still present on the cluster
* @param resource the actual resource existing on the cluster that needs to be removed
* @param context actual context
*/
void deleteBulkResource(P primary, R resource, String key, Context<P> context);
void deleteTargetResource(P primary, R resource, Context<P> context);
Copy link
Collaborator

@csviri csviri Oct 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 for rename

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But not sure we want to remove the key. I'm more to more complete APIs, so that is an information that some might miss if providing a custom implementation. So this way it's more future proof, also integral part.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, was debating this last point myself, actually…


/**
* Determines whether the specified secondary resource matches the desired state with target index
* of a bulk resource as defined from the specified primary resource, given the specified
* {@link Context}.
* Determines whether the specified secondary resource matches the desired state as defined from
* the specified primary resource, given the specified {@link Context}.
*
* @param actualResource the resource we want to determine whether it's matching the desired state
* @param desired the resource's desired state
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,29 @@
import io.javaoperatorsdk.operator.processing.dependent.Matcher.Result;
import io.javaoperatorsdk.operator.processing.event.ResourceID;

class BulkDependentResourceReconciler<R, P extends HasMetadata>
class DynamicallyCreatedDependentResourceReconciler<R, P extends HasMetadata>
implements DependentResourceReconciler<R, P> {

private final BulkDependentResource<R, P> bulkDependentResource;
private final DynamicallyCreatedDependentResource<R, P> delegate;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned don't agree with term 'Dynamic' it's too generic notion. Why Bulk nicely identifies this feature.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bulk doesn't fit either, imo. It kinda worked when the solution was indexed-based but now it's more about dynamically (as opposed to statically known at build time) defined dependents.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But the whole feature / funtionality is about to create resources in bulk. That is the only purpose, the only thing that changed is that the key is not an integer but a string.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bulk implies a large number and that's not really what the feature is about. This is about creating some resources that are determined at runtime, as opposed to the other dependents which are known statically at build-time. I agree that "dynamically created" isn't too appropriate but I don't think that "bulk" is, either…


BulkDependentResourceReconciler(BulkDependentResource<R, P> bulkDependentResource) {
this.bulkDependentResource = bulkDependentResource;
DynamicallyCreatedDependentResourceReconciler(
DynamicallyCreatedDependentResource<R, P> delegate) {
this.delegate = delegate;
}

@Override
public ReconcileResult<R> reconcile(P primary, Context<P> context) {
final var desiredResources = bulkDependentResource.desiredResources(primary, context);
Map<String, R> actualResources = bulkDependentResource.getSecondaryResources(primary, context);
final var desiredResources = delegate.desiredResources(primary, context);
Map<String, R> actualResources = delegate.getSecondaryResources(primary, context);

// remove existing resources that are not needed anymore according to the primary state
deleteBulkResourcesIfRequired(desiredResources.keySet(), actualResources, primary, context);
deleteUnexpectedDynamicResources(desiredResources.keySet(), actualResources, primary, context);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not really unexpected. It's natural to have those. Maybe "surplus" ? but not sure if this word used in this context.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about deleteExtraResources?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds great! 👍


final List<ReconcileResult<R>> results = new ArrayList<>(desiredResources.size());
final var updatable = bulkDependentResource instanceof Updater;
final var updatable = delegate instanceof Updater;
desiredResources.forEach((key, value) -> {
final var instance =
updatable ? new UpdatableBulkDependentResourceInstance<>(bulkDependentResource, value)
: new BulkDependentResourceInstance<>(bulkDependentResource, value);
final var instance = updatable ? new UpdatableDynamicDependentInstance<>(delegate, value)
: new DynamicDependentInstance<>(delegate, value);
results.add(instance.reconcile(primary, actualResources.get(key), context));
});

Expand All @@ -44,41 +44,42 @@ public ReconcileResult<R> reconcile(P primary, Context<P> context) {

@Override
public void delete(P primary, Context<P> context) {
var actualResources = bulkDependentResource.getSecondaryResources(primary, context);
deleteBulkResourcesIfRequired(Collections.emptySet(), actualResources, primary, context);
var actualResources =
delegate.getSecondaryResources(primary, context);
deleteUnexpectedDynamicResources(Collections.emptySet(), actualResources, primary, context);
}

private void deleteBulkResourcesIfRequired(Set<String> expectedKeys,
private void deleteUnexpectedDynamicResources(Set<String> expectedKeys,
Map<String, R> actualResources, P primary, Context<P> context) {
actualResources.forEach((key, value) -> {
if (!expectedKeys.contains(key)) {
bulkDependentResource.deleteBulkResource(primary, value, key, context);
delegate.deleteTargetResource(primary, value, context);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

}
});
}

/**
* Exposes a dynamically-created instance of the bulk dependent resource precursor as an
* AbstractDependentResource so that we can reuse its reconciliation logic.
* Exposes a dynamically-created instance of the dynamically-created dependent resource precursor
* as an AbstractDependentResource so that we can reuse its reconciliation logic.
*
* @param <R>
* @param <P>
*/
private static class BulkDependentResourceInstance<R, P extends HasMetadata>
private static class DynamicDependentInstance<R, P extends HasMetadata>
extends AbstractDependentResource<R, P>
implements Creator<R, P>, Deleter<P> {
private final BulkDependentResource<R, P> bulkDependentResource;
private final DynamicallyCreatedDependentResource<R, P> delegate;
private final R desired;

private BulkDependentResourceInstance(BulkDependentResource<R, P> bulkDependentResource,
private DynamicDependentInstance(DynamicallyCreatedDependentResource<R, P> delegate,
R desired) {
this.bulkDependentResource = bulkDependentResource;
this.delegate = delegate;
this.desired = desired;
}

@SuppressWarnings("unchecked")
private AbstractDependentResource<R, P> asAbstractDependentResource() {
return (AbstractDependentResource<R, P>) bulkDependentResource;
return (AbstractDependentResource<R, P>) delegate;
}

@Override
Expand All @@ -88,12 +89,13 @@ protected R desired(P primary, Context<P> context) {

@SuppressWarnings("unchecked")
public R update(R actual, R desired, P primary, Context<P> context) {
return ((Updater<R, P>) bulkDependentResource).update(actual, desired, primary, context);
return ((Updater<R, P>) delegate).update(actual, desired, primary,
context);
}

@Override
public Result<R> match(R resource, P primary, Context<P> context) {
return bulkDependentResource.match(resource, desired, primary, context);
return delegate.match(resource, desired, primary, context);
}

@Override
Expand All @@ -113,7 +115,7 @@ public Class<R> resourceType() {

@Override
public R create(R desired, P primary, Context<P> context) {
return bulkDependentResource.create(desired, primary, context);
return delegate.create(desired, primary, context);
}
}

Expand All @@ -123,13 +125,12 @@ public R create(R desired, P primary, Context<P> context) {
* @param <R>
* @param <P>
*/
private static class UpdatableBulkDependentResourceInstance<R, P extends HasMetadata>
extends BulkDependentResourceInstance<R, P> implements Updater<R, P> {
private static class UpdatableDynamicDependentInstance<R, P extends HasMetadata>
extends DynamicDependentInstance<R, P> implements Updater<R, P> {

private UpdatableBulkDependentResourceInstance(
BulkDependentResource<R, P> bulkDependentResource,
private UpdatableDynamicDependentInstance(DynamicallyCreatedDependentResource<R, P> delegate,
R desired) {
super(bulkDependentResource, desired);
super(delegate, desired);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package io.javaoperatorsdk.operator.processing.dependent;

import io.fabric8.kubernetes.api.model.HasMetadata;
import io.javaoperatorsdk.operator.api.reconciler.Context;

/**
* Helper for the dynamically-created Dependent Resources to make it more explicit that such
* dependents only to implement
* {@link DynamicallyCreatedDependentResource#match(Object, Object, HasMetadata, Context)}
*
* @param <R> secondary resource type
* @param <P> primary resource type
*/
public interface DynamicallyCreatedUpdater<R, P extends HasMetadata> extends Updater<R, P> {

default Matcher.Result<R> match(R actualResource, P primary, Context<P> context) {
if (!(this instanceof DynamicallyCreatedDependentResource)) {
throw new IllegalStateException(DynamicallyCreatedUpdater.class.getSimpleName()
+ " interface should only be implemented by "
+ DynamicallyCreatedDependentResource.class.getSimpleName() + " implementations");
}
throw new IllegalStateException("This method should not be called from a "
+ DynamicallyCreatedDependentResource.class.getSimpleName() + " implementation");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ protected void handleDelete(P primary, Context<P> context) {
}

@SuppressWarnings("unused")
public void deleteBulkResource(P primary, R resource, String key, Context<P> context) {
public void deleteTargetResource(P primary, R resource, Context<P> context) {
client.resource(resource).delete();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@
import org.junit.jupiter.api.extension.RegisterExtension;

import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension;
import io.javaoperatorsdk.operator.sample.bulkdependent.external.ExternalBulkResourceReconciler;
import io.javaoperatorsdk.operator.sample.bulkdependent.external.ExternalDynamicResourceReconciler;
import io.javaoperatorsdk.operator.sample.bulkdependent.external.ExternalServiceMock;

import static io.javaoperatorsdk.operator.bulkdependent.BulkDependentTestBase.*;
import static io.javaoperatorsdk.operator.bulkdependent.DynamicallyCreatedDependentTestBase.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;

class BulkExternalDependentIT {
class DynamicExternalDependentIT {

@RegisterExtension
LocallyRunOperatorExtension extension =
LocallyRunOperatorExtension.builder().withReconciler(new ExternalBulkResourceReconciler())
LocallyRunOperatorExtension.builder().withReconciler(new ExternalDynamicResourceReconciler())
.build();

ExternalServiceMock externalServiceMock = ExternalServiceMock.getInstance();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@
import org.junit.jupiter.api.extension.RegisterExtension;

import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension;
import io.javaoperatorsdk.operator.sample.bulkdependent.ManagedBulkDependentReconciler;
import io.javaoperatorsdk.operator.sample.bulkdependent.ManagedDeleterDynamicDependentReconciler;

class ManagedBulkDependentIT extends BulkDependentTestBase {
public class DynamicallyCreatedDependentDeleterIT extends DynamicallyCreatedDependentTestBase {

@RegisterExtension
LocallyRunOperatorExtension extension =
LocallyRunOperatorExtension.builder().withReconciler(new ManagedBulkDependentReconciler())
LocallyRunOperatorExtension.builder()
.withReconciler(new ManagedDeleterDynamicDependentReconciler())
.build();


@Override
LocallyRunOperatorExtension extension() {
return extension;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@

import io.fabric8.kubernetes.api.model.ObjectMeta;
import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension;
import io.javaoperatorsdk.operator.sample.bulkdependent.BulkDependentTestCustomResource;
import io.javaoperatorsdk.operator.sample.bulkdependent.BulkDependentTestSpec;
import io.javaoperatorsdk.operator.sample.bulkdependent.ConfigMapDeleterBulkDependentResource;
import io.javaoperatorsdk.operator.sample.bulkdependent.ConfigMapDeleterDynamicallyCreatedDependentResource;
import io.javaoperatorsdk.operator.sample.bulkdependent.DynamicDependentTestCustomResource;
import io.javaoperatorsdk.operator.sample.bulkdependent.DynamicDependentTestSpec;

import static io.javaoperatorsdk.operator.sample.bulkdependent.ConfigMapDeleterBulkDependentResource.LABEL_KEY;
import static io.javaoperatorsdk.operator.sample.bulkdependent.ConfigMapDeleterBulkDependentResource.LABEL_VALUE;
import static io.javaoperatorsdk.operator.sample.bulkdependent.ConfigMapDeleterDynamicallyCreatedDependentResource.LABEL_KEY;
import static io.javaoperatorsdk.operator.sample.bulkdependent.ConfigMapDeleterDynamicallyCreatedDependentResource.LABEL_VALUE;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;

public abstract class BulkDependentTestBase {
public abstract class DynamicallyCreatedDependentTestBase {

public static final String TEST_RESOURCE_NAME = "test";
public static final int INITIAL_NUMBER_OF_CONFIG_MAPS = 3;
Expand Down Expand Up @@ -68,18 +68,17 @@ private void assertAdditionalDataOnConfigMaps(String expectedValue) {
extension().getKubernetesClient().configMaps().inNamespace(extension().getNamespace())
.withLabel(LABEL_KEY, LABEL_VALUE)
.list().getItems();
cms.forEach(cm -> {
assertThat(cm.getData().get(ConfigMapDeleterBulkDependentResource.ADDITIONAL_DATA_KEY))
.isEqualTo(expectedValue);
});
cms.forEach(cm -> assertThat(cm.getData()
.get(ConfigMapDeleterDynamicallyCreatedDependentResource.ADDITIONAL_DATA_KEY))
.isEqualTo(expectedValue));
});
}

public static BulkDependentTestCustomResource testResource() {
BulkDependentTestCustomResource cr = new BulkDependentTestCustomResource();
public static DynamicDependentTestCustomResource testResource() {
DynamicDependentTestCustomResource cr = new DynamicDependentTestCustomResource();
cr.setMetadata(new ObjectMeta());
cr.getMetadata().setName(TEST_RESOURCE_NAME);
cr.setSpec(new BulkDependentTestSpec());
cr.setSpec(new DynamicDependentTestSpec());
cr.getSpec().setNumberOfResources(INITIAL_NUMBER_OF_CONFIG_MAPS);
cr.getSpec().setAdditionalData(INITIAL_ADDITIONAL_DATA);
return cr;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@
import org.junit.jupiter.api.extension.RegisterExtension;

import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension;
import io.javaoperatorsdk.operator.sample.bulkdependent.ManagedDeleterBulkReconciler;
import io.javaoperatorsdk.operator.sample.bulkdependent.ManagedDynamicDependentReconciler;

public class BulkDependentDeleterIT extends BulkDependentTestBase {
class ManagedDynamicallyCreatedDependentIT extends DynamicallyCreatedDependentTestBase {

@RegisterExtension
LocallyRunOperatorExtension extension =
LocallyRunOperatorExtension.builder().withReconciler(new ManagedDeleterBulkReconciler())
LocallyRunOperatorExtension.builder().withReconciler(new ManagedDynamicDependentReconciler())
.build();


@Override
LocallyRunOperatorExtension extension() {
return extension;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
import org.junit.jupiter.api.extension.RegisterExtension;

import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension;
import io.javaoperatorsdk.operator.sample.bulkdependent.StandaloneBulkDependentReconciler;
import io.javaoperatorsdk.operator.sample.bulkdependent.StandaloneDynamicDependentReconciler;

class StandaloneBulkDependentIT extends BulkDependentTestBase {
class StandaloneDynamicallyCreatedDependentIT extends DynamicallyCreatedDependentTestBase {

@RegisterExtension
LocallyRunOperatorExtension extension =
LocallyRunOperatorExtension.builder().withReconciler(new StandaloneBulkDependentReconciler())
LocallyRunOperatorExtension.builder()
.withReconciler(new StandaloneDynamicDependentReconciler())
.build();

@Override
Expand Down
Loading