Merge branch 'main' into testing
59
deploy/crds/vmpools-crd.yaml
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: vmpools.vmoperator.jdrupes.org
|
||||
spec:
|
||||
group: vmoperator.jdrupes.org
|
||||
# list of versions supported by this CustomResourceDefinition
|
||||
versions:
|
||||
- name: v1
|
||||
served: true
|
||||
storage: true
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
type: object
|
||||
properties:
|
||||
spec:
|
||||
type: object
|
||||
properties:
|
||||
permissions:
|
||||
type: array
|
||||
description: >-
|
||||
Defines permissions for accessing and manipulating the Pool.
|
||||
items:
|
||||
type: object
|
||||
description: >-
|
||||
Permissions can be granted to a user or to a role.
|
||||
oneOf:
|
||||
- required:
|
||||
- user
|
||||
- required:
|
||||
- role
|
||||
properties:
|
||||
user:
|
||||
type: string
|
||||
role:
|
||||
type: string
|
||||
may:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
enum:
|
||||
- start
|
||||
- stop
|
||||
- reset
|
||||
- accessConsole
|
||||
- "*"
|
||||
default: []
|
||||
required:
|
||||
- permissions
|
||||
# either Namespaced or Cluster
|
||||
scope: Namespaced
|
||||
names:
|
||||
# plural name to be used in the URL: /apis/<group>/<version>/<plural>
|
||||
plural: vmpools
|
||||
# singular name to be used as an alias on the CLI and for display
|
||||
singular: vmpool
|
||||
# kind is normally the CamelCased singular type. Your resource manifests use this.
|
||||
kind: VmPool
|
||||
listKind: VmPoolList
|
||||
|
|
@ -1019,6 +1019,13 @@ spec:
|
|||
- accessConsole
|
||||
- "*"
|
||||
default: []
|
||||
pools:
|
||||
type: array
|
||||
description: >-
|
||||
List of pools to which this VM belongs.
|
||||
items:
|
||||
type: string
|
||||
default: []
|
||||
loggingProperties:
|
||||
type: string
|
||||
description: >-
|
||||
|
|
|
|||
2
dev-example/.gitignore
vendored
|
|
@ -1 +1,3 @@
|
|||
/test-vm-ci.yaml
|
||||
/kubeconfig.yaml
|
||||
/crds/
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@
|
|||
"/Controller":
|
||||
namespace: vmop-dev
|
||||
"/Reconciler":
|
||||
runnerData:
|
||||
storageClassName: null
|
||||
runnerDataPvc:
|
||||
storageClassName: rook-cephfs
|
||||
loadBalancerService:
|
||||
labels:
|
||||
label1: label1
|
||||
|
|
@ -65,7 +65,7 @@
|
|||
other:
|
||||
- org.jgrapes.webconlet.oidclogin.LoginConlet
|
||||
"/ComponentCollector":
|
||||
"/VmViewer":
|
||||
"/VmAccess":
|
||||
displayResource:
|
||||
preferredIpVersion: ipv4
|
||||
syncPreviewsFor:
|
||||
|
|
|
|||
47
dev-example/gen-pool-vm-crds.sh
Executable file
|
|
@ -0,0 +1,47 @@
|
|||
#!/bin/bash
|
||||
|
||||
function usage() {
|
||||
cat >&2 <<EOF
|
||||
Usage: $0 [OPTION]... [TEMPLATE]
|
||||
Generate VM CRDs using TEMPLATE.
|
||||
|
||||
-c, --count Count of VMs to generate
|
||||
-d, --destination DIR Generate into given directory (default: ".")
|
||||
-h, --help Print this help
|
||||
-p, --prefix PREFIX Prefix for generated file (default: basename of template)
|
||||
EOF
|
||||
exit 1
|
||||
}
|
||||
|
||||
count=0
|
||||
destination=.
|
||||
template=""
|
||||
prefix=""
|
||||
|
||||
while [ "$#" -gt 0 ]; do
|
||||
case "$1" in
|
||||
-c|--count) shift; count=$1;;
|
||||
-d|--destination) shift; destination="$1";;
|
||||
-h|--help) shift; usage;;
|
||||
-p|--prefix) shift; prefix="$1";;
|
||||
-*) echo >&2 "Unknown option: $1"; exit 1;;
|
||||
*) template="$1";;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [ -z "$template" ]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
if [ "$count" = "0" ]; then
|
||||
exit 0
|
||||
fi
|
||||
for number in $(seq 1 $count); do
|
||||
if [ -z "$prefix" ]; then
|
||||
prefix=$(basename $template .tpl.yaml)
|
||||
fi
|
||||
name="$prefix$number"
|
||||
index=$(($number - 1))
|
||||
esh -o $destination/$name.yaml $template number=$number index=$index
|
||||
done
|
||||
|
|
@ -79,7 +79,7 @@ patches:
|
|||
other:
|
||||
- org.jgrapes.webconlet.locallogin.LoginConlet
|
||||
"/ComponentCollector":
|
||||
"/VmViewer":
|
||||
"/VmAccess":
|
||||
displayResource:
|
||||
preferredIpVersion: ipv4
|
||||
syncPreviewsFor:
|
||||
|
|
|
|||
10
dev-example/test-pool.yaml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
apiVersion: "vmoperator.jdrupes.org/v1"
|
||||
kind: VmPool
|
||||
metadata:
|
||||
namespace: vmop-dev
|
||||
name: test-vms
|
||||
spec:
|
||||
permissions:
|
||||
- user: admin
|
||||
may:
|
||||
- accessConsole
|
||||
10
dev-example/test-vm-snapshot.yaml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
apiVersion: snapshot.storage.k8s.io/v1
|
||||
kind: VolumeSnapshot
|
||||
metadata:
|
||||
namespace: vmop-dev
|
||||
name: test-vm-system-disk-snapshot
|
||||
spec:
|
||||
volumeSnapshotClassName: csi-rbdplugin-snapclass
|
||||
source:
|
||||
persistentVolumeClaimName: test-vm-system-disk
|
||||
70
dev-example/test-vm.tpl.yaml
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
apiVersion: "vmoperator.jdrupes.org/v1"
|
||||
kind: VirtualMachine
|
||||
metadata:
|
||||
namespace: vmop-dev
|
||||
name: test-vm<%= ${number} %>
|
||||
annotations:
|
||||
argocd.argoproj.io/sync-wave: "20"
|
||||
|
||||
spec:
|
||||
image:
|
||||
# repository: docker-registry.lan.mnl.de
|
||||
# path: vmoperator/org.jdrupes.vmoperator.runner.qemu-arch
|
||||
# pullPolicy: Always
|
||||
# repository: ghcr.io
|
||||
# path: mnlipp/org.jdrupes.vmoperator.runner.qemu-alpine
|
||||
# version: "3.0.0"
|
||||
source: registry.mnl.de/org/jdrupes/vm-operator/org.jdrupes.vmoperator.runner.qemu-arch:testing
|
||||
pullPolicy: Always
|
||||
|
||||
permissions:
|
||||
- role: admin
|
||||
may:
|
||||
- "*"
|
||||
- user: test
|
||||
may:
|
||||
- accessConsole
|
||||
|
||||
guestShutdownStops: true
|
||||
|
||||
cloudInit:
|
||||
metaData: {}
|
||||
|
||||
pools:
|
||||
- test-vms
|
||||
|
||||
vm:
|
||||
# state: Running
|
||||
bootMenu: true
|
||||
maximumCpus: 4
|
||||
currentCpus: 2
|
||||
maximumRam: 4Gi
|
||||
currentRam: 3Gi
|
||||
|
||||
networks:
|
||||
# No bridge on TC1
|
||||
# - tap: {}
|
||||
- user: {}
|
||||
|
||||
disks:
|
||||
- volumeClaimTemplate:
|
||||
metadata:
|
||||
name: system
|
||||
spec:
|
||||
storageClassName: ceph-rbd3slow
|
||||
dataSource:
|
||||
name: test-vm-system-disk-snapshot
|
||||
kind: VolumeSnapshot
|
||||
apiGroup: snapshot.storage.k8s.io
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 40Gi
|
||||
- cdrom:
|
||||
image: ""
|
||||
# image: https://download.fedoraproject.org/pub/fedora/linux/releases/38/Workstation/x86_64/iso/Fedora-Workstation-Live-x86_64-38-1.6.iso
|
||||
|
||||
display:
|
||||
spice:
|
||||
port: <%= $((5910 + number)) %>
|
||||
|
|
@ -38,4 +38,7 @@ public class Constants {
|
|||
|
||||
/** The Constant VM_OP_KIND_VM. */
|
||||
public static final String VM_OP_KIND_VM = "VirtualMachine";
|
||||
|
||||
/** The Constant VM_OP_KIND_VM_POOL. */
|
||||
public static final String VM_OP_KIND_VM_POOL = "VmPool";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
* VM-Operator
|
||||
* Copyright (C) 2024 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.common;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import org.jdrupes.vmoperator.util.DataPath;
|
||||
|
||||
/**
|
||||
* Represents a VM pool.
|
||||
*/
|
||||
@SuppressWarnings({ "PMD.DataClass" })
|
||||
public class VmPool {
|
||||
|
||||
private String name;
|
||||
private List<Grant> permissions = Collections.emptyList();
|
||||
private final Set<String> vms
|
||||
= Collections.synchronizedSet(new HashSet<>());
|
||||
|
||||
/**
|
||||
* Returns the name.
|
||||
*
|
||||
* @return the name
|
||||
*/
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name.
|
||||
*
|
||||
* @param name the name to set
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the permissions
|
||||
*/
|
||||
public List<Grant> permissions() {
|
||||
return permissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the permissions.
|
||||
*
|
||||
* @param permissions the permissions to set
|
||||
*/
|
||||
public void setPermissions(List<Grant> permissions) {
|
||||
this.permissions = permissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the VM names.
|
||||
*
|
||||
* @return the vms
|
||||
*/
|
||||
public Set<String> vms() {
|
||||
return vms;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("PMD.AvoidLiteralsInIfCondition")
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder(50);
|
||||
builder.append("VmPool [name=").append(name).append(", permissions=")
|
||||
.append(permissions).append(", vms=");
|
||||
if (vms.size() <= 3) {
|
||||
builder.append(vms);
|
||||
} else {
|
||||
builder.append('[');
|
||||
vms.stream().limit(3).map(s -> s + ",").forEach(builder::append);
|
||||
builder.append("...]");
|
||||
}
|
||||
builder.append(']');
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect all permissions for the given user with the given roles.
|
||||
*
|
||||
* @param user the user
|
||||
* @param roles the roles
|
||||
* @return the sets the
|
||||
*/
|
||||
public Set<Permission> permissionsFor(String user,
|
||||
Collection<String> roles) {
|
||||
return permissions.stream()
|
||||
.filter(g -> DataPath.get(g, "user").map(u -> u.equals(user))
|
||||
.orElse(false)
|
||||
|| DataPath.get(g, "role").map(roles::contains).orElse(false))
|
||||
.map(g -> DataPath.<Set<Permission>> get(g, "may")
|
||||
.orElse(Collections.emptySet()).stream())
|
||||
.flatMap(Function.identity()).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
/**
|
||||
* A permission grant to a user or role.
|
||||
*
|
||||
* @param user the user
|
||||
* @param role the role
|
||||
* @param may the may
|
||||
*/
|
||||
public record Grant(String user, String role, Set<Permission> may) {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
if (user != null) {
|
||||
builder.append("User ").append(user);
|
||||
} else {
|
||||
builder.append("Role ").append(role);
|
||||
}
|
||||
builder.append(" may=").append(may).append(']');
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Permissions for accessing and manipulating the pool.
|
||||
*/
|
||||
public enum Permission {
|
||||
START("start"), STOP("stop"), RESET("reset"),
|
||||
ACCESS_CONSOLE("accessConsole");
|
||||
|
||||
@SuppressWarnings("PMD.UseConcurrentHashMap")
|
||||
private static Map<String, Permission> reprs = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (var value : EnumSet.allOf(Permission.class)) {
|
||||
reprs.put(value.repr, value);
|
||||
}
|
||||
}
|
||||
|
||||
private final String repr;
|
||||
|
||||
Permission(String repr) {
|
||||
this.repr = repr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create permission from representation in CRD.
|
||||
*
|
||||
* @param value the value
|
||||
* @return the permission
|
||||
*/
|
||||
@SuppressWarnings("PMD.AvoidLiteralsInIfCondition")
|
||||
public static Set<Permission> parse(String value) {
|
||||
if ("*".equals(value)) {
|
||||
return EnumSet.allOf(Permission.class);
|
||||
}
|
||||
return Set.of(reprs.get(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return repr;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.jdrupes.vmoperator.manager.events;
|
||||
|
||||
import org.jdrupes.vmoperator.common.VmPool;
|
||||
import org.jgrapes.core.Channel;
|
||||
import org.jgrapes.core.Components;
|
||||
import org.jgrapes.core.Event;
|
||||
|
||||
/**
|
||||
* Indicates a change in a pool configuration.
|
||||
*/
|
||||
@SuppressWarnings("PMD.DataClass")
|
||||
public class VmPoolChanged extends Event<Void> {
|
||||
|
||||
private final VmPool vmPool;
|
||||
private final boolean deleted;
|
||||
|
||||
/**
|
||||
* Instantiates a new VM changed event.
|
||||
*
|
||||
* @param pool the pool
|
||||
* @param deleted true, if the pool was deleted
|
||||
*/
|
||||
public VmPoolChanged(VmPool pool, boolean deleted) {
|
||||
vmPool = pool;
|
||||
this.deleted = deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new VM changed event for an existing pool.
|
||||
*
|
||||
* @param pool the pool
|
||||
*/
|
||||
public VmPoolChanged(VmPool pool) {
|
||||
this(pool, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the VM pool.
|
||||
*
|
||||
* @return the vm pool
|
||||
*/
|
||||
public VmPool vmPool() {
|
||||
return vmPool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pool has been deleted.
|
||||
*
|
||||
* @return true, if successful
|
||||
*/
|
||||
public boolean deleted() {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder(30);
|
||||
builder.append(Components.objectName(this))
|
||||
.append(" [");
|
||||
if (deleted) {
|
||||
builder.append("Deleted: ");
|
||||
}
|
||||
builder.append(vmPool);
|
||||
if (channels() != null) {
|
||||
builder.append(", channels=").append(Channel.toString(channels()));
|
||||
}
|
||||
builder.append(']');
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -31,8 +31,8 @@ dependencies {
|
|||
runtimeOnly 'org.slf4j:slf4j-jdk14:[2.0.7,3)'
|
||||
runtimeOnly 'org.apache.logging.log4j:log4j-to-jul:2.20.0'
|
||||
|
||||
runtimeOnly project(':org.jdrupes.vmoperator.vmconlet')
|
||||
runtimeOnly project(':org.jdrupes.vmoperator.vmviewer')
|
||||
runtimeOnly project(':org.jdrupes.vmoperator.vmmgmt')
|
||||
runtimeOnly project(':org.jdrupes.vmoperator.vmaccess')
|
||||
}
|
||||
|
||||
application {
|
||||
|
|
|
|||
|
|
@ -246,7 +246,9 @@ public abstract class AbstractMonitor<O extends KubernetesObject,
|
|||
}
|
||||
|
||||
/**
|
||||
* Handle an observed change.
|
||||
* Handle an observed change. The method is invoked by the observer
|
||||
* thread(s). It is the responsibility of the implementing class to
|
||||
* fire derived events on the appropriate event pipeline.
|
||||
*
|
||||
* @param client the client
|
||||
* @param change the change
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ public class Controller extends Component {
|
|||
// to access the VM's console. Might change in the future.
|
||||
// attach(new ServiceMonitor(channel()).channelManager(chanMgr));
|
||||
attach(new Reconciler(channel()));
|
||||
attach(new PoolManager(channel()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
* VM-Operator
|
||||
* Copyright (C) 2023,2024 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;
|
||||
|
||||
import io.kubernetes.client.openapi.ApiException;
|
||||
import io.kubernetes.client.openapi.models.V1ObjectMeta;
|
||||
import io.kubernetes.client.util.Watch;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import static org.jdrupes.vmoperator.common.Constants.VM_OP_GROUP;
|
||||
import org.jdrupes.vmoperator.common.K8s;
|
||||
import org.jdrupes.vmoperator.common.K8sClient;
|
||||
import org.jdrupes.vmoperator.common.K8sDynamicModel;
|
||||
import org.jdrupes.vmoperator.common.K8sDynamicModels;
|
||||
import org.jdrupes.vmoperator.common.K8sDynamicStub;
|
||||
import org.jdrupes.vmoperator.common.K8sObserver.ResponseType;
|
||||
import org.jdrupes.vmoperator.common.VmPool;
|
||||
import static org.jdrupes.vmoperator.manager.Constants.VM_OP_KIND_VM_POOL;
|
||||
import org.jdrupes.vmoperator.manager.events.VmDefChanged;
|
||||
import org.jdrupes.vmoperator.manager.events.VmPoolChanged;
|
||||
import org.jdrupes.vmoperator.util.GsonPtr;
|
||||
import org.jgrapes.core.Channel;
|
||||
import org.jgrapes.core.EventPipeline;
|
||||
import org.jgrapes.core.annotation.Handler;
|
||||
import org.jgrapes.core.events.Attached;
|
||||
|
||||
/**
|
||||
* Watches for changes of VM pools. Reports the changes using
|
||||
* {@link VmPoolChanged} events fired on a special pipeline to
|
||||
* avoid concurrent change informations.
|
||||
*/
|
||||
@SuppressWarnings({ "PMD.DataflowAnomalyAnalysis", "PMD.ExcessiveImports" })
|
||||
public class PoolManager extends
|
||||
AbstractMonitor<K8sDynamicModel, K8sDynamicModels, Channel> {
|
||||
|
||||
private final ReentrantLock pendingLock = new ReentrantLock();
|
||||
private final Map<String, Set<String>> pending = new ConcurrentHashMap<>();
|
||||
private final Map<String, VmPool> pools = new ConcurrentHashMap<>();
|
||||
private EventPipeline poolPipeline;
|
||||
|
||||
/**
|
||||
* Instantiates a new VM pool manager.
|
||||
*
|
||||
* @param componentChannel the component channel
|
||||
* @param channelManager the channel manager
|
||||
*/
|
||||
public PoolManager(Channel componentChannel) {
|
||||
super(componentChannel, K8sDynamicModel.class,
|
||||
K8sDynamicModels.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* On attached.
|
||||
*
|
||||
* @param event the event
|
||||
*/
|
||||
@Handler
|
||||
@SuppressWarnings("PMD.CompareObjectsWithEquals")
|
||||
public void onAttached(Attached event) {
|
||||
if (event.node() == this) {
|
||||
poolPipeline = newEventPipeline();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void prepareMonitoring() throws IOException, ApiException {
|
||||
client(new K8sClient());
|
||||
|
||||
// Get all our API versions
|
||||
var ctx = K8s.context(client(), VM_OP_GROUP, "", VM_OP_KIND_VM_POOL);
|
||||
if (ctx.isEmpty()) {
|
||||
logger.severe(() -> "Cannot get CRD context.");
|
||||
return;
|
||||
}
|
||||
context(ctx.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleChange(K8sClient client,
|
||||
Watch.Response<K8sDynamicModel> response) {
|
||||
|
||||
var type = ResponseType.valueOf(response.type);
|
||||
var poolName = response.object.metadata().getName();
|
||||
|
||||
// When pool is deleted, save VMs in pending
|
||||
if (type == ResponseType.DELETED) {
|
||||
try {
|
||||
pendingLock.lock();
|
||||
Optional.ofNullable(pools.get(poolName)).ifPresent(
|
||||
p -> {
|
||||
pending.computeIfAbsent(poolName, k -> Collections
|
||||
.synchronizedSet(new HashSet<>())).addAll(p.vms());
|
||||
pools.remove(poolName);
|
||||
poolPipeline.fire(new VmPoolChanged(p, true));
|
||||
});
|
||||
} finally {
|
||||
pendingLock.unlock();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Get full definition
|
||||
var poolModel = response.object;
|
||||
if (poolModel.data() == null) {
|
||||
// ADDED event does not provide data, see
|
||||
// https://github.com/kubernetes-client/java/issues/3215
|
||||
try {
|
||||
poolModel = K8sDynamicStub.get(client(), context(), namespace(),
|
||||
poolModel.metadata().getName()).model().orElse(null);
|
||||
} catch (ApiException e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert to VM pool
|
||||
var vmPool = client().getJSON().getGson().fromJson(
|
||||
GsonPtr.to(poolModel.data()).to("spec").get(),
|
||||
VmPool.class);
|
||||
V1ObjectMeta metadata = response.object.getMetadata();
|
||||
vmPool.setName(metadata.getName());
|
||||
|
||||
// If modified, merge changes
|
||||
if (type == ResponseType.MODIFIED && pools.containsKey(poolName)) {
|
||||
pools.get(poolName).setPermissions(vmPool.permissions());
|
||||
return;
|
||||
}
|
||||
|
||||
// Add new pool
|
||||
try {
|
||||
pendingLock.lock();
|
||||
Optional.ofNullable(pending.get(poolName)).ifPresent(s -> {
|
||||
vmPool.vms().addAll(s);
|
||||
});
|
||||
pending.remove(poolName);
|
||||
pools.put(poolName, vmPool);
|
||||
poolPipeline.fire(new VmPoolChanged(vmPool));
|
||||
} finally {
|
||||
pendingLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Track VM definition changes.
|
||||
*
|
||||
* @param event the event
|
||||
*/
|
||||
@Handler
|
||||
public void onVmDefChanged(VmDefChanged event) {
|
||||
String vmName = event.vmDefinition().name();
|
||||
switch (event.type()) {
|
||||
case ADDED:
|
||||
try {
|
||||
pendingLock.lock();
|
||||
event.vmDefinition().<List<String>> fromSpec("pools")
|
||||
.orElse(Collections.emptyList()).stream().forEach(p -> {
|
||||
if (pools.containsKey(p)) {
|
||||
pools.get(p).vms().add(vmName);
|
||||
} else {
|
||||
pending.computeIfAbsent(p, k -> Collections
|
||||
.synchronizedSet(new HashSet<>())).add(vmName);
|
||||
}
|
||||
poolPipeline.fire(new VmPoolChanged(pools.get(p)));
|
||||
});
|
||||
} finally {
|
||||
pendingLock.unlock();
|
||||
}
|
||||
break;
|
||||
case DELETED:
|
||||
try {
|
||||
pendingLock.lock();
|
||||
pools.values().stream().forEach(p -> {
|
||||
if (p.vms().remove(vmName)) {
|
||||
poolPipeline.fire(new VmPoolChanged(p));
|
||||
}
|
||||
});
|
||||
// Should not be necessary, but just in case
|
||||
pending.values().stream().forEach(s -> s.remove(vmName));
|
||||
} finally {
|
||||
pendingLock.unlock();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
org.jdrupes.vmoperator.vmaccess.VmAccessFactory
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
<div
|
||||
class="jdrupes-vmoperator-vmviewer jdrupes-vmoperator-vmviewer-confirm-reset">
|
||||
class="jdrupes-vmoperator-vmaccess jdrupes-vmoperator-vmaccess-confirm-reset">
|
||||
<p>${_("confirmResetMsg")}</p>
|
||||
<p>
|
||||
<span role="button" tabindex="0" class="svg-icon"
|
||||
onclick="orgJDrupesVmOperatorVmViewer.confirmReset('${conletType}', '${conletId}')">
|
||||
onclick="orgJDrupesVmOperatorVmAccess.confirmReset('${conletType}', '${conletId}')">
|
||||
<svg viewBox="0 0 1541.33 1535.5083">
|
||||
<path d="m 0,127.9968 v 448 c 0,35 29,64 64,64 h 448 c 35,0 64,-29 64,-64 0,-17 -6.92831,-33.07213 -19,-45 C 264.23058,241.7154 337.19508,314.89599 109,82.996795 c -11.999999,-12 -28,-19 -45,-19 -35,0 -64,29 -64,64.000005 z" />
|
||||
<path d="m 772.97656,1535.5046 c 117.57061,0.3623 236.06134,-26.2848 345.77544,-81.4687 292.5708,-147.1572 459.8088,-465.37411 415.5214,-790.12504 C 1489.9861,339.15993 1243.597,77.463924 922.29883,14.342498 601.00067,-48.778928 274.05699,100.37563 110.62891,384.39133 c -34.855139,60.57216 -14.006492,137.9313 46.5664,172.78516 60.57172,34.85381 137.92941,14.00532 172.78321,-46.56641 109.97944,-191.12927 327.69604,-290.34657 543.53515,-247.94336 215.83913,42.40321 380.18953,216.77543 410.00973,435.44141 29.8203,218.66598 -81.8657,430.94957 -278.4863,529.84567 -196.6206,98.8962 -432.84043,61.8202 -589.90233,-92.6777 -24.91016,-24.5038 -85.48587,-83.3326 -119.02246,-52.9832 -24.01114,21.7292 -35.41741,29.5454 -59.9209,54.4559 -24.50381,24.9102 -35.33636,36.9034 -57.54543,60.4713 -38.1335,40.4667 34.10761,93.9685 59.01808,118.472 145.96311,143.5803 339.36149,219.2087 535.3125,219.8125 z"/>
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
<div title="${_("conletName")}"
|
||||
class="jdrupes-vmoperator-vmviewer jdrupes-vmoperator-vmviewer-edit"
|
||||
data-jgwc-on-load="orgJDrupesVmOperatorVmViewer.initEdit"
|
||||
data-jgwc-on-action="orgJDrupesVmOperatorVmViewer.applyEdit"
|
||||
class="jdrupes-vmoperator-vmaccess jdrupes-vmoperator-vmaccess-edit"
|
||||
data-jgwc-on-load="orgJDrupesVmOperatorVmAccess.initEdit"
|
||||
data-jgwc-on-action="orgJDrupesVmOperatorVmAccess.applyEdit"
|
||||
data-jgwc-on-unload="JGConsole.jgwc.unmountVueApps">
|
||||
<form :id="formId" ref="formDom" onsubmit="return false;">
|
||||
<section>
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
<div
|
||||
class="jdrupes-vmoperator-vmviewer jdrupes-vmoperator-vmviewer-preview"
|
||||
class="jdrupes-vmoperator-vmaccess jdrupes-vmoperator-vmaccess-preview"
|
||||
data-conlet-grid-rows="2" data-conlet-grid-columns="2"
|
||||
data-jgwc-on-load="orgJDrupesVmOperatorVmViewer.initPreview"
|
||||
data-jgwc-on-load="orgJDrupesVmOperatorVmAccess.initPreview"
|
||||
data-jgwc-on-unload="JGConsole.jgwc.unmountVueApps"
|
||||
data-conlet-resource-base="${conletResource('')}">
|
||||
</div>
|
||||
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
|
|
@ -1,4 +1,4 @@
|
|||
conletName = VM Console
|
||||
conletName = VM Access
|
||||
|
||||
okayLabel = Apply and Close
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
conletName = VM-Konsole
|
||||
conletName = VM-Zugriff
|
||||
|
||||
okayLabel = Anwenden und Schließen
|
||||
Select\ VM = VM auswählen
|
||||
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
|
|
@ -1,8 +1,8 @@
|
|||
import typescript from 'rollup-plugin-typescript2';
|
||||
import postcss from 'rollup-plugin-postcss';
|
||||
|
||||
let packagePath = "org/jdrupes/vmoperator/vmviewer";
|
||||
let baseName = "VmViewer"
|
||||
let packagePath = "org/jdrupes/vmoperator/vmaccess";
|
||||
let baseName = "VmAccess"
|
||||
let module = "build/generated/resources/" + packagePath
|
||||
+ "/" + baseName + "-functions.js";
|
||||
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.jdrupes.vmoperator.vmviewer;
|
||||
package org.jdrupes.vmoperator.vmaccess;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonGetter;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
|
@ -89,7 +89,7 @@ import org.jgrapes.webconsole.base.events.UpdateConletType;
|
|||
import org.jgrapes.webconsole.base.freemarker.FreeMarkerConlet;
|
||||
|
||||
/**
|
||||
* The Class VmViewer. The component supports the following
|
||||
* The Class {@link VmAccess}. The component supports the following
|
||||
* configuration properties:
|
||||
*
|
||||
* * `displayResource`: a map with the following entries:
|
||||
|
|
@ -107,13 +107,13 @@ import org.jgrapes.webconsole.base.freemarker.FreeMarkerConlet;
|
|||
*/
|
||||
@SuppressWarnings({ "PMD.DataflowAnomalyAnalysis", "PMD.ExcessiveImports",
|
||||
"PMD.CouplingBetweenObjects", "PMD.GodClass", "PMD.TooManyMethods" })
|
||||
public class VmViewer extends FreeMarkerConlet<VmViewer.ViewerModel> {
|
||||
public class VmAccess extends FreeMarkerConlet<VmAccess.ViewerModel> {
|
||||
|
||||
private static final String VM_NAME_PROPERTY = "vmName";
|
||||
private static final String RENDERED
|
||||
= VmViewer.class.getName() + ".rendered";
|
||||
= VmAccess.class.getName() + ".rendered";
|
||||
private static final String PENDING
|
||||
= VmViewer.class.getName() + ".pending";
|
||||
= VmAccess.class.getName() + ".pending";
|
||||
private static final Set<RenderMode> MODES = RenderMode.asSet(
|
||||
RenderMode.Preview, RenderMode.Edit);
|
||||
private static final Set<RenderMode> MODES_FOR_GENERATED = RenderMode.asSet(
|
||||
|
|
@ -140,7 +140,7 @@ public class VmViewer extends FreeMarkerConlet<VmViewer.ViewerModel> {
|
|||
* on by default and that {@link Manager#fire(Event, Channel...)}
|
||||
* sends the event to
|
||||
*/
|
||||
public VmViewer(Channel componentChannel) {
|
||||
public VmAccess(Channel componentChannel) {
|
||||
super(componentChannel);
|
||||
}
|
||||
|
||||
|
|
@ -152,44 +152,57 @@ public class VmViewer extends FreeMarkerConlet<VmViewer.ViewerModel> {
|
|||
@SuppressWarnings({ "unchecked", "PMD.AvoidDuplicateLiterals" })
|
||||
@Handler
|
||||
public void onConfigurationUpdate(ConfigurationUpdate event) {
|
||||
event.structured(componentPath()).ifPresent(c -> {
|
||||
try {
|
||||
var dispRes = (Map<String, Object>) c
|
||||
.getOrDefault("displayResource", Collections.emptyMap());
|
||||
switch ((String) dispRes.getOrDefault("preferredIpVersion",
|
||||
"")) {
|
||||
case "ipv6":
|
||||
preferredIpVersion = Inet6Address.class;
|
||||
break;
|
||||
case "ipv4":
|
||||
default:
|
||||
preferredIpVersion = Inet4Address.class;
|
||||
break;
|
||||
event.structured(componentPath())
|
||||
.or(() -> {
|
||||
var oldConfig = event.structured("/Manager/GuiHttpServer"
|
||||
+ "/ConsoleWeblet/WebConsole/ComponentCollector/VmViewer");
|
||||
if (oldConfig.isPresent()) {
|
||||
logger.warning(() -> "Using configuration with old "
|
||||
+ "component name \"VmViewer\", please update to "
|
||||
+ "\"VmAccess\"");
|
||||
}
|
||||
return oldConfig;
|
||||
})
|
||||
.ifPresent(c -> {
|
||||
try {
|
||||
var dispRes = (Map<String, Object>) c
|
||||
.getOrDefault("displayResource",
|
||||
Collections.emptyMap());
|
||||
switch ((String) dispRes.getOrDefault("preferredIpVersion",
|
||||
"")) {
|
||||
case "ipv6":
|
||||
preferredIpVersion = Inet6Address.class;
|
||||
break;
|
||||
case "ipv4":
|
||||
default:
|
||||
preferredIpVersion = Inet4Address.class;
|
||||
break;
|
||||
}
|
||||
|
||||
// Delete connection file
|
||||
deleteConnectionFile
|
||||
= Optional.ofNullable(c.get("deleteConnectionFile"))
|
||||
.filter(v -> v instanceof String).map(v -> (String) v)
|
||||
.map(Boolean::parseBoolean).orElse(true);
|
||||
// Delete connection file
|
||||
deleteConnectionFile
|
||||
= Optional.ofNullable(c.get("deleteConnectionFile"))
|
||||
.filter(v -> v instanceof String)
|
||||
.map(v -> (String) v)
|
||||
.map(Boolean::parseBoolean).orElse(true);
|
||||
|
||||
// Users or roles for which previews should be synchronized
|
||||
syncUsers = ((List<Map<String, String>>) c.getOrDefault(
|
||||
"syncPreviewsFor", Collections.emptyList())).stream()
|
||||
.map(m -> m.get("user"))
|
||||
.filter(s -> s != null).collect(Collectors.toSet());
|
||||
logger.finest(() -> "Syncing previews for users: "
|
||||
+ syncUsers.toString());
|
||||
syncRoles = ((List<Map<String, String>>) c.getOrDefault(
|
||||
"syncPreviewsFor", Collections.emptyList())).stream()
|
||||
.map(m -> m.get("role"))
|
||||
.filter(s -> s != null).collect(Collectors.toSet());
|
||||
logger.finest(() -> "Syncing previews for roles: "
|
||||
+ syncRoles.toString());
|
||||
} catch (ClassCastException e) {
|
||||
logger.config("Malformed configuration: " + e.getMessage());
|
||||
}
|
||||
});
|
||||
// Users or roles for which previews should be synchronized
|
||||
syncUsers = ((List<Map<String, String>>) c.getOrDefault(
|
||||
"syncPreviewsFor", Collections.emptyList())).stream()
|
||||
.map(m -> m.get("user"))
|
||||
.filter(s -> s != null).collect(Collectors.toSet());
|
||||
logger.finest(() -> "Syncing previews for users: "
|
||||
+ syncUsers.toString());
|
||||
syncRoles = ((List<Map<String, String>>) c.getOrDefault(
|
||||
"syncPreviewsFor", Collections.emptyList())).stream()
|
||||
.map(m -> m.get("role"))
|
||||
.filter(s -> s != null).collect(Collectors.toSet());
|
||||
logger.finest(() -> "Syncing previews for roles: "
|
||||
+ syncRoles.toString());
|
||||
} catch (ClassCastException e) {
|
||||
logger.config("Malformed configuration: " + e.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean syncPreviews(Session session) {
|
||||
|
|
@ -222,7 +235,7 @@ public class VmViewer extends FreeMarkerConlet<VmViewer.ViewerModel> {
|
|||
.addRenderMode(RenderMode.Preview)
|
||||
.addScript(new ScriptResource().setScriptType("module")
|
||||
.setScriptUri(event.renderSupport().conletResource(
|
||||
type(), "VmViewer-functions.js"))));
|
||||
type(), "VmAccess-functions.js"))));
|
||||
channel.session().put(RENDERED, new HashSet<>());
|
||||
}
|
||||
|
||||
|
|
@ -259,7 +272,7 @@ public class VmViewer extends FreeMarkerConlet<VmViewer.ViewerModel> {
|
|||
foundMissing = true;
|
||||
}
|
||||
fire(new AddConletRequest(event.event().event().renderSupport(),
|
||||
VmViewer.class.getName(),
|
||||
VmAccess.class.getName(),
|
||||
RenderMode.asSet(RenderMode.Preview))
|
||||
.addProperty(VM_NAME_PROPERTY, vmName),
|
||||
connection);
|
||||
|
|
@ -283,7 +296,7 @@ public class VmViewer extends FreeMarkerConlet<VmViewer.ViewerModel> {
|
|||
private String storagePath(Session session, String conletId) {
|
||||
return "/" + WebConsoleUtils.userFromSession(session)
|
||||
.map(ConsoleUser::getName).orElse("")
|
||||
+ "/" + VmViewer.class.getName() + "/" + conletId;
|
||||
+ "/" + VmAccess.class.getName() + "/" + conletId;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -365,7 +378,7 @@ public class VmViewer extends FreeMarkerConlet<VmViewer.ViewerModel> {
|
|||
|
||||
// Render
|
||||
Template tpl
|
||||
= freemarkerConfig().getTemplate("VmViewer-preview.ftl.html");
|
||||
= freemarkerConfig().getTemplate("VmAccess-preview.ftl.html");
|
||||
channel.respond(new RenderConlet(type(), conletId,
|
||||
processTemplate(event, tpl,
|
||||
fmModel(event, channel, conletId, model)))
|
||||
|
|
@ -383,7 +396,7 @@ public class VmViewer extends FreeMarkerConlet<VmViewer.ViewerModel> {
|
|||
}
|
||||
if (event.renderAs().contains(RenderMode.Edit)) {
|
||||
Template tpl = freemarkerConfig()
|
||||
.getTemplate("VmViewer-edit.ftl.html");
|
||||
.getTemplate("VmAccess-edit.ftl.html");
|
||||
var fmModel = fmModel(event, channel, conletId, model);
|
||||
fmModel.put("vmNames", accessibleVms(channel));
|
||||
channel.respond(new OpenModalDialog(type(), conletId,
|
||||
|
|
@ -633,7 +646,7 @@ public class VmViewer extends FreeMarkerConlet<VmViewer.ViewerModel> {
|
|||
ResourceBundle resourceBundle) throws TemplateNotFoundException,
|
||||
MalformedTemplateNameException, ParseException, IOException {
|
||||
Template tpl = freemarkerConfig()
|
||||
.getTemplate("VmViewer-confirmReset.ftl.html");
|
||||
.getTemplate("VmAccess-confirmReset.ftl.html");
|
||||
channel.respond(new OpenModalDialog(type(), model.getConletId(),
|
||||
processTemplate(event, tpl,
|
||||
fmModel(event, channel, model.getConletId(), model)))
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.jdrupes.vmoperator.vmviewer;
|
||||
package org.jdrupes.vmoperator.vmaccess;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
|
@ -25,9 +25,9 @@ import org.jgrapes.core.ComponentType;
|
|||
import org.jgrapes.webconsole.base.ConletComponentFactory;
|
||||
|
||||
/**
|
||||
* The factory service for {@link VmViewer}s.
|
||||
* The factory service for {@link VmAccess}s.
|
||||
*/
|
||||
public class VmViewerFactory implements ConletComponentFactory {
|
||||
public class VmAccessFactory implements ConletComponentFactory {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
|
|
@ -36,7 +36,7 @@ public class VmViewerFactory implements ConletComponentFactory {
|
|||
*/
|
||||
@Override
|
||||
public Class<? extends ComponentType> componentType() {
|
||||
return VmViewer.class;
|
||||
return VmAccess.class;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -48,7 +48,7 @@ public class VmViewerFactory implements ConletComponentFactory {
|
|||
@Override
|
||||
public Optional<ComponentType> create(Channel componentChannel,
|
||||
Map<?, ?> properties) {
|
||||
return Optional.of(new VmViewer(componentChannel));
|
||||
return Optional.of(new VmAccess(componentChannel));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -24,12 +24,12 @@ import JgwcPlugin, { JGWC } from "jgwc";
|
|||
import { provideApi, getApi } from "aash-plugin";
|
||||
import l10nBundles from "l10nBundles";
|
||||
|
||||
import "./VmViewer-style.scss";
|
||||
import "./VmAccess-style.scss";
|
||||
|
||||
// For global access
|
||||
declare global {
|
||||
interface Window {
|
||||
orgJDrupesVmOperatorVmViewer: {
|
||||
orgJDrupesVmOperatorVmAccess: {
|
||||
initPreview?: (previewDom: HTMLElement, isUpdate: boolean) => void,
|
||||
initEdit?: (viewDom: HTMLElement, isUpdate: boolean) => void,
|
||||
applyEdit?: (viewDom: HTMLElement, apply: boolean) => void,
|
||||
|
|
@ -38,7 +38,7 @@ declare global {
|
|||
}
|
||||
}
|
||||
|
||||
window.orgJDrupesVmOperatorVmViewer = {};
|
||||
window.orgJDrupesVmOperatorVmAccess = {};
|
||||
|
||||
interface Api {
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
|
@ -51,7 +51,7 @@ const localize = (key: string) => {
|
|||
l10nBundles, JGWC.lang(), key);
|
||||
};
|
||||
|
||||
window.orgJDrupesVmOperatorVmViewer.initPreview = (previewDom: HTMLElement,
|
||||
window.orgJDrupesVmOperatorVmAccess.initPreview = (previewDom: HTMLElement,
|
||||
_isUpdate: boolean) => {
|
||||
const app = createApp({
|
||||
setup(_props: object) {
|
||||
|
|
@ -107,7 +107,7 @@ window.orgJDrupesVmOperatorVmViewer.initPreview = (previewDom: HTMLElement,
|
|||
:title="localize('Open console')"></span><span
|
||||
style="visibility: hidden;"><img
|
||||
:src="resourceBase + 'computer.svg'"></span></td>
|
||||
<td class="jdrupes-vmoperator-vmviewer-preview-action-list">
|
||||
<td class="jdrupes-vmoperator-vmaccess-preview-action-list">
|
||||
<span role="button"
|
||||
:aria-disabled="!startable || !permissions.includes('start')"
|
||||
tabindex="0" class="fa fa-play" :title="localize('Start VM')"
|
||||
|
|
@ -138,25 +138,25 @@ window.orgJDrupesVmOperatorVmViewer.initPreview = (previewDom: HTMLElement,
|
|||
app.mount(previewDom);
|
||||
};
|
||||
|
||||
JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmviewer.VmViewer",
|
||||
JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmaccess.VmAccess",
|
||||
"updateConfig", function(conletId: string, vmName: string) {
|
||||
const conlet = JGConsole.findConletPreview(conletId);
|
||||
if (!conlet) {
|
||||
return;
|
||||
}
|
||||
const api = getApi<Api>(conlet.element().querySelector(
|
||||
":scope .jdrupes-vmoperator-vmviewer-preview"))!;
|
||||
":scope .jdrupes-vmoperator-vmaccess-preview"))!;
|
||||
api.vmName = vmName;
|
||||
});
|
||||
|
||||
JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmviewer.VmViewer",
|
||||
JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmaccess.VmAccess",
|
||||
"updateVmDefinition", function(conletId: string, vmDefinition: any) {
|
||||
const conlet = JGConsole.findConletPreview(conletId);
|
||||
if (!conlet) {
|
||||
return;
|
||||
}
|
||||
const api = getApi<Api>(conlet.element().querySelector(
|
||||
":scope .jdrupes-vmoperator-vmviewer-preview"))!;
|
||||
":scope .jdrupes-vmoperator-vmaccess-preview"))!;
|
||||
// Add some short-cuts for rendering
|
||||
vmDefinition.name = vmDefinition.metadata.name;
|
||||
vmDefinition.currentCpus = vmDefinition.status.cpus;
|
||||
|
|
@ -173,13 +173,13 @@ JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmviewer.VmViewer",
|
|||
api.vmDefinition = vmDefinition;
|
||||
});
|
||||
|
||||
JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmviewer.VmViewer",
|
||||
JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmaccess.VmAccess",
|
||||
"openConsole", function(_conletId: string, mimeType: string, data: string) {
|
||||
let target = document.getElementById(
|
||||
"org.jdrupes.vmoperator.vmviewer.VmViewer.target");
|
||||
"org.jdrupes.vmoperator.vmaccess.VmAccess.target");
|
||||
if (!target) {
|
||||
target = document.createElement("iframe");
|
||||
target.id = "org.jdrupes.vmoperator.vmviewer.VmViewer.target";
|
||||
target.id = "org.jdrupes.vmoperator.vmaccess.VmAccess.target";
|
||||
target.setAttribute("name", target.id);
|
||||
target.setAttribute("style", "display: none;");
|
||||
document.querySelector("body")!.append(target);
|
||||
|
|
@ -188,7 +188,7 @@ JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmviewer.VmViewer",
|
|||
window.open(url, target.id);
|
||||
});
|
||||
|
||||
window.orgJDrupesVmOperatorVmViewer.initEdit = (dialogDom: HTMLElement,
|
||||
window.orgJDrupesVmOperatorVmAccess.initEdit = (dialogDom: HTMLElement,
|
||||
isUpdate: boolean) => {
|
||||
if (isUpdate) {
|
||||
return;
|
||||
|
|
@ -209,7 +209,7 @@ window.orgJDrupesVmOperatorVmViewer.initEdit = (dialogDom: HTMLElement,
|
|||
const conlet = JGConsole.findConletPreview(conletId);
|
||||
if (conlet) {
|
||||
const api = getApi<Api>(conlet.element().querySelector(
|
||||
":scope .jdrupes-vmoperator-vmviewer-preview"))!;
|
||||
":scope .jdrupes-vmoperator-vmaccess-preview"))!;
|
||||
vmNameInput.value = api.vmName;
|
||||
}
|
||||
|
||||
|
|
@ -222,7 +222,7 @@ window.orgJDrupesVmOperatorVmViewer.initEdit = (dialogDom: HTMLElement,
|
|||
app.mount(dialogDom);
|
||||
}
|
||||
|
||||
window.orgJDrupesVmOperatorVmViewer.applyEdit =
|
||||
window.orgJDrupesVmOperatorVmAccess.applyEdit =
|
||||
(dialogDom: HTMLElement, apply: boolean) => {
|
||||
if (!apply) {
|
||||
return;
|
||||
|
|
@ -233,7 +233,7 @@ window.orgJDrupesVmOperatorVmViewer.applyEdit =
|
|||
JGConsole.notifyConletModel(conletId, "selectedVm", vmName);
|
||||
}
|
||||
|
||||
window.orgJDrupesVmOperatorVmViewer.confirmReset =
|
||||
window.orgJDrupesVmOperatorVmAccess.confirmReset =
|
||||
(conletType: string, conletId: string) => {
|
||||
JGConsole.instance.closeModalDialog(conletType, conletId);
|
||||
JGConsole.notifyConletModel(conletId, "resetConfirmed");
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
/*
|
||||
* Conlet specific styles.
|
||||
*/
|
||||
.jdrupes-vmoperator-vmviewer {
|
||||
.jdrupes-vmoperator-vmaccess {
|
||||
|
||||
span[role="button"].svg-icon {
|
||||
display: inline-block;
|
||||
|
|
@ -47,7 +47,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
.jdrupes-vmoperator-vmviewer.jdrupes-vmoperator-vmviewer-preview {
|
||||
.jdrupes-vmoperator-vmaccess.jdrupes-vmoperator-vmaccess-preview {
|
||||
|
||||
img {
|
||||
height: 3em;
|
||||
|
|
@ -58,7 +58,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
.jdrupes-vmoperator-vmviewer-preview-action-list {
|
||||
.jdrupes-vmoperator-vmaccess-preview-action-list {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
|
|
@ -76,13 +76,13 @@
|
|||
}
|
||||
}
|
||||
|
||||
.jdrupes-vmoperator-vmviewer.jdrupes-vmoperator-vmviewer-edit {
|
||||
.jdrupes-vmoperator-vmaccess.jdrupes-vmoperator-vmaccess-edit {
|
||||
select {
|
||||
width: 15em;
|
||||
}
|
||||
}
|
||||
|
||||
.jdrupes-vmoperator-vmviewer.jdrupes-vmoperator-vmviewer-confirm-reset {
|
||||
.jdrupes-vmoperator-vmaccess.jdrupes-vmoperator-vmaccess-confirm-reset {
|
||||
p {
|
||||
text-align: center;
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* VM-Operator
|
||||
* Copyright (C) 2023 Michael N. Lipp
|
||||
* Copyright (C) 2023, 2024 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
|
||||
|
|
@ -16,4 +16,4 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.jdrupes.vmoperator.vmconlet;
|
||||
package org.jdrupes.vmoperator.vmaccess;
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
"aash-plugin": ["./build/unpacked/org/jgrapes/webconsole/provider/jgwcvuecomponents/aash-vue-components/lib/AashPlugin"],
|
||||
"jgconsole": ["./build/unpacked/org/jgrapes/webconsole/base/JGConsole"],
|
||||
"jgwc": ["./build/unpacked/org/jgrapes/webconsole/provider/jgwcvuecomponents/jgwc-vue-components/jgwc-components"],
|
||||
"l10nBundles": ["./src/org/jdrupes/vmoperator/vmviewer/browser/l10nBundles-stub"],
|
||||
"l10nBundles": ["./src/org/jdrupes/vmoperator/vmaccess/browser/l10nBundles-stub"],
|
||||
"vue": ["./build/unpacked/org/jgrapes/webconsole/provider/vue/vue/vue"]
|
||||
}
|
||||
},
|
||||
|
|
@ -1 +0,0 @@
|
|||
org.jdrupes.vmoperator.vmconlet.VmConletFactory
|
||||
|
|
@ -0,0 +1 @@
|
|||
org.jdrupes.vmoperator.vmmgmt.VmMgmtFactory
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<div class="jdrupes-vmoperator-vmconlet jdrupes-vmoperator-vmconlet-preview"
|
||||
<div class="jdrupes-vmoperator-vmmgmt jdrupes-vmoperator-vmmgmt-preview"
|
||||
data-conlet-grid-rows="5"
|
||||
data-jgwc-on-load="orgJDrupesVmOperatorVmConlet.initPreview"
|
||||
data-jgwc-on-load="orgJDrupesVmOperatorVmMgmt.initPreview"
|
||||
data-jgwc-on-unload="JGConsole.jgwc.unmountVueApps">
|
||||
|
||||
<form>
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
<div class="jdrupes-vmoperator-vmconlet jdrupes-vmoperator-vmconlet-view"
|
||||
data-jgwc-on-load="orgJDrupesVmOperatorVmConlet.initView"
|
||||
<div class="jdrupes-vmoperator-vmmgmt jdrupes-vmoperator-vmmgmt-view"
|
||||
data-jgwc-on-load="orgJDrupesVmOperatorVmMgmt.initView"
|
||||
data-jgwc-on-unload="JGConsole.jgwc.unmountVueApps">
|
||||
<div class="jdrupes-vmoperator-vmconlet-view-search">
|
||||
<div class="jdrupes-vmoperator-vmmgmt-view-search">
|
||||
<form>
|
||||
<label class="form__label--horizontal">
|
||||
<span>{{ localize("Filter") }}</span>
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
</form>
|
||||
</div>
|
||||
<table
|
||||
class="table--basic--striped jdrupes-vmoperator-vmconlet-view-table">
|
||||
class="table--basic--striped jdrupes-vmoperator-vmmgmt-view-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th v-for="key in controller.keys"
|
||||
|
|
@ -51,7 +51,7 @@
|
|||
<span v-else
|
||||
v-html="controller.breakBeforeDots(entry[key])"></span>
|
||||
</td>
|
||||
<td class="jdrupes-vmoperator-vmconlet-view-action-list">
|
||||
<td class="jdrupes-vmoperator-vmmgmt-view-action-list">
|
||||
<span role="button"
|
||||
v-if="entry.spec.vm.state != 'Running' && !entry['running']"
|
||||
tabindex="0" class="fa fa-play" :title="localize('Start VM')"
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
conletName = VM Infos
|
||||
conletName = VM Management
|
||||
|
||||
VMsSummary = VMs (running/total)
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
conletName = VM-Informationen
|
||||
conletName = VM-Management
|
||||
|
||||
VMsSummary = VMs (gestartet/gesamt)
|
||||
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
import typescript from 'rollup-plugin-typescript2';
|
||||
import postcss from 'rollup-plugin-postcss';
|
||||
|
||||
let packagePath = "org/jdrupes/vmoperator/vmconlet";
|
||||
let baseName = "VmConlet"
|
||||
let packagePath = "org/jdrupes/vmoperator/vmmgmt";
|
||||
let baseName = "VmMgmt"
|
||||
let module = "build/generated/resources/" + packagePath
|
||||
+ "/" + baseName + "-functions.js";
|
||||
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.jdrupes.vmoperator.vmconlet;
|
||||
package org.jdrupes.vmoperator.vmmgmt;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.jdrupes.vmoperator.vmconlet;
|
||||
package org.jdrupes.vmoperator.vmmgmt;
|
||||
|
||||
import freemarker.core.ParseException;
|
||||
import freemarker.template.MalformedTemplateNameException;
|
||||
|
|
@ -61,11 +61,11 @@ import org.jgrapes.webconsole.base.events.SetLocale;
|
|||
import org.jgrapes.webconsole.base.freemarker.FreeMarkerConlet;
|
||||
|
||||
/**
|
||||
* The Class VmConlet.
|
||||
* The Class {@link VmMgmt}.
|
||||
*/
|
||||
@SuppressWarnings({ "PMD.DataflowAnomalyAnalysis",
|
||||
"PMD.CouplingBetweenObjects" })
|
||||
public class VmConlet extends FreeMarkerConlet<VmConlet.VmsModel> {
|
||||
public class VmMgmt extends FreeMarkerConlet<VmMgmt.VmsModel> {
|
||||
|
||||
private static final Set<RenderMode> MODES = RenderMode.asSet(
|
||||
RenderMode.Preview, RenderMode.View);
|
||||
|
|
@ -88,7 +88,7 @@ public class VmConlet extends FreeMarkerConlet<VmConlet.VmsModel> {
|
|||
* sends the event to
|
||||
*/
|
||||
@SuppressWarnings("PMD.ConstructorCallsOverridableMethod")
|
||||
public VmConlet(Channel componentChannel) {
|
||||
public VmMgmt(Channel componentChannel) {
|
||||
super(componentChannel);
|
||||
setPeriodicRefresh(Duration.ofMinutes(1), () -> new Update());
|
||||
}
|
||||
|
|
@ -115,7 +115,7 @@ public class VmConlet extends FreeMarkerConlet<VmConlet.VmsModel> {
|
|||
.addRenderMode(RenderMode.Preview)
|
||||
.addScript(new ScriptResource().setScriptType("module")
|
||||
.setScriptUri(event.renderSupport().conletResource(
|
||||
type(), "VmConlet-functions.js"))));
|
||||
type(), "VmMgmt-functions.js"))));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -133,7 +133,7 @@ public class VmConlet extends FreeMarkerConlet<VmConlet.VmsModel> {
|
|||
boolean sendVmInfos = false;
|
||||
if (event.renderAs().contains(RenderMode.Preview)) {
|
||||
Template tpl
|
||||
= freemarkerConfig().getTemplate("VmConlet-preview.ftl.html");
|
||||
= freemarkerConfig().getTemplate("VmMgmt-preview.ftl.html");
|
||||
channel.respond(new RenderConlet(type(), conletId,
|
||||
processTemplate(event, tpl,
|
||||
fmModel(event, channel, conletId, conletState)))
|
||||
|
|
@ -150,7 +150,7 @@ public class VmConlet extends FreeMarkerConlet<VmConlet.VmsModel> {
|
|||
}
|
||||
if (event.renderAs().contains(RenderMode.View)) {
|
||||
Template tpl
|
||||
= freemarkerConfig().getTemplate("VmConlet-view.ftl.html");
|
||||
= freemarkerConfig().getTemplate("VmMgmt-view.ftl.html");
|
||||
channel.respond(new RenderConlet(type(), conletId,
|
||||
processTemplate(event, tpl,
|
||||
fmModel(event, channel, conletId, conletState)))
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.jdrupes.vmoperator.vmconlet;
|
||||
package org.jdrupes.vmoperator.vmmgmt;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
|
@ -25,9 +25,9 @@ import org.jgrapes.core.ComponentType;
|
|||
import org.jgrapes.webconsole.base.ConletComponentFactory;
|
||||
|
||||
/**
|
||||
* The factory service for {@link VmConlet}s.
|
||||
* The factory service for {@link VmMgmt}s.
|
||||
*/
|
||||
public class VmConletFactory implements ConletComponentFactory {
|
||||
public class VmMgmtFactory implements ConletComponentFactory {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
|
|
@ -36,7 +36,7 @@ public class VmConletFactory implements ConletComponentFactory {
|
|||
*/
|
||||
@Override
|
||||
public Class<? extends ComponentType> componentType() {
|
||||
return VmConlet.class;
|
||||
return VmMgmt.class;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -48,7 +48,7 @@ public class VmConletFactory implements ConletComponentFactory {
|
|||
@Override
|
||||
public Optional<ComponentType> create(Channel componentChannel,
|
||||
Map<?, ?> properties) {
|
||||
return Optional.of(new VmConlet(componentChannel));
|
||||
return Optional.of(new VmMgmt(componentChannel));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -27,19 +27,19 @@ import { formatMemory, parseMemory } from "./MemorySize";
|
|||
import CpuRamChart from "./CpuRamChart";
|
||||
import ConditionlInputController from "./ConditionalInputController";
|
||||
|
||||
import "./VmConlet-style.scss";
|
||||
import "./VmMgmt-style.scss";
|
||||
|
||||
// For global access
|
||||
declare global {
|
||||
interface Window {
|
||||
orgJDrupesVmOperatorVmConlet: {
|
||||
orgJDrupesVmOperatorVmMgmt: {
|
||||
initPreview?: (previewDom: HTMLElement, isUpdate: boolean) => void,
|
||||
initView?: (viewDom: HTMLElement, isUpdate: boolean) => void
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.orgJDrupesVmOperatorVmConlet = {};
|
||||
window.orgJDrupesVmOperatorVmMgmt = {};
|
||||
|
||||
const vmInfos = reactive(new Map());
|
||||
const vmSummary = reactive({
|
||||
|
|
@ -64,7 +64,7 @@ const shortDateTime = (time: Date) => {
|
|||
const chartData = new TimeSeries(2);
|
||||
const chartDateUpdate = ref<Date>(null);
|
||||
|
||||
window.orgJDrupesVmOperatorVmConlet.initPreview = (previewDom: HTMLElement,
|
||||
window.orgJDrupesVmOperatorVmMgmt.initPreview = (previewDom: HTMLElement,
|
||||
_isUpdate: boolean) => {
|
||||
const app = createApp({
|
||||
setup(_props: object) {
|
||||
|
|
@ -98,7 +98,7 @@ window.orgJDrupesVmOperatorVmConlet.initPreview = (previewDom: HTMLElement,
|
|||
app.mount(previewDom);
|
||||
};
|
||||
|
||||
window.orgJDrupesVmOperatorVmConlet.initView = (viewDom: HTMLElement,
|
||||
window.orgJDrupesVmOperatorVmMgmt.initView = (viewDom: HTMLElement,
|
||||
_isUpdate: boolean) => {
|
||||
const app = createApp({
|
||||
setup(_props: object) {
|
||||
|
|
@ -174,7 +174,7 @@ window.orgJDrupesVmOperatorVmConlet.initView = (viewDom: HTMLElement,
|
|||
app.mount(viewDom);
|
||||
};
|
||||
|
||||
JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmconlet.VmConlet",
|
||||
JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmmgmt.VmMgmt",
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
"updateVm", function(_conletId: string, vmDefinition: any) {
|
||||
// Add some short-cuts for table controller
|
||||
|
|
@ -194,12 +194,12 @@ JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmconlet.VmConlet",
|
|||
vmInfos.set(vmDefinition.name, vmDefinition);
|
||||
});
|
||||
|
||||
JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmconlet.VmConlet",
|
||||
JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmmgmt.VmMgmt",
|
||||
"removeVm", function(_conletId: string, vmName: string) {
|
||||
vmInfos.delete(vmName);
|
||||
});
|
||||
|
||||
JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmconlet.VmConlet",
|
||||
JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmmgmt.VmMgmt",
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
"summarySeries", function(_conletId: string, series: any[]) {
|
||||
chartData.clear();
|
||||
|
|
@ -210,7 +210,7 @@ JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmconlet.VmConlet",
|
|||
chartDateUpdate.value = new Date();
|
||||
});
|
||||
|
||||
JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmconlet.VmConlet",
|
||||
JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmmgmt.VmMgmt",
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
"updateSummary", function(_conletId: string, summary: any) {
|
||||
chartData.push(new Date(), summary.usedCpus, Number(summary.usedRam));
|
||||
|
|
@ -20,7 +20,7 @@
|
|||
* Conlet specific styles.
|
||||
*/
|
||||
|
||||
.jdrupes-vmoperator-vmconlet-preview {
|
||||
.jdrupes-vmoperator-vmmgmt-preview {
|
||||
form {
|
||||
float: right;
|
||||
padding: 0.15em 0.3em;
|
||||
|
|
@ -37,7 +37,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
.jdrupes-vmoperator-vmconlet-view-search {
|
||||
.jdrupes-vmoperator-vmmgmt-view-search {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
|
|
@ -46,7 +46,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
.jdrupes-vmoperator-vmconlet-view-table {
|
||||
.jdrupes-vmoperator-vmmgmt-view-table {
|
||||
td {
|
||||
vertical-align: top;
|
||||
|
||||
|
|
@ -94,7 +94,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
.jdrupes-vmoperator-vmconlet-view-action-list {
|
||||
.jdrupes-vmoperator-vmmgmt-view-action-list {
|
||||
white-space: nowrap;
|
||||
|
||||
[role=button] {
|
||||
|
|
@ -16,4 +16,4 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.jdrupes.vmoperator.vmviewer;
|
||||
package org.jdrupes.vmoperator.vmmgmt;
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
"aash-plugin": ["./build/unpacked/org/jgrapes/webconsole/provider/jgwcvuecomponents/aash-vue-components/lib/AashPlugin"],
|
||||
"jgconsole": ["./build/unpacked/org/jgrapes/webconsole/base/JGConsole"],
|
||||
"jgwc": ["./build/unpacked/org/jgrapes/webconsole/provider/jgwcvuecomponents/jgwc-vue-components/jgwc-components"],
|
||||
"l10nBundles": ["./src/org/jdrupes/vmoperator/vmconlet/browser/l10nBundles-stub"],
|
||||
"l10nBundles": ["./src/org/jdrupes/vmoperator/vmmgmt/browser/l10nBundles-stub"],
|
||||
"vue": ["./build/unpacked/org/jgrapes/webconsole/provider/vue/vue/vue"],
|
||||
"chartjs": ["./build/unpacked/org/jgrapes/webconsole/provider/chartjs/chart.js/auto/auto"]
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
org.jdrupes.vmoperator.vmviewer.VmViewerFactory
|
||||
|
|
@ -12,8 +12,8 @@ rootProject.name = 'VM-Operator'
|
|||
|
||||
include 'org.jdrupes.vmoperator.manager'
|
||||
include 'org.jdrupes.vmoperator.manager.events'
|
||||
include 'org.jdrupes.vmoperator.vmconlet'
|
||||
include 'org.jdrupes.vmoperator.vmviewer'
|
||||
include 'org.jdrupes.vmoperator.vmaccess'
|
||||
include 'org.jdrupes.vmoperator.vmmgmt'
|
||||
include 'org.jdrupes.vmoperator.runner.qemu'
|
||||
include 'org.jdrupes.vmoperator.common'
|
||||
include 'org.jdrupes.vmoperator.util'
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
|
@ -5,6 +5,19 @@ layout: vm-operator
|
|||
|
||||
# Upgrading
|
||||
|
||||
## To version 4.0.0
|
||||
|
||||
The VmViewer conlet has been renamed to VmAccess. This affects the
|
||||
[configuration](https://jdrupes.org/vm-operator/user-gui.html). Configuration information using the old path
|
||||
"/Manager/GuiHttpServer/ConsoleWeblet/WebConsole/ComponentCollector/VmViewer"
|
||||
is still accepted for backward compatibility, but should be updated.
|
||||
|
||||
The change of name also causes conlets added to the overview page by
|
||||
users to "disappear" from the GUI. They have to be re-added.
|
||||
|
||||
The latter behavior also applies to the VmConlet conlet which has been
|
||||
renamed to VmMgmt.
|
||||
|
||||
## To version 3.4.0
|
||||
|
||||
Starting with this version, the VM-Operator no longer uses a stateful set
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ The idea of the user view is to provide an intuitive widget that
|
|||
allows the users to access their own VMs and to optionally start
|
||||
and stop them.
|
||||
|
||||

|
||||

|
||||
|
||||
The configuration options resulting from this seemingly simple
|
||||
requirement are unexpectedly complex.
|
||||
|
|
@ -62,7 +62,7 @@ objects that either specify a role or a user.
|
|||
"/ConsoleWeblet":
|
||||
"/WebConsole":
|
||||
"/ComponentCollector":
|
||||
"/VmViewer":
|
||||
"/VmAccess":
|
||||
syncPreviewsFor:
|
||||
- role: user
|
||||
- user: test
|
||||
|
|
|
|||