Add reset support.
Some checks failed
Java CI with Gradle / build (push) Has been cancelled

This commit is contained in:
Michael Lipp 2024-06-09 12:48:20 +02:00
parent 0a1f89a270
commit 6a3f6c5e3e
19 changed files with 275 additions and 36 deletions

View file

@ -18,10 +18,10 @@ dependencies {
implementation 'org.jgrapes:org.jgrapes.http:[3.1.0,4)'
implementation 'org.jgrapes:org.jgrapes.util:[1.34.0,2)'
implementation 'org.jgrapes:org.jgrapes.webconsole.base:[1.5.0,2)'
implementation 'org.jgrapes:org.jgrapes.webconsole.base:[1.7.0,2)'
implementation 'org.jgrapes:org.jgrapes.webconsole.vuejs:[1.5.0,2)'
implementation 'org.jgrapes:org.jgrapes.webconsole.rbac:[1.3.0,2)'
implementation 'org.jgrapes:org.jgrapes.webconlet.oidclogin:[1.3.0,2)'
implementation 'org.jgrapes:org.jgrapes.webconlet.oidclogin:[1.4.0,2)'
implementation 'org.jgrapes:org.jgrapes.webconlet.markdowndisplay:[1.2.0,2)'
runtimeOnly 'org.jgrapes:org.jgrapes.webconlet.sysinfo:[1.4.0,2)'

View file

@ -48,6 +48,12 @@ data:
# Whether a shutdown initiated by the guest stops the pod deployment
guestShutdownStops: ${ cr.spec.guestShutdownStops!false?c }
# When incremented, the VM is reset. The value has no default value,
# i.e. if you start the VM without a value for this property, and
# decide to trigger a reset later, you have to first set the value
# and then inrement it.
resetCounter: ${ cr.resetCount }
# Forward the cloud-init data if provided
<#if cr.spec.cloudInit??>
cloudInit:

View file

@ -36,7 +36,6 @@ import org.jdrupes.vmoperator.common.K8s;
import static org.jdrupes.vmoperator.manager.Constants.APP_NAME;
import static org.jdrupes.vmoperator.manager.Constants.VM_OP_NAME;
import org.jdrupes.vmoperator.manager.events.VmChannel;
import org.jdrupes.vmoperator.manager.events.VmDefChanged;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;
@ -62,7 +61,6 @@ import org.yaml.snakeyaml.constructor.SafeConstructor;
/**
* Reconcile.
*
* @param event the event
* @param model the model
* @param channel the channel
* @return the dynamic kubernetes object
@ -70,8 +68,8 @@ import org.yaml.snakeyaml.constructor.SafeConstructor;
* @throws TemplateException the template exception
* @throws ApiException the api exception
*/
public DynamicKubernetesObject reconcile(VmDefChanged event,
Map<String, Object> model, VmChannel channel)
public DynamicKubernetesObject reconcile(Map<String, Object> model,
VmChannel channel)
throws IOException, TemplateException, ApiException {
// Get API
DynamicKubernetesApi cmApi = new DynamicKubernetesApi("", "v1",

View file

@ -181,13 +181,12 @@ public class Controller extends Component {
@Handler
public void onModifyVm(ModifyVm event, VmChannel channel)
throws ApiException, IOException {
patchVmSpec(channel.client(), event.name(), event.path(),
patchVmDef(channel.client(), event.name(), "spec/vm/" + event.path(),
event.value());
}
private void patchVmSpec(K8sClient client, String name, String path,
Object value)
throws ApiException, IOException {
private void patchVmDef(K8sClient client, String name, String path,
Object value) throws ApiException, IOException {
var vmStub = K8sDynamicStub.get(client,
new GroupVersionKind(VM_OP_GROUP, "", VM_OP_KIND_VM), namespace,
name);
@ -197,7 +196,7 @@ public class Controller extends Component {
? "\"" + value + "\""
: value.toString();
var res = vmStub.patch(V1Patch.PATCH_FORMAT_JSON_PATCH,
new V1Patch("[{\"op\": \"replace\", \"path\": \"/spec/vm/"
new V1Patch("[{\"op\": \"replace\", \"path\": \"/"
+ path + "\", \"value\": " + valueAsText + "}]"),
client.defaultPatchOptions());
if (!res.isPresent()) {

View file

@ -51,6 +51,7 @@ import org.jdrupes.vmoperator.common.K8sDynamicModel;
import org.jdrupes.vmoperator.common.K8sObserver;
import org.jdrupes.vmoperator.common.K8sV1SecretStub;
import static org.jdrupes.vmoperator.manager.Constants.COMP_DISPLAY_SECRET;
import org.jdrupes.vmoperator.manager.events.ResetVm;
import org.jdrupes.vmoperator.manager.events.VmChannel;
import org.jdrupes.vmoperator.manager.events.VmDefChanged;
import org.jdrupes.vmoperator.util.ExtendedObjectWrapper;
@ -209,13 +210,35 @@ public class Reconciler extends Component {
// Reconcile, use "augmented" vm definition for model
Map<String, Object> model
= prepareModel(channel.client(), patchCr(event.vmDefinition()));
var configMap = cmReconciler.reconcile(event, model, channel);
var configMap = cmReconciler.reconcile(model, channel);
model.put("cm", configMap.getRaw());
dsReconciler.reconcile(event, model, channel);
stsReconciler.reconcile(event, model, channel);
lbReconciler.reconcile(event, model, channel);
}
/**
* Reset the VM by incrementing the reset count and doing a
* partial reconcile (configmap only).
*
* @param event the event
* @param channel the channel
* @throws IOException
* @throws ApiException
* @throws TemplateException
*/
@Handler
public void onResetVm(ResetVm event, VmChannel channel)
throws ApiException, IOException, TemplateException {
var defRoot
= GsonPtr.to(channel.vmDefinition().data()).get(JsonObject.class);
defRoot.addProperty("resetCount",
defRoot.get("resetCount").getAsLong() + 1);
Map<String, Object> model
= prepareModel(channel.client(), patchCr(channel.vmDefinition()));
cmReconciler.reconcile(model, channel);
}
private DynamicKubernetesObject patchCr(K8sDynamicModel vmDef) {
var json = vmDef.data().deepCopy();
// Adjust cdromImage path

View file

@ -25,13 +25,13 @@ import io.kubernetes.client.openapi.models.V1ObjectMeta;
import io.kubernetes.client.util.Watch;
import io.kubernetes.client.util.generic.options.ListOptions;
import java.io.IOException;
import java.util.Optional;
import java.util.Set;
import java.util.logging.Level;
import java.util.stream.Collectors;
import static org.jdrupes.vmoperator.common.Constants.VM_OP_GROUP;
import org.jdrupes.vmoperator.common.K8s;
import org.jdrupes.vmoperator.common.K8sClient;
import org.jdrupes.vmoperator.common.K8sDynamicModel;
import org.jdrupes.vmoperator.common.K8sDynamicStub;
import org.jdrupes.vmoperator.common.K8sObserver.ResponseType;
import org.jdrupes.vmoperator.common.K8sV1ConfigMapStub;
@ -121,7 +121,7 @@ public class VmMonitor extends
}
if (vmDef.data() != null) {
// New data, augment and save
addDynamicData(channel.client(), vmDef);
addDynamicData(channel.client(), vmDef, channel.vmDefinition());
channel.setVmDefinition(vmDef);
} else {
// Reuse cached
@ -151,8 +151,16 @@ public class VmMonitor extends
}
}
private void addDynamicData(K8sClient client, K8sDynamicModel vmState) {
private void addDynamicData(K8sClient client, VmDefinitionModel vmState,
VmDefinitionModel prevState) {
var rootNode = GsonPtr.to(vmState.data()).get(JsonObject.class);
// Maintain (or initialize) the resetCount
rootNode.addProperty("resetCount", Optional.ofNullable(prevState)
.map(ps -> GsonPtr.to(ps.data()))
.flatMap(d -> d.getAsLong("resetCount")).orElse(0L));
// Add defaults in case the VM is not running
rootNode.addProperty("nodeName", "");
rootNode.addProperty("nodeAddress", "");