Reduce to secret query.

This commit is contained in:
Michael Lipp 2025-03-03 21:19:34 +01:00
parent 17e2a7c6f0
commit 701194799f
4 changed files with 43 additions and 80 deletions

View file

@ -25,46 +25,29 @@ import org.jgrapes.core.Event;
* Gets the current display secret and optionally updates it. * Gets the current display secret and optionally updates it.
*/ */
@SuppressWarnings("PMD.DataClass") @SuppressWarnings("PMD.DataClass")
public class PrepareConsole extends Event<String> { public class GetDisplaySecret extends Event<String> {
private final VmDefinition vmDef; private final VmDefinition vmDef;
private final String user; private final String user;
private final boolean loginUser;
/** /**
* Instantiates a new request for the display secret. * Instantiates a new request for the display secret.
* After handling the event, a result of `null` means that * After handling the event, a result of `null` means that
* no password is needed. No result means that the console * no secret is needed. No result means that the console
* is not accessible.
*
* @param vmDef the vm name
* @param user the requesting user
* @param loginUser login the user
*/
public PrepareConsole(VmDefinition vmDef, String user,
boolean loginUser) {
this.vmDef = vmDef;
this.user = user;
this.loginUser = loginUser;
}
/**
* Instantiates a new request for the display secret.
* After handling the event, a result of `null` means that
* no password is needed. No result means that the console
* is not accessible. * is not accessible.
* *
* @param vmDef the vm name * @param vmDef the vm name
* @param user the requesting user * @param user the requesting user
*/ */
public PrepareConsole(VmDefinition vmDef, String user) { public GetDisplaySecret(VmDefinition vmDef, String user) {
this(vmDef, user, false); this.vmDef = vmDef;
this.user = user;
} }
/** /**
* Gets the vm definition. * Gets the VM definition.
* *
* @return the vm definition * @return the VM definition
*/ */
public VmDefinition vmDefinition() { public VmDefinition vmDefinition() {
return vmDef; return vmDef;
@ -79,24 +62,15 @@ public class PrepareConsole extends Event<String> {
return user; return user;
} }
/**
* Checks if the user should be logged in before allowing access.
*
* @return the loginUser
*/
public boolean loginUser() {
return loginUser;
}
/** /**
* Returns `true` if a password is available. May only be called * Returns `true` if a password is available. May only be called
* when the event is completed. Note that the password returned * when the event is completed. Note that the password returned
* by {@link #password()} may be `null`, indicating that no password * by {@link #secret()} may be `null`, indicating that no password
* is needed. * is needed.
* *
* @return true, if successful * @return true, if successful
*/ */
public boolean passwordAvailable() { public boolean secretAvailable() {
if (!isDone()) { if (!isDone()) {
throw new IllegalStateException("Event is not done."); throw new IllegalStateException("Event is not done.");
} }
@ -104,13 +78,13 @@ public class PrepareConsole extends Event<String> {
} }
/** /**
* Return the password. May only be called when the event has been * Return the secret. May only be called when the event has been
* completed with a valid result (see {@link #passwordAvailable()}). * completed with a valid result (see {@link #secretAvailable()}).
* *
* @return the password. A value of `null` means that no password * @return the password. A value of `null` means that no password
* is required. * is required.
*/ */
public String password() { public String secret() {
if (!isDone() || currentResults().isEmpty()) { if (!isDone() || currentResults().isEmpty()) {
throw new IllegalStateException("Event is not done."); throw new IllegalStateException("Event is not done.");
} }

View file

@ -43,7 +43,7 @@ import org.jdrupes.vmoperator.common.Constants.Status;
import org.jdrupes.vmoperator.common.K8sV1SecretStub; import org.jdrupes.vmoperator.common.K8sV1SecretStub;
import org.jdrupes.vmoperator.common.VmDefinition; import org.jdrupes.vmoperator.common.VmDefinition;
import org.jdrupes.vmoperator.common.VmDefinitionStub; import org.jdrupes.vmoperator.common.VmDefinitionStub;
import org.jdrupes.vmoperator.manager.events.PrepareConsole; import org.jdrupes.vmoperator.manager.events.GetDisplaySecret;
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.jdrupes.vmoperator.util.DataPath; import org.jdrupes.vmoperator.util.DataPath;
@ -71,7 +71,7 @@ public class DisplaySecretReconciler extends Component {
protected final Logger logger = Logger.getLogger(getClass().getName()); protected final Logger logger = Logger.getLogger(getClass().getName());
private int passwordValidity = 10; private int passwordValidity = 10;
private final List<PendingPrepare> pendingPrepares private final List<PendingRequest> pendingPrepares
= Collections.synchronizedList(new LinkedList<>()); = Collections.synchronizedList(new LinkedList<>());
/** /**
@ -184,21 +184,23 @@ public class DisplaySecretReconciler extends Component {
*/ */
@Handler @Handler
@SuppressWarnings("PMD.StringInstantiation") @SuppressWarnings("PMD.StringInstantiation")
public void onPrepareConsole(PrepareConsole event, VmChannel channel) public void onGetDisplaySecret(GetDisplaySecret event, VmChannel channel)
throws ApiException { throws ApiException {
// Update console user in status // Get VM definition and check if running
var vmDef = updateConsoleUser(event, channel); var vmStub = VmDefinitionStub.get(channel.client(),
if (vmDef == null) { new GroupVersionKind(Crd.GROUP, "", Crd.KIND_VM),
event.vmDefinition().namespace(), event.vmDefinition().name());
var vmDef = vmStub.model().orElse(null);
if (vmDef == null || !vmDef.conditionStatus("Running").orElse(false)) {
return; return;
} }
// Check if access is possible // Update console user in status
if (event.loginUser() vmDef = vmStub.updateStatus(from -> {
? !vmDef.<String> fromStatus(Status.LOGGED_IN_USER) JsonObject status = from.statusJson();
.map(u -> u.equals(event.user())).orElse(false) status.addProperty(Status.CONSOLE_USER, event.user());
: !vmDef.conditionStatus("Running").orElse(false)) { return status;
return; }).get();
}
// Get secret and update password in secret // Get secret and update password in secret
var stub = getSecretStub(event, channel, vmDef); var stub = getSecretStub(event, channel, vmDef);
@ -212,7 +214,7 @@ public class DisplaySecretReconciler extends Component {
// Register wait for confirmation (by VM status change, // Register wait for confirmation (by VM status change,
// after secret update) // after secret update)
var pending = new PendingPrepare(event, var pending = new PendingRequest(event,
event.vmDefinition().displayPasswordSerial().orElse(0L) + 1, event.vmDefinition().displayPasswordSerial().orElse(0L) + 1,
new CompletionLock(event, 1500)); new CompletionLock(event, 1500));
pendingPrepares.add(pending); pendingPrepares.add(pending);
@ -224,19 +226,7 @@ public class DisplaySecretReconciler extends Component {
stub.update(secret).getObject(); stub.update(secret).getObject();
} }
private VmDefinition updateConsoleUser(PrepareConsole event, private K8sV1SecretStub getSecretStub(GetDisplaySecret event,
VmChannel channel) throws ApiException {
var vmStub = VmDefinitionStub.get(channel.client(),
new GroupVersionKind(Crd.GROUP, "", Crd.KIND_VM),
event.vmDefinition().namespace(), event.vmDefinition().name());
return vmStub.updateStatus(from -> {
JsonObject status = from.statusJson();
status.addProperty(Status.CONSOLE_USER, event.user());
return status;
}).orElse(null);
}
private K8sV1SecretStub getSecretStub(PrepareConsole event,
VmChannel channel, VmDefinition vmDef) throws ApiException { VmChannel channel, VmDefinition vmDef) throws ApiException {
// Look for secret // Look for secret
ListOptions options = new ListOptions(); ListOptions options = new ListOptions();
@ -253,7 +243,7 @@ public class DisplaySecretReconciler extends Component {
return stubs.iterator().next(); return stubs.iterator().next();
} }
private boolean updatePassword(V1Secret secret, PrepareConsole event) { private boolean updatePassword(V1Secret secret, GetDisplaySecret event) {
var expiry = Optional.ofNullable(secret.getData() var expiry = Optional.ofNullable(secret.getData()
.get(DisplaySecret.EXPIRY)).map(b -> new String(b)).orElse(null); .get(DisplaySecret.EXPIRY)).map(b -> new String(b)).orElse(null);
if (secret.getData().get(DisplaySecret.PASSWORD) != null if (secret.getData().get(DisplaySecret.PASSWORD) != null
@ -323,8 +313,8 @@ public class DisplaySecretReconciler extends Component {
* The Class PendingGet. * The Class PendingGet.
*/ */
@SuppressWarnings("PMD.DataClass") @SuppressWarnings("PMD.DataClass")
private static class PendingPrepare { private static class PendingRequest {
public final PrepareConsole event; public final GetDisplaySecret event;
public final long expectedSerial; public final long expectedSerial;
public final CompletionLock lock; public final CompletionLock lock;
@ -334,7 +324,7 @@ public class DisplaySecretReconciler extends Component {
* @param event the event * @param event the event
* @param expectedSerial the expected serial * @param expectedSerial the expected serial
*/ */
public PendingPrepare(PrepareConsole event, long expectedSerial, public PendingRequest(GetDisplaySecret event, long expectedSerial,
CompletionLock lock) { CompletionLock lock) {
super(); super();
this.event = event; this.event = event;

View file

@ -49,11 +49,11 @@ 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.AssignVm; import org.jdrupes.vmoperator.manager.events.AssignVm;
import org.jdrupes.vmoperator.manager.events.GetDisplaySecret;
import org.jdrupes.vmoperator.manager.events.GetPools; import org.jdrupes.vmoperator.manager.events.GetPools;
import org.jdrupes.vmoperator.manager.events.GetVms; import org.jdrupes.vmoperator.manager.events.GetVms;
import org.jdrupes.vmoperator.manager.events.GetVms.VmData; 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.PrepareConsole;
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;
import org.jdrupes.vmoperator.manager.events.VmDefChanged; import org.jdrupes.vmoperator.manager.events.VmDefChanged;
@ -808,18 +808,17 @@ public class VmAccess extends FreeMarkerConlet<VmAccess.ResourceModel> {
Map.of("autoClose", 5_000, "type", "Warning"))); Map.of("autoClose", 5_000, "type", "Warning")));
return; return;
} }
var pwQuery = Event.onCompletion(new PrepareConsole(vmDef, user, var pwQuery = Event.onCompletion(new GetDisplaySecret(vmDef, user),
model.mode() == ResourceModel.Mode.POOL),
e -> gotPassword(channel, model, vmDef, e)); e -> gotPassword(channel, model, vmDef, e));
fire(pwQuery, vmChannel); fire(pwQuery, vmChannel);
} }
private void gotPassword(ConsoleConnection channel, ResourceModel model, private void gotPassword(ConsoleConnection channel, ResourceModel model,
VmDefinition vmDef, PrepareConsole event) { VmDefinition vmDef, GetDisplaySecret event) {
if (!event.passwordAvailable()) { if (!event.secretAvailable()) {
return; return;
} }
vmDef.extra().map(xtra -> xtra.connectionFile(event.password(), vmDef.extra().map(xtra -> xtra.connectionFile(event.secret(),
preferredIpVersion, deleteConnectionFile)) preferredIpVersion, deleteConnectionFile))
.ifPresent(cf -> channel.respond(new NotifyConletView(type(), .ifPresent(cf -> channel.respond(new NotifyConletView(type(),
model.getConletId(), "openConsole", cf))); model.getConletId(), "openConsole", cf)));

View file

@ -44,8 +44,8 @@ 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.VmExtraData; import org.jdrupes.vmoperator.common.VmExtraData;
import org.jdrupes.vmoperator.manager.events.ChannelTracker; import org.jdrupes.vmoperator.manager.events.ChannelTracker;
import org.jdrupes.vmoperator.manager.events.GetDisplaySecret;
import org.jdrupes.vmoperator.manager.events.ModifyVm; import org.jdrupes.vmoperator.manager.events.ModifyVm;
import org.jdrupes.vmoperator.manager.events.PrepareConsole;
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;
import org.jdrupes.vmoperator.manager.events.VmDefChanged; import org.jdrupes.vmoperator.manager.events.VmDefChanged;
@ -484,17 +484,17 @@ public class VmMgmt extends FreeMarkerConlet<VmMgmt.VmsModel> {
Map.of("autoClose", 5_000, "type", "Warning"))); Map.of("autoClose", 5_000, "type", "Warning")));
return; return;
} }
var pwQuery = Event.onCompletion(new PrepareConsole(vmDef, user), var pwQuery = Event.onCompletion(new GetDisplaySecret(vmDef, user),
e -> gotPassword(channel, model, vmDef, e)); e -> gotPassword(channel, model, vmDef, e));
fire(pwQuery, vmChannel); fire(pwQuery, vmChannel);
} }
private void gotPassword(ConsoleConnection channel, VmsModel model, private void gotPassword(ConsoleConnection channel, VmsModel model,
VmDefinition vmDef, PrepareConsole event) { VmDefinition vmDef, GetDisplaySecret event) {
if (!event.passwordAvailable()) { if (!event.secretAvailable()) {
return; return;
} }
vmDef.extra().map(xtra -> xtra.connectionFile(event.password(), vmDef.extra().map(xtra -> xtra.connectionFile(event.secret(),
preferredIpVersion, deleteConnectionFile)).ifPresent( preferredIpVersion, deleteConnectionFile)).ifPresent(
cf -> channel.respond(new NotifyConletView(type(), cf -> channel.respond(new NotifyConletView(type(),
model.getConletId(), "openConsole", cf))); model.getConletId(), "openConsole", cf)));