Don't duplicate VM management.
This commit is contained in:
parent
5bd6700541
commit
76be59a5b3
5 changed files with 315 additions and 85 deletions
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,34 +498,36 @@ 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()
|
||||||
try {
|
.findFirst().map(d -> d.definition()).ifPresent(vmDef -> {
|
||||||
var vmDef = item.associated();
|
try {
|
||||||
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()),
|
||||||
"spec", vmDef.spec(),
|
"spec", vmDef.spec(),
|
||||||
"status", vmDef.getStatus(),
|
"status", vmDef.getStatus(),
|
||||||
"userPermissions",
|
"userPermissions",
|
||||||
vmPermissions(vmDef, channel.session()).stream()
|
vmPermissions(vmDef, channel.session()).stream()
|
||||||
.map(VmDefinition.Permission::toString).toList());
|
.map(VmDefinition.Permission::toString).toList());
|
||||||
channel.respond(new NotifyConletView(type(),
|
channel.respond(new NotifyConletView(type(),
|
||||||
model.getConletId(), "updateVmDefinition", data));
|
model.getConletId(), "updateVmDefinition", data));
|
||||||
} catch (JsonSyntaxException e) {
|
} catch (JsonSyntaxException e) {
|
||||||
logger.log(Level.SEVERE, e,
|
logger.log(Level.SEVERE, e,
|
||||||
() -> "Failed to serialize VM definition");
|
() -> "Failed to serialize VM definition");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue