Implement basic reconciliation "loop".
This commit is contained in:
parent
de17d323c3
commit
50bff5d38f
10 changed files with 461 additions and 68 deletions
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
|
|
@ -24,7 +24,7 @@
|
||||||
"mainClass": "org.jdrupes.vmoperator.runner.qemu.Runner",
|
"mainClass": "org.jdrupes.vmoperator.runner.qemu.Runner",
|
||||||
"projectName": "org.jdrupes.vmoperator.runner.qemu",
|
"projectName": "org.jdrupes.vmoperator.runner.qemu",
|
||||||
"cwd": "${workspaceFolder}/org.jdrupes.vmoperator.runner.qemu",
|
"cwd": "${workspaceFolder}/org.jdrupes.vmoperator.runner.qemu",
|
||||||
"vmArgs": "-ea -Djava.util.logging.config.file=jul-debug.properties -Dorg.jdrupes.vmoperator.runner.qemu.config=./config.yaml"
|
"vmArgs": "-ea -Djava.util.logging.manager=org.jdrupes.vmoperator.util.LongLoggingManager"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -17,6 +17,8 @@ spec:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
image:
|
image:
|
||||||
|
description: >-
|
||||||
|
The image to use for the pod. Must run a runner.
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
repository:
|
repository:
|
||||||
|
|
@ -34,25 +36,71 @@ spec:
|
||||||
default: "IfNotPresent"
|
default: "IfNotPresent"
|
||||||
vm:
|
vm:
|
||||||
type: object
|
type: object
|
||||||
|
description: Defines the VM.
|
||||||
properties:
|
properties:
|
||||||
name:
|
|
||||||
type: string
|
|
||||||
machineUuid:
|
machineUuid:
|
||||||
|
description: >-
|
||||||
|
The machine's uuid. If none is specified, a uuid
|
||||||
|
is generated and stored in the data directory.
|
||||||
|
If the uuid is important (e.g. because licenses
|
||||||
|
depend on it) it is recommaned to specify it
|
||||||
|
explicitly or to carefully backup the data
|
||||||
|
directory.
|
||||||
type: string
|
type: string
|
||||||
host:
|
host:
|
||||||
|
description: The host to run this vm on.
|
||||||
type: string
|
type: string
|
||||||
useTpm:
|
useTpm:
|
||||||
|
description: Whether to provide a software TPM.
|
||||||
type: boolean
|
type: boolean
|
||||||
default: false
|
default: false
|
||||||
firmware:
|
firmware:
|
||||||
|
description: >-
|
||||||
|
How to boot.
|
||||||
type: string
|
type: string
|
||||||
|
enum: ["bios", "uefi", "uefi-4m", "secure", "secure-4m"]
|
||||||
default: "uefi"
|
default: "uefi"
|
||||||
|
bootMenu:
|
||||||
|
description: Whether to show a boot menu.
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
powerdownTimeout:
|
||||||
|
description: >-
|
||||||
|
When terminating, a graceful powerdown is attempted.
|
||||||
|
If it doesn't succeed within the given timeout
|
||||||
|
(seconds) SIGTERM is sent to Qemu.
|
||||||
|
type: integer
|
||||||
|
default: 900
|
||||||
cpuModel:
|
cpuModel:
|
||||||
|
description: Any model supported by Qemu.
|
||||||
type: string
|
type: string
|
||||||
default: "host"
|
default: "host"
|
||||||
maximumCpus:
|
maximumCpus:
|
||||||
|
description: >-
|
||||||
|
Either maximumCpus or cpuTopology may be specified.
|
||||||
|
If currentCpus is greater than maximumCpus, the
|
||||||
|
latter is adjusted. Setting maximumCpus to 1 omits
|
||||||
|
the "-smp" options.
|
||||||
type: integer
|
type: integer
|
||||||
default: 4
|
default: 4
|
||||||
|
cpuTopology:
|
||||||
|
description: >-
|
||||||
|
The defaults (0) cause the corresponding property
|
||||||
|
to be omitted from the "-smp" option.
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
sockets:
|
||||||
|
type: integer
|
||||||
|
default: 0
|
||||||
|
diesPerSocket:
|
||||||
|
type: integer
|
||||||
|
default: 0
|
||||||
|
coresPerSocket:
|
||||||
|
type: integer
|
||||||
|
default: 0
|
||||||
|
threadsPerSocket:
|
||||||
|
type: integer
|
||||||
|
default: 0
|
||||||
currentCpus:
|
currentCpus:
|
||||||
type: integer
|
type: integer
|
||||||
default: 2
|
default: 2
|
||||||
|
|
@ -62,25 +110,73 @@ spec:
|
||||||
currentRam:
|
currentRam:
|
||||||
type: string
|
type: string
|
||||||
rtcBase:
|
rtcBase:
|
||||||
|
description: Passed to Qemu unmodified.
|
||||||
type: string
|
type: string
|
||||||
default: "utc"
|
default: "utc"
|
||||||
spicePort:
|
|
||||||
type: integer
|
|
||||||
networks:
|
networks:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
|
description: >-
|
||||||
|
Supported types are "tap" and "user" (for debugging).
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
bridge:
|
tap:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
name:
|
device:
|
||||||
|
description: The device to use.
|
||||||
|
type: string
|
||||||
|
default: "virtio-net"
|
||||||
|
bridge:
|
||||||
|
description: The bridge to attach to.
|
||||||
type: string
|
type: string
|
||||||
default: "br0"
|
default: "br0"
|
||||||
mac:
|
mac:
|
||||||
type: string
|
type: string
|
||||||
required:
|
user:
|
||||||
- name
|
type: object
|
||||||
|
properties:
|
||||||
|
net:
|
||||||
|
type: string
|
||||||
|
oneOf:
|
||||||
|
- properties:
|
||||||
|
tap:
|
||||||
|
user:
|
||||||
|
disks:
|
||||||
|
description: >-
|
||||||
|
Disks make persistent storage available. The
|
||||||
|
storage may be provided by a device on the
|
||||||
|
host (preallocated, e.g. a LV).
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
hostDevice:
|
||||||
|
type: string
|
||||||
|
bootindex:
|
||||||
|
type: integer
|
||||||
|
displays:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
spice:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
port:
|
||||||
|
type: integer
|
||||||
|
default: 5900
|
||||||
|
ticket:
|
||||||
|
type: string
|
||||||
|
streamingVideo:
|
||||||
|
type: string
|
||||||
|
usbRedirects:
|
||||||
|
type: integer
|
||||||
|
default: 2
|
||||||
|
oneOf:
|
||||||
|
- properties:
|
||||||
|
maximumCpus:
|
||||||
|
cpuTopology:
|
||||||
required:
|
required:
|
||||||
- vm
|
- vm
|
||||||
# either Namespaced or Cluster
|
# either Namespaced or Cluster
|
||||||
|
|
@ -91,4 +187,5 @@ spec:
|
||||||
# singular name to be used as an alias on the CLI and for display
|
# singular name to be used as an alias on the CLI and for display
|
||||||
singular: vm
|
singular: vm
|
||||||
# kind is normally the CamelCased singular type. Your resource manifests use this.
|
# kind is normally the CamelCased singular type. Your resource manifests use this.
|
||||||
kind: Vm
|
kind: VirtualMachine
|
||||||
|
listKind: VirtualMachineList
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,24 @@
|
||||||
image:
|
apiVersion: "vmoperator.jdrupes.org/v1"
|
||||||
repository: docker-registry.lan.mnl.de
|
kind: VirtualMachine
|
||||||
path: vmoperator/org.jdrupes.vmoperator.runner.qemu-arch
|
metadata:
|
||||||
pullPolicy: Always
|
name: test-vm
|
||||||
|
spec:
|
||||||
|
image:
|
||||||
|
repository: docker-registry.lan.mnl.de
|
||||||
|
path: vmoperator/org.jdrupes.vmoperator.runner.qemu-arch
|
||||||
|
pullPolicy: Always
|
||||||
|
|
||||||
vm:
|
vm:
|
||||||
maximumCpus: 4
|
maximumCpus: 4
|
||||||
currentCpus: 4
|
currentCpus: 4
|
||||||
maximumMemory: "8 GiB"
|
maximumRam: "8 GiB"
|
||||||
currentMemory: "4 GiB"
|
currentRam: "4 GiB"
|
||||||
spicePort: 5910
|
|
||||||
|
|
||||||
# Currently only block devices are supported as VM disks
|
networks:
|
||||||
disks:
|
- tap:
|
||||||
- device: /dev/vgmain/test-vm
|
mac: "00:16:3e:33:59:10"
|
||||||
size: 40Gi
|
disks:
|
||||||
networks:
|
- hostDevice: /dev/vgmain/test-vm
|
||||||
- bridge:
|
displays:
|
||||||
mac: "00:16:3e:33:59:10"
|
- spice:
|
||||||
|
port: 5910
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ dependencies {
|
||||||
|
|
||||||
implementation 'commons-cli:commons-cli:1.5.0'
|
implementation 'commons-cli:commons-cli:1.5.0'
|
||||||
implementation 'io.kubernetes:client-java:18.0.0'
|
implementation 'io.kubernetes:client-java:18.0.0'
|
||||||
|
|
||||||
|
runtimeOnly 'org.slf4j:slf4j-jdk14:[2.0.7,3)'
|
||||||
}
|
}
|
||||||
|
|
||||||
application {
|
application {
|
||||||
|
|
|
||||||
|
|
@ -18,17 +18,6 @@
|
||||||
|
|
||||||
package org.jdrupes.vmoperator.manager;
|
package org.jdrupes.vmoperator.manager;
|
||||||
|
|
||||||
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.V1Pod;
|
|
||||||
import io.kubernetes.client.openapi.models.V1PodList;
|
|
||||||
import io.kubernetes.client.util.Config;
|
|
||||||
import io.kubernetes.client.util.Yaml;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
|
@ -38,48 +27,38 @@ import org.jgrapes.core.Channel;
|
||||||
import org.jgrapes.core.Component;
|
import org.jgrapes.core.Component;
|
||||||
import org.jgrapes.core.Components;
|
import org.jgrapes.core.Components;
|
||||||
import org.jgrapes.core.annotation.Handler;
|
import org.jgrapes.core.annotation.Handler;
|
||||||
import org.jgrapes.core.events.Start;
|
|
||||||
import org.jgrapes.core.events.Stop;
|
import org.jgrapes.core.events.Stop;
|
||||||
import org.jgrapes.io.NioDispatcher;
|
import org.jgrapes.io.NioDispatcher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The application class.
|
||||||
|
*/
|
||||||
public class Manager extends Component {
|
public class Manager extends Component {
|
||||||
|
|
||||||
|
/** The Constant APP_NAME. */
|
||||||
public static final String APP_NAME = "vmoperator";
|
public static final String APP_NAME = "vmoperator";
|
||||||
private static Manager app;
|
private static Manager app;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new manager.
|
||||||
|
*
|
||||||
|
* @throws IOException Signals that an I/O exception has occurred.
|
||||||
|
*/
|
||||||
public Manager() throws IOException {
|
public Manager() throws IOException {
|
||||||
// Attach a general nio dispatcher
|
// Prepare component tree
|
||||||
attach(new NioDispatcher());
|
attach(new NioDispatcher());
|
||||||
|
attach(new VmDefinitionWatcher(channel()));
|
||||||
|
attach(new Reconciliator(channel()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle the start event.
|
* On stop.
|
||||||
*
|
*
|
||||||
* @param event the event
|
* @param event the event
|
||||||
* @throws IOException
|
|
||||||
* @throws ApiException
|
|
||||||
*/
|
*/
|
||||||
@Handler
|
@Handler(priority = -1000)
|
||||||
public void onStart(Start event) throws IOException, ApiException {
|
|
||||||
ApiClient client = Config.defaultClient();
|
|
||||||
Configuration.setDefaultApiClient(client);
|
|
||||||
|
|
||||||
CoreV1Api api = new CoreV1Api();
|
|
||||||
V1PodList list = api.listPodForAllNamespaces(null, null, null, null,
|
|
||||||
null, null, null, null, null, null);
|
|
||||||
for (V1Pod item : list.getItems()) {
|
|
||||||
System.out.println(item.getMetadata().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
// CustomObjectsApi cApi = new CustomObjectsApi();
|
|
||||||
// var obj = cApi.getNamespacedCustomObject("vmoperator.jdrupes.org", "v1",
|
|
||||||
// "default", "vms", "test");
|
|
||||||
// obj = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Handler
|
|
||||||
public void onStop(Stop event) {
|
public void onStop(Stop event) {
|
||||||
System.out.println("(Done.)");
|
logger.fine(() -> "Applictaion stopped.");
|
||||||
}
|
}
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
package org.jdrupes.vmoperator.manager;
|
||||||
|
|
||||||
|
import org.jgrapes.core.Channel;
|
||||||
|
import org.jgrapes.core.Component;
|
||||||
|
import org.jgrapes.core.annotation.Handler;
|
||||||
|
|
||||||
|
public class Reconciliator extends Component {
|
||||||
|
|
||||||
|
public Reconciliator(Channel componentChannel) {
|
||||||
|
super(componentChannel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Handler
|
||||||
|
public void onVmChanged(VmChangedEvent event, WatchChannel channel) {
|
||||||
|
event = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* JGrapes Event Driven Framework
|
||||||
|
* Copyright (C) 2018 Michael N. Lipp
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU 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 General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jdrupes.vmoperator.manager;
|
||||||
|
|
||||||
|
import io.kubernetes.client.openapi.models.V1ObjectMeta;
|
||||||
|
|
||||||
|
import org.jgrapes.core.Channel;
|
||||||
|
import org.jgrapes.core.Components;
|
||||||
|
import org.jgrapes.core.Event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates a change in a VM definition.
|
||||||
|
*/
|
||||||
|
public class VmChangedEvent extends Event<Void> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of change.
|
||||||
|
*/
|
||||||
|
public enum Type {
|
||||||
|
ADDED, MODIFIED, DELETED
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Type type;
|
||||||
|
private final V1ObjectMeta metadata;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new VM changed event.
|
||||||
|
*
|
||||||
|
* @param type the type
|
||||||
|
* @param metadata the metadata
|
||||||
|
*/
|
||||||
|
public VmChangedEvent(Type type, V1ObjectMeta metadata) {
|
||||||
|
this.type = type;
|
||||||
|
this.metadata = metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type.
|
||||||
|
*
|
||||||
|
* @return the type
|
||||||
|
*/
|
||||||
|
public Type type() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the metadata.
|
||||||
|
*
|
||||||
|
* @return the metadata
|
||||||
|
*/
|
||||||
|
public V1ObjectMeta metadata() {
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
builder.append(Components.objectName(this)).append(" [").append(type)
|
||||||
|
.append(' ').append(metadata.getName());
|
||||||
|
if (channels() != null) {
|
||||||
|
builder.append(", channels=");
|
||||||
|
builder.append(Channel.toString(channels()));
|
||||||
|
}
|
||||||
|
builder.append(']');
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,131 @@
|
||||||
|
/*
|
||||||
|
* JGrapes Event Driven Framework
|
||||||
|
* Copyright (C) 2018 Michael N. Lipp
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU 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 General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jdrupes.vmoperator.manager;
|
||||||
|
|
||||||
|
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;
|
||||||
|
import io.kubernetes.client.openapi.models.V1ObjectMeta;
|
||||||
|
import io.kubernetes.client.util.Config;
|
||||||
|
import io.kubernetes.client.util.Watch;
|
||||||
|
import java.io.IOException;
|
||||||
|
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 org.jgrapes.core.Channel;
|
||||||
|
import org.jgrapes.core.Component;
|
||||||
|
import org.jgrapes.core.annotation.Handler;
|
||||||
|
import org.jgrapes.core.events.Start;
|
||||||
|
import org.jgrapes.core.events.Stop;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Watches for changes of VM definitions.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
|
||||||
|
public class VmDefinitionWatcher 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 V1APIResource vmsCrd;
|
||||||
|
private String managedNamespace = "default";
|
||||||
|
private final Map<String, WatchChannel> channels
|
||||||
|
= new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new VM definition watcher.
|
||||||
|
*
|
||||||
|
* @param componentChannel the component channel
|
||||||
|
*/
|
||||||
|
public VmDefinitionWatcher(Channel componentChannel) {
|
||||||
|
super(componentChannel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the start event.
|
||||||
|
*
|
||||||
|
* @param event the event
|
||||||
|
* @throws IOException
|
||||||
|
* @throws ApiException
|
||||||
|
*/
|
||||||
|
@Handler
|
||||||
|
public void onStart(Start event) throws IOException, ApiException {
|
||||||
|
ApiClient client = Config.defaultClient();
|
||||||
|
Configuration.setDefaultApiClient(client);
|
||||||
|
|
||||||
|
// Get access to APIs
|
||||||
|
api = new CoreV1Api();
|
||||||
|
coa = new CustomObjectsApi();
|
||||||
|
|
||||||
|
// Derive all information from the CRD
|
||||||
|
var resources = coa.getAPIResources(CR_GROUP, CR_VERSION);
|
||||||
|
vmsCrd = resources.getResources().stream()
|
||||||
|
.filter(r -> CR_KIND.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);
|
||||||
|
new Thread(() -> {
|
||||||
|
try (Watch<V1Namespace> watch = Watch.createWatch(client,
|
||||||
|
call, new TypeToken<Watch.Response<V1Namespace>>() {
|
||||||
|
}.getType())) {
|
||||||
|
for (Watch.Response<V1Namespace> item : watch) {
|
||||||
|
handleCrEvent(item);
|
||||||
|
}
|
||||||
|
} catch (IOException | ApiException e) {
|
||||||
|
logger.log(Level.FINE, e, () -> "Probem while watching: "
|
||||||
|
+ e.getMessage());
|
||||||
|
}
|
||||||
|
fire(new Stop());
|
||||||
|
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleCrEvent(Watch.Response<V1Namespace> 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove VM channel when VM is deleted.
|
||||||
|
*
|
||||||
|
* @param event the event
|
||||||
|
* @param channel the channel
|
||||||
|
*/
|
||||||
|
@Handler(priority = -10_000)
|
||||||
|
public void onVmChanged(VmChangedEvent event, WatchChannel channel) {
|
||||||
|
if (event.type() == Type.DELETED) {
|
||||||
|
channels.remove(event.metadata().getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
* JGrapes Event Driven Framework
|
||||||
|
* Copyright (C) 2018 Michael N. Lipp
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU 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 General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jdrupes.vmoperator.manager;
|
||||||
|
|
||||||
|
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||||
|
import io.kubernetes.client.openapi.apis.CustomObjectsApi;
|
||||||
|
import org.jgrapes.core.Channel;
|
||||||
|
import org.jgrapes.core.EventPipeline;
|
||||||
|
import org.jgrapes.core.Subchannel.DefaultSubchannel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A subchannel used to send the events related to a specific
|
||||||
|
* VM.
|
||||||
|
*/
|
||||||
|
public class WatchChannel extends DefaultSubchannel {
|
||||||
|
|
||||||
|
private final EventPipeline pipeline;
|
||||||
|
private final CoreV1Api api;
|
||||||
|
private final CustomObjectsApi coa;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new watch channel.
|
||||||
|
*
|
||||||
|
* @param mainChannel the main channel
|
||||||
|
* @param pipeline the pipeline
|
||||||
|
*/
|
||||||
|
public WatchChannel(Channel mainChannel, EventPipeline pipeline,
|
||||||
|
CoreV1Api api, CustomObjectsApi coa) {
|
||||||
|
super(mainChannel);
|
||||||
|
this.pipeline = pipeline;
|
||||||
|
this.api = api;
|
||||||
|
this.coa = coa;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the pipeline.
|
||||||
|
*
|
||||||
|
* @return the event pipeline
|
||||||
|
*/
|
||||||
|
public EventPipeline pipeline() {
|
||||||
|
return pipeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the API object for invoking kubernetes functions.
|
||||||
|
*
|
||||||
|
* @return the API object
|
||||||
|
*/
|
||||||
|
public CoreV1Api api() {
|
||||||
|
return api;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the API object for invoking kubernetes custom object
|
||||||
|
* functions.
|
||||||
|
*
|
||||||
|
* @return the API object
|
||||||
|
*/
|
||||||
|
public CustomObjectsApi coa() {
|
||||||
|
return coa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
#
|
#
|
||||||
#Tue Jun 13 14:18:19 CEST 2023
|
#Fri Jul 21 17:39:36 CEST 2023
|
||||||
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
|
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
|
||||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
|
||||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
|
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
|
||||||
|
|
@ -22,12 +22,12 @@ org.eclipse.jdt.core.formatter.blank_lines_after_package=1
|
||||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
|
||||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
|
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
|
||||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
|
||||||
org.eclipse.jdt.core.formatter.comment.indent_root_tags=false
|
|
||||||
org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
|
org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
|
||||||
|
org.eclipse.jdt.core.formatter.comment.indent_root_tags=false
|
||||||
org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
|
org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
|
||||||
org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=false
|
org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=false
|
||||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
|
|
||||||
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
|
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
|
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
|
||||||
org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
|
org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
|
||||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
|
||||||
org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
|
org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
|
||||||
|
|
@ -43,8 +43,8 @@ org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invoc
|
||||||
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
|
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
|
||||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
|
||||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
|
||||||
org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=true
|
|
||||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
|
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
|
||||||
|
org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=true
|
||||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
|
||||||
org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
|
org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
|
||||||
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
|
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
|
||||||
|
|
@ -63,8 +63,8 @@ org.eclipse.jdt.core.formatter.alignment_for_type_parameters=16
|
||||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||||
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
|
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
|
||||||
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
|
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
|
||||||
org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
|
|
||||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
|
||||||
org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=false
|
org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=false
|
||||||
org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines
|
org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines
|
||||||
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
|
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue