Skip to content

Commit

Permalink
fix: issue with cluster scoped resource (#1549)
Browse files Browse the repository at this point in the history
  • Loading branch information
csviri authored Oct 19, 2022
1 parent b97d36e commit 86515f6
Show file tree
Hide file tree
Showing 7 changed files with 203 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@

import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.api.model.KubernetesResourceList;
import io.fabric8.kubernetes.api.model.Namespaced;
import io.fabric8.kubernetes.client.CustomResource;
import io.fabric8.kubernetes.client.KubernetesClientException;
import io.fabric8.kubernetes.client.dsl.MixedOperation;
import io.fabric8.kubernetes.client.dsl.Resource;
import io.fabric8.kubernetes.client.dsl.internal.HasMetadataOperationsImpl;
import io.javaoperatorsdk.operator.OperatorException;
import io.javaoperatorsdk.operator.api.ObservedGenerationAware;
import io.javaoperatorsdk.operator.api.config.ConfigurationServiceProvider;
Expand Down Expand Up @@ -355,29 +355,29 @@ public CustomResourceFacade(
}

public R getResource(String namespace, String name) {
return resourceOperation.inNamespace(namespace).withName(name).get();
if (namespace != null) {
return resourceOperation.inNamespace(namespace).withName(name).get();
} else {
return resourceOperation.withName(name).get();
}
}

public R updateResource(R resource) {
log.debug(
"Trying to replace resource {}, version: {}",
getName(resource),
resource.getMetadata().getResourceVersion());
return resourceOperation
.inNamespace(resource.getMetadata().getNamespace())
.resource(resource)
.lockResourceVersion(resource.getMetadata().getResourceVersion())

return resource(resource).lockResourceVersion(resource.getMetadata().getResourceVersion())
.replace();
}

@SuppressWarnings({"rawtypes", "unchecked"})
public R updateStatus(R resource) {
log.trace("Updating status for resource: {}", resource);
HasMetadataOperationsImpl hasMetadataOperation = (HasMetadataOperationsImpl) resourceOperation
.inNamespace(resource.getMetadata().getNamespace())
.withName(getName(resource))
.lockResourceVersion(resource.getMetadata().getResourceVersion());
return (R) hasMetadataOperation.replaceStatus(resource);
return resource(resource)
.lockResourceVersion()
.replaceStatus();
}

public R patchStatus(R resource, R originalResource) {
Expand All @@ -387,15 +387,19 @@ public R patchStatus(R resource, R originalResource) {
originalResource.getMetadata().setResourceVersion(null);
resource.getMetadata().setResourceVersion(null);
try {
return resourceOperation
.inNamespace(resource.getMetadata().getNamespace())
.resource(originalResource)
return resource(originalResource)
.editStatus(r -> resource);
} finally {
// restore initial resource version
originalResource.getMetadata().setResourceVersion(resourceVersion);
resource.getMetadata().setResourceVersion(resourceVersion);
}
}

private Resource<R> resource(R resource) {
return resource instanceof Namespaced ? resourceOperation
.inNamespace(resource.getMetadata().getNamespace())
.resource(resource) : resourceOperation.resource(resource);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.slf4j.LoggerFactory;

import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.api.model.Namespaced;
import io.fabric8.kubernetes.client.CustomResource;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.LocalPortForward;
Expand Down Expand Up @@ -128,7 +129,11 @@ protected void before(ExtensionContext context) {

for (var ref : reconcilers) {
final var config = configurationService.getConfigurationFor(ref.reconciler);
final var oconfig = override(config).settingNamespace(namespace);
final var oconfig = override(config);

if (Namespaced.class.isAssignableFrom(config.getResourceClass())) {
oconfig.settingNamespace(namespace);
}

if (ref.retry != null) {
oconfig.withRetry(ref.retry);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package io.javaoperatorsdk.operator;

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

import io.fabric8.kubernetes.api.model.ConfigMap;
import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension;
import io.javaoperatorsdk.operator.sample.clusterscopedresource.ClusterScopedCustomResource;
import io.javaoperatorsdk.operator.sample.clusterscopedresource.ClusterScopedCustomResourceReconciler;
import io.javaoperatorsdk.operator.sample.clusterscopedresource.ClusterScopedCustomResourceSpec;

import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;

class ClusterScopedResourceIT {

public static final String TEST_NAME = "test1";
public static final String INITIAL_DATA = "initialData";
public static final String UPDATED_DATA = "updatedData";
@RegisterExtension
LocallyRunOperatorExtension operator =
LocallyRunOperatorExtension.builder()
.withReconciler(new ClusterScopedCustomResourceReconciler()).build();

@Test
void crudOperationOnClusterScopedCustomResource() {
var resource = operator.create(testResource());

await().untilAsserted(() -> {
var res = operator.get(ClusterScopedCustomResource.class, TEST_NAME);
assertThat(res.getStatus()).isNotNull();
assertThat(res.getStatus().getCreated()).isTrue();
var cm = operator.get(ConfigMap.class, TEST_NAME);
assertThat(cm).isNotNull();
assertThat(cm.getData().get(ClusterScopedCustomResourceReconciler.DATA_KEY))
.isEqualTo(INITIAL_DATA);
});

resource.getSpec().setData(UPDATED_DATA);
operator.replace(resource);
await().untilAsserted(() -> {
var cm = operator.get(ConfigMap.class, TEST_NAME);
assertThat(cm).isNotNull();
assertThat(cm.getData().get(ClusterScopedCustomResourceReconciler.DATA_KEY))
.isEqualTo(UPDATED_DATA);
});

operator.delete(resource);
await().untilAsserted(() -> assertThat(operator.get(ConfigMap.class, TEST_NAME)).isNull());
}


ClusterScopedCustomResource testResource() {
var res = new ClusterScopedCustomResource();
res.setMetadata(new ObjectMetaBuilder()
.withName(TEST_NAME)
.build());
res.setSpec(new ClusterScopedCustomResourceSpec());
res.getSpec().setTargetNamespace(operator.getNamespace());
res.getSpec().setData(INITIAL_DATA);

return res;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package io.javaoperatorsdk.operator.sample.clusterscopedresource;

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("csc")
public class ClusterScopedCustomResource
extends CustomResource<ClusterScopedCustomResourceSpec, ClusterScopedCustomResourceStatus> {


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package io.javaoperatorsdk.operator.sample.clusterscopedresource;

import java.util.Map;

import io.fabric8.kubernetes.api.model.ConfigMap;
import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.javaoperatorsdk.operator.api.reconciler.*;
import io.javaoperatorsdk.operator.junit.KubernetesClientAware;

@ControllerConfiguration
public class ClusterScopedCustomResourceReconciler
implements Reconciler<ClusterScopedCustomResource>, Cleaner<ClusterScopedCustomResource>,
KubernetesClientAware {

public static final String DATA_KEY = "data-key";

private KubernetesClient client;

@Override
public UpdateControl<ClusterScopedCustomResource> reconcile(
ClusterScopedCustomResource resource, Context<ClusterScopedCustomResource> context) {

client.configMaps().resource(desired(resource)).createOrReplace();

resource.setStatus(new ClusterScopedCustomResourceStatus());
resource.getStatus().setCreated(true);
return UpdateControl.patchStatus(resource);
}

private ConfigMap desired(ClusterScopedCustomResource resource) {
return new ConfigMapBuilder()
.withMetadata(new ObjectMetaBuilder()
.withName(resource.getMetadata().getName())
.withNamespace(resource.getSpec().getTargetNamespace())
.build())
.withData(Map.of(DATA_KEY, resource.getSpec().getData()))
.build();
}

@Override
public KubernetesClient getKubernetesClient() {
return client;
}

@Override
public void setKubernetesClient(KubernetesClient kubernetesClient) {
this.client = kubernetesClient;
}

@Override
public DeleteControl cleanup(ClusterScopedCustomResource resource,
Context<ClusterScopedCustomResource> context) {
client.configMaps().resource(desired(resource)).delete();
return DeleteControl.defaultDelete();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package io.javaoperatorsdk.operator.sample.clusterscopedresource;

public class ClusterScopedCustomResourceSpec {

private String data;
private String targetNamespace;

public String getData() {
return data;
}

public ClusterScopedCustomResourceSpec setData(String data) {
this.data = data;
return this;
}

public String getTargetNamespace() {
return targetNamespace;
}

public ClusterScopedCustomResourceSpec setTargetNamespace(String targetNamespace) {
this.targetNamespace = targetNamespace;
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package io.javaoperatorsdk.operator.sample.clusterscopedresource;

public class ClusterScopedCustomResourceStatus {

private Boolean created;

public Boolean getCreated() {
return created;
}

public ClusterScopedCustomResourceStatus setCreated(Boolean created) {
this.created = created;
return this;
}
}

0 comments on commit 86515f6

Please sign in to comment.