Skip to content

Commit b40605f

Browse files
committed
wip
Signed-off-by: csviri <[email protected]>
1 parent 7d4ecf4 commit b40605f

File tree

3 files changed

+123
-27
lines changed

3 files changed

+123
-27
lines changed

src/main/java/io/csviri/operator/resourceglue/Utils.java

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77

88
import io.csviri.operator.resourceglue.customresource.glue.DependentResourceSpec;
99
import io.csviri.operator.resourceglue.customresource.glue.Glue;
10+
import io.csviri.operator.resourceglue.customresource.glue.RelatedResourceSpec;
1011
import io.fabric8.kubernetes.api.model.GenericKubernetesResource;
12+
import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
1113
import io.javaoperatorsdk.operator.api.reconciler.Context;
1214
import io.javaoperatorsdk.operator.processing.GroupVersionKind;
1315
import io.javaoperatorsdk.operator.processing.event.ResourceID;
@@ -32,7 +34,8 @@ public static Map<String, GenericKubernetesResource> getActualResourcesByNameInW
3234
.filter(r -> Utils.getApiVersion(r).equals(sr.getApiVersion())
3335
&& Utils.getKind(r).equals(sr.getKind())
3436
// checking the name from annotation since it might be templated name
35-
// therefore "Utils.getName(r).equals(sr.getMetadata().getName())" would not work
37+
// therefore "Utils.getName(relatedResourceSpec).equals(sr.getMetadata().getName())" would not
38+
// work
3639
&& r.getName()
3740
.equals(sr.getMetadata().getAnnotations().get(DEPENDENT_NAME_ANNOTATION_KEY))
3841
// namespace not compared here, it should be done it is just not trivial, now it is limited to
@@ -42,29 +45,54 @@ public static Map<String, GenericKubernetesResource> getActualResourcesByNameInW
4245
});
4346

4447
glue.getSpec().getRelatedResources().forEach(r -> {
45-
var gvk = new GroupVersionKind(r.getApiVersion(), r.getKind());
46-
log.debug("Getting event source for gvk: {}", gvk);
47-
var es =
48-
(InformerEventSource<GenericKubernetesResource, Glue>) context
49-
.eventSourceRetriever()
50-
.getResourceEventSourceFor(GenericKubernetesResource.class, gvk.toString());
51-
var namespace =
52-
r.getNamespace() == null ? glue.getMetadata().getNamespace() : r.getNamespace();
53-
if (r.getResourceNames().size() == 1) {
54-
es.get(new ResourceID(r.getResourceNames().get(0), namespace)).ifPresentOrElse(resource -> {
55-
res.put(r.getName(), resource);
56-
}, () -> res.put(r.getName(), null));
48+
var relatedResources = getRelatedResources(glue, r, context);
49+
if (relatedResources.size() == 1) {
50+
var resourceEntry = relatedResources.entrySet().iterator().next();
51+
res.put(r.getName(), resourceEntry.getValue());
52+
5753
} else {
58-
r.getResourceNames().forEach(resourceName -> es.get(new ResourceID(resourceName, namespace))
59-
.ifPresentOrElse(
60-
resource -> res.put(r.getName() + RESOURCE_NAME_DELIMITER + resourceName, resource),
61-
() -> res.put(r.getName() + "#" + resourceName, null)));
54+
relatedResources.forEach((resourceName, resource) -> res
55+
.put(r.getName() + RESOURCE_NAME_DELIMITER + resourceName, resource));
6256
}
6357
});
6458

6559
return res;
6660
}
6761

62+
@SuppressWarnings("unchecked")
63+
public static Map<String, GenericKubernetesResource> getRelatedResources(Glue glue,
64+
RelatedResourceSpec relatedResourceSpec,
65+
Context<?> context) {
66+
var gvk =
67+
new GroupVersionKind(relatedResourceSpec.getApiVersion(), relatedResourceSpec.getKind());
68+
log.debug("Getting event source for gvk: {}", gvk);
69+
var es =
70+
(InformerEventSource<GenericKubernetesResource, Glue>) context
71+
.eventSourceRetriever()
72+
.getResourceEventSourceFor(GenericKubernetesResource.class, gvk.toString());
73+
var namespace =
74+
relatedResourceSpec.getNamespace() == null ? glue.getMetadata().getNamespace()
75+
: relatedResourceSpec.getNamespace();
76+
77+
var res = new HashMap<String, GenericKubernetesResource>();
78+
79+
relatedResourceSpec.getResourceNames()
80+
.forEach(r -> res.put(r, es.get(new ResourceID(r, namespace)).orElse(null)));
81+
return res;
82+
}
83+
84+
public static GenericKubernetesResource getResourceForSSAFrom(
85+
GenericKubernetesResource resourceFromServer) {
86+
var res = new GenericKubernetesResource();
87+
res.setKind(resourceFromServer.getKind());
88+
res.setApiVersion(resourceFromServer.getApiVersion());
89+
res.setMetadata(new ObjectMetaBuilder()
90+
.withName(resourceFromServer.getMetadata().getName())
91+
.withNamespace(resourceFromServer.getMetadata().getNamespace())
92+
.build());
93+
return res;
94+
}
95+
6896
public static GroupVersionKind getGVK(DependentResourceSpec spec) {
6997
return new GroupVersionKind(getApiVersion(spec), getKind(spec));
7098
}

src/main/java/io/csviri/operator/resourceglue/reconciler/glue/GlueReconciler.java

Lines changed: 77 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import io.csviri.operator.resourceglue.templating.GenericTemplateHandler;
2020
import io.fabric8.kubernetes.api.model.GenericKubernetesResource;
2121
import io.fabric8.kubernetes.client.KubernetesClientException;
22+
import io.fabric8.kubernetes.client.dsl.base.PatchContext;
23+
import io.fabric8.kubernetes.client.dsl.base.PatchType;
2224
import io.javaoperatorsdk.operator.api.reconciler.*;
2325
import io.javaoperatorsdk.operator.processing.GroupVersionKind;
2426
import io.javaoperatorsdk.operator.processing.dependent.workflow.Condition;
@@ -27,11 +29,15 @@
2729
import io.javaoperatorsdk.operator.processing.event.ResourceID;
2830
import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource;
2931

32+
import static io.csviri.operator.resourceglue.Utils.getResourceForSSAFrom;
33+
import static io.csviri.operator.resourceglue.reconciler.operator.GlueOperatorReconciler.PARENT_RELATED_RESOURCE_NAME;
34+
3035
@ControllerConfiguration
3136
public class GlueReconciler implements Reconciler<Glue>, Cleaner<Glue> {
3237

3338
private static final Logger log = LoggerFactory.getLogger(GlueReconciler.class);
3439
public static final String DEPENDENT_NAME_ANNOTATION_KEY = "io.csviri.operator.resourceflow/name";
40+
public static final String PARENT_GLUE_FINALIZER_PREFIX = "io.csviri.operator.resourceflow.glue/";
3541

3642
private final KubernetesResourceDeletedCondition deletePostCondition =
3743
new KubernetesResourceDeletedCondition();
@@ -44,8 +50,8 @@ public UpdateControl<Glue> reconcile(Glue primary,
4450

4551
log.debug("Reconciling glue. name: {} namespace: {}",
4652
primary.getMetadata().getName(), primary.getMetadata().getNamespace());
47-
addFinalizersToParentResource(primary);
4853
registerRelatedResourceInformers(context, primary);
54+
addFinalizersToParentResource(primary, context);
4955
if (ownersBeingDeleted(primary, context)) {
5056
return UpdateControl.noUpdate();
5157
}
@@ -57,12 +63,6 @@ public UpdateControl<Glue> reconcile(Glue primary,
5763
return UpdateControl.noUpdate();
5864
}
5965

60-
// todo issue, condition if resource exists (related resource exists)
61-
// todo, also remove finalizer on cleanup
62-
// add just
63-
private void addFinalizersToParentResource(Glue primary) {
64-
65-
}
6666

6767
/**
6868
* If a parent gets deleted, the glue is reconciled still, but we don't want that in that case.
@@ -92,9 +92,6 @@ private boolean ownersBeingDeleted(Glue primary, Context<Glue> context) {
9292

9393
@Override
9494
public DeleteControl cleanup(Glue primary, Context<Glue> context) {
95-
// todo if related resource referenced to name the resource (name / namespace) the related
96-
// resource might be deleted
97-
// at this point - shall we add finalizer?
9895

9996
var actualWorkflow = buildWorkflowAndRegisterInformers(primary, context);
10097
var result = actualWorkflow.cleanup(primary, context);
@@ -103,6 +100,7 @@ public DeleteControl cleanup(Glue primary, Context<Glue> context) {
103100
if (!result.allPostConditionsMet()) {
104101
return DeleteControl.noFinalizerRemoval();
105102
} else {
103+
removeFinalizerForParent(primary, context);
106104
actualWorkflow.getDependentResourcesByNameWithoutActivationCondition().forEach((n, dr) -> {
107105
var genericDependentResource = (GenericDependentResource) dr;
108106
informerRegister.deRegisterInformer(genericDependentResource.getGroupVersionKind(),
@@ -217,4 +215,73 @@ private Condition toCondition(ConditionSpec condition) {
217215
throw new IllegalStateException("Unknown condition: " + condition);
218216
}
219217

218+
// todo docs
219+
private void addFinalizersToParentResource(Glue primary, Context<Glue> context) {
220+
var parentRelated = primary.getSpec().getRelatedResources().stream()
221+
.filter(r -> r.getName().equals(PARENT_RELATED_RESOURCE_NAME))
222+
.findAny();
223+
parentRelated.ifPresent(r -> {
224+
var relatedResources = Utils.getRelatedResources(primary, r, context);
225+
if (relatedResources.size() > 1) {
226+
throw new IllegalStateException(
227+
"parent related resource contains more resourceNames for glue name: "
228+
+ primary.getMetadata().getName()
229+
+ " namespace: " + primary.getMetadata().getNamespace());
230+
}
231+
// theoretically can happen that parent was deleted meanwhile
232+
if (relatedResources.isEmpty()) {
233+
return;
234+
}
235+
var parent = relatedResources.entrySet().iterator().next().getValue();
236+
String finalizer = parentFinalizer(primary.getMetadata().getName());
237+
if (!parent.getMetadata().getFinalizers().contains(finalizer)) {
238+
var res = getResourceForSSAFrom(parent);
239+
res.getMetadata().getFinalizers().add(finalizer);
240+
context.getClient().resource(res)
241+
.patch(new PatchContext.Builder()
242+
.withFieldManager(context.getControllerConfiguration().fieldManager())
243+
.withForce(true)
244+
.withPatchType(PatchType.SERVER_SIDE_APPLY)
245+
.build());
246+
}
247+
});
248+
}
249+
250+
private void removeFinalizerForParent(Glue primary, Context<Glue> context) {
251+
var parentRelated = primary.getSpec().getRelatedResources().stream()
252+
.filter(r -> r.getName().equals(PARENT_RELATED_RESOURCE_NAME))
253+
.findAny();
254+
parentRelated.ifPresent(r -> {
255+
var relatedResources = Utils.getRelatedResources(primary, r, context);
256+
if (relatedResources.size() > 1) {
257+
throw new IllegalStateException(
258+
"parent related resource contains more resourceNames for glue name: "
259+
+ primary.getMetadata().getName()
260+
+ " namespace: " + primary.getMetadata().getNamespace());
261+
}
262+
// theoretically can happen that parent was deleted meanwhile
263+
if (relatedResources.isEmpty()) {
264+
log.warn("Parent resource expected to be present on cleanup. Glue name: {} namespace: {}",
265+
primary.getMetadata().getName(), primary.getMetadata().getNamespace());
266+
return;
267+
}
268+
var parent = relatedResources.entrySet().iterator().next().getValue();
269+
String finalizer = parentFinalizer(primary.getMetadata().getName());
270+
if (parent.getMetadata().getFinalizers().contains(finalizer)) {
271+
var res = getResourceForSSAFrom(parent);
272+
context.getClient().resource(res)
273+
.patch(new PatchContext.Builder()
274+
.withFieldManager(context.getControllerConfiguration().fieldManager())
275+
.withForce(true)
276+
.withPatchType(PatchType.SERVER_SIDE_APPLY)
277+
.build());
278+
}
279+
});
280+
}
281+
282+
private String parentFinalizer(String glueName) {
283+
return PARENT_GLUE_FINALIZER_PREFIX + glueName;
284+
}
285+
286+
220287
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
quarkus.application.name=resource-glue-operator

0 commit comments

Comments
 (0)