Skip to content

feat: secondary to primary in dependent resources #1742

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 8 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
36 changes: 36 additions & 0 deletions docs/documentation/v4-3-migration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
title: Migrating from v4.2 to v4.3
description: Migrating from v4.2 to v4.3
layout: docs
permalink: /docs/v4-3-migration
---

# Migrating from v4.2 to v4.3

## Condition API Change

In Workflows the target of the condition was the managed resource itself, not a dependent resource. This changed, from
not the API contains the dependent resource.

New API:

```java
public interface Condition<R, P extends HasMetadata> {

boolean isMet(DependentResource<R, P> dependentResource, P primary, Context<P> context);

}
```

Former API:

```java
public interface Condition<R, P extends HasMetadata> {

boolean isMet(P primary, R secondary, Context<P> context);

}
```

Migration is trivial. Since the secondary resource can be accessed from the dependent resource. So to access the secondary
resource just use `dependentResource.getSecondaryResource(primary,context)`.
2 changes: 1 addition & 1 deletion micrometer-support/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<artifactId>java-operator-sdk</artifactId>
<groupId>io.javaoperatorsdk</groupId>
<version>4.2.4-SNAPSHOT</version>
<version>4.3.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand Down
2 changes: 1 addition & 1 deletion operator-framework-bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>io.javaoperatorsdk</groupId>
<artifactId>operator-framework-bom</artifactId>
<version>4.2.4-SNAPSHOT</version>
<version>4.3.0-SNAPSHOT</version>
<name>Operator SDK - Bill of Materials</name>
<packaging>pom</packaging>
<description>Java SDK for implementing Kubernetes operators</description>
Expand Down
17 changes: 15 additions & 2 deletions operator-framework-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>io.javaoperatorsdk</groupId>
<artifactId>java-operator-sdk</artifactId>
<version>4.2.4-SNAPSHOT</version>
<version>4.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down Expand Up @@ -40,13 +40,26 @@
<generateGitPropertiesFilename>${project.build.outputDirectory}/version.properties
</generateGitPropertiesFilename>
<includeOnlyProperties>
<includeOnlyProperty>^git.build.(time|version)$</includeOnlyProperty>
<includeOnlyProperty>^git.build.time$</includeOnlyProperty>
<includeOnlyProperty>^git.commit.id.(abbrev|full)$</includeOnlyProperty>
<includeOnlyProperty>git.branch</includeOnlyProperty>
</includeOnlyProperties>
<commitIdGenerationMode>full</commitIdGenerationMode>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>templating-maven-plugin</artifactId>
<version>1.0.0</version>
<executions>
<execution>
<id>filtering-java-templates</id>
<goals>
<goal>filter-sources</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package io.javaoperatorsdk.operator.api.config;

public final class Versions {

private Versions() {}

protected static final String JOSDK = "${project.version}";
protected static final String KUBERNETES_CLIENT = "${fabric8-client.version}";

}
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ public static Version loadFromProperties() {
builtTime = Date.from(Instant.EPOCH);
}
return new Version(
properties.getProperty("git.build.version", "unknown"),
properties.getProperty("git.commit.id.abbrev", "unknown"),
builtTime);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,11 @@
/** A class encapsulating the version information associated with this SDK instance. */
public class Version {

public static final Version UNKNOWN = new Version("unknown", "unknown", Date.from(Instant.EPOCH));

private final String sdk;
public static final Version UNKNOWN = new Version("unknown", Date.from(Instant.EPOCH));
private final String commit;
private final Date builtTime;

public Version(String sdkVersion, String commit, Date builtTime) {
this.sdk = sdkVersion;
public Version(String commit, Date builtTime) {
this.commit = commit;
this.builtTime = builtTime;
}
Expand All @@ -24,7 +21,7 @@ public Version(String sdkVersion, String commit, Date builtTime) {
* @return the SDK project version
*/
public String getSdkVersion() {
return sdk;
return Versions.JOSDK;
}

/**
Expand All @@ -45,4 +42,14 @@ public String getCommit() {
public Date getBuiltTime() {
return builtTime;
}

/**
* Returns the version of the Fabric8 Kubernetes Client being used by this version of the SDK
*
* @return the Fabric8 Kubernetes Client version
*/
@SuppressWarnings("unused")
public String getKubernetesClientVersion() {
return Versions.KUBERNETES_CLIENT;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import io.javaoperatorsdk.operator.processing.dependent.Matcher;
import io.javaoperatorsdk.operator.processing.dependent.Matcher.Result;
import io.javaoperatorsdk.operator.processing.event.ResourceID;
import io.javaoperatorsdk.operator.processing.event.source.PrimaryToSecondaryMapper;
import io.javaoperatorsdk.operator.processing.event.source.SecondaryToPrimaryMapper;
import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource;
import io.javaoperatorsdk.operator.processing.event.source.informer.Mappers;
Expand Down Expand Up @@ -76,6 +77,7 @@ private void configureWith(String labelSelector, Set<String> namespaces,
var ic = InformerConfiguration.from(resourceType())
.withLabelSelector(labelSelector)
.withSecondaryToPrimaryMapper(getSecondaryToPrimaryMapper())
.withPrimaryToSecondaryMapper(getPrimaryToSecondaryMapper())
.withNamespaces(namespaces, inheritNamespacesOnChange)
.build();

Expand All @@ -97,6 +99,15 @@ private SecondaryToPrimaryMapper<R> getSecondaryToPrimaryMapper() {
}
}

@SuppressWarnings("unchecked")
private PrimaryToSecondaryMapper<P> getPrimaryToSecondaryMapper() {
if (this instanceof PrimaryToSecondaryMapper) {
return (PrimaryToSecondaryMapper<P>) this;
} else {
return null;
}
}

/**
* Use to share informers between event more resources.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,12 @@ public ResourceDiscriminator getResourceDiscriminator() {
public void changeNamespaces(Set<String> namespaces) {
if (!wereNamespacesConfigured()) {
this.namespacesWereConfigured = true;
setNamespaces(namespaces);
}
}

protected void setNamespaces(Set<String> namespaces) {
if (namespaces != null && !namespaces.isEmpty()) {
this.namespaces = namespaces;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import io.fabric8.kubernetes.api.model.HasMetadata;
import io.javaoperatorsdk.operator.api.reconciler.Context;
import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource;
import io.javaoperatorsdk.operator.processing.dependent.BulkDependentResource;

@SuppressWarnings("rawtypes")
public abstract class AbstractWorkflowExecutor<P extends HasMetadata> {
Expand Down Expand Up @@ -103,15 +102,7 @@ protected synchronized void handleNodeExecutionFinish(
@SuppressWarnings("unchecked")
protected <R> boolean isConditionMet(Optional<Condition<R, P>> condition,
DependentResource<R, P> dependentResource) {
if (condition.isEmpty()) {
return true;
}
var resources = dependentResource instanceof BulkDependentResource
? ((BulkDependentResource) dependentResource).getSecondaryResources(primary, context)
: dependentResource.getSecondaryResource(primary, context).orElse(null);

return condition.map(c -> c.isMet(primary,
(R) resources, context))
return condition.map(c -> c.isMet(dependentResource, primary, context))
.orElse(true);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

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

public interface Condition<R, P extends HasMetadata> {

Expand All @@ -10,12 +11,10 @@ public interface Condition<R, P extends HasMetadata> {
* {@link io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource} based on the
* observed cluster state.
*
* @param dependentResource for which the condition applies to
* @param primary the primary resource being considered
* @param secondary the secondary resource associated with the specified primary resource or
* {@code null} if no such secondary resource exists (for example because it's been
* deleted)
* @param context the current reconciliation {@link Context}
* @return {@code true} if the condition holds, {@code false} otherwise
*/
boolean isMet(P primary, R secondary, Context<P> context);
boolean isMet(DependentResource<R, P> dependentResource, P primary, Context<P> context);
}
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,9 @@ public UpdateControl<ConfigMap> reconcile(ConfigMap resource, Context<ConfigMap>
private static class TestCondition implements Condition<ConfigMap, ConfigMap> {

@Override
public boolean isMet(ConfigMap primary, ConfigMap secondary, Context<ConfigMap> context) {
public boolean isMet(DependentResource<ConfigMap, ConfigMap> dependentResource,
ConfigMap primary,
Context<ConfigMap> context) {
return true;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.javaoperatorsdk.operator.api.config;

import org.junit.jupiter.api.Test;

import static org.junit.Assert.assertEquals;

public class VersionTest {

@Test
void versionShouldReturnTheSameResultFromMavenAndProperties() {
String versionFromProperties = Utils.loadFromProperties().getSdkVersion();
String versionFromMaven = Version.UNKNOWN.getSdkVersion();

assertEquals(versionFromProperties, versionFromMaven);
}

}
2 changes: 1 addition & 1 deletion operator-framework-junit5/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<artifactId>java-operator-sdk</artifactId>
<groupId>io.javaoperatorsdk</groupId>
<version>4.2.4-SNAPSHOT</version>
<version>4.3.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand Down
2 changes: 1 addition & 1 deletion operator-framework/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<artifactId>java-operator-sdk</artifactId>
<groupId>io.javaoperatorsdk</groupId>
<version>4.2.4-SNAPSHOT</version>
<version>4.3.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.javaoperatorsdk.operator;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension;
import io.javaoperatorsdk.operator.sample.primarytosecondarydependent.PrimaryToSecondaryDependentReconciler;

class PrimaryToSecondaryForDependentIT {

@RegisterExtension
LocallyRunOperatorExtension operator =
LocallyRunOperatorExtension.builder()
.withReconciler(new PrimaryToSecondaryDependentReconciler()).build();

@Test
void testReconcilePreconditionOnReadOnlyResource() {

}

}
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
package io.javaoperatorsdk.operator.sample.bulkdependent;

import java.util.Map;

import io.fabric8.kubernetes.api.model.ConfigMap;
import io.javaoperatorsdk.operator.api.reconciler.Context;
import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource;
import io.javaoperatorsdk.operator.processing.dependent.workflow.Condition;

public class SampleBulkCondition
implements Condition<Map<String, ConfigMap>, BulkDependentTestCustomResource> {
implements Condition<ConfigMap, BulkDependentTestCustomResource> {

// We use ConfigMaps here just to show how to check some properties of resources managed by a
// BulkDependentResource. In real life example this would be rather based on some status of those
// resources, like Pods.

@Override
public boolean isMet(BulkDependentTestCustomResource primary, Map<String, ConfigMap> secondary,
public boolean isMet(
DependentResource<ConfigMap, BulkDependentTestCustomResource> dependentResource,
BulkDependentTestCustomResource primary,
Context<BulkDependentTestCustomResource> context) {
return secondary.values().stream().noneMatch(cm -> cm.getData().isEmpty());

var resources = ((CRUDConfigMapBulkDependentResource) dependentResource)
.getSecondaryResources(primary, context);
return resources.values().stream().noneMatch(cm -> cm.getData().isEmpty());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,23 @@

import io.fabric8.kubernetes.api.model.apps.StatefulSet;
import io.javaoperatorsdk.operator.api.reconciler.Context;
import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource;
import io.javaoperatorsdk.operator.processing.dependent.workflow.Condition;
import io.javaoperatorsdk.operator.sample.complexdependent.ComplexDependentCustomResource;

public class StatefulSetReadyCondition
implements Condition<StatefulSet, ComplexDependentCustomResource> {

@Override
public boolean isMet(ComplexDependentCustomResource primary, StatefulSet secondary,
public boolean isMet(
DependentResource<StatefulSet, ComplexDependentCustomResource> dependentResource,
ComplexDependentCustomResource primary,
Context<ComplexDependentCustomResource> context) {

var readyReplicas = secondary.getStatus().getReadyReplicas();
return readyReplicas != null && readyReplicas > 0;
return dependentResource.getSecondaryResource(primary, context).map(secondary -> {
var readyReplicas = secondary.getStatus().getReadyReplicas();
return readyReplicas != null && readyReplicas > 0;
})
.orElse(false);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package io.javaoperatorsdk.operator.sample.primarytosecondarydependent;

import io.fabric8.kubernetes.api.model.Namespaced;
import io.fabric8.kubernetes.client.CustomResource;
import io.fabric8.kubernetes.model.annotation.Group;
import io.fabric8.kubernetes.model.annotation.ShortNames;
import io.fabric8.kubernetes.model.annotation.Version;

@Group("sample.javaoperatorsdk")
@Version("v1")
@ShortNames("ptsd")
public class PrimaryToSecondaryDependentCustomResource
extends CustomResource<Void, Void>
implements Namespaced {

}
Loading