Rename templates, change model.

This commit is contained in:
Michael Lipp 2023-07-27 18:45:37 +02:00
parent dd8407fb2d
commit 7655b7ab1a
2 changed files with 81 additions and 56 deletions

View file

@ -1,11 +1,11 @@
apiVersion: v1 apiVersion: v1
kind: ConfigMap kind: ConfigMap
metadata: metadata:
namespace: ${ metadata.namespace.asString } namespace: ${ cr.metadata.namespace.asString }
name: ${ metadata.name.asString } name: ${ cr.metadata.name.asString }
labels: labels:
app.kubernetes.io/name: ${ constants.APP_NAME } app.kubernetes.io/name: ${ constants.APP_NAME }
app.kubernetes.io/instance: ${ metadata.name.asString } app.kubernetes.io/instance: ${ cr.metadata.name.asString }
app.kubernetes.io/managed-by: ${ constants.VM_OP_NAME } app.kubernetes.io/managed-by: ${ constants.VM_OP_NAME }
data: data:
@ -13,17 +13,17 @@ data:
"/Runner": "/Runner":
# The directory used to store data files. Defaults to (depending on # The directory used to store data files. Defaults to (depending on
# values available): # values available):
# * $XDG_DATA_HOME/vmrunner/${ metadata.name.asString } # * $XDG_DATA_HOME/vmrunner/${ cr.metadata.name.asString }
# * $HOME/.local/share/vmrunner/${ metadata.name.asString } # * $HOME/.local/share/vmrunner/${ cr.metadata.name.asString }
# * ./${ metadata.name.asString } # * ./${ cr.metadata.name.asString }
dataDir: /var/local/vm-data dataDir: /var/local/vm-data
# The directory used to store runtime files. Defaults to (depending on # The directory used to store runtime files. Defaults to (depending on
# values available): # values available):
# * $XDG_RUNTIME_DIR/vmrunner/${ metadata.name.asString } # * $XDG_RUNTIME_DIR/vmrunner/${ cr.metadata.name.asString }
# * /tmp/$USER/vmrunner/${ metadata.name.asString } # * /tmp/$USER/vmrunner/${ cr.metadata.name.asString }
# * /tmp/vmrunner/${ metadata.name.asString } # * /tmp/vmrunner/${ cr.metadata.name.asString }
# runtimeDir: "$XDG_RUNTIME_DIR/vmrunner/${ metadata.name.asString }" # runtimeDir: "$XDG_RUNTIME_DIR/vmrunner/${ cr.metadata.name.asString }"
# The template to use. Resolved relative to /usr/share/vmrunner/templates. # The template to use. Resolved relative to /usr/share/vmrunner/templates.
# template: "Standard-VM-latest.ftl.yaml" # template: "Standard-VM-latest.ftl.yaml"
@ -35,67 +35,67 @@ data:
# Define the VM (required) # Define the VM (required)
vm: vm:
# The VM's name (required) # The VM's name (required)
name: ${ metadata.name.asString } name: ${ cr.metadata.name.asString }
# The machine's uuid. If none is specified, a uuid is generated # The machine's uuid. If none is specified, a uuid is generated
# and stored in the data directory. If the uuid is important # and stored in the data directory. If the uuid is important
# (e.g. because licenses depend on it) it is recommaned to specify # (e.g. because licenses depend on it) it is recommaned to specify
# it here explicitly or to carefully backup the data directory. # it here explicitly or to carefully backup the data directory.
# uuid: "generated uuid" # uuid: "generated uuid"
<#if spec.vm.machineUuid??> <#if cr.spec.vm.machineUuid??>
uuid: "${ spec.vm.machineUuid.asString }" uuid: "${ cr.spec.vm.machineUuid.asString }"
</#if> </#if>
# Whether to provide a software TPM (defaults to false) # Whether to provide a software TPM (defaults to false)
# useTpm: false # useTpm: false
useTpm: ${ spec.vm.useTpm.asBoolean?c } useTpm: ${ cr.spec.vm.useTpm.asBoolean?c }
# How to boot (see https://github.com/mnlipp/VM-Operator/blob/main/org.jdrupes.vmoperator.runner.qemu/resources/org/jdrupes/vmoperator/runner/qemu/defaults.yaml): # How to boot (see https://github.com/mnlipp/VM-Operator/blob/main/org.jdrupes.vmoperator.runner.qemu/resources/org/jdrupes/vmoperator/runner/qemu/defaults.yaml):
# * bios # * bios
# * uefi[-4m] # * uefi[-4m]
# * secure[-4m] # * secure[-4m]
firmware: ${ spec.vm.firmware.asString } firmware: ${ cr.spec.vm.firmware.asString }
# Whether to show a boot menu. # Whether to show a boot menu.
# bootMenu: false # bootMenu: false
bootMenu: ${ spec.vm.bootMenu.asBoolean?c } bootMenu: ${ cr.spec.vm.bootMenu.asBoolean?c }
# When terminating, a graceful powerdown is attempted. If it # When terminating, a graceful powerdown is attempted. If it
# doesn't succeed within the given timeout (seconds) SIGTERM # doesn't succeed within the given timeout (seconds) SIGTERM
# is sent to Qemu. # is sent to Qemu.
# powerdownTimeout: 900 # powerdownTimeout: 900
powerdownTimeout: ${ spec.vm.powerdownTimeout.asLong?c } powerdownTimeout: ${ cr.spec.vm.powerdownTimeout.asLong?c }
# CPU settings # CPU settings
cpuModel: ${ spec.vm.cpuModel.asString } cpuModel: ${ cr.spec.vm.cpuModel.asString }
# Setting maximumCpus to 1 omits the "-smp" options. The defaults (0) # Setting maximumCpus to 1 omits the "-smp" options. The defaults (0)
# cause the corresponding property to be omitted from the "-smp" option. # cause the corresponding property to be omitted from the "-smp" option.
# If currentCpus is greater than maximumCpus, the latter is adjusted. # If currentCpus is greater than maximumCpus, the latter is adjusted.
<#if spec.vm.maximumCpus?? > <#if cr.spec.vm.maximumCpus?? >
maximumCpus: ${ spec.vm.maximumCpus.asInt?c } maximumCpus: ${ cr.spec.vm.maximumCpus.asInt?c }
</#if> </#if>
<#if spec.vm.cpuTopology?? > <#if cr.spec.vm.cpuTopology?? >
cpuSockets: ${ spec.vm.cpuTopology.cpuSockets.asInt?c } cpuSockets: ${ cr.spec.vm.cpuTopology.cpuSockets.asInt?c }
diesPerSocket: ${ spec.vm.cpuTopology.diesPerSocket.asInt?c } diesPerSocket: ${ cr.spec.vm.cpuTopology.diesPerSocket.asInt?c }
coresPerSocket: ${ spec.vm.cpuTopology.coresPerSocket.asInt?c } coresPerSocket: ${ cr.spec.vm.cpuTopology.coresPerSocket.asInt?c }
threadsPerCore: ${ spec.vm.cpuTopology.threadsPerCore.asInt?c } threadsPerCore: ${ cr.spec.vm.cpuTopology.threadsPerCore.asInt?c }
</#if> </#if>
<#if spec.vm.currentCpus?? > <#if cr.spec.vm.currentCpus?? >
currentCpus: ${ spec.vm.currentCpus.asInt?c } currentCpus: ${ cr.spec.vm.currentCpus.asInt?c }
</#if> </#if>
# RAM settings # RAM settings
# Maximum defaults to 1G # Maximum defaults to 1G
maximumRam: "${ spec.vm.maximumRam.asString }" maximumRam: "${ cr.spec.vm.maximumRam.asString }"
<#if spec.vm.currentRam?? > <#if cr.spec.vm.currentRam?? >
currentRam: "${ spec.vm.currentRam.asString }" currentRam: "${ cr.spec.vm.currentRam.asString }"
</#if> </#if>
# RTC settings. # RTC settings.
# rtcBase: utc # rtcBase: utc
# rtcClock: rt # rtcClock: rt
rtcBase: ${ spec.vm.rtcBase.asString } rtcBase: ${ cr.spec.vm.rtcBase.asString }
rtcClock: ${ spec.vm.rtcClock.asString } rtcClock: ${ cr.spec.vm.rtcClock.asString }
# Network settings # Network settings
# Supported types are "tap" and "user" (for debugging). Type "user" # Supported types are "tap" and "user" (for debugging). Type "user"
@ -107,7 +107,7 @@ data:
# mac: (undefined) # mac: (undefined)
network: network:
<#assign nwCounter = 0/> <#assign nwCounter = 0/>
<#list spec.vm.networks.asList() as itf> <#list cr.spec.vm.networks.asList() as itf>
<#if itf.tap??> <#if itf.tap??>
- type: tap - type: tap
device: ${ itf.tap.device.asString } device: ${ itf.tap.device.asString }
@ -135,7 +135,7 @@ data:
# file: (undefined) # file: (undefined)
drives: drives:
<#assign drvCounter = 0/> <#assign drvCounter = 0/>
<#list spec.vm.disks.asList() as disk> <#list cr.spec.vm.disks.asList() as disk>
<#if disk.volumeClaimTemplate.metadata?? <#if disk.volumeClaimTemplate.metadata??
&& disk.volumeClaimTemplate.metadata.name??> && disk.volumeClaimTemplate.metadata.name??>
<#assign name = disk.volumeClaimTemplate.metadata.name.asString> <#assign name = disk.volumeClaimTemplate.metadata.name.asString>
@ -147,16 +147,16 @@ data:
</#list> </#list>
display: display:
<#if spec.vm.display.spice??> <#if cr.spec.vm.display.spice??>
spice: spice:
port: ${ spec.vm.display.spice.port.asInt?c } port: ${ cr.spec.vm.display.spice.port.asInt?c }
<#if spec.vm.display.spice.ticket??> <#if cr.spec.vm.display.spice.ticket??>
ticket: "${ spec.vm.display.spice.ticket.asString }" ticket: "${ cr.spec.vm.display.spice.ticket.asString }"
</#if> </#if>
<#if spec.vm.display.spice.streamingVideo??> <#if cr.spec.vm.display.spice.streamingVideo??>
ticket: "${ spec.vm.display.spice.streamingVideo.asString }" ticket: "${ cr.spec.vm.display.spice.streamingVideo.asString }"
</#if> </#if>
usbRedirects: ${ spec.vm.display.spice.usbRedirects.asInt?c } usbRedirects: ${ cr.spec.vm.display.spice.usbRedirects.asInt?c }
</#if> </#if>
logging.properties: | logging.properties: |

View file

@ -100,8 +100,19 @@ public class Reconciler extends Component {
var vmDef = vmDefApi.get(defMeta.getNamespace(), defMeta.getName()) var vmDef = vmDefApi.get(defMeta.getNamespace(), defMeta.getName())
.getObject(); .getObject();
// Prepare Freemarker model
@SuppressWarnings("PMD.UseConcurrentHashMap")
Map<String, Object> model = new HashMap<>();
model.put("cr", vmDef.getRaw());
model.put("constants",
(TemplateHashModel) new DefaultObjectWrapperBuilder(
Configuration.VERSION_2_3_32)
.build().getStaticModels().get(Constants.class.getName()));
// Reconcile
reconcileDisks(vmDef, channel); reconcileDisks(vmDef, channel);
reconcileConfigMap(vmDef, channel); reconcileConfigMap(model, channel);
reconcilePod(model, channel);
} }
private void reconcileDisks(DynamicKubernetesObject vmDef, private void reconcileDisks(DynamicKubernetesObject vmDef,
@ -168,21 +179,13 @@ public class Reconciler extends Component {
} }
} }
private void reconcileConfigMap(DynamicKubernetesObject vmDefinition, private void reconcileConfigMap(Map<String, Object> model,
WatchChannel channel) throws TemplateNotFoundException, WatchChannel channel)
MalformedTemplateNameException, ParseException, IOException, throws TemplateNotFoundException, MalformedTemplateNameException,
TemplateException, ApiException { ParseException, IOException, TemplateException, ApiException {
// Combine template and data and parse result // Combine template and data and parse result
// (tempting, but no need to use a pipe here) var fmTemplate = fmConfig.getTemplate("runnerConfig.ftl.yaml");
var fmTemplate = fmConfig.getTemplate("etcConfig.ftl.yaml");
StringWriter out = new StringWriter(); StringWriter out = new StringWriter();
@SuppressWarnings("PMD.UseConcurrentHashMap")
Map<String, Object> model = new HashMap<>();
model.putAll(vmDefinition.getRaw().asMap());
model.put("constants",
(TemplateHashModel) new DefaultObjectWrapperBuilder(
Configuration.VERSION_2_3_32)
.build().getStaticModels().get(Constants.class.getName()));
fmTemplate.process(model, out); fmTemplate.process(model, out);
// Apply // Apply
@ -191,11 +194,33 @@ public class Reconciler extends Component {
opts.setFieldManager("kubernetes-java-kubectl-apply"); opts.setFieldManager("kubernetes-java-kubectl-apply");
DynamicKubernetesApi pvcApi = new DynamicKubernetesApi("", "v1", DynamicKubernetesApi pvcApi = new DynamicKubernetesApi("", "v1",
"configmaps", channel.client()); "configmaps", channel.client());
var vmDef = GsonPtr.to(vmDefinition.getRaw()); var vmDef = GsonPtr.to((JsonObject) model.get("cr"));
pvcApi.patch(vmDef.getAsString("metadata", "namespace").get(), pvcApi.patch(vmDef.getAsString("metadata", "namespace").get(),
vmDef.getAsString("metadata", "name").get(), vmDef.getAsString("metadata", "name").get(),
V1Patch.PATCH_FORMAT_APPLY_YAML, new V1Patch(out.toString()), V1Patch.PATCH_FORMAT_APPLY_YAML, new V1Patch(out.toString()),
opts).throwsApiException(); opts).throwsApiException();
} }
private void reconcilePod(Map<String, Object> model, WatchChannel channel)
throws TemplateNotFoundException, MalformedTemplateNameException,
ParseException, IOException, TemplateException, ApiException {
// Combine template and data and parse result
var fmTemplate = fmConfig.getTemplate("runnerPod.ftl.yaml");
StringWriter out = new StringWriter();
fmTemplate.process(model, out);
out = null;
// // Apply
// PatchOptions opts = new PatchOptions();
// opts.setForce(false);
// opts.setFieldManager("kubernetes-java-kubectl-apply");
// DynamicKubernetesApi pvcApi = new DynamicKubernetesApi("", "v1",
// "pod", channel.client());
// var vmDef = GsonPtr.to((JsonObject) model.get("cr"));
// pvcApi.patch(vmDef.getAsString("metadata", "namespace").get(),
// vmDef.getAsString("metadata", "name").get(),
// V1Patch.PATCH_FORMAT_APPLY_YAML, new V1Patch(out.toString()),
// opts).throwsApiException();
}
} }