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
|
- accessConsole
|
||||||
- "*"
|
- "*"
|
||||||
default: []
|
default: []
|
||||||
|
pools:
|
||||||
|
type: array
|
||||||
|
description: >-
|
||||||
|
List of pools to which this VM belongs.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
default: []
|
||||||
loggingProperties:
|
loggingProperties:
|
||||||
type: string
|
type: string
|
||||||
description: >-
|
description: >-
|
||||||
|
|
|
||||||
2
dev-example/.gitignore
vendored
|
|
@ -1 +1,3 @@
|
||||||
/test-vm-ci.yaml
|
/test-vm-ci.yaml
|
||||||
|
/kubeconfig.yaml
|
||||||
|
/crds/
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@
|
||||||
"/Controller":
|
"/Controller":
|
||||||
namespace: vmop-dev
|
namespace: vmop-dev
|
||||||
"/Reconciler":
|
"/Reconciler":
|
||||||
runnerData:
|
runnerDataPvc:
|
||||||
storageClassName: null
|
storageClassName: rook-cephfs
|
||||||
loadBalancerService:
|
loadBalancerService:
|
||||||
labels:
|
labels:
|
||||||
label1: label1
|
label1: label1
|
||||||
|
|
@ -65,7 +65,7 @@
|
||||||
other:
|
other:
|
||||||
- org.jgrapes.webconlet.oidclogin.LoginConlet
|
- org.jgrapes.webconlet.oidclogin.LoginConlet
|
||||||
"/ComponentCollector":
|
"/ComponentCollector":
|
||||||
"/VmViewer":
|
"/VmAccess":
|
||||||
displayResource:
|
displayResource:
|
||||||
preferredIpVersion: ipv4
|
preferredIpVersion: ipv4
|
||||||
syncPreviewsFor:
|
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:
|
other:
|
||||||
- org.jgrapes.webconlet.locallogin.LoginConlet
|
- org.jgrapes.webconlet.locallogin.LoginConlet
|
||||||
"/ComponentCollector":
|
"/ComponentCollector":
|
||||||
"/VmViewer":
|
"/VmAccess":
|
||||||
displayResource:
|
displayResource:
|
||||||
preferredIpVersion: ipv4
|
preferredIpVersion: ipv4
|
||||||
syncPreviewsFor:
|
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. */
|
/** The Constant VM_OP_KIND_VM. */
|
||||||
public static final String VM_OP_KIND_VM = "VirtualMachine";
|
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.slf4j:slf4j-jdk14:[2.0.7,3)'
|
||||||
runtimeOnly 'org.apache.logging.log4j:log4j-to-jul:2.20.0'
|
runtimeOnly 'org.apache.logging.log4j:log4j-to-jul:2.20.0'
|
||||||
|
|
||||||
runtimeOnly project(':org.jdrupes.vmoperator.vmconlet')
|
runtimeOnly project(':org.jdrupes.vmoperator.vmmgmt')
|
||||||
runtimeOnly project(':org.jdrupes.vmoperator.vmviewer')
|
runtimeOnly project(':org.jdrupes.vmoperator.vmaccess')
|
||||||
}
|
}
|
||||||
|
|
||||||
application {
|
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 client the client
|
||||||
* @param change the change
|
* @param change the change
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,7 @@ public class Controller extends Component {
|
||||||
// to access the VM's console. Might change in the future.
|
// to access the VM's console. Might change in the future.
|
||||||
// attach(new ServiceMonitor(channel()).channelManager(chanMgr));
|
// attach(new ServiceMonitor(channel()).channelManager(chanMgr));
|
||||||
attach(new Reconciler(channel()));
|
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
|
<div
|
||||||
class="jdrupes-vmoperator-vmviewer jdrupes-vmoperator-vmviewer-confirm-reset">
|
class="jdrupes-vmoperator-vmaccess jdrupes-vmoperator-vmaccess-confirm-reset">
|
||||||
<p>${_("confirmResetMsg")}</p>
|
<p>${_("confirmResetMsg")}</p>
|
||||||
<p>
|
<p>
|
||||||
<span role="button" tabindex="0" class="svg-icon"
|
<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">
|
<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 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"/>
|
<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")}"
|
<div title="${_("conletName")}"
|
||||||
class="jdrupes-vmoperator-vmviewer jdrupes-vmoperator-vmviewer-edit"
|
class="jdrupes-vmoperator-vmaccess jdrupes-vmoperator-vmaccess-edit"
|
||||||
data-jgwc-on-load="orgJDrupesVmOperatorVmViewer.initEdit"
|
data-jgwc-on-load="orgJDrupesVmOperatorVmAccess.initEdit"
|
||||||
data-jgwc-on-action="orgJDrupesVmOperatorVmViewer.applyEdit"
|
data-jgwc-on-action="orgJDrupesVmOperatorVmAccess.applyEdit"
|
||||||
data-jgwc-on-unload="JGConsole.jgwc.unmountVueApps">
|
data-jgwc-on-unload="JGConsole.jgwc.unmountVueApps">
|
||||||
<form :id="formId" ref="formDom" onsubmit="return false;">
|
<form :id="formId" ref="formDom" onsubmit="return false;">
|
||||||
<section>
|
<section>
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<div
|
<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-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-jgwc-on-unload="JGConsole.jgwc.unmountVueApps"
|
||||||
data-conlet-resource-base="${conletResource('')}">
|
data-conlet-resource-base="${conletResource('')}">
|
||||||
</div>
|
</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
|
okayLabel = Apply and Close
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
conletName = VM-Konsole
|
conletName = VM-Zugriff
|
||||||
|
|
||||||
okayLabel = Anwenden und Schließen
|
okayLabel = Anwenden und Schließen
|
||||||
Select\ VM = VM auswählen
|
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 typescript from 'rollup-plugin-typescript2';
|
||||||
import postcss from 'rollup-plugin-postcss';
|
import postcss from 'rollup-plugin-postcss';
|
||||||
|
|
||||||
let packagePath = "org/jdrupes/vmoperator/vmviewer";
|
let packagePath = "org/jdrupes/vmoperator/vmaccess";
|
||||||
let baseName = "VmViewer"
|
let baseName = "VmAccess"
|
||||||
let module = "build/generated/resources/" + packagePath
|
let module = "build/generated/resources/" + packagePath
|
||||||
+ "/" + baseName + "-functions.js";
|
+ "/" + baseName + "-functions.js";
|
||||||
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* 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.JsonGetter;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
@ -89,7 +89,7 @@ import org.jgrapes.webconsole.base.events.UpdateConletType;
|
||||||
import org.jgrapes.webconsole.base.freemarker.FreeMarkerConlet;
|
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:
|
* configuration properties:
|
||||||
*
|
*
|
||||||
* * `displayResource`: a map with the following entries:
|
* * `displayResource`: a map with the following entries:
|
||||||
|
|
@ -107,13 +107,13 @@ import org.jgrapes.webconsole.base.freemarker.FreeMarkerConlet;
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings({ "PMD.DataflowAnomalyAnalysis", "PMD.ExcessiveImports",
|
@SuppressWarnings({ "PMD.DataflowAnomalyAnalysis", "PMD.ExcessiveImports",
|
||||||
"PMD.CouplingBetweenObjects", "PMD.GodClass", "PMD.TooManyMethods" })
|
"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 VM_NAME_PROPERTY = "vmName";
|
||||||
private static final String RENDERED
|
private static final String RENDERED
|
||||||
= VmViewer.class.getName() + ".rendered";
|
= VmAccess.class.getName() + ".rendered";
|
||||||
private static final String PENDING
|
private static final String PENDING
|
||||||
= VmViewer.class.getName() + ".pending";
|
= VmAccess.class.getName() + ".pending";
|
||||||
private static final Set<RenderMode> MODES = RenderMode.asSet(
|
private static final Set<RenderMode> MODES = RenderMode.asSet(
|
||||||
RenderMode.Preview, RenderMode.Edit);
|
RenderMode.Preview, RenderMode.Edit);
|
||||||
private static final Set<RenderMode> MODES_FOR_GENERATED = RenderMode.asSet(
|
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...)}
|
* on by default and that {@link Manager#fire(Event, Channel...)}
|
||||||
* sends the event to
|
* sends the event to
|
||||||
*/
|
*/
|
||||||
public VmViewer(Channel componentChannel) {
|
public VmAccess(Channel componentChannel) {
|
||||||
super(componentChannel);
|
super(componentChannel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -152,44 +152,57 @@ public class VmViewer extends FreeMarkerConlet<VmViewer.ViewerModel> {
|
||||||
@SuppressWarnings({ "unchecked", "PMD.AvoidDuplicateLiterals" })
|
@SuppressWarnings({ "unchecked", "PMD.AvoidDuplicateLiterals" })
|
||||||
@Handler
|
@Handler
|
||||||
public void onConfigurationUpdate(ConfigurationUpdate event) {
|
public void onConfigurationUpdate(ConfigurationUpdate event) {
|
||||||
event.structured(componentPath()).ifPresent(c -> {
|
event.structured(componentPath())
|
||||||
try {
|
.or(() -> {
|
||||||
var dispRes = (Map<String, Object>) c
|
var oldConfig = event.structured("/Manager/GuiHttpServer"
|
||||||
.getOrDefault("displayResource", Collections.emptyMap());
|
+ "/ConsoleWeblet/WebConsole/ComponentCollector/VmViewer");
|
||||||
switch ((String) dispRes.getOrDefault("preferredIpVersion",
|
if (oldConfig.isPresent()) {
|
||||||
"")) {
|
logger.warning(() -> "Using configuration with old "
|
||||||
case "ipv6":
|
+ "component name \"VmViewer\", please update to "
|
||||||
preferredIpVersion = Inet6Address.class;
|
+ "\"VmAccess\"");
|
||||||
break;
|
|
||||||
case "ipv4":
|
|
||||||
default:
|
|
||||||
preferredIpVersion = Inet4Address.class;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
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
|
// Delete connection file
|
||||||
deleteConnectionFile
|
deleteConnectionFile
|
||||||
= Optional.ofNullable(c.get("deleteConnectionFile"))
|
= Optional.ofNullable(c.get("deleteConnectionFile"))
|
||||||
.filter(v -> v instanceof String).map(v -> (String) v)
|
.filter(v -> v instanceof String)
|
||||||
.map(Boolean::parseBoolean).orElse(true);
|
.map(v -> (String) v)
|
||||||
|
.map(Boolean::parseBoolean).orElse(true);
|
||||||
|
|
||||||
// Users or roles for which previews should be synchronized
|
// Users or roles for which previews should be synchronized
|
||||||
syncUsers = ((List<Map<String, String>>) c.getOrDefault(
|
syncUsers = ((List<Map<String, String>>) c.getOrDefault(
|
||||||
"syncPreviewsFor", Collections.emptyList())).stream()
|
"syncPreviewsFor", Collections.emptyList())).stream()
|
||||||
.map(m -> m.get("user"))
|
.map(m -> m.get("user"))
|
||||||
.filter(s -> s != null).collect(Collectors.toSet());
|
.filter(s -> s != null).collect(Collectors.toSet());
|
||||||
logger.finest(() -> "Syncing previews for users: "
|
logger.finest(() -> "Syncing previews for users: "
|
||||||
+ syncUsers.toString());
|
+ syncUsers.toString());
|
||||||
syncRoles = ((List<Map<String, String>>) c.getOrDefault(
|
syncRoles = ((List<Map<String, String>>) c.getOrDefault(
|
||||||
"syncPreviewsFor", Collections.emptyList())).stream()
|
"syncPreviewsFor", Collections.emptyList())).stream()
|
||||||
.map(m -> m.get("role"))
|
.map(m -> m.get("role"))
|
||||||
.filter(s -> s != null).collect(Collectors.toSet());
|
.filter(s -> s != null).collect(Collectors.toSet());
|
||||||
logger.finest(() -> "Syncing previews for roles: "
|
logger.finest(() -> "Syncing previews for roles: "
|
||||||
+ syncRoles.toString());
|
+ syncRoles.toString());
|
||||||
} catch (ClassCastException e) {
|
} catch (ClassCastException e) {
|
||||||
logger.config("Malformed configuration: " + e.getMessage());
|
logger.config("Malformed configuration: " + e.getMessage());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean syncPreviews(Session session) {
|
private boolean syncPreviews(Session session) {
|
||||||
|
|
@ -222,7 +235,7 @@ public class VmViewer extends FreeMarkerConlet<VmViewer.ViewerModel> {
|
||||||
.addRenderMode(RenderMode.Preview)
|
.addRenderMode(RenderMode.Preview)
|
||||||
.addScript(new ScriptResource().setScriptType("module")
|
.addScript(new ScriptResource().setScriptType("module")
|
||||||
.setScriptUri(event.renderSupport().conletResource(
|
.setScriptUri(event.renderSupport().conletResource(
|
||||||
type(), "VmViewer-functions.js"))));
|
type(), "VmAccess-functions.js"))));
|
||||||
channel.session().put(RENDERED, new HashSet<>());
|
channel.session().put(RENDERED, new HashSet<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -259,7 +272,7 @@ public class VmViewer extends FreeMarkerConlet<VmViewer.ViewerModel> {
|
||||||
foundMissing = true;
|
foundMissing = true;
|
||||||
}
|
}
|
||||||
fire(new AddConletRequest(event.event().event().renderSupport(),
|
fire(new AddConletRequest(event.event().event().renderSupport(),
|
||||||
VmViewer.class.getName(),
|
VmAccess.class.getName(),
|
||||||
RenderMode.asSet(RenderMode.Preview))
|
RenderMode.asSet(RenderMode.Preview))
|
||||||
.addProperty(VM_NAME_PROPERTY, vmName),
|
.addProperty(VM_NAME_PROPERTY, vmName),
|
||||||
connection);
|
connection);
|
||||||
|
|
@ -283,7 +296,7 @@ public class VmViewer extends FreeMarkerConlet<VmViewer.ViewerModel> {
|
||||||
private String storagePath(Session session, String conletId) {
|
private String storagePath(Session session, String conletId) {
|
||||||
return "/" + WebConsoleUtils.userFromSession(session)
|
return "/" + WebConsoleUtils.userFromSession(session)
|
||||||
.map(ConsoleUser::getName).orElse("")
|
.map(ConsoleUser::getName).orElse("")
|
||||||
+ "/" + VmViewer.class.getName() + "/" + conletId;
|
+ "/" + VmAccess.class.getName() + "/" + conletId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -365,7 +378,7 @@ public class VmViewer extends FreeMarkerConlet<VmViewer.ViewerModel> {
|
||||||
|
|
||||||
// Render
|
// Render
|
||||||
Template tpl
|
Template tpl
|
||||||
= freemarkerConfig().getTemplate("VmViewer-preview.ftl.html");
|
= freemarkerConfig().getTemplate("VmAccess-preview.ftl.html");
|
||||||
channel.respond(new RenderConlet(type(), conletId,
|
channel.respond(new RenderConlet(type(), conletId,
|
||||||
processTemplate(event, tpl,
|
processTemplate(event, tpl,
|
||||||
fmModel(event, channel, conletId, model)))
|
fmModel(event, channel, conletId, model)))
|
||||||
|
|
@ -383,7 +396,7 @@ public class VmViewer extends FreeMarkerConlet<VmViewer.ViewerModel> {
|
||||||
}
|
}
|
||||||
if (event.renderAs().contains(RenderMode.Edit)) {
|
if (event.renderAs().contains(RenderMode.Edit)) {
|
||||||
Template tpl = freemarkerConfig()
|
Template tpl = freemarkerConfig()
|
||||||
.getTemplate("VmViewer-edit.ftl.html");
|
.getTemplate("VmAccess-edit.ftl.html");
|
||||||
var fmModel = fmModel(event, channel, conletId, model);
|
var fmModel = fmModel(event, channel, conletId, model);
|
||||||
fmModel.put("vmNames", accessibleVms(channel));
|
fmModel.put("vmNames", accessibleVms(channel));
|
||||||
channel.respond(new OpenModalDialog(type(), conletId,
|
channel.respond(new OpenModalDialog(type(), conletId,
|
||||||
|
|
@ -633,7 +646,7 @@ public class VmViewer extends FreeMarkerConlet<VmViewer.ViewerModel> {
|
||||||
ResourceBundle resourceBundle) throws TemplateNotFoundException,
|
ResourceBundle resourceBundle) throws TemplateNotFoundException,
|
||||||
MalformedTemplateNameException, ParseException, IOException {
|
MalformedTemplateNameException, ParseException, IOException {
|
||||||
Template tpl = freemarkerConfig()
|
Template tpl = freemarkerConfig()
|
||||||
.getTemplate("VmViewer-confirmReset.ftl.html");
|
.getTemplate("VmAccess-confirmReset.ftl.html");
|
||||||
channel.respond(new OpenModalDialog(type(), model.getConletId(),
|
channel.respond(new OpenModalDialog(type(), model.getConletId(),
|
||||||
processTemplate(event, tpl,
|
processTemplate(event, tpl,
|
||||||
fmModel(event, channel, model.getConletId(), model)))
|
fmModel(event, channel, model.getConletId(), model)))
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* 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.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
@ -25,9 +25,9 @@ import org.jgrapes.core.ComponentType;
|
||||||
import org.jgrapes.webconsole.base.ConletComponentFactory;
|
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)
|
* (non-Javadoc)
|
||||||
|
|
@ -36,7 +36,7 @@ public class VmViewerFactory implements ConletComponentFactory {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Class<? extends ComponentType> componentType() {
|
public Class<? extends ComponentType> componentType() {
|
||||||
return VmViewer.class;
|
return VmAccess.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -48,7 +48,7 @@ public class VmViewerFactory implements ConletComponentFactory {
|
||||||
@Override
|
@Override
|
||||||
public Optional<ComponentType> create(Channel componentChannel,
|
public Optional<ComponentType> create(Channel componentChannel,
|
||||||
Map<?, ?> properties) {
|
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 { provideApi, getApi } from "aash-plugin";
|
||||||
import l10nBundles from "l10nBundles";
|
import l10nBundles from "l10nBundles";
|
||||||
|
|
||||||
import "./VmViewer-style.scss";
|
import "./VmAccess-style.scss";
|
||||||
|
|
||||||
// For global access
|
// For global access
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
orgJDrupesVmOperatorVmViewer: {
|
orgJDrupesVmOperatorVmAccess: {
|
||||||
initPreview?: (previewDom: HTMLElement, isUpdate: boolean) => void,
|
initPreview?: (previewDom: HTMLElement, isUpdate: boolean) => void,
|
||||||
initEdit?: (viewDom: HTMLElement, isUpdate: boolean) => void,
|
initEdit?: (viewDom: HTMLElement, isUpdate: boolean) => void,
|
||||||
applyEdit?: (viewDom: HTMLElement, apply: boolean) => void,
|
applyEdit?: (viewDom: HTMLElement, apply: boolean) => void,
|
||||||
|
|
@ -38,7 +38,7 @@ declare global {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.orgJDrupesVmOperatorVmViewer = {};
|
window.orgJDrupesVmOperatorVmAccess = {};
|
||||||
|
|
||||||
interface Api {
|
interface Api {
|
||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
|
@ -51,7 +51,7 @@ const localize = (key: string) => {
|
||||||
l10nBundles, JGWC.lang(), key);
|
l10nBundles, JGWC.lang(), key);
|
||||||
};
|
};
|
||||||
|
|
||||||
window.orgJDrupesVmOperatorVmViewer.initPreview = (previewDom: HTMLElement,
|
window.orgJDrupesVmOperatorVmAccess.initPreview = (previewDom: HTMLElement,
|
||||||
_isUpdate: boolean) => {
|
_isUpdate: boolean) => {
|
||||||
const app = createApp({
|
const app = createApp({
|
||||||
setup(_props: object) {
|
setup(_props: object) {
|
||||||
|
|
@ -107,7 +107,7 @@ window.orgJDrupesVmOperatorVmViewer.initPreview = (previewDom: HTMLElement,
|
||||||
:title="localize('Open console')"></span><span
|
:title="localize('Open console')"></span><span
|
||||||
style="visibility: hidden;"><img
|
style="visibility: hidden;"><img
|
||||||
:src="resourceBase + 'computer.svg'"></span></td>
|
: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"
|
<span role="button"
|
||||||
:aria-disabled="!startable || !permissions.includes('start')"
|
:aria-disabled="!startable || !permissions.includes('start')"
|
||||||
tabindex="0" class="fa fa-play" :title="localize('Start VM')"
|
tabindex="0" class="fa fa-play" :title="localize('Start VM')"
|
||||||
|
|
@ -138,25 +138,25 @@ window.orgJDrupesVmOperatorVmViewer.initPreview = (previewDom: HTMLElement,
|
||||||
app.mount(previewDom);
|
app.mount(previewDom);
|
||||||
};
|
};
|
||||||
|
|
||||||
JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmviewer.VmViewer",
|
JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmaccess.VmAccess",
|
||||||
"updateConfig", function(conletId: string, vmName: string) {
|
"updateConfig", function(conletId: string, vmName: string) {
|
||||||
const conlet = JGConsole.findConletPreview(conletId);
|
const conlet = JGConsole.findConletPreview(conletId);
|
||||||
if (!conlet) {
|
if (!conlet) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const api = getApi<Api>(conlet.element().querySelector(
|
const api = getApi<Api>(conlet.element().querySelector(
|
||||||
":scope .jdrupes-vmoperator-vmviewer-preview"))!;
|
":scope .jdrupes-vmoperator-vmaccess-preview"))!;
|
||||||
api.vmName = vmName;
|
api.vmName = vmName;
|
||||||
});
|
});
|
||||||
|
|
||||||
JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmviewer.VmViewer",
|
JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmaccess.VmAccess",
|
||||||
"updateVmDefinition", function(conletId: string, vmDefinition: any) {
|
"updateVmDefinition", function(conletId: string, vmDefinition: any) {
|
||||||
const conlet = JGConsole.findConletPreview(conletId);
|
const conlet = JGConsole.findConletPreview(conletId);
|
||||||
if (!conlet) {
|
if (!conlet) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const api = getApi<Api>(conlet.element().querySelector(
|
const api = getApi<Api>(conlet.element().querySelector(
|
||||||
":scope .jdrupes-vmoperator-vmviewer-preview"))!;
|
":scope .jdrupes-vmoperator-vmaccess-preview"))!;
|
||||||
// Add some short-cuts for rendering
|
// Add some short-cuts for rendering
|
||||||
vmDefinition.name = vmDefinition.metadata.name;
|
vmDefinition.name = vmDefinition.metadata.name;
|
||||||
vmDefinition.currentCpus = vmDefinition.status.cpus;
|
vmDefinition.currentCpus = vmDefinition.status.cpus;
|
||||||
|
|
@ -173,13 +173,13 @@ JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmviewer.VmViewer",
|
||||||
api.vmDefinition = vmDefinition;
|
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) {
|
"openConsole", function(_conletId: string, mimeType: string, data: string) {
|
||||||
let target = document.getElementById(
|
let target = document.getElementById(
|
||||||
"org.jdrupes.vmoperator.vmviewer.VmViewer.target");
|
"org.jdrupes.vmoperator.vmaccess.VmAccess.target");
|
||||||
if (!target) {
|
if (!target) {
|
||||||
target = document.createElement("iframe");
|
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("name", target.id);
|
||||||
target.setAttribute("style", "display: none;");
|
target.setAttribute("style", "display: none;");
|
||||||
document.querySelector("body")!.append(target);
|
document.querySelector("body")!.append(target);
|
||||||
|
|
@ -188,7 +188,7 @@ JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmviewer.VmViewer",
|
||||||
window.open(url, target.id);
|
window.open(url, target.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
window.orgJDrupesVmOperatorVmViewer.initEdit = (dialogDom: HTMLElement,
|
window.orgJDrupesVmOperatorVmAccess.initEdit = (dialogDom: HTMLElement,
|
||||||
isUpdate: boolean) => {
|
isUpdate: boolean) => {
|
||||||
if (isUpdate) {
|
if (isUpdate) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -209,7 +209,7 @@ window.orgJDrupesVmOperatorVmViewer.initEdit = (dialogDom: HTMLElement,
|
||||||
const conlet = JGConsole.findConletPreview(conletId);
|
const conlet = JGConsole.findConletPreview(conletId);
|
||||||
if (conlet) {
|
if (conlet) {
|
||||||
const api = getApi<Api>(conlet.element().querySelector(
|
const api = getApi<Api>(conlet.element().querySelector(
|
||||||
":scope .jdrupes-vmoperator-vmviewer-preview"))!;
|
":scope .jdrupes-vmoperator-vmaccess-preview"))!;
|
||||||
vmNameInput.value = api.vmName;
|
vmNameInput.value = api.vmName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -222,7 +222,7 @@ window.orgJDrupesVmOperatorVmViewer.initEdit = (dialogDom: HTMLElement,
|
||||||
app.mount(dialogDom);
|
app.mount(dialogDom);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.orgJDrupesVmOperatorVmViewer.applyEdit =
|
window.orgJDrupesVmOperatorVmAccess.applyEdit =
|
||||||
(dialogDom: HTMLElement, apply: boolean) => {
|
(dialogDom: HTMLElement, apply: boolean) => {
|
||||||
if (!apply) {
|
if (!apply) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -233,7 +233,7 @@ window.orgJDrupesVmOperatorVmViewer.applyEdit =
|
||||||
JGConsole.notifyConletModel(conletId, "selectedVm", vmName);
|
JGConsole.notifyConletModel(conletId, "selectedVm", vmName);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.orgJDrupesVmOperatorVmViewer.confirmReset =
|
window.orgJDrupesVmOperatorVmAccess.confirmReset =
|
||||||
(conletType: string, conletId: string) => {
|
(conletType: string, conletId: string) => {
|
||||||
JGConsole.instance.closeModalDialog(conletType, conletId);
|
JGConsole.instance.closeModalDialog(conletType, conletId);
|
||||||
JGConsole.notifyConletModel(conletId, "resetConfirmed");
|
JGConsole.notifyConletModel(conletId, "resetConfirmed");
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
/*
|
/*
|
||||||
* Conlet specific styles.
|
* Conlet specific styles.
|
||||||
*/
|
*/
|
||||||
.jdrupes-vmoperator-vmviewer {
|
.jdrupes-vmoperator-vmaccess {
|
||||||
|
|
||||||
span[role="button"].svg-icon {
|
span[role="button"].svg-icon {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|
@ -47,7 +47,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.jdrupes-vmoperator-vmviewer.jdrupes-vmoperator-vmviewer-preview {
|
.jdrupes-vmoperator-vmaccess.jdrupes-vmoperator-vmaccess-preview {
|
||||||
|
|
||||||
img {
|
img {
|
||||||
height: 3em;
|
height: 3em;
|
||||||
|
|
@ -58,7 +58,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.jdrupes-vmoperator-vmviewer-preview-action-list {
|
.jdrupes-vmoperator-vmaccess-preview-action-list {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -76,13 +76,13 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.jdrupes-vmoperator-vmviewer.jdrupes-vmoperator-vmviewer-edit {
|
.jdrupes-vmoperator-vmaccess.jdrupes-vmoperator-vmaccess-edit {
|
||||||
select {
|
select {
|
||||||
width: 15em;
|
width: 15em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.jdrupes-vmoperator-vmviewer.jdrupes-vmoperator-vmviewer-confirm-reset {
|
.jdrupes-vmoperator-vmaccess.jdrupes-vmoperator-vmaccess-confirm-reset {
|
||||||
p {
|
p {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* VM-Operator
|
* 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
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as
|
* 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/>.
|
* 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"],
|
"aash-plugin": ["./build/unpacked/org/jgrapes/webconsole/provider/jgwcvuecomponents/aash-vue-components/lib/AashPlugin"],
|
||||||
"jgconsole": ["./build/unpacked/org/jgrapes/webconsole/base/JGConsole"],
|
"jgconsole": ["./build/unpacked/org/jgrapes/webconsole/base/JGConsole"],
|
||||||
"jgwc": ["./build/unpacked/org/jgrapes/webconsole/provider/jgwcvuecomponents/jgwc-vue-components/jgwc-components"],
|
"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"]
|
"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-conlet-grid-rows="5"
|
||||||
data-jgwc-on-load="orgJDrupesVmOperatorVmConlet.initPreview"
|
data-jgwc-on-load="orgJDrupesVmOperatorVmMgmt.initPreview"
|
||||||
data-jgwc-on-unload="JGConsole.jgwc.unmountVueApps">
|
data-jgwc-on-unload="JGConsole.jgwc.unmountVueApps">
|
||||||
|
|
||||||
<form>
|
<form>
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<div class="jdrupes-vmoperator-vmconlet jdrupes-vmoperator-vmconlet-view"
|
<div class="jdrupes-vmoperator-vmmgmt jdrupes-vmoperator-vmmgmt-view"
|
||||||
data-jgwc-on-load="orgJDrupesVmOperatorVmConlet.initView"
|
data-jgwc-on-load="orgJDrupesVmOperatorVmMgmt.initView"
|
||||||
data-jgwc-on-unload="JGConsole.jgwc.unmountVueApps">
|
data-jgwc-on-unload="JGConsole.jgwc.unmountVueApps">
|
||||||
<div class="jdrupes-vmoperator-vmconlet-view-search">
|
<div class="jdrupes-vmoperator-vmmgmt-view-search">
|
||||||
<form>
|
<form>
|
||||||
<label class="form__label--horizontal">
|
<label class="form__label--horizontal">
|
||||||
<span>{{ localize("Filter") }}</span>
|
<span>{{ localize("Filter") }}</span>
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<table
|
<table
|
||||||
class="table--basic--striped jdrupes-vmoperator-vmconlet-view-table">
|
class="table--basic--striped jdrupes-vmoperator-vmmgmt-view-table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th v-for="key in controller.keys"
|
<th v-for="key in controller.keys"
|
||||||
|
|
@ -51,7 +51,7 @@
|
||||||
<span v-else
|
<span v-else
|
||||||
v-html="controller.breakBeforeDots(entry[key])"></span>
|
v-html="controller.breakBeforeDots(entry[key])"></span>
|
||||||
</td>
|
</td>
|
||||||
<td class="jdrupes-vmoperator-vmconlet-view-action-list">
|
<td class="jdrupes-vmoperator-vmmgmt-view-action-list">
|
||||||
<span role="button"
|
<span role="button"
|
||||||
v-if="entry.spec.vm.state != 'Running' && !entry['running']"
|
v-if="entry.spec.vm.state != 'Running' && !entry['running']"
|
||||||
tabindex="0" class="fa fa-play" :title="localize('Start VM')"
|
tabindex="0" class="fa fa-play" :title="localize('Start VM')"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
conletName = VM Infos
|
conletName = VM Management
|
||||||
|
|
||||||
VMsSummary = VMs (running/total)
|
VMsSummary = VMs (running/total)
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
conletName = VM-Informationen
|
conletName = VM-Management
|
||||||
|
|
||||||
VMsSummary = VMs (gestartet/gesamt)
|
VMsSummary = VMs (gestartet/gesamt)
|
||||||
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import typescript from 'rollup-plugin-typescript2';
|
import typescript from 'rollup-plugin-typescript2';
|
||||||
import postcss from 'rollup-plugin-postcss';
|
import postcss from 'rollup-plugin-postcss';
|
||||||
|
|
||||||
let packagePath = "org/jdrupes/vmoperator/vmconlet";
|
let packagePath = "org/jdrupes/vmoperator/vmmgmt";
|
||||||
let baseName = "VmConlet"
|
let baseName = "VmMgmt"
|
||||||
let module = "build/generated/resources/" + packagePath
|
let module = "build/generated/resources/" + packagePath
|
||||||
+ "/" + baseName + "-functions.js";
|
+ "/" + baseName + "-functions.js";
|
||||||
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* 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.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* 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.core.ParseException;
|
||||||
import freemarker.template.MalformedTemplateNameException;
|
import freemarker.template.MalformedTemplateNameException;
|
||||||
|
|
@ -61,11 +61,11 @@ import org.jgrapes.webconsole.base.events.SetLocale;
|
||||||
import org.jgrapes.webconsole.base.freemarker.FreeMarkerConlet;
|
import org.jgrapes.webconsole.base.freemarker.FreeMarkerConlet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Class VmConlet.
|
* The Class {@link VmMgmt}.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings({ "PMD.DataflowAnomalyAnalysis",
|
@SuppressWarnings({ "PMD.DataflowAnomalyAnalysis",
|
||||||
"PMD.CouplingBetweenObjects" })
|
"PMD.CouplingBetweenObjects" })
|
||||||
public class VmConlet extends FreeMarkerConlet<VmConlet.VmsModel> {
|
public class VmMgmt extends FreeMarkerConlet<VmMgmt.VmsModel> {
|
||||||
|
|
||||||
private static final Set<RenderMode> MODES = RenderMode.asSet(
|
private static final Set<RenderMode> MODES = RenderMode.asSet(
|
||||||
RenderMode.Preview, RenderMode.View);
|
RenderMode.Preview, RenderMode.View);
|
||||||
|
|
@ -88,7 +88,7 @@ public class VmConlet extends FreeMarkerConlet<VmConlet.VmsModel> {
|
||||||
* sends the event to
|
* sends the event to
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("PMD.ConstructorCallsOverridableMethod")
|
@SuppressWarnings("PMD.ConstructorCallsOverridableMethod")
|
||||||
public VmConlet(Channel componentChannel) {
|
public VmMgmt(Channel componentChannel) {
|
||||||
super(componentChannel);
|
super(componentChannel);
|
||||||
setPeriodicRefresh(Duration.ofMinutes(1), () -> new Update());
|
setPeriodicRefresh(Duration.ofMinutes(1), () -> new Update());
|
||||||
}
|
}
|
||||||
|
|
@ -115,7 +115,7 @@ public class VmConlet extends FreeMarkerConlet<VmConlet.VmsModel> {
|
||||||
.addRenderMode(RenderMode.Preview)
|
.addRenderMode(RenderMode.Preview)
|
||||||
.addScript(new ScriptResource().setScriptType("module")
|
.addScript(new ScriptResource().setScriptType("module")
|
||||||
.setScriptUri(event.renderSupport().conletResource(
|
.setScriptUri(event.renderSupport().conletResource(
|
||||||
type(), "VmConlet-functions.js"))));
|
type(), "VmMgmt-functions.js"))));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -133,7 +133,7 @@ public class VmConlet extends FreeMarkerConlet<VmConlet.VmsModel> {
|
||||||
boolean sendVmInfos = false;
|
boolean sendVmInfos = false;
|
||||||
if (event.renderAs().contains(RenderMode.Preview)) {
|
if (event.renderAs().contains(RenderMode.Preview)) {
|
||||||
Template tpl
|
Template tpl
|
||||||
= freemarkerConfig().getTemplate("VmConlet-preview.ftl.html");
|
= freemarkerConfig().getTemplate("VmMgmt-preview.ftl.html");
|
||||||
channel.respond(new RenderConlet(type(), conletId,
|
channel.respond(new RenderConlet(type(), conletId,
|
||||||
processTemplate(event, tpl,
|
processTemplate(event, tpl,
|
||||||
fmModel(event, channel, conletId, conletState)))
|
fmModel(event, channel, conletId, conletState)))
|
||||||
|
|
@ -150,7 +150,7 @@ public class VmConlet extends FreeMarkerConlet<VmConlet.VmsModel> {
|
||||||
}
|
}
|
||||||
if (event.renderAs().contains(RenderMode.View)) {
|
if (event.renderAs().contains(RenderMode.View)) {
|
||||||
Template tpl
|
Template tpl
|
||||||
= freemarkerConfig().getTemplate("VmConlet-view.ftl.html");
|
= freemarkerConfig().getTemplate("VmMgmt-view.ftl.html");
|
||||||
channel.respond(new RenderConlet(type(), conletId,
|
channel.respond(new RenderConlet(type(), conletId,
|
||||||
processTemplate(event, tpl,
|
processTemplate(event, tpl,
|
||||||
fmModel(event, channel, conletId, conletState)))
|
fmModel(event, channel, conletId, conletState)))
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* 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.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
@ -25,9 +25,9 @@ import org.jgrapes.core.ComponentType;
|
||||||
import org.jgrapes.webconsole.base.ConletComponentFactory;
|
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)
|
* (non-Javadoc)
|
||||||
|
|
@ -36,7 +36,7 @@ public class VmConletFactory implements ConletComponentFactory {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Class<? extends ComponentType> componentType() {
|
public Class<? extends ComponentType> componentType() {
|
||||||
return VmConlet.class;
|
return VmMgmt.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -48,7 +48,7 @@ public class VmConletFactory implements ConletComponentFactory {
|
||||||
@Override
|
@Override
|
||||||
public Optional<ComponentType> create(Channel componentChannel,
|
public Optional<ComponentType> create(Channel componentChannel,
|
||||||
Map<?, ?> properties) {
|
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 CpuRamChart from "./CpuRamChart";
|
||||||
import ConditionlInputController from "./ConditionalInputController";
|
import ConditionlInputController from "./ConditionalInputController";
|
||||||
|
|
||||||
import "./VmConlet-style.scss";
|
import "./VmMgmt-style.scss";
|
||||||
|
|
||||||
// For global access
|
// For global access
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
orgJDrupesVmOperatorVmConlet: {
|
orgJDrupesVmOperatorVmMgmt: {
|
||||||
initPreview?: (previewDom: HTMLElement, isUpdate: boolean) => void,
|
initPreview?: (previewDom: HTMLElement, isUpdate: boolean) => void,
|
||||||
initView?: (viewDom: HTMLElement, isUpdate: boolean) => void
|
initView?: (viewDom: HTMLElement, isUpdate: boolean) => void
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.orgJDrupesVmOperatorVmConlet = {};
|
window.orgJDrupesVmOperatorVmMgmt = {};
|
||||||
|
|
||||||
const vmInfos = reactive(new Map());
|
const vmInfos = reactive(new Map());
|
||||||
const vmSummary = reactive({
|
const vmSummary = reactive({
|
||||||
|
|
@ -64,7 +64,7 @@ const shortDateTime = (time: Date) => {
|
||||||
const chartData = new TimeSeries(2);
|
const chartData = new TimeSeries(2);
|
||||||
const chartDateUpdate = ref<Date>(null);
|
const chartDateUpdate = ref<Date>(null);
|
||||||
|
|
||||||
window.orgJDrupesVmOperatorVmConlet.initPreview = (previewDom: HTMLElement,
|
window.orgJDrupesVmOperatorVmMgmt.initPreview = (previewDom: HTMLElement,
|
||||||
_isUpdate: boolean) => {
|
_isUpdate: boolean) => {
|
||||||
const app = createApp({
|
const app = createApp({
|
||||||
setup(_props: object) {
|
setup(_props: object) {
|
||||||
|
|
@ -98,7 +98,7 @@ window.orgJDrupesVmOperatorVmConlet.initPreview = (previewDom: HTMLElement,
|
||||||
app.mount(previewDom);
|
app.mount(previewDom);
|
||||||
};
|
};
|
||||||
|
|
||||||
window.orgJDrupesVmOperatorVmConlet.initView = (viewDom: HTMLElement,
|
window.orgJDrupesVmOperatorVmMgmt.initView = (viewDom: HTMLElement,
|
||||||
_isUpdate: boolean) => {
|
_isUpdate: boolean) => {
|
||||||
const app = createApp({
|
const app = createApp({
|
||||||
setup(_props: object) {
|
setup(_props: object) {
|
||||||
|
|
@ -174,7 +174,7 @@ window.orgJDrupesVmOperatorVmConlet.initView = (viewDom: HTMLElement,
|
||||||
app.mount(viewDom);
|
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
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
"updateVm", function(_conletId: string, vmDefinition: any) {
|
"updateVm", function(_conletId: string, vmDefinition: any) {
|
||||||
// Add some short-cuts for table controller
|
// Add some short-cuts for table controller
|
||||||
|
|
@ -194,12 +194,12 @@ JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmconlet.VmConlet",
|
||||||
vmInfos.set(vmDefinition.name, vmDefinition);
|
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) {
|
"removeVm", function(_conletId: string, vmName: string) {
|
||||||
vmInfos.delete(vmName);
|
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
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
"summarySeries", function(_conletId: string, series: any[]) {
|
"summarySeries", function(_conletId: string, series: any[]) {
|
||||||
chartData.clear();
|
chartData.clear();
|
||||||
|
|
@ -210,7 +210,7 @@ JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmconlet.VmConlet",
|
||||||
chartDateUpdate.value = new Date();
|
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
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
"updateSummary", function(_conletId: string, summary: any) {
|
"updateSummary", function(_conletId: string, summary: any) {
|
||||||
chartData.push(new Date(), summary.usedCpus, Number(summary.usedRam));
|
chartData.push(new Date(), summary.usedCpus, Number(summary.usedRam));
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
* Conlet specific styles.
|
* Conlet specific styles.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.jdrupes-vmoperator-vmconlet-preview {
|
.jdrupes-vmoperator-vmmgmt-preview {
|
||||||
form {
|
form {
|
||||||
float: right;
|
float: right;
|
||||||
padding: 0.15em 0.3em;
|
padding: 0.15em 0.3em;
|
||||||
|
|
@ -37,7 +37,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.jdrupes-vmoperator-vmconlet-view-search {
|
.jdrupes-vmoperator-vmmgmt-view-search {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
|
|
||||||
|
|
@ -46,7 +46,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.jdrupes-vmoperator-vmconlet-view-table {
|
.jdrupes-vmoperator-vmmgmt-view-table {
|
||||||
td {
|
td {
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
|
|
||||||
|
|
@ -94,7 +94,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.jdrupes-vmoperator-vmconlet-view-action-list {
|
.jdrupes-vmoperator-vmmgmt-view-action-list {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
||||||
[role=button] {
|
[role=button] {
|
||||||
|
|
@ -16,4 +16,4 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* 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"],
|
"aash-plugin": ["./build/unpacked/org/jgrapes/webconsole/provider/jgwcvuecomponents/aash-vue-components/lib/AashPlugin"],
|
||||||
"jgconsole": ["./build/unpacked/org/jgrapes/webconsole/base/JGConsole"],
|
"jgconsole": ["./build/unpacked/org/jgrapes/webconsole/base/JGConsole"],
|
||||||
"jgwc": ["./build/unpacked/org/jgrapes/webconsole/provider/jgwcvuecomponents/jgwc-vue-components/jgwc-components"],
|
"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"],
|
"vue": ["./build/unpacked/org/jgrapes/webconsole/provider/vue/vue/vue"],
|
||||||
"chartjs": ["./build/unpacked/org/jgrapes/webconsole/provider/chartjs/chart.js/auto/auto"]
|
"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'
|
||||||
include 'org.jdrupes.vmoperator.manager.events'
|
include 'org.jdrupes.vmoperator.manager.events'
|
||||||
include 'org.jdrupes.vmoperator.vmconlet'
|
include 'org.jdrupes.vmoperator.vmaccess'
|
||||||
include 'org.jdrupes.vmoperator.vmviewer'
|
include 'org.jdrupes.vmoperator.vmmgmt'
|
||||||
include 'org.jdrupes.vmoperator.runner.qemu'
|
include 'org.jdrupes.vmoperator.runner.qemu'
|
||||||
include 'org.jdrupes.vmoperator.common'
|
include 'org.jdrupes.vmoperator.common'
|
||||||
include 'org.jdrupes.vmoperator.util'
|
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
|
# 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
|
## To version 3.4.0
|
||||||
|
|
||||||
Starting with this version, the VM-Operator no longer uses a stateful set
|
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
|
allows the users to access their own VMs and to optionally start
|
||||||
and stop them.
|
and stop them.
|
||||||
|
|
||||||

|

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