diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/Constants.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/Constants.java new file mode 100644 index 0000000..0d03ea6 --- /dev/null +++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/Constants.java @@ -0,0 +1,30 @@ +/* + * 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; + +/** + * Some constants. + */ +public class Constants { + + static final String VM_OP_GROUP = "vmoperator.jdrupes.org"; + static final String VM_OP_VERSION = "v1"; + static final String VM_OP_KIND_VM = "VirtualMachine"; + +} diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/Manager.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/Manager.java index 0a62134..675c11a 100644 --- a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/Manager.java +++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/Manager.java @@ -47,7 +47,7 @@ public class Manager extends Component { public Manager() throws IOException { // Prepare component tree attach(new NioDispatcher()); - attach(new VmDefinitionWatcher(channel())); + attach(new VmWatcher(channel())); attach(new Reconciler(channel())); } 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 67abd9f..2cbf29d 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 @@ -1,18 +1,80 @@ +/* + * 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 io.kubernetes.client.openapi.ApiException; +import io.kubernetes.client.util.generic.dynamic.DynamicKubernetesApi; +import static org.jdrupes.vmoperator.manager.Constants.VM_OP_GROUP; +import static org.jdrupes.vmoperator.manager.Constants.VM_OP_VERSION; import org.jgrapes.core.Channel; import org.jgrapes.core.Component; import org.jgrapes.core.annotation.Handler; +/** + * Adapts Kubenetes resources to changes in VM definitions (CRs). + */ public class Reconciler extends Component { + /** + * Instantiates a new reconciler. + * + * @param componentChannel the component channel + */ public Reconciler(Channel componentChannel) { super(componentChannel); } + /** + * Handles the change event. + * + * @param event the event + * @param channel the channel + * @throws ApiException the api exception + */ @Handler - public void onVmChanged(VmChangedEvent event, WatchChannel channel) { + public void onVmDefChanged(VmDefChanged event, WatchChannel channel) + throws ApiException { + DynamicKubernetesApi vmDefApi = new DynamicKubernetesApi(VM_OP_GROUP, + VM_OP_VERSION, event.crd().getName(), channel.client()); + var defMeta = event.metadata(); + var vmDef = vmDefApi.get(defMeta.getNamespace(), defMeta.getName()); + +// DynamicKubernetesApi cmApi = new DynamicKubernetesApi("", "v1", +// "configmaps", channel.client()); +// var cm = new DynamicKubernetesObject(); +// cm.setApiVersion("v1"); +// cm.setKind("ConfigMap"); +// V1ObjectMeta metadata = new V1ObjectMeta(); +// metadata.setNamespace("default"); +// metadata.setName("test"); +// cm.setMetadata(metadata); +// JsonObject data = new JsonObject(); +// data.addProperty("test", "value"); +// cm.getRaw().add("data", data); +// +// var response = cmApi.create("default", cm, new CreateOptions()) +// .throwsApiException(); + +// var obj = channel.coa().getNamespacedCustomObject(VM_OP_GROUP, VM_OP_VERSION, +// md.getNamespace(), event.crd().getName(), md.getName()); event = null; + } } diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/VmChangedEvent.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/VmDefChanged.java similarity index 84% rename from org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/VmChangedEvent.java rename to org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/VmDefChanged.java index 424c09b..d3e6f34 100644 --- a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/VmChangedEvent.java +++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/VmDefChanged.java @@ -18,8 +18,8 @@ package org.jdrupes.vmoperator.manager; +import io.kubernetes.client.openapi.models.V1APIResource; import io.kubernetes.client.openapi.models.V1ObjectMeta; - import org.jgrapes.core.Channel; import org.jgrapes.core.Components; import org.jgrapes.core.Event; @@ -27,7 +27,7 @@ import org.jgrapes.core.Event; /** * Indicates a change in a VM definition. */ -public class VmChangedEvent extends Event { +public class VmDefChanged extends Event { /** * The type of change. @@ -37,6 +37,7 @@ public class VmChangedEvent extends Event { } private final Type type; + private final V1APIResource crd; private final V1ObjectMeta metadata; /** @@ -45,8 +46,9 @@ public class VmChangedEvent extends Event { * @param type the type * @param metadata the metadata */ - public VmChangedEvent(Type type, V1ObjectMeta metadata) { + public VmDefChanged(Type type, V1APIResource crd, V1ObjectMeta metadata) { this.type = type; + this.crd = crd; this.metadata = metadata; } @@ -59,6 +61,15 @@ public class VmChangedEvent extends Event { return type; } + /** + * Returns the Crd. + * + * @return the v 1 API resource + */ + public V1APIResource crd() { + return crd; + } + /** * Returns the metadata. * diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/VmDefinitionWatcher.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/VmWatcher.java similarity index 72% rename from org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/VmDefinitionWatcher.java rename to org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/VmWatcher.java index 8a32769..fc9933f 100644 --- a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/VmDefinitionWatcher.java +++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/VmWatcher.java @@ -22,7 +22,6 @@ import com.google.gson.reflect.TypeToken; import io.kubernetes.client.openapi.ApiClient; import io.kubernetes.client.openapi.ApiException; import io.kubernetes.client.openapi.Configuration; -import io.kubernetes.client.openapi.apis.CoreV1Api; import io.kubernetes.client.openapi.apis.CustomObjectsApi; import io.kubernetes.client.openapi.models.V1APIResource; import io.kubernetes.client.openapi.models.V1Namespace; @@ -34,7 +33,9 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; import okhttp3.Call; -import org.jdrupes.vmoperator.manager.VmChangedEvent.Type; +import static org.jdrupes.vmoperator.manager.Constants.VM_OP_GROUP; +import static org.jdrupes.vmoperator.manager.Constants.VM_OP_VERSION; +import org.jdrupes.vmoperator.manager.VmDefChanged.Type; import org.jgrapes.core.Channel; import org.jgrapes.core.Component; import org.jgrapes.core.annotation.Handler; @@ -45,13 +46,9 @@ import org.jgrapes.core.events.Stop; * Watches for changes of VM definitions. */ @SuppressWarnings("PMD.DataflowAnomalyAnalysis") -public class VmDefinitionWatcher extends Component { +public class VmWatcher extends Component { - private static final String CR_GROUP = "vmoperator.jdrupes.org"; - private static final String CR_VERSION = "v1"; - private static final String CR_KIND = "VirtualMachine"; - private CoreV1Api api; - private CustomObjectsApi coa; + private ApiClient client; private V1APIResource vmsCrd; private String managedNamespace = "default"; private final Map channels @@ -62,7 +59,7 @@ public class VmDefinitionWatcher extends Component { * * @param componentChannel the component channel */ - public VmDefinitionWatcher(Channel componentChannel) { + public VmWatcher(Channel componentChannel) { super(componentChannel); } @@ -75,44 +72,44 @@ public class VmDefinitionWatcher extends Component { */ @Handler public void onStart(Start event) throws IOException, ApiException { - ApiClient client = Config.defaultClient(); + client = Config.defaultClient(); Configuration.setDefaultApiClient(client); - // Get access to APIs - api = new CoreV1Api(); - coa = new CustomObjectsApi(); + // Get access to API + var coa = new CustomObjectsApi(client); // Derive all information from the CRD - var resources = coa.getAPIResources(CR_GROUP, CR_VERSION); + var resources + = coa.getAPIResources(VM_OP_GROUP, VM_OP_VERSION); vmsCrd = resources.getResources().stream() - .filter(r -> CR_KIND.equals(r.getKind())).findFirst().get(); + .filter(r -> Constants.VM_OP_KIND_VM.equals(r.getKind())) + .findFirst().get(); // Watch the resources (vm definitions) Call call = coa.listNamespacedCustomObjectCall( - CR_GROUP, CR_VERSION, managedNamespace, vmsCrd.getName(), null, - false, null, null, null, null, null, null, null, true, null); + VM_OP_GROUP, VM_OP_VERSION, managedNamespace, vmsCrd.getName(), + null, false, null, null, null, null, null, null, null, true, null); new Thread(() -> { - try (Watch watch = Watch.createWatch(client, - call, new TypeToken>() { + try (Watch watch = Watch.createWatch(client, call, + new TypeToken>() { }.getType())) { for (Watch.Response item : watch) { - handleCrEvent(item); + handleVmDefinitionEvent(item); } } catch (IOException | ApiException e) { logger.log(Level.FINE, e, () -> "Probem while watching: " + e.getMessage()); } fire(new Stop()); - }).start(); } - private void handleCrEvent(Watch.Response item) { + private void handleVmDefinitionEvent(Watch.Response item) { V1ObjectMeta metadata = item.object.getMetadata(); WatchChannel channel = channels.computeIfAbsent(metadata.getName(), - k -> new WatchChannel(channel(), newEventPipeline(), api, coa)); - channel.pipeline().fire(new VmChangedEvent( - VmChangedEvent.Type.valueOf(item.type), metadata), channel); + k -> new WatchChannel(channel(), newEventPipeline(), client)); + channel.pipeline().fire(new VmDefChanged( + VmDefChanged.Type.valueOf(item.type), vmsCrd, metadata), channel); } /** @@ -122,7 +119,7 @@ public class VmDefinitionWatcher extends Component { * @param channel the channel */ @Handler(priority = -10_000) - public void onVmChanged(VmChangedEvent event, WatchChannel channel) { + public void onVmDefChanged(VmDefChanged event, WatchChannel channel) { if (event.type() == Type.DELETED) { channels.remove(event.metadata().getName()); } diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/WatchChannel.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/WatchChannel.java index 17ae66f..ab5e2c5 100644 --- a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/WatchChannel.java +++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/WatchChannel.java @@ -18,8 +18,8 @@ package org.jdrupes.vmoperator.manager; -import io.kubernetes.client.openapi.apis.CoreV1Api; -import io.kubernetes.client.openapi.apis.CustomObjectsApi; +import io.kubernetes.client.openapi.ApiClient; + import org.jgrapes.core.Channel; import org.jgrapes.core.EventPipeline; import org.jgrapes.core.Subchannel.DefaultSubchannel; @@ -31,21 +31,20 @@ import org.jgrapes.core.Subchannel.DefaultSubchannel; public class WatchChannel extends DefaultSubchannel { private final EventPipeline pipeline; - private final CoreV1Api api; - private final CustomObjectsApi coa; + private final ApiClient client; /** * Instantiates a new watch channel. * * @param mainChannel the main channel * @param pipeline the pipeline + * @param client */ public WatchChannel(Channel mainChannel, EventPipeline pipeline, - CoreV1Api api, CustomObjectsApi coa) { + ApiClient client) { super(mainChannel); this.pipeline = pipeline; - this.api = api; - this.coa = coa; + this.client = client; } /** @@ -58,21 +57,11 @@ public class WatchChannel extends DefaultSubchannel { } /** - * Returns the API object for invoking kubernetes functions. + * Returns the API client. * - * @return the API object + * @return the API client */ - public CoreV1Api api() { - return api; - } - - /** - * Returns the API object for invoking kubernetes custom object - * functions. - * - * @return the API object - */ - public CustomObjectsApi coa() { - return coa; + public ApiClient client() { + return client; } }