Choose suitable API.
This commit is contained in:
parent
ddf412302b
commit
f1b1b2c059
6 changed files with 141 additions and 52 deletions
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -47,7 +47,7 @@ public class Manager extends Component {
|
||||||
public Manager() throws IOException {
|
public Manager() throws IOException {
|
||||||
// Prepare component tree
|
// Prepare component tree
|
||||||
attach(new NioDispatcher());
|
attach(new NioDispatcher());
|
||||||
attach(new VmDefinitionWatcher(channel()));
|
attach(new VmWatcher(channel()));
|
||||||
attach(new Reconciler(channel()));
|
attach(new Reconciler(channel()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
package org.jdrupes.vmoperator.manager;
|
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.Channel;
|
||||||
import org.jgrapes.core.Component;
|
import org.jgrapes.core.Component;
|
||||||
import org.jgrapes.core.annotation.Handler;
|
import org.jgrapes.core.annotation.Handler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapts Kubenetes resources to changes in VM definitions (CRs).
|
||||||
|
*/
|
||||||
public class Reconciler extends Component {
|
public class Reconciler extends Component {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new reconciler.
|
||||||
|
*
|
||||||
|
* @param componentChannel the component channel
|
||||||
|
*/
|
||||||
public Reconciler(Channel componentChannel) {
|
public Reconciler(Channel componentChannel) {
|
||||||
super(componentChannel);
|
super(componentChannel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the change event.
|
||||||
|
*
|
||||||
|
* @param event the event
|
||||||
|
* @param channel the channel
|
||||||
|
* @throws ApiException the api exception
|
||||||
|
*/
|
||||||
@Handler
|
@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;
|
event = null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@
|
||||||
|
|
||||||
package org.jdrupes.vmoperator.manager;
|
package org.jdrupes.vmoperator.manager;
|
||||||
|
|
||||||
|
import io.kubernetes.client.openapi.models.V1APIResource;
|
||||||
import io.kubernetes.client.openapi.models.V1ObjectMeta;
|
import io.kubernetes.client.openapi.models.V1ObjectMeta;
|
||||||
|
|
||||||
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;
|
||||||
|
|
@ -27,7 +27,7 @@ import org.jgrapes.core.Event;
|
||||||
/**
|
/**
|
||||||
* Indicates a change in a VM definition.
|
* Indicates a change in a VM definition.
|
||||||
*/
|
*/
|
||||||
public class VmChangedEvent extends Event<Void> {
|
public class VmDefChanged extends Event<Void> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of change.
|
* The type of change.
|
||||||
|
|
@ -37,6 +37,7 @@ public class VmChangedEvent extends Event<Void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Type type;
|
private final Type type;
|
||||||
|
private final V1APIResource crd;
|
||||||
private final V1ObjectMeta metadata;
|
private final V1ObjectMeta metadata;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -45,8 +46,9 @@ public class VmChangedEvent extends Event<Void> {
|
||||||
* @param type the type
|
* @param type the type
|
||||||
* @param metadata the metadata
|
* @param metadata the metadata
|
||||||
*/
|
*/
|
||||||
public VmChangedEvent(Type type, V1ObjectMeta metadata) {
|
public VmDefChanged(Type type, V1APIResource crd, V1ObjectMeta metadata) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
this.crd = crd;
|
||||||
this.metadata = metadata;
|
this.metadata = metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -59,6 +61,15 @@ public class VmChangedEvent extends Event<Void> {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Crd.
|
||||||
|
*
|
||||||
|
* @return the v 1 API resource
|
||||||
|
*/
|
||||||
|
public V1APIResource crd() {
|
||||||
|
return crd;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the metadata.
|
* Returns the metadata.
|
||||||
*
|
*
|
||||||
|
|
@ -22,7 +22,6 @@ import com.google.gson.reflect.TypeToken;
|
||||||
import io.kubernetes.client.openapi.ApiClient;
|
import io.kubernetes.client.openapi.ApiClient;
|
||||||
import io.kubernetes.client.openapi.ApiException;
|
import io.kubernetes.client.openapi.ApiException;
|
||||||
import io.kubernetes.client.openapi.Configuration;
|
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.apis.CustomObjectsApi;
|
||||||
import io.kubernetes.client.openapi.models.V1APIResource;
|
import io.kubernetes.client.openapi.models.V1APIResource;
|
||||||
import io.kubernetes.client.openapi.models.V1Namespace;
|
import io.kubernetes.client.openapi.models.V1Namespace;
|
||||||
|
|
@ -34,7 +33,9 @@ import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import okhttp3.Call;
|
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.Channel;
|
||||||
import org.jgrapes.core.Component;
|
import org.jgrapes.core.Component;
|
||||||
import org.jgrapes.core.annotation.Handler;
|
import org.jgrapes.core.annotation.Handler;
|
||||||
|
|
@ -45,13 +46,9 @@ import org.jgrapes.core.events.Stop;
|
||||||
* Watches for changes of VM definitions.
|
* Watches for changes of VM definitions.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
|
@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
|
||||||
public class VmDefinitionWatcher extends Component {
|
public class VmWatcher extends Component {
|
||||||
|
|
||||||
private static final String CR_GROUP = "vmoperator.jdrupes.org";
|
private ApiClient client;
|
||||||
private static final String CR_VERSION = "v1";
|
|
||||||
private static final String CR_KIND = "VirtualMachine";
|
|
||||||
private CoreV1Api api;
|
|
||||||
private CustomObjectsApi coa;
|
|
||||||
private V1APIResource vmsCrd;
|
private V1APIResource vmsCrd;
|
||||||
private String managedNamespace = "default";
|
private String managedNamespace = "default";
|
||||||
private final Map<String, WatchChannel> channels
|
private final Map<String, WatchChannel> channels
|
||||||
|
|
@ -62,7 +59,7 @@ public class VmDefinitionWatcher extends Component {
|
||||||
*
|
*
|
||||||
* @param componentChannel the component channel
|
* @param componentChannel the component channel
|
||||||
*/
|
*/
|
||||||
public VmDefinitionWatcher(Channel componentChannel) {
|
public VmWatcher(Channel componentChannel) {
|
||||||
super(componentChannel);
|
super(componentChannel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -75,44 +72,44 @@ public class VmDefinitionWatcher extends Component {
|
||||||
*/
|
*/
|
||||||
@Handler
|
@Handler
|
||||||
public void onStart(Start event) throws IOException, ApiException {
|
public void onStart(Start event) throws IOException, ApiException {
|
||||||
ApiClient client = Config.defaultClient();
|
client = Config.defaultClient();
|
||||||
Configuration.setDefaultApiClient(client);
|
Configuration.setDefaultApiClient(client);
|
||||||
|
|
||||||
// Get access to APIs
|
// Get access to API
|
||||||
api = new CoreV1Api();
|
var coa = new CustomObjectsApi(client);
|
||||||
coa = new CustomObjectsApi();
|
|
||||||
|
|
||||||
// Derive all information from the CRD
|
// 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()
|
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)
|
// Watch the resources (vm definitions)
|
||||||
Call call = coa.listNamespacedCustomObjectCall(
|
Call call = coa.listNamespacedCustomObjectCall(
|
||||||
CR_GROUP, CR_VERSION, managedNamespace, vmsCrd.getName(), null,
|
VM_OP_GROUP, VM_OP_VERSION, managedNamespace, vmsCrd.getName(),
|
||||||
false, null, null, null, null, null, null, null, true, null);
|
null, false, null, null, null, null, null, null, null, true, null);
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
try (Watch<V1Namespace> watch = Watch.createWatch(client,
|
try (Watch<V1Namespace> watch = Watch.createWatch(client, call,
|
||||||
call, new TypeToken<Watch.Response<V1Namespace>>() {
|
new TypeToken<Watch.Response<V1Namespace>>() {
|
||||||
}.getType())) {
|
}.getType())) {
|
||||||
for (Watch.Response<V1Namespace> item : watch) {
|
for (Watch.Response<V1Namespace> item : watch) {
|
||||||
handleCrEvent(item);
|
handleVmDefinitionEvent(item);
|
||||||
}
|
}
|
||||||
} catch (IOException | ApiException e) {
|
} catch (IOException | ApiException e) {
|
||||||
logger.log(Level.FINE, e, () -> "Probem while watching: "
|
logger.log(Level.FINE, e, () -> "Probem while watching: "
|
||||||
+ e.getMessage());
|
+ e.getMessage());
|
||||||
}
|
}
|
||||||
fire(new Stop());
|
fire(new Stop());
|
||||||
|
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleCrEvent(Watch.Response<V1Namespace> item) {
|
private void handleVmDefinitionEvent(Watch.Response<V1Namespace> item) {
|
||||||
V1ObjectMeta metadata = item.object.getMetadata();
|
V1ObjectMeta metadata = item.object.getMetadata();
|
||||||
WatchChannel channel = channels.computeIfAbsent(metadata.getName(),
|
WatchChannel channel = channels.computeIfAbsent(metadata.getName(),
|
||||||
k -> new WatchChannel(channel(), newEventPipeline(), api, coa));
|
k -> new WatchChannel(channel(), newEventPipeline(), client));
|
||||||
channel.pipeline().fire(new VmChangedEvent(
|
channel.pipeline().fire(new VmDefChanged(
|
||||||
VmChangedEvent.Type.valueOf(item.type), metadata), channel);
|
VmDefChanged.Type.valueOf(item.type), vmsCrd, metadata), channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -122,7 +119,7 @@ public class VmDefinitionWatcher extends Component {
|
||||||
* @param channel the channel
|
* @param channel the channel
|
||||||
*/
|
*/
|
||||||
@Handler(priority = -10_000)
|
@Handler(priority = -10_000)
|
||||||
public void onVmChanged(VmChangedEvent event, WatchChannel channel) {
|
public void onVmDefChanged(VmDefChanged event, WatchChannel channel) {
|
||||||
if (event.type() == Type.DELETED) {
|
if (event.type() == Type.DELETED) {
|
||||||
channels.remove(event.metadata().getName());
|
channels.remove(event.metadata().getName());
|
||||||
}
|
}
|
||||||
|
|
@ -18,8 +18,8 @@
|
||||||
|
|
||||||
package org.jdrupes.vmoperator.manager;
|
package org.jdrupes.vmoperator.manager;
|
||||||
|
|
||||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
import io.kubernetes.client.openapi.ApiClient;
|
||||||
import io.kubernetes.client.openapi.apis.CustomObjectsApi;
|
|
||||||
import org.jgrapes.core.Channel;
|
import org.jgrapes.core.Channel;
|
||||||
import org.jgrapes.core.EventPipeline;
|
import org.jgrapes.core.EventPipeline;
|
||||||
import org.jgrapes.core.Subchannel.DefaultSubchannel;
|
import org.jgrapes.core.Subchannel.DefaultSubchannel;
|
||||||
|
|
@ -31,21 +31,20 @@ import org.jgrapes.core.Subchannel.DefaultSubchannel;
|
||||||
public class WatchChannel extends DefaultSubchannel {
|
public class WatchChannel extends DefaultSubchannel {
|
||||||
|
|
||||||
private final EventPipeline pipeline;
|
private final EventPipeline pipeline;
|
||||||
private final CoreV1Api api;
|
private final ApiClient client;
|
||||||
private final CustomObjectsApi coa;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiates a new watch channel.
|
* Instantiates a new watch channel.
|
||||||
*
|
*
|
||||||
* @param mainChannel the main channel
|
* @param mainChannel the main channel
|
||||||
* @param pipeline the pipeline
|
* @param pipeline the pipeline
|
||||||
|
* @param client
|
||||||
*/
|
*/
|
||||||
public WatchChannel(Channel mainChannel, EventPipeline pipeline,
|
public WatchChannel(Channel mainChannel, EventPipeline pipeline,
|
||||||
CoreV1Api api, CustomObjectsApi coa) {
|
ApiClient client) {
|
||||||
super(mainChannel);
|
super(mainChannel);
|
||||||
this.pipeline = pipeline;
|
this.pipeline = pipeline;
|
||||||
this.api = api;
|
this.client = client;
|
||||||
this.coa = coa;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -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() {
|
public ApiClient client() {
|
||||||
return api;
|
return client;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the API object for invoking kubernetes custom object
|
|
||||||
* functions.
|
|
||||||
*
|
|
||||||
* @return the API object
|
|
||||||
*/
|
|
||||||
public CustomObjectsApi coa() {
|
|
||||||
return coa;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue