Merge branch 'main' into testing
This commit is contained in:
commit
e314e8f63e
18 changed files with 152 additions and 262 deletions
|
|
@ -300,8 +300,8 @@ public class VmDefinition extends K8sDynamicModel {
|
||||||
*
|
*
|
||||||
* @return the data
|
* @return the data
|
||||||
*/
|
*/
|
||||||
public Optional<VmExtraData> extra() {
|
public VmExtraData extra() {
|
||||||
return Optional.ofNullable(extraData);
|
return extraData;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ public class VmExtraData {
|
||||||
* @param deleteConnectionFile the delete connection file
|
* @param deleteConnectionFile the delete connection file
|
||||||
* @return the string
|
* @return the string
|
||||||
*/
|
*/
|
||||||
public String connectionFile(String password,
|
public Optional<String> connectionFile(String password,
|
||||||
Class<?> preferredIpVersion, boolean deleteConnectionFile) {
|
Class<?> preferredIpVersion, boolean deleteConnectionFile) {
|
||||||
var addr = displayIp(preferredIpVersion);
|
var addr = displayIp(preferredIpVersion);
|
||||||
if (addr.isEmpty()) {
|
if (addr.isEmpty()) {
|
||||||
|
|
@ -144,7 +144,7 @@ public class VmExtraData {
|
||||||
if (deleteConnectionFile) {
|
if (deleteConnectionFile) {
|
||||||
data.append("delete-this-file=1\n");
|
data.append("delete-this-file=1\n");
|
||||||
}
|
}
|
||||||
return data.toString();
|
return Optional.of(data.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<InetAddress> displayIp(Class<?> preferredIpVersion) {
|
private Optional<InetAddress> displayIp(Class<?> preferredIpVersion) {
|
||||||
|
|
|
||||||
|
|
@ -177,7 +177,7 @@ public class VmPool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Additional check in case lastUsed has not been updated
|
// Additional check in case lastUsed has not been updated
|
||||||
// by PoolMonitor#onVmDefChanged() yet ("race condition")
|
// by PoolMonitor#onVmResourceChanged() yet ("race condition")
|
||||||
if (vmDef.condition("ConsoleConnected")
|
if (vmDef.condition("ConsoleConnected")
|
||||||
.map(cc -> cc.getLastTransitionTime().toInstant())
|
.map(cc -> cc.getLastTransitionTime().toInstant())
|
||||||
.map(this::retainUntil)
|
.map(this::retainUntil)
|
||||||
|
|
|
||||||
|
|
@ -25,31 +25,35 @@ import org.jgrapes.core.Components;
|
||||||
import org.jgrapes.core.Event;
|
import org.jgrapes.core.Event;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates a change in a VM definition. Note that the definition
|
* Indicates a change in a VM "resource". Note that the resource
|
||||||
* consists of the metadata (mostly immutable), the "spec" and the
|
* combines the VM CR's metadata (mostly immutable), the VM CR's
|
||||||
* "status" parts. Consumers that are only interested in "spec"
|
* "spec" part, the VM CR's "status" subresource and state information
|
||||||
* changes should check {@link #specChanged()} before processing
|
* from the pod. Consumers that are only interested in "spec" changes
|
||||||
* the event any further.
|
* should check {@link #specChanged()} before processing the event any
|
||||||
|
* further.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("PMD.DataClass")
|
@SuppressWarnings("PMD.DataClass")
|
||||||
public class VmDefChanged extends Event<Void> {
|
public class VmResourceChanged extends Event<Void> {
|
||||||
|
|
||||||
private final K8sObserver.ResponseType type;
|
private final K8sObserver.ResponseType type;
|
||||||
private final boolean specChanged;
|
|
||||||
private final VmDefinition vmDefinition;
|
private final VmDefinition vmDefinition;
|
||||||
|
private final boolean specChanged;
|
||||||
|
private final boolean podChanged;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiates a new VM changed event.
|
* Instantiates a new VM changed event.
|
||||||
*
|
*
|
||||||
* @param type the type
|
* @param type the type
|
||||||
* @param specChanged the spec part changed
|
|
||||||
* @param vmDefinition the VM definition
|
* @param vmDefinition the VM definition
|
||||||
|
* @param specChanged the spec part changed
|
||||||
*/
|
*/
|
||||||
public VmDefChanged(K8sObserver.ResponseType type, boolean specChanged,
|
public VmResourceChanged(K8sObserver.ResponseType type,
|
||||||
VmDefinition vmDefinition) {
|
VmDefinition vmDefinition, boolean specChanged,
|
||||||
|
boolean podChanged) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.specChanged = specChanged;
|
|
||||||
this.vmDefinition = vmDefinition;
|
this.vmDefinition = vmDefinition;
|
||||||
|
this.specChanged = specChanged;
|
||||||
|
this.podChanged = podChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -61,6 +65,15 @@ public class VmDefChanged extends Event<Void> {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the VM definition.
|
||||||
|
*
|
||||||
|
* @return the VM definition
|
||||||
|
*/
|
||||||
|
public VmDefinition vmDefinition() {
|
||||||
|
return vmDefinition;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates if the "spec" part changed.
|
* Indicates if the "spec" part changed.
|
||||||
*/
|
*/
|
||||||
|
|
@ -69,12 +82,10 @@ public class VmDefChanged extends Event<Void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the VM definition.
|
* Indicates if the pod status changed.
|
||||||
*
|
|
||||||
* @return the VM definition
|
|
||||||
*/
|
*/
|
||||||
public VmDefinition vmDefinition() {
|
public boolean podChanged() {
|
||||||
return vmDefinition;
|
return podChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -53,7 +53,7 @@ data:
|
||||||
# i.e. if you start the VM without a value for this property, and
|
# 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
|
# decide to trigger a reset later, you have to first set the value
|
||||||
# and then inrement it.
|
# and then inrement it.
|
||||||
resetCounter: ${ cr.extra().get().resetCount()?c }
|
resetCounter: ${ cr.extra().resetCount()?c }
|
||||||
|
|
||||||
# Forward the cloud-init data if provided
|
# Forward the cloud-init data if provided
|
||||||
<#if spec.cloudInit??>
|
<#if spec.cloudInit??>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* VM-Operator
|
* VM-Operator
|
||||||
* Copyright (C) 2023 Michael N. Lipp
|
* Copyright (C) 2023, 2025 Michael N. Lipp
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
|
@ -46,8 +46,8 @@ import org.jdrupes.vmoperator.manager.events.ModifyVm;
|
||||||
import org.jdrupes.vmoperator.manager.events.PodChanged;
|
import org.jdrupes.vmoperator.manager.events.PodChanged;
|
||||||
import org.jdrupes.vmoperator.manager.events.UpdateAssignment;
|
import org.jdrupes.vmoperator.manager.events.UpdateAssignment;
|
||||||
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.VmPoolChanged;
|
import org.jdrupes.vmoperator.manager.events.VmPoolChanged;
|
||||||
|
import org.jdrupes.vmoperator.manager.events.VmResourceChanged;
|
||||||
import org.jgrapes.core.Channel;
|
import org.jgrapes.core.Channel;
|
||||||
import org.jgrapes.core.Component;
|
import org.jgrapes.core.Component;
|
||||||
import org.jgrapes.core.annotation.Handler;
|
import org.jgrapes.core.annotation.Handler;
|
||||||
|
|
@ -61,7 +61,7 @@ import org.jgrapes.util.events.ConfigurationUpdate;
|
||||||
*
|
*
|
||||||
* The implementation splits the controller in two components. The
|
* The implementation splits the controller in two components. The
|
||||||
* {@link VmMonitor} and the {@link Reconciler}. The former watches
|
* {@link VmMonitor} and the {@link Reconciler}. The former watches
|
||||||
* the VM definitions (CRs) and generates {@link VmDefChanged} events
|
* the VM definitions (CRs) and generates {@link VmResourceChanged} events
|
||||||
* when they change. The latter handles the changes and reconciles the
|
* when they change. The latter handles the changes and reconciles the
|
||||||
* resources in the cluster.
|
* resources in the cluster.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ import org.jdrupes.vmoperator.common.VmDefinition;
|
||||||
import org.jdrupes.vmoperator.common.VmDefinitionStub;
|
import org.jdrupes.vmoperator.common.VmDefinitionStub;
|
||||||
import org.jdrupes.vmoperator.manager.events.GetDisplaySecret;
|
import org.jdrupes.vmoperator.manager.events.GetDisplaySecret;
|
||||||
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.VmResourceChanged;
|
||||||
import org.jdrupes.vmoperator.util.DataPath;
|
import org.jdrupes.vmoperator.util.DataPath;
|
||||||
import org.jgrapes.core.Channel;
|
import org.jgrapes.core.Channel;
|
||||||
import org.jgrapes.core.CompletionLock;
|
import org.jgrapes.core.CompletionLock;
|
||||||
|
|
@ -123,13 +123,19 @@ public class DisplaySecretReconciler extends Component {
|
||||||
* @param vmDef the VM definition
|
* @param vmDef the VM definition
|
||||||
* @param model the model
|
* @param model the model
|
||||||
* @param channel the channel
|
* @param channel the channel
|
||||||
|
* @param specChanged the spec changed
|
||||||
* @throws IOException Signals that an I/O exception has occurred.
|
* @throws IOException Signals that an I/O exception has occurred.
|
||||||
* @throws TemplateException the template exception
|
* @throws TemplateException the template exception
|
||||||
* @throws ApiException the api exception
|
* @throws ApiException the api exception
|
||||||
*/
|
*/
|
||||||
public void reconcile(VmDefinition vmDef, Map<String, Object> model,
|
public void reconcile(VmDefinition vmDef, Map<String, Object> model,
|
||||||
VmChannel channel)
|
VmChannel channel, boolean specChanged)
|
||||||
throws IOException, TemplateException, ApiException {
|
throws IOException, TemplateException, ApiException {
|
||||||
|
// Nothing to do unless spec changed
|
||||||
|
if (!specChanged) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Secret needed at all?
|
// Secret needed at all?
|
||||||
var display = vmDef.fromVm("display").get();
|
var display = vmDef.fromVm("display").get();
|
||||||
if (!DataPath.<Boolean> get(display, "spice", "generateSecret")
|
if (!DataPath.<Boolean> get(display, "spice", "generateSecret")
|
||||||
|
|
@ -292,7 +298,7 @@ public class DisplaySecretReconciler extends Component {
|
||||||
*/
|
*/
|
||||||
@Handler
|
@Handler
|
||||||
@SuppressWarnings("PMD.AvoidSynchronizedStatement")
|
@SuppressWarnings("PMD.AvoidSynchronizedStatement")
|
||||||
public void onVmDefChanged(VmDefChanged event, Channel channel) {
|
public void onVmResourceChanged(VmResourceChanged event, Channel channel) {
|
||||||
synchronized (pendingPrepares) {
|
synchronized (pendingPrepares) {
|
||||||
String vmName = event.vmDefinition().name();
|
String vmName = event.vmDefinition().name();
|
||||||
for (var pending : pendingPrepares) {
|
for (var pending : pendingPrepares) {
|
||||||
|
|
|
||||||
|
|
@ -71,13 +71,19 @@ import org.yaml.snakeyaml.constructor.SafeConstructor;
|
||||||
* @param vmDef the VM definition
|
* @param vmDef the VM definition
|
||||||
* @param model the model
|
* @param model the model
|
||||||
* @param channel the channel
|
* @param channel the channel
|
||||||
|
* @param specChanged the spec changed
|
||||||
* @throws IOException Signals that an I/O exception has occurred.
|
* @throws IOException Signals that an I/O exception has occurred.
|
||||||
* @throws TemplateException the template exception
|
* @throws TemplateException the template exception
|
||||||
* @throws ApiException the api exception
|
* @throws ApiException the api exception
|
||||||
*/
|
*/
|
||||||
public void reconcile(VmDefinition vmDef,
|
public void reconcile(VmDefinition vmDef, Map<String, Object> model,
|
||||||
Map<String, Object> model, VmChannel channel)
|
VmChannel channel, boolean specChanged)
|
||||||
throws IOException, TemplateException, ApiException {
|
throws IOException, TemplateException, ApiException {
|
||||||
|
// Nothing to do unless spec changed
|
||||||
|
if (!specChanged) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if to be generated
|
// Check if to be generated
|
||||||
@SuppressWarnings({ "PMD.AvoidDuplicateLiterals", "unchecked" })
|
@SuppressWarnings({ "PMD.AvoidDuplicateLiterals", "unchecked" })
|
||||||
var lbsDef = Optional.of(model)
|
var lbsDef = Optional.of(model)
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ import org.jdrupes.vmoperator.common.K8sV1PodStub;
|
||||||
import org.jdrupes.vmoperator.manager.events.ChannelDictionary;
|
import org.jdrupes.vmoperator.manager.events.ChannelDictionary;
|
||||||
import org.jdrupes.vmoperator.manager.events.PodChanged;
|
import org.jdrupes.vmoperator.manager.events.PodChanged;
|
||||||
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.VmResourceChanged;
|
||||||
import org.jgrapes.core.Channel;
|
import org.jgrapes.core.Channel;
|
||||||
import org.jgrapes.core.annotation.Handler;
|
import org.jgrapes.core.annotation.Handler;
|
||||||
|
|
||||||
|
|
@ -118,7 +118,8 @@ public class PodMonitor extends AbstractMonitor<V1Pod, V1PodList, VmChannel> {
|
||||||
* @param channel the channel
|
* @param channel the channel
|
||||||
*/
|
*/
|
||||||
@Handler
|
@Handler
|
||||||
public void onVmDefChanged(VmDefChanged event, VmChannel channel) {
|
public void onVmResourceChanged(VmResourceChanged event,
|
||||||
|
VmChannel channel) {
|
||||||
Optional.ofNullable(pendingChanges.remove(event.vmDefinition().name()))
|
Optional.ofNullable(pendingChanges.remove(event.vmDefinition().name()))
|
||||||
.map(PendingChange::change).ifPresent(change -> {
|
.map(PendingChange::change).ifPresent(change -> {
|
||||||
logger.finer(() -> "Firing pending pod change for "
|
logger.finer(() -> "Firing pending pod change for "
|
||||||
|
|
|
||||||
|
|
@ -64,18 +64,14 @@ import org.yaml.snakeyaml.constructor.SafeConstructor;
|
||||||
* @param vmDef the vm def
|
* @param vmDef the vm def
|
||||||
* @param model the model
|
* @param model the model
|
||||||
* @param channel the channel
|
* @param channel the channel
|
||||||
|
* @param specChanged the spec changed
|
||||||
* @throws IOException Signals that an I/O exception has occurred.
|
* @throws IOException Signals that an I/O exception has occurred.
|
||||||
* @throws TemplateException the template exception
|
* @throws TemplateException the template exception
|
||||||
* @throws ApiException the api exception
|
* @throws ApiException the api exception
|
||||||
*/
|
*/
|
||||||
public void reconcile(VmDefinition vmDef, Map<String, Object> model,
|
public void reconcile(VmDefinition vmDef, Map<String, Object> model,
|
||||||
VmChannel channel)
|
VmChannel channel, boolean specChanged)
|
||||||
throws IOException, TemplateException, ApiException {
|
throws IOException, TemplateException, ApiException {
|
||||||
// Don't do anything if stateful set is still in use (pre v3.4)
|
|
||||||
if ((Boolean) model.get("usingSts")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get pod stub.
|
// Get pod stub.
|
||||||
var podStub = K8sV1PodStub.get(channel.client(), vmDef.namespace(),
|
var podStub = K8sV1PodStub.get(channel.client(), vmDef.namespace(),
|
||||||
vmDef.name());
|
vmDef.name());
|
||||||
|
|
|
||||||
|
|
@ -40,8 +40,8 @@ import org.jdrupes.vmoperator.common.VmDefinition.Assignment;
|
||||||
import org.jdrupes.vmoperator.common.VmDefinitionStub;
|
import org.jdrupes.vmoperator.common.VmDefinitionStub;
|
||||||
import org.jdrupes.vmoperator.common.VmPool;
|
import org.jdrupes.vmoperator.common.VmPool;
|
||||||
import org.jdrupes.vmoperator.manager.events.GetPools;
|
import org.jdrupes.vmoperator.manager.events.GetPools;
|
||||||
import org.jdrupes.vmoperator.manager.events.VmDefChanged;
|
|
||||||
import org.jdrupes.vmoperator.manager.events.VmPoolChanged;
|
import org.jdrupes.vmoperator.manager.events.VmPoolChanged;
|
||||||
|
import org.jdrupes.vmoperator.manager.events.VmResourceChanged;
|
||||||
import org.jdrupes.vmoperator.util.GsonPtr;
|
import org.jdrupes.vmoperator.util.GsonPtr;
|
||||||
import org.jgrapes.core.Channel;
|
import org.jgrapes.core.Channel;
|
||||||
import org.jgrapes.core.EventPipeline;
|
import org.jgrapes.core.EventPipeline;
|
||||||
|
|
@ -142,7 +142,8 @@ public class PoolMonitor extends
|
||||||
* @throws ApiException
|
* @throws ApiException
|
||||||
*/
|
*/
|
||||||
@Handler
|
@Handler
|
||||||
public void onVmDefChanged(VmDefChanged event) throws ApiException {
|
public void onVmResourceChanged(VmResourceChanged event)
|
||||||
|
throws ApiException {
|
||||||
final var vmDef = event.vmDefinition();
|
final var vmDef = event.vmDefinition();
|
||||||
final String vmName = vmDef.name();
|
final String vmName = vmDef.name();
|
||||||
switch (event.type()) {
|
switch (event.type()) {
|
||||||
|
|
|
||||||
|
|
@ -67,30 +67,35 @@ import org.yaml.snakeyaml.constructor.SafeConstructor;
|
||||||
/**
|
/**
|
||||||
* Reconcile the PVCs.
|
* Reconcile the PVCs.
|
||||||
*
|
*
|
||||||
* @param vmDef the vm def
|
* @param vmDef the VM definition
|
||||||
* @param model the model
|
* @param model the model
|
||||||
* @param channel the channel
|
* @param channel the channel
|
||||||
|
* @param specChanged the spec changed
|
||||||
* @throws IOException Signals that an I/O exception has occurred.
|
* @throws IOException Signals that an I/O exception has occurred.
|
||||||
* @throws TemplateException the template exception
|
* @throws TemplateException the template exception
|
||||||
* @throws ApiException the api exception
|
* @throws ApiException the api exception
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
|
@SuppressWarnings({ "PMD.AvoidDuplicateLiterals", "unchecked" })
|
||||||
public void reconcile(VmDefinition vmDef, Map<String, Object> model,
|
public void reconcile(VmDefinition vmDef, Map<String, Object> model,
|
||||||
VmChannel channel)
|
VmChannel channel, boolean specChanged)
|
||||||
throws IOException, TemplateException, ApiException {
|
throws IOException, TemplateException, ApiException {
|
||||||
// Existing disks
|
Set<String> knownPvcs;
|
||||||
|
if (!specChanged && channel.associated(this, Set.class).isPresent()) {
|
||||||
|
knownPvcs = (Set<String>) channel.associated(this, Set.class).get();
|
||||||
|
} else {
|
||||||
ListOptions listOpts = new ListOptions();
|
ListOptions listOpts = new ListOptions();
|
||||||
listOpts.setLabelSelector(
|
listOpts.setLabelSelector(
|
||||||
"app.kubernetes.io/managed-by=" + VM_OP_NAME + ","
|
"app.kubernetes.io/managed-by=" + VM_OP_NAME + ","
|
||||||
+ "app.kubernetes.io/name=" + APP_NAME + ","
|
+ "app.kubernetes.io/name=" + APP_NAME + ","
|
||||||
+ "app.kubernetes.io/instance=" + vmDef.name());
|
+ "app.kubernetes.io/instance=" + vmDef.name());
|
||||||
var knownDisks = K8sV1PvcStub.list(channel.client(),
|
knownPvcs = K8sV1PvcStub.list(channel.client(),
|
||||||
vmDef.namespace(), listOpts);
|
vmDef.namespace(), listOpts).stream().map(K8sV1PvcStub::name)
|
||||||
var knownPvcs = knownDisks.stream().map(K8sV1PvcStub::name)
|
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
|
channel.setAssociated(this, knownPvcs);
|
||||||
|
}
|
||||||
|
|
||||||
// Reconcile runner data pvc
|
// Reconcile runner data pvc
|
||||||
reconcileRunnerDataPvc(vmDef, model, channel, knownPvcs);
|
reconcileRunnerDataPvc(vmDef, model, channel, knownPvcs, specChanged);
|
||||||
|
|
||||||
// Reconcile pvcs for defined disks
|
// Reconcile pvcs for defined disks
|
||||||
var diskDefs = vmDef.<List<Map<String, Object>>> fromVm("disks")
|
var diskDefs = vmDef.<List<Map<String, Object>>> fromVm("disks")
|
||||||
|
|
@ -114,15 +119,13 @@ import org.yaml.snakeyaml.constructor.SafeConstructor;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update PVC
|
// Update PVC
|
||||||
model.put("disk", diskDef);
|
reconcileRunnerDiskPvc(vmDef, model, channel, specChanged, diskDef);
|
||||||
reconcileRunnerDiskPvc(vmDef, model, channel);
|
|
||||||
}
|
}
|
||||||
model.remove("disk");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void reconcileRunnerDataPvc(VmDefinition vmDef,
|
private void reconcileRunnerDataPvc(VmDefinition vmDef,
|
||||||
Map<String, Object> model, VmChannel channel,
|
Map<String, Object> model, VmChannel channel,
|
||||||
Set<String> knownPvcs)
|
Set<String> knownPvcs, boolean specChanged)
|
||||||
throws TemplateNotFoundException, MalformedTemplateNameException,
|
throws TemplateNotFoundException, MalformedTemplateNameException,
|
||||||
ParseException, IOException, TemplateException, ApiException {
|
ParseException, IOException, TemplateException, ApiException {
|
||||||
|
|
||||||
|
|
@ -135,7 +138,12 @@ import org.yaml.snakeyaml.constructor.SafeConstructor;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate PVC
|
// Generate PVC
|
||||||
model.put("runnerDataPvcName", vmDef.name() + "-runner-data");
|
var runnerDataPvcName = vmDef.name() + "-runner-data";
|
||||||
|
model.put("runnerDataPvcName", runnerDataPvcName);
|
||||||
|
if (!specChanged) {
|
||||||
|
// Augmenting the model is all we have to do
|
||||||
|
return;
|
||||||
|
}
|
||||||
var fmTemplate = fmConfig.getTemplate("runnerDataPvc.ftl.yaml");
|
var fmTemplate = fmConfig.getTemplate("runnerDataPvc.ftl.yaml");
|
||||||
StringWriter out = new StringWriter();
|
StringWriter out = new StringWriter();
|
||||||
fmTemplate.process(model, out);
|
fmTemplate.process(model, out);
|
||||||
|
|
@ -159,17 +167,24 @@ import org.yaml.snakeyaml.constructor.SafeConstructor;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void reconcileRunnerDiskPvc(VmDefinition vmDef,
|
private void reconcileRunnerDiskPvc(VmDefinition vmDef,
|
||||||
Map<String, Object> model, VmChannel channel)
|
Map<String, Object> model, VmChannel channel, boolean specChanged,
|
||||||
|
Map<String, Object> diskDef)
|
||||||
throws TemplateNotFoundException, MalformedTemplateNameException,
|
throws TemplateNotFoundException, MalformedTemplateNameException,
|
||||||
ParseException, IOException, TemplateException, ApiException {
|
ParseException, IOException, TemplateException, ApiException {
|
||||||
// Generate PVC
|
// Generate PVC
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
var diskDef = (Map<String, Object>) model.get("disk");
|
|
||||||
var pvcName = vmDef.name() + "-" + diskDef.get("generatedDiskName");
|
var pvcName = vmDef.name() + "-" + diskDef.get("generatedDiskName");
|
||||||
diskDef.put("generatedPvcName", pvcName);
|
diskDef.put("generatedPvcName", pvcName);
|
||||||
|
if (!specChanged) {
|
||||||
|
// Augmenting the model is all we have to do
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate PVC
|
||||||
|
model.put("disk", diskDef);
|
||||||
var fmTemplate = fmConfig.getTemplate("runnerDiskPvc.ftl.yaml");
|
var fmTemplate = fmConfig.getTemplate("runnerDiskPvc.ftl.yaml");
|
||||||
StringWriter out = new StringWriter();
|
StringWriter out = new StringWriter();
|
||||||
fmTemplate.process(model, out);
|
fmTemplate.process(model, out);
|
||||||
|
model.remove("disk");
|
||||||
// Avoid Yaml.load due to
|
// Avoid Yaml.load due to
|
||||||
// https://github.com/kubernetes-client/java/issues/2741
|
// https://github.com/kubernetes-client/java/issues/2741
|
||||||
var pvcDef = Dynamics.newFromYaml(
|
var pvcDef = Dynamics.newFromYaml(
|
||||||
|
|
|
||||||
|
|
@ -44,15 +44,13 @@ import java.util.Optional;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import org.jdrupes.vmoperator.common.Convertions;
|
import org.jdrupes.vmoperator.common.Convertions;
|
||||||
import org.jdrupes.vmoperator.common.K8sObserver;
|
import org.jdrupes.vmoperator.common.K8sObserver;
|
||||||
import org.jdrupes.vmoperator.common.K8sObserver.ResponseType;
|
|
||||||
import org.jdrupes.vmoperator.common.VmDefinition;
|
import org.jdrupes.vmoperator.common.VmDefinition;
|
||||||
import org.jdrupes.vmoperator.common.VmDefinition.Assignment;
|
import org.jdrupes.vmoperator.common.VmDefinition.Assignment;
|
||||||
import org.jdrupes.vmoperator.common.VmPool;
|
import org.jdrupes.vmoperator.common.VmPool;
|
||||||
import org.jdrupes.vmoperator.manager.events.GetPools;
|
import org.jdrupes.vmoperator.manager.events.GetPools;
|
||||||
import org.jdrupes.vmoperator.manager.events.PodChanged;
|
|
||||||
import org.jdrupes.vmoperator.manager.events.ResetVm;
|
import org.jdrupes.vmoperator.manager.events.ResetVm;
|
||||||
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.VmResourceChanged;
|
||||||
import org.jdrupes.vmoperator.util.ExtendedObjectWrapper;
|
import org.jdrupes.vmoperator.util.ExtendedObjectWrapper;
|
||||||
import org.jgrapes.core.Channel;
|
import org.jgrapes.core.Channel;
|
||||||
import org.jgrapes.core.Component;
|
import org.jgrapes.core.Component;
|
||||||
|
|
@ -151,7 +149,6 @@ public class Reconciler extends Component {
|
||||||
private final Configuration fmConfig;
|
private final Configuration fmConfig;
|
||||||
private final ConfigMapReconciler cmReconciler;
|
private final ConfigMapReconciler cmReconciler;
|
||||||
private final DisplaySecretReconciler dsReconciler;
|
private final DisplaySecretReconciler dsReconciler;
|
||||||
private final StatefulSetReconciler stsReconciler;
|
|
||||||
private final PvcReconciler pvcReconciler;
|
private final PvcReconciler pvcReconciler;
|
||||||
private final PodReconciler podReconciler;
|
private final PodReconciler podReconciler;
|
||||||
private final LoadBalancerReconciler lbReconciler;
|
private final LoadBalancerReconciler lbReconciler;
|
||||||
|
|
@ -179,7 +176,6 @@ public class Reconciler extends Component {
|
||||||
|
|
||||||
cmReconciler = new ConfigMapReconciler(fmConfig);
|
cmReconciler = new ConfigMapReconciler(fmConfig);
|
||||||
dsReconciler = attach(new DisplaySecretReconciler(componentChannel));
|
dsReconciler = attach(new DisplaySecretReconciler(componentChannel));
|
||||||
stsReconciler = new StatefulSetReconciler(fmConfig);
|
|
||||||
pvcReconciler = new PvcReconciler(fmConfig);
|
pvcReconciler = new PvcReconciler(fmConfig);
|
||||||
podReconciler = new PodReconciler(fmConfig);
|
podReconciler = new PodReconciler(fmConfig);
|
||||||
lbReconciler = new LoadBalancerReconciler(fmConfig);
|
lbReconciler = new LoadBalancerReconciler(fmConfig);
|
||||||
|
|
@ -208,64 +204,27 @@ public class Reconciler extends Component {
|
||||||
*/
|
*/
|
||||||
@Handler
|
@Handler
|
||||||
@SuppressWarnings("PMD.ConfusingTernary")
|
@SuppressWarnings("PMD.ConfusingTernary")
|
||||||
public void onVmDefChanged(VmDefChanged event, VmChannel channel)
|
public void onVmResourceChanged(VmResourceChanged event, VmChannel channel)
|
||||||
throws ApiException, TemplateException, IOException {
|
throws ApiException, TemplateException, IOException {
|
||||||
// Ownership relationships takes care of deletions
|
// Ownership relationships takes care of deletions
|
||||||
if (event.type() == K8sObserver.ResponseType.DELETED) {
|
if (event.type() == K8sObserver.ResponseType.DELETED) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reconcile
|
|
||||||
reconcile(event, channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void reconcile(VmDefChanged event, VmChannel channel)
|
|
||||||
throws TemplateModelException, ApiException, IOException,
|
|
||||||
TemplateException {
|
|
||||||
// Create model for processing templates
|
// Create model for processing templates
|
||||||
var vmDef = event.vmDefinition();
|
var vmDef = event.vmDefinition();
|
||||||
Map<String, Object> model = prepareModel(vmDef);
|
Map<String, Object> model = prepareModel(vmDef);
|
||||||
cmReconciler.reconcile(model, channel, event.specChanged());
|
cmReconciler.reconcile(model, channel, event.specChanged());
|
||||||
|
|
||||||
// The remaining reconcilers depend only on changes of the spec part.
|
// The remaining reconcilers depend only on changes of the spec part
|
||||||
if (!event.specChanged()) {
|
// or the pod state.
|
||||||
|
if (!event.specChanged() && !event.podChanged()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dsReconciler.reconcile(vmDef, model, channel);
|
dsReconciler.reconcile(vmDef, model, channel, event.specChanged());
|
||||||
// Manage (eventual) removal of stateful set.
|
pvcReconciler.reconcile(vmDef, model, channel, event.specChanged());
|
||||||
stsReconciler.reconcile(vmDef, model, channel);
|
podReconciler.reconcile(vmDef, model, channel, event.specChanged());
|
||||||
pvcReconciler.reconcile(vmDef, model, channel);
|
lbReconciler.reconcile(vmDef, model, channel, event.specChanged());
|
||||||
podReconciler.reconcile(vmDef, model, channel);
|
|
||||||
lbReconciler.reconcile(vmDef, model, channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* On pod changed.
|
|
||||||
*
|
|
||||||
* @param event the event
|
|
||||||
* @param channel the channel
|
|
||||||
* @throws ApiException the api exception
|
|
||||||
* @throws IOException Signals that an I/O exception has occurred.
|
|
||||||
* @throws TemplateException the template exception
|
|
||||||
*/
|
|
||||||
@Handler
|
|
||||||
public void onPodChanged(PodChanged event, VmChannel channel)
|
|
||||||
throws ApiException, IOException, TemplateException {
|
|
||||||
if (event.type() != ResponseType.DELETED) {
|
|
||||||
// Nothing to reconcile
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the pod was deleted, it may be necessary to recreate it
|
|
||||||
var vmDef = channel.vmDefinition();
|
|
||||||
Map<String, Object> model = prepareModel(vmDef);
|
|
||||||
|
|
||||||
// Call all steps because they may augment the model
|
|
||||||
cmReconciler.reconcile(model, channel, false);
|
|
||||||
dsReconciler.reconcile(vmDef, model, channel);
|
|
||||||
stsReconciler.reconcile(vmDef, model, channel);
|
|
||||||
pvcReconciler.reconcile(vmDef, model, channel);
|
|
||||||
podReconciler.reconcile(vmDef, model, channel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -282,7 +241,8 @@ public class Reconciler extends Component {
|
||||||
public void onResetVm(ResetVm event, VmChannel channel)
|
public void onResetVm(ResetVm event, VmChannel channel)
|
||||||
throws ApiException, IOException, TemplateException {
|
throws ApiException, IOException, TemplateException {
|
||||||
var vmDef = channel.vmDefinition();
|
var vmDef = channel.vmDefinition();
|
||||||
vmDef.extra().ifPresent(e -> e.resetCount(e.resetCount() + 1));
|
var extra = vmDef.extra();
|
||||||
|
extra.resetCount(extra.resetCount() + 1);
|
||||||
Map<String, Object> model
|
Map<String, Object> model
|
||||||
= prepareModel(channel.vmDefinition());
|
= prepareModel(channel.vmDefinition());
|
||||||
cmReconciler.reconcile(model, channel, true);
|
cmReconciler.reconcile(model, channel, true);
|
||||||
|
|
|
||||||
|
|
@ -1,107 +0,0 @@
|
||||||
/*
|
|
||||||
* VM-Operator
|
|
||||||
* Copyright (C) 2023 Michael N. Lipp
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as
|
|
||||||
* published by the Free Software Foundation, either version 3 of the
|
|
||||||
* License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jdrupes.vmoperator.manager;
|
|
||||||
|
|
||||||
import freemarker.template.Configuration;
|
|
||||||
import freemarker.template.TemplateException;
|
|
||||||
import io.kubernetes.client.custom.V1Patch;
|
|
||||||
import io.kubernetes.client.openapi.ApiException;
|
|
||||||
import io.kubernetes.client.util.generic.options.PatchOptions;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import org.jdrupes.vmoperator.common.K8sV1StatefulSetStub;
|
|
||||||
import org.jdrupes.vmoperator.common.VmDefinition;
|
|
||||||
import org.jdrupes.vmoperator.common.VmDefinition.RequestedVmState;
|
|
||||||
import org.jdrupes.vmoperator.manager.events.VmChannel;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Before version 3.4, the pod running the VM was created by a stateful set.
|
|
||||||
* Starting with version 3.4, this reconciler simply deletes the stateful
|
|
||||||
* set, provided that the VM is not running.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
|
|
||||||
/* default */ class StatefulSetReconciler {
|
|
||||||
|
|
||||||
protected final Logger logger = Logger.getLogger(getClass().getName());
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiates a new stateful set reconciler.
|
|
||||||
*
|
|
||||||
* @param fmConfig the fm config
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("PMD.UnusedFormalParameter")
|
|
||||||
public StatefulSetReconciler(Configuration fmConfig) {
|
|
||||||
// Nothing to do
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reconcile stateful set.
|
|
||||||
*
|
|
||||||
* @param vmDef the VM definition
|
|
||||||
* @param model the model
|
|
||||||
* @param channel the channel
|
|
||||||
* @throws IOException Signals that an I/O exception has occurred.
|
|
||||||
* @throws TemplateException the template exception
|
|
||||||
* @throws ApiException the api exception
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("PMD.AvoidLiteralsInIfCondition")
|
|
||||||
public void reconcile(VmDefinition vmDef, Map<String, Object> model,
|
|
||||||
VmChannel channel)
|
|
||||||
throws IOException, TemplateException, ApiException {
|
|
||||||
model.put("usingSts", false);
|
|
||||||
|
|
||||||
// If exists, delete when not running or supposed to be not running.
|
|
||||||
var stsStub = K8sV1StatefulSetStub.get(channel.client(),
|
|
||||||
vmDef.namespace(), vmDef.name());
|
|
||||||
if (stsStub.model().isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stateful set still exists, check if replicas is 0 so we can
|
|
||||||
// delete it.
|
|
||||||
var stsModel = stsStub.model().get();
|
|
||||||
if (stsModel.getSpec().getReplicas() == 0) {
|
|
||||||
stsStub.delete();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cannot yet delete the stateful set.
|
|
||||||
model.put("usingSts", true);
|
|
||||||
|
|
||||||
// Check if VM is supposed to be stopped. If so,
|
|
||||||
// set replicas to 0. This is the first step of the transition,
|
|
||||||
// the stateful set will be deleted when the VM is restarted.
|
|
||||||
if (vmDef.vmState() == RequestedVmState.RUNNING) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do apply changes (set replicas to 0)
|
|
||||||
PatchOptions opts = new PatchOptions();
|
|
||||||
opts.setForce(true);
|
|
||||||
opts.setFieldManager("kubernetes-java-kubectl-apply");
|
|
||||||
if (stsStub.patch(V1Patch.PATCH_FORMAT_JSON_PATCH,
|
|
||||||
new V1Patch("[{\"op\": \"replace\", \"path\": \"/spec/replicas"
|
|
||||||
+ "\", \"value\": 0}]"),
|
|
||||||
channel.client().defaultPatchOptions()).isEmpty()) {
|
|
||||||
logger.warning(
|
|
||||||
() -> "Could not patch stateful set for " + stsStub.name());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -30,7 +30,6 @@ import java.net.HttpURLConnection;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
@ -54,7 +53,7 @@ import org.jdrupes.vmoperator.manager.events.ModifyVm;
|
||||||
import org.jdrupes.vmoperator.manager.events.PodChanged;
|
import org.jdrupes.vmoperator.manager.events.PodChanged;
|
||||||
import org.jdrupes.vmoperator.manager.events.UpdateAssignment;
|
import org.jdrupes.vmoperator.manager.events.UpdateAssignment;
|
||||||
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.VmResourceChanged;
|
||||||
import org.jdrupes.vmoperator.util.GsonPtr;
|
import org.jdrupes.vmoperator.util.GsonPtr;
|
||||||
import org.jgrapes.core.Channel;
|
import org.jgrapes.core.Channel;
|
||||||
import org.jgrapes.core.Event;
|
import org.jgrapes.core.Event;
|
||||||
|
|
@ -157,11 +156,11 @@ public class VmMonitor extends
|
||||||
|
|
||||||
// Create and fire changed event. Remove channel from channel
|
// Create and fire changed event. Remove channel from channel
|
||||||
// manager on completion.
|
// manager on completion.
|
||||||
VmDefChanged chgEvt
|
VmResourceChanged chgEvt
|
||||||
= new VmDefChanged(ResponseType.valueOf(response.type),
|
= new VmResourceChanged(ResponseType.valueOf(response.type), vmDef,
|
||||||
channel.setGeneration(response.object.getMetadata()
|
channel.setGeneration(response.object.getMetadata()
|
||||||
.getGeneration()),
|
.getGeneration()),
|
||||||
vmDef);
|
false);
|
||||||
if (ResponseType.valueOf(response.type) == ResponseType.DELETED) {
|
if (ResponseType.valueOf(response.type) == ResponseType.DELETED) {
|
||||||
chgEvt = Event.onCompletion(chgEvt,
|
chgEvt = Event.onCompletion(chgEvt,
|
||||||
e -> channelManager.remove(e.vmDefinition().name()));
|
e -> channelManager.remove(e.vmDefinition().name()));
|
||||||
|
|
@ -181,8 +180,7 @@ public class VmMonitor extends
|
||||||
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
|
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
|
||||||
private void addExtraData(VmDefinition vmDef, VmDefinition prevState) {
|
private void addExtraData(VmDefinition vmDef, VmDefinition prevState) {
|
||||||
var extra = new VmExtraData(vmDef);
|
var extra = new VmExtraData(vmDef);
|
||||||
var prevExtra
|
var prevExtra = Optional.ofNullable(prevState).map(VmDefinition::extra);
|
||||||
= Optional.ofNullable(prevState).flatMap(VmDefinition::extra);
|
|
||||||
|
|
||||||
// Maintain (or initialize) the resetCount
|
// Maintain (or initialize) the resetCount
|
||||||
extra.resetCount(prevExtra.map(VmExtraData::resetCount).orElse(0L));
|
extra.resetCount(prevExtra.map(VmExtraData::resetCount).orElse(0L));
|
||||||
|
|
@ -200,36 +198,36 @@ public class VmMonitor extends
|
||||||
*/
|
*/
|
||||||
@Handler
|
@Handler
|
||||||
public void onPodChanged(PodChanged event, VmChannel channel) {
|
public void onPodChanged(PodChanged event, VmChannel channel) {
|
||||||
if (channel.vmDefinition().extra().isEmpty()) {
|
var vmDef = channel.vmDefinition();
|
||||||
return;
|
updateNodeInfo(event, vmDef);
|
||||||
|
channel
|
||||||
|
.fire(new VmResourceChanged(ResponseType.MODIFIED, vmDef, false, true));
|
||||||
}
|
}
|
||||||
var extra = channel.vmDefinition().extra().get();
|
|
||||||
var pod = event.pod();
|
private void updateNodeInfo(PodChanged event, VmDefinition vmDef) {
|
||||||
|
var extra = vmDef.extra();
|
||||||
if (event.type() == ResponseType.DELETED) {
|
if (event.type() == ResponseType.DELETED) {
|
||||||
// The status of a deleted pod is the status before deletion,
|
// The status of a deleted pod is the status before deletion,
|
||||||
// i.e. the node info is still there.
|
// i.e. the node info is still cached and must be removed.
|
||||||
extra.nodeInfo("", Collections.emptyList());
|
extra.nodeInfo("", Collections.emptyList());
|
||||||
} else {
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get current node info from pod
|
||||||
|
var pod = event.pod();
|
||||||
var nodeName = Optional
|
var nodeName = Optional
|
||||||
.ofNullable(pod.getSpec().getNodeName()).orElse("");
|
.ofNullable(pod.getSpec().getNodeName()).orElse("");
|
||||||
logger.finer(() -> "Adding node name " + nodeName
|
logger.finer(() -> "Adding node name " + nodeName
|
||||||
+ " to VM info for " + channel.vmDefinition().name());
|
+ " to VM info for " + vmDef.name());
|
||||||
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
|
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
|
||||||
var addrs = new ArrayList<String>();
|
var addrs = new ArrayList<String>();
|
||||||
Optional.ofNullable(pod.getStatus().getPodIPs())
|
Optional.ofNullable(pod.getStatus().getPodIPs())
|
||||||
.orElse(Collections.emptyList()).stream()
|
.orElse(Collections.emptyList()).stream()
|
||||||
.map(ip -> ip.getIp()).forEach(addrs::add);
|
.map(ip -> ip.getIp()).forEach(addrs::add);
|
||||||
logger.finer(() -> "Adding node addresses " + addrs
|
logger.finer(() -> "Adding node addresses " + addrs
|
||||||
+ " to VM info for " + channel.vmDefinition().name());
|
+ " to VM info for " + vmDef.name());
|
||||||
if (Objects.equals(nodeName, extra.nodeName())
|
|
||||||
&& Objects.equals(addrs, extra.nodeAddresses())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
extra.nodeInfo(nodeName, addrs);
|
extra.nodeInfo(nodeName, addrs);
|
||||||
}
|
}
|
||||||
channel.fire(new VmDefChanged(ResponseType.MODIFIED, false,
|
|
||||||
channel.vmDefinition()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On modify vm.
|
* On modify vm.
|
||||||
|
|
|
||||||
|
|
@ -57,8 +57,8 @@ import org.jdrupes.vmoperator.manager.events.GetVms.VmData;
|
||||||
import org.jdrupes.vmoperator.manager.events.ModifyVm;
|
import org.jdrupes.vmoperator.manager.events.ModifyVm;
|
||||||
import org.jdrupes.vmoperator.manager.events.ResetVm;
|
import org.jdrupes.vmoperator.manager.events.ResetVm;
|
||||||
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.VmPoolChanged;
|
import org.jdrupes.vmoperator.manager.events.VmPoolChanged;
|
||||||
|
import org.jdrupes.vmoperator.manager.events.VmResourceChanged;
|
||||||
import org.jgrapes.core.Channel;
|
import org.jgrapes.core.Channel;
|
||||||
import org.jgrapes.core.Components;
|
import org.jgrapes.core.Components;
|
||||||
import org.jgrapes.core.Event;
|
import org.jgrapes.core.Event;
|
||||||
|
|
@ -658,7 +658,7 @@ public class VmAccess extends FreeMarkerConlet<VmAccess.ResourceModel> {
|
||||||
@SuppressWarnings({ "PMD.ConfusingTernary", "PMD.CognitiveComplexity",
|
@SuppressWarnings({ "PMD.ConfusingTernary", "PMD.CognitiveComplexity",
|
||||||
"PMD.AvoidInstantiatingObjectsInLoops", "PMD.AvoidDuplicateLiterals",
|
"PMD.AvoidInstantiatingObjectsInLoops", "PMD.AvoidDuplicateLiterals",
|
||||||
"PMD.ConfusingArgumentToVarargsMethod" })
|
"PMD.ConfusingArgumentToVarargsMethod" })
|
||||||
public void onVmDefChanged(VmDefChanged event, VmChannel channel)
|
public void onVmResourceChanged(VmResourceChanged event, VmChannel channel)
|
||||||
throws IOException, InterruptedException {
|
throws IOException, InterruptedException {
|
||||||
var vmDef = event.vmDefinition();
|
var vmDef = event.vmDefinition();
|
||||||
|
|
||||||
|
|
@ -847,8 +847,8 @@ public class VmAccess extends FreeMarkerConlet<VmAccess.ResourceModel> {
|
||||||
if (!event.secretAvailable()) {
|
if (!event.secretAvailable()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
vmDef.extra().map(xtra -> xtra.connectionFile(event.secret(),
|
vmDef.extra().connectionFile(event.secret(),
|
||||||
preferredIpVersion, deleteConnectionFile))
|
preferredIpVersion, deleteConnectionFile)
|
||||||
.ifPresent(cf -> channel.respond(new NotifyConletView(type(),
|
.ifPresent(cf -> channel.respond(new NotifyConletView(type(),
|
||||||
model.getConletId(), "openConsole", cf)));
|
model.getConletId(), "openConsole", cf)));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,13 +42,12 @@ import org.jdrupes.vmoperator.common.Constants.Status;
|
||||||
import org.jdrupes.vmoperator.common.K8sObserver;
|
import org.jdrupes.vmoperator.common.K8sObserver;
|
||||||
import org.jdrupes.vmoperator.common.VmDefinition;
|
import org.jdrupes.vmoperator.common.VmDefinition;
|
||||||
import org.jdrupes.vmoperator.common.VmDefinition.Permission;
|
import org.jdrupes.vmoperator.common.VmDefinition.Permission;
|
||||||
import org.jdrupes.vmoperator.common.VmExtraData;
|
|
||||||
import org.jdrupes.vmoperator.manager.events.ChannelTracker;
|
import org.jdrupes.vmoperator.manager.events.ChannelTracker;
|
||||||
import org.jdrupes.vmoperator.manager.events.GetDisplaySecret;
|
import org.jdrupes.vmoperator.manager.events.GetDisplaySecret;
|
||||||
import org.jdrupes.vmoperator.manager.events.ModifyVm;
|
import org.jdrupes.vmoperator.manager.events.ModifyVm;
|
||||||
import org.jdrupes.vmoperator.manager.events.ResetVm;
|
import org.jdrupes.vmoperator.manager.events.ResetVm;
|
||||||
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.VmResourceChanged;
|
||||||
import org.jdrupes.vmoperator.util.DataPath;
|
import org.jdrupes.vmoperator.util.DataPath;
|
||||||
import org.jgrapes.core.Channel;
|
import org.jgrapes.core.Channel;
|
||||||
import org.jgrapes.core.Event;
|
import org.jgrapes.core.Event;
|
||||||
|
|
@ -258,7 +257,7 @@ public class VmMgmt extends FreeMarkerConlet<VmMgmt.VmsModel> {
|
||||||
"name", vmDef.name()),
|
"name", vmDef.name()),
|
||||||
"spec", spec,
|
"spec", spec,
|
||||||
"status", status,
|
"status", status,
|
||||||
"nodeName", vmDef.extra().map(VmExtraData::nodeName).orElse(""),
|
"nodeName", vmDef.extra().nodeName(),
|
||||||
"consoleAccessible", vmDef.consoleAccessible(user, perms),
|
"consoleAccessible", vmDef.consoleAccessible(user, perms),
|
||||||
"permissions", perms);
|
"permissions", perms);
|
||||||
}
|
}
|
||||||
|
|
@ -274,7 +273,7 @@ public class VmMgmt extends FreeMarkerConlet<VmMgmt.VmsModel> {
|
||||||
@SuppressWarnings({ "PMD.ConfusingTernary", "PMD.CognitiveComplexity",
|
@SuppressWarnings({ "PMD.ConfusingTernary", "PMD.CognitiveComplexity",
|
||||||
"PMD.AvoidInstantiatingObjectsInLoops", "PMD.AvoidDuplicateLiterals",
|
"PMD.AvoidInstantiatingObjectsInLoops", "PMD.AvoidDuplicateLiterals",
|
||||||
"PMD.ConfusingArgumentToVarargsMethod" })
|
"PMD.ConfusingArgumentToVarargsMethod" })
|
||||||
public void onVmDefChanged(VmDefChanged event, VmChannel channel)
|
public void onVmResourceChanged(VmResourceChanged event, VmChannel channel)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
var vmName = event.vmDefinition().name();
|
var vmName = event.vmDefinition().name();
|
||||||
if (event.type() == K8sObserver.ResponseType.DELETED) {
|
if (event.type() == K8sObserver.ResponseType.DELETED) {
|
||||||
|
|
@ -494,8 +493,8 @@ public class VmMgmt extends FreeMarkerConlet<VmMgmt.VmsModel> {
|
||||||
if (!event.secretAvailable()) {
|
if (!event.secretAvailable()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
vmDef.extra().map(xtra -> xtra.connectionFile(event.secret(),
|
vmDef.extra().connectionFile(event.secret(),
|
||||||
preferredIpVersion, deleteConnectionFile)).ifPresent(
|
preferredIpVersion, deleteConnectionFile).ifPresent(
|
||||||
cf -> channel.respond(new NotifyConletView(type(),
|
cf -> channel.respond(new NotifyConletView(type(),
|
||||||
model.getConletId(), "openConsole", cf)));
|
model.getConletId(), "openConsole", cf)));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,10 @@ layout: vm-operator
|
||||||
have to add a virtual serial port (see the git history of the standard
|
have to add a virtual serial port (see the git history of the standard
|
||||||
template for the required addition).
|
template for the required addition).
|
||||||
|
|
||||||
|
* Stateful sets from pre 3.4.0 versions are no longer removed automatically
|
||||||
|
(see notes below). However, PVCs with the old naming scheme are still
|
||||||
|
reused.
|
||||||
|
|
||||||
## To version 3.4.0
|
## To version 3.4.0
|
||||||
|
|
||||||
Starting with this version, the VM-Operator no longer uses a stateful set
|
Starting with this version, the VM-Operator no longer uses a stateful set
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue