Skip to content

Commit 93948b2

Browse files
committed
reconciler for IT
1 parent 0060457 commit 93948b2

File tree

8 files changed

+183
-3
lines changed

8 files changed

+183
-3
lines changed

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/AbstractEventSource.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ public EventSourceStartPriority priority() {
3636
return eventSourceStartPriority;
3737
}
3838

39-
public AbstractEventSource setEventSourcePriority(EventSourceStartPriority eventSourceStartPriority) {
39+
public AbstractEventSource setEventSourcePriority(
40+
EventSourceStartPriority eventSourceStartPriority) {
4041
this.eventSourceStartPriority = eventSourceStartPriority;
4142
return this;
4243
}

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/EventSourceStartPriority.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22

33
public enum EventSourceStartPriority {
44

5-
RESOURCE_STATE_LOADER,
6-
DEFAULT
5+
RESOURCE_STATE_LOADER, DEFAULT
76

87

98
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package io.javaoperatorsdk.operator;
2+
3+
public class ExternalStateIT {
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package io.javaoperatorsdk.operator.sample.externalstate;
2+
3+
import io.fabric8.kubernetes.api.model.Namespaced;
4+
import io.fabric8.kubernetes.client.CustomResource;
5+
import io.fabric8.kubernetes.model.annotation.Group;
6+
import io.fabric8.kubernetes.model.annotation.ShortNames;
7+
import io.fabric8.kubernetes.model.annotation.Version;
8+
9+
@Group("sample.javaoperatorsdk")
10+
@Version("v1")
11+
@ShortNames("ess")
12+
public class ExternalStateCustomResource
13+
extends CustomResource<Void, Void>
14+
implements Namespaced {
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package io.javaoperatorsdk.operator.sample.externalstate;
2+
3+
import java.util.Collections;
4+
import java.util.Map;
5+
import java.util.Set;
6+
import java.util.concurrent.atomic.AtomicInteger;
7+
8+
import io.fabric8.kubernetes.api.model.ConfigMap;
9+
import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
10+
import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
11+
import io.fabric8.kubernetes.client.KubernetesClient;
12+
import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration;
13+
import io.javaoperatorsdk.operator.api.reconciler.*;
14+
import io.javaoperatorsdk.operator.junit.KubernetesClientAware;
15+
import io.javaoperatorsdk.operator.processing.event.ResourceID;
16+
import io.javaoperatorsdk.operator.processing.event.source.EventSource;
17+
import io.javaoperatorsdk.operator.processing.event.source.EventSourceStartPriority;
18+
import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource;
19+
import io.javaoperatorsdk.operator.processing.event.source.polling.PerResourcePollingEventSource;
20+
import io.javaoperatorsdk.operator.support.ExternalIDGenServiceMock;
21+
import io.javaoperatorsdk.operator.support.ExternalResource;
22+
import io.javaoperatorsdk.operator.support.TestExecutionInfoProvider;
23+
24+
@ControllerConfiguration()
25+
public class ExternalStateReconciler
26+
implements Reconciler<ExternalStateCustomResource>, Cleaner<ExternalStateCustomResource>,
27+
EventSourceInitializer<ExternalStateCustomResource>, KubernetesClientAware,
28+
TestExecutionInfoProvider {
29+
30+
public static final String ID_KEY = "id";
31+
private final AtomicInteger numberOfExecutions = new AtomicInteger(0);
32+
33+
private ExternalIDGenServiceMock externalService = ExternalIDGenServiceMock.getInstance();
34+
private KubernetesClient client;
35+
36+
InformerEventSource<ConfigMap, ExternalStateCustomResource> configMapEventSource;
37+
PerResourcePollingEventSource<ExternalResource, ExternalStateCustomResource> externalResourceEventSource;
38+
39+
@Override
40+
public UpdateControl<ExternalStateCustomResource> reconcile(
41+
ExternalStateCustomResource resource, Context<ExternalStateCustomResource> context) {
42+
numberOfExecutions.addAndGet(1);
43+
44+
var externalResource = context.getSecondaryResource(ExternalResource.class);
45+
if (externalResource.isEmpty()) {
46+
createExternalResource(resource);
47+
}
48+
return UpdateControl.noUpdate();
49+
}
50+
51+
private void createExternalResource(ExternalStateCustomResource resource) {
52+
var createdResource =
53+
externalService.create(new ExternalResource(resource.getMetadata().getName()));
54+
var configMap = new ConfigMapBuilder()
55+
.withMetadata(new ObjectMetaBuilder()
56+
.withName(resource.getMetadata().getName())
57+
.withNamespace(resource.getMetadata().getNamespace())
58+
.build())
59+
.withData(Map.of(ID_KEY, createdResource.getId()))
60+
.build();
61+
client.configMaps().resource(configMap).create();
62+
63+
var primaryID = ResourceID.fromResource(resource);
64+
configMapEventSource.handleRecentResourceCreate(primaryID, configMap);
65+
externalResourceEventSource.handleRecentResourceCreate(primaryID, createdResource);
66+
}
67+
68+
@Override
69+
public DeleteControl cleanup(ExternalStateCustomResource resource,
70+
Context<ExternalStateCustomResource> context) {
71+
client.configMaps().inNamespace(resource.getMetadata().getNamespace())
72+
.withName(resource.getMetadata().getName()).delete();
73+
return DeleteControl.defaultDelete();
74+
}
75+
76+
public int getNumberOfExecutions() {
77+
return numberOfExecutions.get();
78+
}
79+
80+
@Override
81+
public Map<String, EventSource> prepareEventSources(
82+
EventSourceContext<ExternalStateCustomResource> context) {
83+
84+
configMapEventSource = new InformerEventSource<>(
85+
InformerConfiguration.from(ConfigMap.class, context).build(), context);
86+
configMapEventSource.setEventSourcePriority(EventSourceStartPriority.RESOURCE_STATE_LOADER);
87+
88+
externalResourceEventSource = new PerResourcePollingEventSource<>(primaryResource -> {
89+
var configMap = configMapEventSource.getSecondaryResource(primaryResource).orElseThrow();
90+
var id = configMap.getData().get(ID_KEY);
91+
var externalResource = externalService.read(id);
92+
return externalResource.map(er -> Set.of(er)).orElse(Collections.emptySet());
93+
}, context.getPrimaryCache(), 300L, ExternalResource.class);
94+
95+
return EventSourceInitializer.nameEventSources(configMapEventSource,
96+
externalResourceEventSource);
97+
}
98+
99+
@Override
100+
public KubernetesClient getKubernetesClient() {
101+
return client;
102+
}
103+
104+
@Override
105+
public void setKubernetesClient(KubernetesClient kubernetesClient) {
106+
this.client = kubernetesClient;
107+
}
108+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package io.javaoperatorsdk.operator.support;
2+
3+
import java.util.*;
4+
import java.util.concurrent.ConcurrentHashMap;
5+
6+
public class ExternalIDGenServiceMock {
7+
8+
private static ExternalIDGenServiceMock serviceMock = new ExternalIDGenServiceMock();
9+
10+
private Map<String, ExternalResource> resourceMap = new ConcurrentHashMap<>();
11+
12+
public ExternalResource create(ExternalResource externalResource) {
13+
if (externalResource.getId() != null) {
14+
throw new IllegalArgumentException("ID provided for external resource");
15+
}
16+
String id = UUID.randomUUID().toString();
17+
resourceMap.put(id, new ExternalResource(id, externalResource.getData()));
18+
return externalResource;
19+
}
20+
21+
public Optional<ExternalResource> read(String id) {
22+
return Optional.ofNullable(resourceMap.get(id));
23+
}
24+
25+
public ExternalResource update(ExternalResource externalResource) {
26+
return resourceMap.put(externalResource.getId(), externalResource);
27+
}
28+
29+
public Optional<ExternalResource> delete(String id) {
30+
return Optional.ofNullable(resourceMap.remove(id));
31+
}
32+
33+
public List<ExternalResource> listResources() {
34+
return new ArrayList<>(resourceMap.values());
35+
}
36+
37+
public static ExternalIDGenServiceMock getInstance() {
38+
return serviceMock;
39+
}
40+
41+
}

operator-framework/src/test/java/io/javaoperatorsdk/operator/support/ExternalResource.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,15 @@ public class ExternalResource {
1212
private String id;
1313
private String data;
1414

15+
/**
16+
* For the case that ide is generated by server
17+
*
18+
* @param data to store
19+
*/
20+
public ExternalResource(String data) {
21+
this.data = data;
22+
}
23+
1524
public ExternalResource(String id, String data) {
1625
this.id = id;
1726
this.data = data;

operator-framework/src/test/java/io/javaoperatorsdk/operator/support/ExternalServiceMock.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ public class ExternalServiceMock {
1313
private Map<String, ExternalResource> resourceMap = new ConcurrentHashMap<>();
1414

1515
public ExternalResource create(ExternalResource externalResource) {
16+
if (externalResource.getId() == null) {
17+
throw new IllegalArgumentException("id of the resource is null");
18+
}
1619
resourceMap.put(externalResource.getId(), externalResource);
1720
return externalResource;
1821
}

0 commit comments

Comments
 (0)