diff --git a/org.jdrupes.vmoperator.manager/resources/org/jdrupes/vmoperator/manager/runnerService.ftl.yaml b/org.jdrupes.vmoperator.manager/resources/org/jdrupes/vmoperator/manager/runnerService.ftl.yaml
new file mode 100644
index 0000000..ee0d88d
--- /dev/null
+++ b/org.jdrupes.vmoperator.manager/resources/org/jdrupes/vmoperator/manager/runnerService.ftl.yaml
@@ -0,0 +1,17 @@
+apiVersion: v1
+kind: Service
+metadata:
+ namespace: ${ cr.metadata.namespace.asString }
+ name: ${ cr.metadata.name.asString }
+ labels:
+ app.kubernetes.io/name: ${ constants.APP_NAME }
+ app.kubernetes.io/instance: ${ cr.metadata.name.asString }
+ app.kubernetes.io/managed-by: ${ constants.VM_OP_NAME }
+spec:
+ ports:
+ - name: spice
+ port: ${ cr.spec.vm.display.spice.port.asInt?c }
+ clusterIP: None
+ selector:
+ app.kubernetes.io/name: ${ cr.metadata.name.asString }
+ app.kubernetes.io/instance: ${ cr.metadata.name.asString }
diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/Reconciler.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/Reconciler.java
index e0c18a9..1e32a0d 100644
--- a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/Reconciler.java
+++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/Reconciler.java
@@ -53,6 +53,7 @@ public class Reconciler extends Component {
private final Configuration fmConfig;
private final CmReconciler cmReconciler;
private final StsReconciler stsReconciler;
+ private final ServiceReconciler serviceReconciler;
/**
* Instantiates a new reconciler.
@@ -74,6 +75,7 @@ public class Reconciler extends Component {
cmReconciler = new CmReconciler(fmConfig);
stsReconciler = new StsReconciler(fmConfig);
+ serviceReconciler = new ServiceReconciler(fmConfig);
}
/**
@@ -121,7 +123,9 @@ public class Reconciler extends Component {
var configMap = cmReconciler.reconcile(event, model, channel);
model.put("cm", configMap.getRaw());
stsReconciler.reconcile(event, model, channel);
+ serviceReconciler.reconcile(event, model, channel);
} else {
+ serviceReconciler.reconcile(event, model, channel);
stsReconciler.reconcile(event, model, channel);
cmReconciler.reconcile(event, model, channel);
}
diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/ServiceReconciler.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/ServiceReconciler.java
new file mode 100644
index 0000000..aef4898
--- /dev/null
+++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/ServiceReconciler.java
@@ -0,0 +1,88 @@
+/*
+ * 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 .
+ */
+
+package org.jdrupes.vmoperator.manager;
+
+import freemarker.template.Configuration;
+import freemarker.template.TemplateException;
+import io.kubernetes.client.openapi.ApiException;
+import io.kubernetes.client.util.generic.dynamic.DynamicKubernetesApi;
+import io.kubernetes.client.util.generic.dynamic.Dynamics;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.Map;
+import java.util.logging.Logger;
+import org.jdrupes.vmoperator.manager.VmDefChanged.Type;
+
+/**
+ * Delegee for reconciling the service
+ */
+@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
+/* default */ class ServiceReconciler {
+
+ protected final Logger logger = Logger.getLogger(getClass().getName());
+ private final Configuration fmConfig;
+
+ /**
+ * Instantiates a new service reconciler.
+ *
+ * @param fmConfig the fm config
+ */
+ public ServiceReconciler(Configuration fmConfig) {
+ this.fmConfig = fmConfig;
+ }
+
+ /**
+ * Reconcile.
+ *
+ * @param event the event
+ * @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 model, VmChannel channel)
+ throws IOException, TemplateException, ApiException {
+ // Get API and check if exists
+ DynamicKubernetesApi svcApi = new DynamicKubernetesApi("", "v1",
+ "services", channel.client());
+ var existing = K8s.get(svcApi, event.object().getMetadata());
+
+ // If deleted, delete
+ if (event.type() == Type.DELETED) {
+ if (existing.isPresent()) {
+ K8s.delete(svcApi, existing.get());
+ }
+ return;
+ }
+
+ // Combine template and data and parse result
+ var fmTemplate = fmConfig.getTemplate("runnerService.ftl.yaml");
+ StringWriter out = new StringWriter();
+ fmTemplate.process(model, out);
+ // Avoid Yaml.load due to
+ // https://github.com/kubernetes-client/java/issues/2741
+ var mapDef = Dynamics.newFromYaml(out.toString());
+
+ // Apply
+ K8s.apply(svcApi, mapDef, out.toString());
+ }
+
+}