diff --git a/org.jdrupes.vmoperator.manager/resources/org/jdrupes/vmoperator/manager/runnerPod.ftl.yaml b/org.jdrupes.vmoperator.manager/resources/org/jdrupes/vmoperator/manager/runnerPod.ftl.yaml index 823924a..d6f0b93 100644 --- a/org.jdrupes.vmoperator.manager/resources/org/jdrupes/vmoperator/manager/runnerPod.ftl.yaml +++ b/org.jdrupes.vmoperator.manager/resources/org/jdrupes/vmoperator/manager/runnerPod.ftl.yaml @@ -7,7 +7,11 @@ metadata: app.kubernetes.io/name: ${ constants.APP_NAME } app.kubernetes.io/instance: ${ cr.metadata.name.asString } app.kubernetes.io/managed-by: ${ constants.VM_OP_NAME } - + annotations: + # Triggers update of config map mounted in pod + # See https://ahmet.im/blog/kubernetes-secret-volumes-delay/ + vmrunner.jdrupes.org/cmVersion: "${ cm.metadata.resourceVersion.asString }" + spec: containers: - name: ${ cr.metadata.name.asString } diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/K8s.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/K8s.java index dc4aec0..f2f84a5 100644 --- a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/K8s.java +++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/K8s.java @@ -122,15 +122,15 @@ public class K8s { * @throws ApiException the api exception */ public static - void - apply(GenericKubernetesApi api, T existing, String update) + T apply(GenericKubernetesApi api, T existing, String update) throws ApiException { PatchOptions opts = new PatchOptions(); opts.setForce(false); opts.setFieldManager("kubernetes-java-kubectl-apply"); - api.patch(existing.getMetadata().getNamespace(), + var response = api.patch(existing.getMetadata().getNamespace(), existing.getMetadata().getName(), V1Patch.PATCH_FORMAT_APPLY_YAML, new V1Patch(update), opts).throwsApiException(); + return response.getObject(); } } diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/Reconciler.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/Reconciler.java index fd12b51..a5b08bf 100644 --- a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/Reconciler.java +++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/Reconciler.java @@ -29,6 +29,7 @@ import freemarker.template.TemplateException; import freemarker.template.TemplateExceptionHandler; import freemarker.template.TemplateHashModel; import freemarker.template.TemplateNotFoundException; +import io.kubernetes.client.custom.V1Patch; import io.kubernetes.client.openapi.ApiException; import io.kubernetes.client.util.generic.dynamic.DynamicKubernetesApi; import io.kubernetes.client.util.generic.dynamic.DynamicKubernetesObject; @@ -118,7 +119,8 @@ public class Reconciler extends Component { if (event.type() != Type.DELETED) { reconcileDataPvc(model, channel); reconcileDisks(vmDef, channel); - reconcileConfigMap(event, model, channel); + var configMap = reconcileConfigMap(event, model, channel); + model.put("cm", configMap.getRaw()); reconcilePod(event, model, channel); } else { reconcilePod(event, model, channel); @@ -229,7 +231,7 @@ public class Reconciler extends Component { } } - private void reconcileConfigMap(VmDefChanged event, + private DynamicKubernetesObject reconcileConfigMap(VmDefChanged event, Map model, WatchChannel channel) throws IOException, TemplateException, ApiException { // Get API and check if exists @@ -242,7 +244,7 @@ public class Reconciler extends Component { if (existing.isPresent()) { K8s.delete(cmApi, existing.get()); } - return; + return null; } // Combine template and data and parse result @@ -254,7 +256,7 @@ public class Reconciler extends Component { var mapDef = Dynamics.newFromYaml(out.toString()); // Apply - K8s.apply(cmApi, mapDef, out.toString()); + return K8s.apply(cmApi, mapDef, out.toString()); } private void reconcilePod(VmDefChanged event, Map model, @@ -281,9 +283,21 @@ public class Reconciler extends Component { // https://github.com/kubernetes-client/java/issues/2741 var podDef = Dynamics.newFromYaml(out.toString()); - // Nothing can be updated here + // Check if update if (existing.isEmpty()) { podApi.create(podDef); + } else { + // only annotations are updated + var metadata = new JsonObject(); + metadata.add("annotations", GsonPtr.to(podDef.getRaw()) + .to("metadata").get(JsonObject.class, "annotations").get()); + var patch = new JsonObject(); + patch.add("metadata", metadata); + podApi.patch(existing.get().getMetadata().getNamespace(), + existing.get().getMetadata().getName(), + V1Patch.PATCH_FORMAT_JSON_MERGE_PATCH, + new V1Patch(channel.client().getJSON().serialize(patch))) + .throwsApiException(); } }