Don't duplicate VM management.

This commit is contained in:
Michael Lipp 2025-01-18 17:02:30 +01:00
parent 5bd6700541
commit 76be59a5b3
5 changed files with 315 additions and 85 deletions

View file

@ -0,0 +1,67 @@
/*
* 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.manager.events;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.jdrupes.vmoperator.common.VmPool;
import org.jgrapes.core.Event;
/**
* Gets the known pools' definitions.
*/
@SuppressWarnings("PMD.DataClass")
public class GetPools extends Event<List<VmPool>> {
private String user;
private List<String> roles = Collections.emptyList();
/**
* Return only {@link VmPool}s that are accessible by
* the given user or roles.
*
* @param user the user
* @param roles the roles
* @return the event
*/
public GetPools accessibleFor(String user, List<String> roles) {
this.user = user;
this.roles = roles;
return this;
}
/**
* Returns the user filter criterion, if set.
*
* @return the optional
*/
public Optional<String> forUser() {
return Optional.ofNullable(user);
}
/**
* Returns the roles criterion.
*
* @return the list
*/
public List<String> forRoles() {
return roles;
}
}

View file

@ -0,0 +1,97 @@
/*
* 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.manager.events;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.jdrupes.vmoperator.common.VmDefinition;
import org.jgrapes.core.Event;
/**
* Gets the known VMs' definitions and channels.
*/
@SuppressWarnings("PMD.DataClass")
public class GetVms extends Event<List<GetVms.VmData>> {
private String name;
private String user;
private List<String> roles = Collections.emptyList();
/**
* Return only the VMs with the given name.
*
* @param name the name
* @return the returns the vms
*/
public GetVms withName(String name) {
this.name = name;
return this;
}
/**
* Return only {@link VmDefinition}s that are accessible by
* the given user or roles.
*
* @param user the user
* @param roles the roles
* @return the event
*/
public GetVms accessibleFor(String user, List<String> roles) {
this.user = user;
this.roles = roles;
return this;
}
/**
* Returns the name filter criterion, if set.
*
* @return the optional
*/
public Optional<String> name() {
return Optional.ofNullable(name);
}
/**
* Returns the user filter criterion, if set.
*
* @return the optional
*/
public Optional<String> user() {
return Optional.ofNullable(user);
}
/**
* Returns the roles criterion.
*
* @return the list
*/
public List<String> roles() {
return roles;
}
/**
* Return tuple.
*
* @param definition the definition
* @param channel the channel
*/
public record VmData(VmDefinition definition, VmChannel channel) {
}
}

View file

@ -35,6 +35,7 @@ import org.jdrupes.vmoperator.common.K8sDynamicStub;
import org.jdrupes.vmoperator.common.K8sObserver.ResponseType; import org.jdrupes.vmoperator.common.K8sObserver.ResponseType;
import org.jdrupes.vmoperator.common.VmPool; import org.jdrupes.vmoperator.common.VmPool;
import static org.jdrupes.vmoperator.manager.Constants.VM_OP_KIND_VM_POOL; import static org.jdrupes.vmoperator.manager.Constants.VM_OP_KIND_VM_POOL;
import org.jdrupes.vmoperator.manager.events.GetPools;
import org.jdrupes.vmoperator.manager.events.VmDefChanged; import org.jdrupes.vmoperator.manager.events.VmDefChanged;
import org.jdrupes.vmoperator.manager.events.VmPoolChanged; import org.jdrupes.vmoperator.manager.events.VmPoolChanged;
import org.jdrupes.vmoperator.util.GsonPtr; import org.jdrupes.vmoperator.util.GsonPtr;
@ -161,4 +162,18 @@ public class PoolMonitor extends
break; break;
} }
} }
/**
* Return the requested pools.
*
* @param event the event
*/
@Handler
public void onGetPools(GetPools event) {
event.setResult(pools.values().stream()
.filter(p -> event.forUser().isEmpty() && event.forRoles().isEmpty()
|| !p.permissionsFor(event.forUser().orElse(null),
event.forRoles()).isEmpty())
.toList());
}
} }

View file

@ -44,10 +44,13 @@ import static org.jdrupes.vmoperator.manager.Constants.APP_NAME;
import static org.jdrupes.vmoperator.manager.Constants.VM_OP_KIND_VM; import static org.jdrupes.vmoperator.manager.Constants.VM_OP_KIND_VM;
import static org.jdrupes.vmoperator.manager.Constants.VM_OP_NAME; import static org.jdrupes.vmoperator.manager.Constants.VM_OP_NAME;
import org.jdrupes.vmoperator.manager.events.ChannelManager; import org.jdrupes.vmoperator.manager.events.ChannelManager;
import org.jdrupes.vmoperator.manager.events.GetVms;
import org.jdrupes.vmoperator.manager.events.GetVms.VmData;
import org.jdrupes.vmoperator.manager.events.VmChannel; import org.jdrupes.vmoperator.manager.events.VmChannel;
import org.jdrupes.vmoperator.manager.events.VmDefChanged; import org.jdrupes.vmoperator.manager.events.VmDefChanged;
import org.jgrapes.core.Channel; import org.jgrapes.core.Channel;
import org.jgrapes.core.Event; import org.jgrapes.core.Event;
import org.jgrapes.core.annotation.Handler;
/** /**
* Watches for changes of VM definitions. * Watches for changes of VM definitions.
@ -208,4 +211,21 @@ public class VmMonitor extends
() -> "Cannot access node information: " + e.getMessage()); () -> "Cannot access node information: " + e.getMessage());
} }
} }
/**
* Returns the VM data.
*
* @param event the event
*/
@Handler
public void onGetVms(GetVms event) {
event.setResult(channelManager.channels().stream()
.filter(c -> event.name().isEmpty()
|| c.vmDefinition().name().equals(event.name().get()))
.filter(c -> event.user().isEmpty() && event.roles().isEmpty()
|| !c.vmDefinition().permissionsFor(event.user().orElse(null),
event.roles()).isEmpty())
.map(c -> new VmData(c.vmDefinition(), c))
.toList());
}
} }

View file

@ -52,8 +52,10 @@ import org.jdrupes.vmoperator.common.K8sObserver;
import org.jdrupes.vmoperator.common.VmDefinition; import org.jdrupes.vmoperator.common.VmDefinition;
import org.jdrupes.vmoperator.common.VmDefinition.Permission; import org.jdrupes.vmoperator.common.VmDefinition.Permission;
import org.jdrupes.vmoperator.common.VmPool; import org.jdrupes.vmoperator.common.VmPool;
import org.jdrupes.vmoperator.manager.events.ChannelTracker;
import org.jdrupes.vmoperator.manager.events.GetDisplayPassword; import org.jdrupes.vmoperator.manager.events.GetDisplayPassword;
import org.jdrupes.vmoperator.manager.events.GetPools;
import org.jdrupes.vmoperator.manager.events.GetVms;
import org.jdrupes.vmoperator.manager.events.GetVms.VmData;
import org.jdrupes.vmoperator.manager.events.ModifyVm; import org.jdrupes.vmoperator.manager.events.ModifyVm;
import org.jdrupes.vmoperator.manager.events.ResetVm; import org.jdrupes.vmoperator.manager.events.ResetVm;
import org.jdrupes.vmoperator.manager.events.VmChannel; import org.jdrupes.vmoperator.manager.events.VmChannel;
@ -62,8 +64,10 @@ import org.jdrupes.vmoperator.manager.events.VmPoolChanged;
import org.jgrapes.core.Channel; import org.jgrapes.core.Channel;
import org.jgrapes.core.Components; import org.jgrapes.core.Components;
import org.jgrapes.core.Event; import org.jgrapes.core.Event;
import org.jgrapes.core.EventPipeline;
import org.jgrapes.core.Manager; import org.jgrapes.core.Manager;
import org.jgrapes.core.annotation.Handler; import org.jgrapes.core.annotation.Handler;
import org.jgrapes.core.events.Start;
import org.jgrapes.http.Session; import org.jgrapes.http.Session;
import org.jgrapes.util.events.ConfigurationUpdate; import org.jgrapes.util.events.ConfigurationUpdate;
import org.jgrapes.util.events.KeyValueStoreQuery; import org.jgrapes.util.events.KeyValueStoreQuery;
@ -122,8 +126,7 @@ public class VmAccess extends FreeMarkerConlet<VmAccess.ResourceModel> {
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(
RenderMode.Preview, RenderMode.StickyPreview); RenderMode.Preview, RenderMode.StickyPreview);
private final ChannelTracker<String, VmChannel, private EventPipeline appPipeline;
VmDefinition> channelTracker = new ChannelTracker<>();
private static ObjectMapper objectMapper private static ObjectMapper objectMapper
= new ObjectMapper().registerModule(new JavaTimeModule()); = new ObjectMapper().registerModule(new JavaTimeModule());
private Class<?> preferredIpVersion = Inet4Address.class; private Class<?> preferredIpVersion = Inet4Address.class;
@ -150,6 +153,16 @@ public class VmAccess extends FreeMarkerConlet<VmAccess.ResourceModel> {
super(componentChannel); super(componentChannel);
} }
/**
* On start.
*
* @param event the event
*/
@Handler
public void onStart(Start event) {
appPipeline = event.processedBy().get();
}
/** /**
* Configure the component. * Configure the component.
* *
@ -263,18 +276,24 @@ public class VmAccess extends FreeMarkerConlet<VmAccess.ResourceModel> {
if (!syncPreviews(connection.session())) { if (!syncPreviews(connection.session())) {
return; return;
} }
addMissingConlets(event, connection, rendered);
addMissingVms(event, connection, rendered);
} }
@SuppressWarnings({ "PMD.AvoidInstantiatingObjectsInLoops", @SuppressWarnings({ "PMD.AvoidInstantiatingObjectsInLoops",
"PMD.AvoidDuplicateLiterals" }) "PMD.AvoidDuplicateLiterals" })
private void addMissingVms(ConsoleConfigured event, private void addMissingConlets(ConsoleConfigured event,
ConsoleConnection connection, final Set<ResourceModel> rendered) { ConsoleConnection connection, final Set<ResourceModel> rendered)
throws InterruptedException {
boolean foundMissing = false; boolean foundMissing = false;
for (var vmName : accessibleVms(connection)) { var session = connection.session();
for (var vmName : appPipeline.fire(new GetVms().accessibleFor(
WebConsoleUtils.userFromSession(session)
.map(ConsoleUser::getName).orElse(null),
WebConsoleUtils.rolesFromSession(session).stream()
.map(ConsoleRole::getName).toList()))
.get().stream().map(d -> d.definition().name()).toList()) {
if (rendered.stream() if (rendered.stream()
.anyMatch(r -> r.type() == ResourceModel.Type.VM .anyMatch(r -> r.mode() == ResourceModel.Mode.VM
&& r.name().equals(vmName))) { && r.name().equals(vmName))) {
continue; continue;
} }
@ -318,7 +337,7 @@ public class VmAccess extends FreeMarkerConlet<VmAccess.ResourceModel> {
protected Optional<ResourceModel> createNewState(AddConletRequest event, protected Optional<ResourceModel> createNewState(AddConletRequest event,
ConsoleConnection connection, String conletId) throws Exception { ConsoleConnection connection, String conletId) throws Exception {
var model = new ResourceModel(conletId); var model = new ResourceModel(conletId);
model.setType(ResourceModel.Type.VM); model.setMode(ResourceModel.Mode.VM);
model model
.setName((String) event.properties().get(VM_NAME_PROPERTY)); .setName((String) event.properties().get(VM_NAME_PROPERTY));
String jsonState = objectMapper.writeValueAsString(model); String jsonState = objectMapper.writeValueAsString(model);
@ -373,11 +392,25 @@ public class VmAccess extends FreeMarkerConlet<VmAccess.ResourceModel> {
ResourceBundle resourceBundle = resourceBundle(channel.locale()); ResourceBundle resourceBundle = resourceBundle(channel.locale());
Set<RenderMode> renderedAs = EnumSet.noneOf(RenderMode.class); Set<RenderMode> renderedAs = EnumSet.noneOf(RenderMode.class);
if (event.renderAs().contains(RenderMode.Edit)) { if (event.renderAs().contains(RenderMode.Edit)) {
Template tpl = freemarkerConfig() var session = channel.session();
.getTemplate("VmAccess-edit.ftl.html"); var vmNames = appPipeline.fire(new GetVms().accessibleFor(
WebConsoleUtils.userFromSession(session)
.map(ConsoleUser::getName).orElse(null),
WebConsoleUtils.rolesFromSession(session).stream()
.map(ConsoleRole::getName).toList()))
.get().stream().map(d -> d.definition().name()).sorted()
.toList();
var poolNames = appPipeline.fire(new GetPools().accessibleFor(
WebConsoleUtils.userFromSession(session)
.map(ConsoleUser::getName).orElse(null),
WebConsoleUtils.rolesFromSession(session).stream()
.map(ConsoleRole::getName).toList()))
.get().stream().map(VmPool::name).sorted().toList();
Template tpl
= freemarkerConfig().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", vmNames);
fmModel.put("poolNames", accessiblePools(channel)); fmModel.put("poolNames", poolNames);
channel.respond(new OpenModalDialog(type(), conletId, channel.respond(new OpenModalDialog(type(), conletId,
processTemplate(event, tpl, fmModel)) processTemplate(event, tpl, fmModel))
.addOption("cancelable", true) .addOption("cancelable", true)
@ -391,27 +424,32 @@ public class VmAccess extends FreeMarkerConlet<VmAccess.ResourceModel> {
private Set<RenderMode> renderPreview(RenderConletRequestBase<?> event, private Set<RenderMode> renderPreview(RenderConletRequestBase<?> event,
ConsoleConnection channel, String conletId, ResourceModel model) ConsoleConnection channel, String conletId, ResourceModel model)
throws TemplateNotFoundException, MalformedTemplateNameException, throws TemplateNotFoundException, MalformedTemplateNameException,
ParseException, IOException { ParseException, IOException, InterruptedException {
channel.associated(PENDING, Event.class) channel.associated(PENDING, Event.class)
.ifPresent(e -> { .ifPresent(e -> {
e.resumeHandling(); e.resumeHandling();
channel.setAssociated(PENDING, null); channel.setAssociated(PENDING, null);
}); });
if (model.type() == ResourceModel.Type.VM && model.name() != null) { var session = channel.session();
if (model.mode() == ResourceModel.Mode.VM && model.name() != null) {
// Remove conlet if VM definition has been removed // Remove conlet if VM definition has been removed
// or user has not at least one permission // or user has not at least one permission
Optional<VmDefinition> vmDef Optional<VmData> vmData = appPipeline.fire(new GetVms()
= channelTracker.associated(model.name()); .withName(model.name()).accessibleFor(
if (vmDef.isEmpty() WebConsoleUtils.userFromSession(session)
|| vmPermissions(vmDef.get(), channel.session()).isEmpty()) { .map(ConsoleUser::getName).orElse(null),
WebConsoleUtils.rolesFromSession(session).stream()
.map(ConsoleRole::getName).toList()))
.get().stream().findFirst();
if (vmData.isEmpty()) {
channel.respond( channel.respond(
new DeleteConlet(conletId, Collections.emptySet())); new DeleteConlet(conletId, Collections.emptySet()));
return Collections.emptySet(); return Collections.emptySet();
} }
} }
if (model.type() == ResourceModel.Type.POOL && model.name() != null) { if (model.mode() == ResourceModel.Mode.POOL && model.name() != null) {
// Remove conlet if pool definition has been removed // Remove conlet if pool definition has been removed
// or user has not at least one permission // or user has not at least one permission
VmPool pool = vmPools.get(model.name()); VmPool pool = vmPools.get(model.name());
@ -442,12 +480,6 @@ public class VmAccess extends FreeMarkerConlet<VmAccess.ResourceModel> {
return EnumSet.of(RenderMode.Preview); return EnumSet.of(RenderMode.Preview);
} }
private List<String> accessibleVms(ConsoleConnection channel) {
return channelTracker.associated().stream()
.filter(d -> !vmPermissions(d, channel.session()).isEmpty())
.map(d -> d.getMetadata().getName()).sorted().toList();
}
private Set<Permission> vmPermissions(VmDefinition vmDef, private Set<Permission> vmPermissions(VmDefinition vmDef,
Session session) { Session session) {
var user = WebConsoleUtils.userFromSession(session) var user = WebConsoleUtils.userFromSession(session)
@ -457,12 +489,6 @@ public class VmAccess extends FreeMarkerConlet<VmAccess.ResourceModel> {
return vmDef.permissionsFor(user, roles); return vmDef.permissionsFor(user, roles);
} }
private List<String> accessiblePools(ConsoleConnection channel) {
return vmPools.values().stream()
.filter(d -> !poolPermissions(d, channel.session()).isEmpty())
.map(d -> d.name()).sorted().toList();
}
private Set<Permission> poolPermissions(VmPool pool, private Set<Permission> poolPermissions(VmPool pool,
Session session) { Session session) {
var user = WebConsoleUtils.userFromSession(session) var user = WebConsoleUtils.userFromSession(session)
@ -472,19 +498,21 @@ public class VmAccess extends FreeMarkerConlet<VmAccess.ResourceModel> {
return pool.permissionsFor(user, roles); return pool.permissionsFor(user, roles);
} }
private void updateConfig(ConsoleConnection channel, ResourceModel model) { private void updateConfig(ConsoleConnection channel, ResourceModel model)
throws InterruptedException {
channel.respond(new NotifyConletView(type(), channel.respond(new NotifyConletView(type(),
model.getConletId(), "updateConfig", model.type(), model.name())); model.getConletId(), "updateConfig", model.mode(), model.name()));
updateVmDef(channel, model); updateVmDef(channel, model);
} }
private void updateVmDef(ConsoleConnection channel, ResourceModel model) { private void updateVmDef(ConsoleConnection channel, ResourceModel model)
throws InterruptedException {
if (Strings.isNullOrEmpty(model.name())) { if (Strings.isNullOrEmpty(model.name())) {
return; return;
} }
channelTracker.value(model.name()).ifPresent(item -> { appPipeline.fire(new GetVms().withName(model.name())).get().stream()
.findFirst().map(d -> d.definition()).ifPresent(vmDef -> {
try { try {
var vmDef = item.associated();
var data = Map.of("metadata", var data = Map.of("metadata",
Map.of("namespace", vmDef.namespace(), Map.of("namespace", vmDef.namespace(),
"name", vmDef.name()), "name", vmDef.name()),
@ -519,20 +547,15 @@ public class VmAccess extends FreeMarkerConlet<VmAccess.ResourceModel> {
* @param event the event * @param event the event
* @param channel the channel * @param channel the channel
* @throws IOException * @throws IOException
* @throws InterruptedException
*/ */
@Handler(namedChannels = "manager") @Handler(namedChannels = "manager")
@SuppressWarnings({ "PMD.ConfusingTernary", "PMD.CognitiveComplexity", @SuppressWarnings({ "PMD.ConfusingTernary", "PMD.CognitiveComplexity",
"PMD.AvoidInstantiatingObjectsInLoops", "PMD.AvoidDuplicateLiterals", "PMD.AvoidInstantiatingObjectsInLoops", "PMD.AvoidDuplicateLiterals",
"PMD.ConfusingArgumentToVarargsMethod" }) "PMD.ConfusingArgumentToVarargsMethod" })
public void onVmDefChanged(VmDefChanged event, VmChannel channel) public void onVmDefChanged(VmDefChanged event, VmChannel channel)
throws IOException { throws IOException, InterruptedException {
var vmDef = event.vmDefinition(); var vmDef = event.vmDefinition();
var vmName = vmDef.name();
if (event.type() == K8sObserver.ResponseType.DELETED) {
channelTracker.remove(vmName);
} else {
channelTracker.put(vmName, channel, vmDef);
}
// Update known conlets // Update known conlets
for (var entry : conletIdsByConsoleConnection().entrySet()) { for (var entry : conletIdsByConsoleConnection().entrySet()) {
@ -540,8 +563,8 @@ public class VmAccess extends FreeMarkerConlet<VmAccess.ResourceModel> {
for (var conletId : entry.getValue()) { for (var conletId : entry.getValue()) {
var model = stateFromSession(connection.session(), conletId); var model = stateFromSession(connection.session(), conletId);
if (model.isEmpty() if (model.isEmpty()
|| model.get().type() != ResourceModel.Type.VM || model.get().mode() != ResourceModel.Mode.VM
|| !Objects.areEqual(model.get().name(), vmName)) { || !Objects.areEqual(model.get().name(), vmDef.name())) {
continue; continue;
} }
if (event.type() == K8sObserver.ResponseType.DELETED if (event.type() == K8sObserver.ResponseType.DELETED
@ -577,7 +600,7 @@ public class VmAccess extends FreeMarkerConlet<VmAccess.ResourceModel> {
for (var conletId : entry.getValue()) { for (var conletId : entry.getValue()) {
var model = stateFromSession(connection.session(), conletId); var model = stateFromSession(connection.session(), conletId);
if (model.isEmpty() if (model.isEmpty()
|| model.get().type() != ResourceModel.Type.POOL || model.get().mode() != ResourceModel.Mode.POOL
|| !Objects.areEqual(model.get().name(), poolName)) { || !Objects.areEqual(model.get().name(), poolName)) {
continue; continue;
} }
@ -605,13 +628,13 @@ public class VmAccess extends FreeMarkerConlet<VmAccess.ResourceModel> {
} }
// Handle command for selected VM // Handle command for selected VM
var both = Optional.ofNullable(model.name()) var vmData = appPipeline.fire(new GetVms().withName(model.name())).get()
.flatMap(vm -> channelTracker.value(vm)); .stream().findFirst();
if (both.isEmpty()) { if (vmData.isEmpty()) {
return; return;
} }
var vmChannel = both.get().channel(); var vmChannel = vmData.get().channel();
var vmDef = both.get().associated(); var vmDef = vmData.get().definition();
var vmName = vmDef.metadata().getName(); var vmName = vmDef.metadata().getName();
var perms = vmPermissions(vmDef, channel.session()); var perms = vmPermissions(vmDef, channel.session());
var resourceBundle = resourceBundle(channel.locale()); var resourceBundle = resourceBundle(channel.locale());
@ -656,9 +679,9 @@ public class VmAccess extends FreeMarkerConlet<VmAccess.ResourceModel> {
"PMD.UseLocaleWithCaseConversions" }) "PMD.UseLocaleWithCaseConversions" })
private void selectResource(NotifyConletModel event, private void selectResource(NotifyConletModel event,
ConsoleConnection channel, ResourceModel model) ConsoleConnection channel, ResourceModel model)
throws JsonProcessingException { throws JsonProcessingException, InterruptedException {
try { try {
model.setType(ResourceModel.Type model.setMode(ResourceModel.Mode
.valueOf(event.<String> param(0).toUpperCase())); .valueOf(event.<String> param(0).toUpperCase()));
model.setName(event.param(1)); model.setName(event.param(1));
String jsonState = objectMapper.writeValueAsString(model); String jsonState = objectMapper.writeValueAsString(model);
@ -672,7 +695,13 @@ public class VmAccess extends FreeMarkerConlet<VmAccess.ResourceModel> {
private void openConsole(String vmName, ConsoleConnection connection, private void openConsole(String vmName, ConsoleConnection connection,
ResourceModel model, String password) { ResourceModel model, String password) {
var vmDef = channelTracker.associated(vmName).orElse(null); VmDefinition vmDef;
try {
vmDef = appPipeline.fire(new GetVms().withName(model.name())).get()
.stream().findFirst().map(VmData::definition).orElse(null);
} catch (InterruptedException e) {
return;
}
if (vmDef == null) { if (vmDef == null) {
return; return;
} }
@ -771,11 +800,11 @@ public class VmAccess extends FreeMarkerConlet<VmAccess.ResourceModel> {
* The Enum ResourceType. * The Enum ResourceType.
*/ */
@SuppressWarnings("PMD.ShortVariable") @SuppressWarnings("PMD.ShortVariable")
public enum Type { public enum Mode {
VM, POOL VM, POOL
} }
private Type type; private Mode mode;
private String name; private String name;
/** /**
@ -807,27 +836,29 @@ public class VmAccess extends FreeMarkerConlet<VmAccess.ResourceModel> {
} }
/** /**
* Returns the mode.
*
* @return the resourceType * @return the resourceType
*/ */
@JsonGetter("type") @JsonGetter("mode")
public Type type() { public Mode mode() {
return type; return mode;
} }
/** /**
* Sets the type. * Sets the mode.
* *
* @param type the resource type to set * @param mode the resource mode to set
*/ */
public void setType(Type type) { public void setMode(Mode mode) {
this.type = type; this.mode = mode;
} }
@Override @Override
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;
int result = super.hashCode(); int result = super.hashCode();
result = prime * result + java.util.Objects.hash(name, type); result = prime * result + java.util.Objects.hash(name, mode);
return result; return result;
} }
@ -844,14 +875,14 @@ public class VmAccess extends FreeMarkerConlet<VmAccess.ResourceModel> {
} }
ResourceModel other = (ResourceModel) obj; ResourceModel other = (ResourceModel) obj;
return java.util.Objects.equals(name, other.name) return java.util.Objects.equals(name, other.name)
&& type == other.type; && mode == other.mode;
} }
@Override @Override
public String toString() { public String toString() {
StringBuilder builder = new StringBuilder(50); StringBuilder builder = new StringBuilder(50);
builder.append("AccessModel [resourceType=").append(type) builder.append("AccessModel [mode=").append(mode)
.append(", resourceName=").append(name).append(']'); .append(", name=").append(name).append(']');
return builder.toString(); return builder.toString();
} }