Let the operator manage pod restarts.
This commit is contained in:
parent
7a70d73330
commit
e8097d87d9
8 changed files with 77 additions and 41 deletions
|
|
@ -133,3 +133,4 @@ spec:
|
|||
affinity: ${ toJson(spec.affinity) }
|
||||
</#if>
|
||||
serviceAccountName: vm-runner
|
||||
restartPolicy: Never
|
||||
|
|
|
|||
|
|
@ -86,16 +86,20 @@ import org.yaml.snakeyaml.constructor.SafeConstructor;
|
|||
boolean modelChanged)
|
||||
throws IOException, TemplateException, ApiException {
|
||||
// Check if an update is needed
|
||||
Object prevInputs
|
||||
= channel.associated(PrevData.class, Object.class).orElse(null);
|
||||
var prevData = channel.associated(PrevData.class)
|
||||
.orElseGet(() -> new PrevData(null, new HashMap<>()));
|
||||
Object newInputs = model.get("loginRequestedFor");
|
||||
if (!modelChanged && Objects.equals(prevInputs, newInputs)) {
|
||||
if (!modelChanged && Objects.equals(prevData.inputs, newInputs)) {
|
||||
// Make added data available in new model
|
||||
model.putAll(prevData.added);
|
||||
return;
|
||||
}
|
||||
channel.setAssociated(PrevData.class, newInputs);
|
||||
prevData = new PrevData(newInputs, prevData.added);
|
||||
channel.setAssociated(PrevData.class, prevData);
|
||||
|
||||
// Combine template and data and parse result
|
||||
model.put("adjustCloudInitMeta", adjustCloudInitMetaModel);
|
||||
prevData.added.put("adjustCloudInitMeta", adjustCloudInitMetaModel);
|
||||
var fmTemplate = fmConfig.getTemplate("runnerConfig.ftl.yaml");
|
||||
StringWriter out = new StringWriter();
|
||||
fmTemplate.process(model, out);
|
||||
|
|
@ -127,12 +131,14 @@ import org.yaml.snakeyaml.constructor.SafeConstructor;
|
|||
maybeForceUpdate(channel.client(), updatedCm);
|
||||
model.put("configMapResourceVersion",
|
||||
updatedCm.getMetadata().getResourceVersion());
|
||||
prevData.added.put("configMapResourceVersion",
|
||||
updatedCm.getMetadata().getResourceVersion());
|
||||
}
|
||||
|
||||
/**
|
||||
* Key for association.
|
||||
*/
|
||||
private final class PrevData {
|
||||
private record PrevData(Object inputs, Map<String, Object> added) {
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -120,25 +120,24 @@ public class DisplaySecretReconciler extends Component {
|
|||
* secret with a random password and immediate expiration, thus
|
||||
* preventing access to the display.
|
||||
*
|
||||
* @param event the event
|
||||
* @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
|
||||
*/
|
||||
public void reconcile(VmDefChanged event,
|
||||
Map<String, Object> model, VmChannel channel)
|
||||
public void reconcile(VmDefinition vmDef, Map<String, Object> model,
|
||||
VmChannel channel)
|
||||
throws IOException, TemplateException, ApiException {
|
||||
// Secret needed at all?
|
||||
var display = event.vmDefinition().fromVm("display").get();
|
||||
var display = vmDef.fromVm("display").get();
|
||||
if (!DataPath.<Boolean> get(display, "spice", "generateSecret")
|
||||
.orElse(true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if exists
|
||||
var vmDef = event.vmDefinition();
|
||||
ListOptions options = new ListOptions();
|
||||
options.setLabelSelector("app.kubernetes.io/name=" + APP_NAME + ","
|
||||
+ "app.kubernetes.io/component=" + DisplaySecret.NAME + ","
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ import java.util.logging.Logger;
|
|||
import org.jdrupes.vmoperator.common.K8sV1ServiceStub;
|
||||
import org.jdrupes.vmoperator.common.VmDefinition;
|
||||
import org.jdrupes.vmoperator.manager.events.VmChannel;
|
||||
import org.jdrupes.vmoperator.manager.events.VmDefChanged;
|
||||
import org.jdrupes.vmoperator.util.GsonPtr;
|
||||
import org.yaml.snakeyaml.LoaderOptions;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
|
@ -69,14 +68,14 @@ import org.yaml.snakeyaml.constructor.SafeConstructor;
|
|||
/**
|
||||
* Reconcile.
|
||||
*
|
||||
* @param event the event
|
||||
* @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
|
||||
*/
|
||||
public void reconcile(VmDefChanged event,
|
||||
public void reconcile(VmDefinition vmDef,
|
||||
Map<String, Object> model, VmChannel channel)
|
||||
throws IOException, TemplateException, ApiException {
|
||||
// Check if to be generated
|
||||
|
|
@ -95,7 +94,6 @@ import org.yaml.snakeyaml.constructor.SafeConstructor;
|
|||
}
|
||||
|
||||
// Load balancer can also be turned off for VM
|
||||
var vmDef = event.vmDefinition();
|
||||
if (vmDef
|
||||
.<Map<String, Map<String, String>>> fromSpec(LOAD_BALANCER_SERVICE)
|
||||
.map(m -> m.isEmpty()).orElse(false)) {
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ import org.jdrupes.vmoperator.common.K8sV1SecretStub;
|
|||
import org.jdrupes.vmoperator.common.VmDefinition;
|
||||
import org.jdrupes.vmoperator.common.VmDefinition.RequestedVmState;
|
||||
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,14 +61,14 @@ import org.yaml.snakeyaml.constructor.SafeConstructor;
|
|||
/**
|
||||
* Reconcile the pod.
|
||||
*
|
||||
* @param event the event
|
||||
* @param vmDef the vm def
|
||||
* @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
|
||||
*/
|
||||
public void reconcile(VmDefChanged event, Map<String, Object> model,
|
||||
public void reconcile(VmDefinition vmDef, Map<String, Object> model,
|
||||
VmChannel channel)
|
||||
throws IOException, TemplateException, ApiException {
|
||||
// Don't do anything if stateful set is still in use (pre v3.4)
|
||||
|
|
@ -78,7 +77,6 @@ import org.yaml.snakeyaml.constructor.SafeConstructor;
|
|||
}
|
||||
|
||||
// Get pod stub.
|
||||
var vmDef = event.vmDefinition();
|
||||
var podStub = K8sV1PodStub.get(channel.client(), vmDef.namespace(),
|
||||
vmDef.name());
|
||||
|
||||
|
|
|
|||
|
|
@ -38,8 +38,8 @@ import java.util.stream.Collectors;
|
|||
import static org.jdrupes.vmoperator.common.Constants.APP_NAME;
|
||||
import static org.jdrupes.vmoperator.common.Constants.VM_OP_NAME;
|
||||
import org.jdrupes.vmoperator.common.K8sV1PvcStub;
|
||||
import org.jdrupes.vmoperator.common.VmDefinition;
|
||||
import org.jdrupes.vmoperator.manager.events.VmChannel;
|
||||
import org.jdrupes.vmoperator.manager.events.VmDefChanged;
|
||||
import org.jdrupes.vmoperator.util.DataPath;
|
||||
import org.jdrupes.vmoperator.util.GsonPtr;
|
||||
import org.yaml.snakeyaml.LoaderOptions;
|
||||
|
|
@ -67,7 +67,7 @@ import org.yaml.snakeyaml.constructor.SafeConstructor;
|
|||
/**
|
||||
* Reconcile the PVCs.
|
||||
*
|
||||
* @param event the event
|
||||
* @param vmDef the vm def
|
||||
* @param model the model
|
||||
* @param channel the channel
|
||||
* @throws IOException Signals that an I/O exception has occurred.
|
||||
|
|
@ -75,11 +75,9 @@ import org.yaml.snakeyaml.constructor.SafeConstructor;
|
|||
* @throws ApiException the api exception
|
||||
*/
|
||||
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
|
||||
public void reconcile(VmDefChanged event, Map<String, Object> model,
|
||||
public void reconcile(VmDefinition vmDef, Map<String, Object> model,
|
||||
VmChannel channel)
|
||||
throws IOException, TemplateException, ApiException {
|
||||
var vmDef = event.vmDefinition();
|
||||
|
||||
// Existing disks
|
||||
ListOptions listOpts = new ListOptions();
|
||||
listOpts.setLabelSelector(
|
||||
|
|
@ -92,7 +90,7 @@ import org.yaml.snakeyaml.constructor.SafeConstructor;
|
|||
.collect(Collectors.toSet());
|
||||
|
||||
// Reconcile runner data pvc
|
||||
reconcileRunnerDataPvc(event, model, channel, knownPvcs);
|
||||
reconcileRunnerDataPvc(vmDef, model, channel, knownPvcs);
|
||||
|
||||
// Reconcile pvcs for defined disks
|
||||
var diskDefs = vmDef.<List<Map<String, Object>>> fromVm("disks")
|
||||
|
|
@ -117,17 +115,16 @@ import org.yaml.snakeyaml.constructor.SafeConstructor;
|
|||
|
||||
// Update PVC
|
||||
model.put("disk", diskDef);
|
||||
reconcileRunnerDiskPvc(event, model, channel);
|
||||
reconcileRunnerDiskPvc(vmDef, model, channel);
|
||||
}
|
||||
model.remove("disk");
|
||||
}
|
||||
|
||||
private void reconcileRunnerDataPvc(VmDefChanged event,
|
||||
private void reconcileRunnerDataPvc(VmDefinition vmDef,
|
||||
Map<String, Object> model, VmChannel channel,
|
||||
Set<String> knownPvcs)
|
||||
throws TemplateNotFoundException, MalformedTemplateNameException,
|
||||
ParseException, IOException, TemplateException, ApiException {
|
||||
var vmDef = event.vmDefinition();
|
||||
|
||||
// Look for old (sts generated) name.
|
||||
var stsRunnerDataPvcName
|
||||
|
|
@ -161,12 +158,10 @@ import org.yaml.snakeyaml.constructor.SafeConstructor;
|
|||
}
|
||||
}
|
||||
|
||||
private void reconcileRunnerDiskPvc(VmDefChanged event,
|
||||
private void reconcileRunnerDiskPvc(VmDefinition vmDef,
|
||||
Map<String, Object> model, VmChannel channel)
|
||||
throws TemplateNotFoundException, MalformedTemplateNameException,
|
||||
ParseException, IOException, TemplateException, ApiException {
|
||||
var vmDef = event.vmDefinition();
|
||||
|
||||
// Generate PVC
|
||||
@SuppressWarnings("unchecked")
|
||||
var diskDef = (Map<String, Object>) model.get("disk");
|
||||
|
|
|
|||
|
|
@ -44,10 +44,12 @@ import java.util.Optional;
|
|||
import java.util.logging.Level;
|
||||
import org.jdrupes.vmoperator.common.Convertions;
|
||||
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.Assignment;
|
||||
import org.jdrupes.vmoperator.common.VmPool;
|
||||
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.VmChannel;
|
||||
import org.jdrupes.vmoperator.manager.events.VmDefChanged;
|
||||
|
|
@ -213,20 +215,57 @@ public class Reconciler extends Component {
|
|||
return;
|
||||
}
|
||||
|
||||
// Reconcile
|
||||
reconcile(event, channel);
|
||||
}
|
||||
|
||||
private void reconcile(VmDefChanged event, VmChannel channel)
|
||||
throws TemplateModelException, ApiException, IOException,
|
||||
TemplateException {
|
||||
// Create model for processing templates
|
||||
Map<String, Object> model = prepareModel(event.vmDefinition());
|
||||
var vmDef = event.vmDefinition();
|
||||
Map<String, Object> model = prepareModel(vmDef);
|
||||
cmReconciler.reconcile(model, channel, event.specChanged());
|
||||
|
||||
// The remaining reconcilers depend only on changes of the spec part.
|
||||
if (!event.specChanged()) {
|
||||
return;
|
||||
}
|
||||
dsReconciler.reconcile(event, model, channel);
|
||||
dsReconciler.reconcile(vmDef, model, channel);
|
||||
// Manage (eventual) removal of stateful set.
|
||||
stsReconciler.reconcile(event, model, channel);
|
||||
pvcReconciler.reconcile(event, model, channel);
|
||||
podReconciler.reconcile(event, model, channel);
|
||||
lbReconciler.reconcile(event, model, channel);
|
||||
stsReconciler.reconcile(vmDef, model, channel);
|
||||
pvcReconciler.reconcile(vmDef, model, channel);
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -27,9 +27,9 @@ 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;
|
||||
import org.jdrupes.vmoperator.manager.events.VmDefChanged;
|
||||
|
||||
/**
|
||||
* Before version 3.4, the pod running the VM was created by a stateful set.
|
||||
|
|
@ -54,7 +54,7 @@ import org.jdrupes.vmoperator.manager.events.VmDefChanged;
|
|||
/**
|
||||
* Reconcile stateful set.
|
||||
*
|
||||
* @param event the event
|
||||
* @param vmDef the VM definition
|
||||
* @param model the model
|
||||
* @param channel the channel
|
||||
* @throws IOException Signals that an I/O exception has occurred.
|
||||
|
|
@ -62,14 +62,14 @@ import org.jdrupes.vmoperator.manager.events.VmDefChanged;
|
|||
* @throws ApiException the api exception
|
||||
*/
|
||||
@SuppressWarnings("PMD.AvoidLiteralsInIfCondition")
|
||||
public void reconcile(VmDefChanged event, Map<String, Object> model,
|
||||
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(),
|
||||
event.vmDefinition().namespace(), event.vmDefinition().name());
|
||||
vmDef.namespace(), vmDef.name());
|
||||
if (stsStub.model().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -88,7 +88,7 @@ import org.jdrupes.vmoperator.manager.events.VmDefChanged;
|
|||
// 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 (event.vmDefinition().vmState() == RequestedVmState.RUNNING) {
|
||||
if (vmDef.vmState() == RequestedVmState.RUNNING) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue