diff --git a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinition.java b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinition.java index 71ea7f1..bab0802 100644 --- a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinition.java +++ b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinition.java @@ -94,6 +94,28 @@ public class VmDefinition { } } + /** + * Permissions granted 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 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(); + } + } + /** * Gets the kind. * @@ -292,7 +314,6 @@ public class VmDefinition { * @return the string */ public RequestedVmState vmState() { - // TODO return fromVm("state") .map(s -> "Running".equals(s) ? RequestedVmState.RUNNING : RequestedVmState.STOPPED) diff --git a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmPool.java b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmPool.java index 4b29adc..07e0616 100644 --- a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmPool.java +++ b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmPool.java @@ -20,14 +20,13 @@ 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.common.VmDefinition.Grant; +import org.jdrupes.vmoperator.common.VmDefinition.Permission; import org.jdrupes.vmoperator.util.DataPath; /** @@ -60,7 +59,7 @@ public class VmPool { } /** - * All permissions. + * Permissions granted for a VM from the pool. * * @return the permissions */ @@ -120,68 +119,4 @@ public class VmPool { .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 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 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 parse(String value) { - if ("*".equals(value)) { - return EnumSet.allOf(Permission.class); - } - return Set.of(reprs.get(value)); - } - - @Override - public String toString() { - return repr; - } - } - } diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PoolManager.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PoolManager.java index fb1de27..7bc455d 100644 --- a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PoolManager.java +++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PoolManager.java @@ -142,9 +142,10 @@ public class PoolManager extends V1ObjectMeta metadata = response.object.getMetadata(); vmPool.setName(metadata.getName()); - // If modified, merge changes + // If modified, merge changes and notify if (type == ResponseType.MODIFIED && pools.containsKey(poolName)) { pools.get(poolName).setPermissions(vmPool.permissions()); + poolPipeline.fire(new VmPoolChanged(vmPool)); return; } diff --git a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java index f671e93..4f4ef53 100644 --- a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java +++ b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java @@ -50,6 +50,7 @@ import java.util.stream.Collectors; import org.bouncycastle.util.Objects; import org.jdrupes.vmoperator.common.K8sObserver; import org.jdrupes.vmoperator.common.VmDefinition; +import org.jdrupes.vmoperator.common.VmDefinition.Permission; import org.jdrupes.vmoperator.common.VmPool; import org.jdrupes.vmoperator.manager.events.ChannelTracker; import org.jdrupes.vmoperator.manager.events.GetDisplayPassword; @@ -108,7 +109,8 @@ import org.jgrapes.webconsole.base.freemarker.FreeMarkerConlet; * */ @SuppressWarnings({ "PMD.DataflowAnomalyAnalysis", "PMD.ExcessiveImports", - "PMD.CouplingBetweenObjects", "PMD.GodClass", "PMD.TooManyMethods" }) + "PMD.CouplingBetweenObjects", "PMD.GodClass", "PMD.TooManyMethods", + "PMD.CyclomaticComplexity" }) public class VmAccess extends FreeMarkerConlet { private static final String VM_NAME_PROPERTY = "vmName"; @@ -265,7 +267,8 @@ public class VmAccess extends FreeMarkerConlet { addMissingVms(event, connection, rendered); } - @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") + @SuppressWarnings({ "PMD.AvoidInstantiatingObjectsInLoops", + "PMD.AvoidDuplicateLiterals" }) private void addMissingVms(ConsoleConfigured event, ConsoleConnection connection, final Set rendered) { boolean foundMissing = false; @@ -445,7 +448,7 @@ public class VmAccess extends FreeMarkerConlet { .map(d -> d.getMetadata().getName()).sorted().toList(); } - private Set vmPermissions(VmDefinition vmDef, + private Set vmPermissions(VmDefinition vmDef, Session session) { var user = WebConsoleUtils.userFromSession(session) .map(ConsoleUser::getName).orElse(null); @@ -460,7 +463,7 @@ public class VmAccess extends FreeMarkerConlet { .map(d -> d.name()).sorted().toList(); } - private Set poolPermissions(VmPool pool, + private Set poolPermissions(VmPool pool, Session session) { var user = WebConsoleUtils.userFromSession(session) .map(ConsoleUser::getName).orElse(null); @@ -530,15 +533,19 @@ public class VmAccess extends FreeMarkerConlet { } else { channelTracker.put(vmName, channel, vmDef); } + + // Update known conlets for (var entry : conletIdsByConsoleConnection().entrySet()) { var connection = entry.getKey(); for (var conletId : entry.getValue()) { var model = stateFromSession(connection.session(), conletId); if (model.isEmpty() + || model.get().type() != ResourceModel.Type.VM || !Objects.areEqual(model.get().name(), vmName)) { continue; } - if (event.type() == K8sObserver.ResponseType.DELETED) { + if (event.type() == K8sObserver.ResponseType.DELETED + || vmPermissions(vmDef, connection.session()).isEmpty()) { connection.respond( new DeleteConlet(conletId, Collections.emptySet())); } else { @@ -555,12 +562,33 @@ public class VmAccess extends FreeMarkerConlet { * @param channel the channel */ @Handler(namedChannels = "manager") + @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") public void onVmPoolChanged(VmPoolChanged event) { + var poolName = event.vmPool().name(); if (event.deleted()) { - vmPools.remove(event.vmPool().name()); - return; + vmPools.remove(poolName); + } else { + vmPools.put(poolName, event.vmPool()); + } + + // Update known conlets + for (var entry : conletIdsByConsoleConnection().entrySet()) { + var connection = entry.getKey(); + for (var conletId : entry.getValue()) { + var model = stateFromSession(connection.session(), conletId); + if (model.isEmpty() + || model.get().type() != ResourceModel.Type.POOL + || !Objects.areEqual(model.get().name(), poolName)) { + continue; + } + if (event.deleted() + || poolPermissions(event.vmPool(), connection.session()) + .isEmpty()) { + connection.respond( + new DeleteConlet(conletId, Collections.emptySet())); + } + } } - vmPools.put(event.vmPool().name(), event.vmPool()); } @Override