Avoid updating immutable fields.
This commit is contained in:
parent
9318b1279a
commit
a5ddf6ac97
2 changed files with 97 additions and 4 deletions
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
package org.jdrupes.vmoperator.manager;
|
package org.jdrupes.vmoperator.manager;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
import freemarker.core.ParseException;
|
import freemarker.core.ParseException;
|
||||||
import freemarker.template.Configuration;
|
import freemarker.template.Configuration;
|
||||||
import freemarker.template.MalformedTemplateNameException;
|
import freemarker.template.MalformedTemplateNameException;
|
||||||
|
|
@ -25,6 +26,7 @@ import freemarker.template.TemplateException;
|
||||||
import freemarker.template.TemplateNotFoundException;
|
import freemarker.template.TemplateNotFoundException;
|
||||||
import io.kubernetes.client.custom.V1Patch;
|
import io.kubernetes.client.custom.V1Patch;
|
||||||
import io.kubernetes.client.openapi.ApiException;
|
import io.kubernetes.client.openapi.ApiException;
|
||||||
|
import io.kubernetes.client.util.generic.dynamic.DynamicKubernetesObject;
|
||||||
import io.kubernetes.client.util.generic.dynamic.Dynamics;
|
import io.kubernetes.client.util.generic.dynamic.Dynamics;
|
||||||
import io.kubernetes.client.util.generic.options.ListOptions;
|
import io.kubernetes.client.util.generic.options.ListOptions;
|
||||||
import io.kubernetes.client.util.generic.options.PatchOptions;
|
import io.kubernetes.client.util.generic.options.PatchOptions;
|
||||||
|
|
@ -41,6 +43,7 @@ import org.jdrupes.vmoperator.common.K8sV1PvcStub;
|
||||||
import org.jdrupes.vmoperator.manager.events.VmChannel;
|
import org.jdrupes.vmoperator.manager.events.VmChannel;
|
||||||
import org.jdrupes.vmoperator.manager.events.VmDefChanged;
|
import org.jdrupes.vmoperator.manager.events.VmDefChanged;
|
||||||
import org.jdrupes.vmoperator.util.DataPath;
|
import org.jdrupes.vmoperator.util.DataPath;
|
||||||
|
import org.jdrupes.vmoperator.util.GsonPtr;
|
||||||
import org.yaml.snakeyaml.LoaderOptions;
|
import org.yaml.snakeyaml.LoaderOptions;
|
||||||
import org.yaml.snakeyaml.Yaml;
|
import org.yaml.snakeyaml.Yaml;
|
||||||
import org.yaml.snakeyaml.constructor.SafeConstructor;
|
import org.yaml.snakeyaml.constructor.SafeConstructor;
|
||||||
|
|
@ -179,9 +182,13 @@ import org.yaml.snakeyaml.constructor.SafeConstructor;
|
||||||
var pvcDef = Dynamics.newFromYaml(
|
var pvcDef = Dynamics.newFromYaml(
|
||||||
new Yaml(new SafeConstructor(new LoaderOptions())), out.toString());
|
new Yaml(new SafeConstructor(new LoaderOptions())), out.toString());
|
||||||
|
|
||||||
// Do apply changes
|
// Apply changes
|
||||||
var pvcStub
|
var pvcStub
|
||||||
= K8sV1PvcStub.get(channel.client(), vmDef.namespace(), pvcName);
|
= K8sV1PvcStub.get(channel.client(), vmDef.namespace(), pvcName);
|
||||||
|
var pvc = pvcStub.model();
|
||||||
|
if (pvc.isEmpty()
|
||||||
|
|| !"Bound".equals(pvc.get().getStatus().getPhase())) {
|
||||||
|
// Does not exist or isn't bound, use apply
|
||||||
PatchOptions opts = new PatchOptions();
|
PatchOptions opts = new PatchOptions();
|
||||||
opts.setForce(true);
|
opts.setForce(true);
|
||||||
opts.setFieldManager("kubernetes-java-kubectl-apply");
|
opts.setFieldManager("kubernetes-java-kubectl-apply");
|
||||||
|
|
@ -191,5 +198,35 @@ import org.yaml.snakeyaml.constructor.SafeConstructor;
|
||||||
logger.warning(
|
logger.warning(
|
||||||
() -> "Could not patch pvc for " + pvcStub.name());
|
() -> "Could not patch pvc for " + pvcStub.name());
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If bound, use json merge, omitting immutable fields
|
||||||
|
var spec = GsonPtr.to(pvcDef.getRaw()).to("spec");
|
||||||
|
spec.removeExcept("volumeAttributesClassName", "resources");
|
||||||
|
spec.access("resources").ifPresent(p -> p.removeExcept("requests"));
|
||||||
|
PatchOptions opts = new PatchOptions();
|
||||||
|
opts.setFieldManager("kubernetes-java-kubectl-apply");
|
||||||
|
if (pvcStub.patch(V1Patch.PATCH_FORMAT_JSON_MERGE_PATCH,
|
||||||
|
new V1Patch(channel.client().getJSON().serialize(pvcDef)), opts)
|
||||||
|
.isEmpty()) {
|
||||||
|
logger.warning(
|
||||||
|
() -> "Could not patch pvc for " + pvcStub.name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("PMD.AvoidLiteralsInIfCondition")
|
||||||
|
private void removeImmutable(DynamicKubernetesObject pvcDef) {
|
||||||
|
var spec = GsonPtr.to(pvcDef.getRaw()).to("spec").get(JsonObject.class);
|
||||||
|
for (var itr = spec.entrySet().iterator(); itr.hasNext();) {
|
||||||
|
var entry = itr.next();
|
||||||
|
if ("volumeAttributesClassName".equals(entry.getKey())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ("resources".equals(entry.getKey())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
itr.remove();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonPrimitive;
|
import com.google.gson.JsonPrimitive;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
@ -62,7 +63,8 @@ public class GsonPtr {
|
||||||
* @param selectors the selectors
|
* @param selectors the selectors
|
||||||
* @return the Gson pointer
|
* @return the Gson pointer
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings({ "PMD.ShortMethodName", "PMD.PreserveStackTrace" })
|
@SuppressWarnings({ "PMD.ShortMethodName", "PMD.PreserveStackTrace",
|
||||||
|
"PMD.AvoidDuplicateLiterals" })
|
||||||
public GsonPtr to(Object... selectors) {
|
public GsonPtr to(Object... selectors) {
|
||||||
JsonElement element = position;
|
JsonElement element = position;
|
||||||
for (Object sel : selectors) {
|
for (Object sel : selectors) {
|
||||||
|
|
@ -91,6 +93,42 @@ public class GsonPtr {
|
||||||
return new GsonPtr(element);
|
return new GsonPtr(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new instance pointing to the {@link JsonElement}
|
||||||
|
* selected by the given selectors. If a selector of type
|
||||||
|
* {@link String} denotes a non-existant member of a
|
||||||
|
* {@link JsonObject} the result is empty.
|
||||||
|
*
|
||||||
|
* @param selectors the selectors
|
||||||
|
* @return the Gson pointer
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({ "PMD.ShortMethodName", "PMD.PreserveStackTrace" })
|
||||||
|
public Optional<GsonPtr> access(Object... selectors) {
|
||||||
|
JsonElement element = position;
|
||||||
|
for (Object sel : selectors) {
|
||||||
|
if (element instanceof JsonObject obj
|
||||||
|
&& sel instanceof String member) {
|
||||||
|
element = obj.get(member);
|
||||||
|
if (element == null) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (element instanceof JsonArray arr
|
||||||
|
&& sel instanceof Integer index) {
|
||||||
|
try {
|
||||||
|
element = arr.get(index);
|
||||||
|
} catch (IndexOutOfBoundsException e) {
|
||||||
|
throw new IllegalStateException("Selected array index"
|
||||||
|
+ " may not be empty.");
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("Invalid selection");
|
||||||
|
}
|
||||||
|
return Optional.of(new GsonPtr(element));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns {@link JsonElement} that the pointer points to.
|
* Returns {@link JsonElement} that the pointer points to.
|
||||||
*
|
*
|
||||||
|
|
@ -336,4 +374,22 @@ public class GsonPtr {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all properties except the specified ones.
|
||||||
|
*
|
||||||
|
* @param properties the properties
|
||||||
|
*/
|
||||||
|
public void removeExcept(String... properties) {
|
||||||
|
if (!position.isJsonObject()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (var itr = ((JsonObject) position).entrySet().iterator();
|
||||||
|
itr.hasNext();) {
|
||||||
|
var entry = itr.next();
|
||||||
|
if (Arrays.asList(properties).contains(entry.getKey())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
itr.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue