Develop/v3 (#27)
Some checks failed
Java CI with Gradle / build (push) Has been cancelled

Prepare release.
This commit is contained in:
Michael N. Lipp 2024-06-09 22:54:42 +02:00 committed by GitHub
parent 659463b3b4
commit 65a5cfd286
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
39 changed files with 500 additions and 132 deletions

View file

@ -18,10 +18,10 @@ dependencies {
implementation 'org.jgrapes:org.jgrapes.http:[3.1.0,4)'
implementation 'org.jgrapes:org.jgrapes.util:[1.34.0,2)'
implementation 'org.jgrapes:org.jgrapes.webconsole.base:[1.5.0,2)'
implementation 'org.jgrapes:org.jgrapes.webconsole.base:[1.7.0,2)'
implementation 'org.jgrapes:org.jgrapes.webconsole.vuejs:[1.5.0,2)'
implementation 'org.jgrapes:org.jgrapes.webconsole.rbac:[1.3.0,2)'
implementation 'org.jgrapes:org.jgrapes.webconlet.oidclogin:[1.3.0,2)'
implementation 'org.jgrapes:org.jgrapes.webconlet.oidclogin:[1.4.0,2)'
implementation 'org.jgrapes:org.jgrapes.webconlet.markdowndisplay:[1.2.0,2)'
runtimeOnly 'org.jgrapes:org.jgrapes.webconlet.sysinfo:[1.4.0,2)'

View file

@ -1,5 +1,5 @@
You can use the "puzzle piece" icon on the top right corner of the
You can use the "puzzle piece" icon on the top right corner of the
page to add display widgets (conlets) to the overview tab.
Use the "full screen" icon on the top right corner of any
conlet (if available) to get a detailed view.
conlet (if available) to get a detailed view.

View file

@ -1,4 +1,4 @@
Verwenden Sie das "Puzzle"-Icon auf der rechten oberen Ecke
Verwenden Sie das "Puzzle"-Icon auf der rechten oberen Ecke
der Seite, um Anzeige-Widgets (Conlets) hinzuzufügen.
Wenn sich in der rechten oberen Ecke eines Conlets ein Vollbild-Icon

View file

@ -48,6 +48,12 @@ data:
# Whether a shutdown initiated by the guest stops the pod deployment
guestShutdownStops: ${ cr.spec.guestShutdownStops!false?c }
# When incremented, the VM is reset. The value has no default value,
# i.e. if you start the VM without a value for this property, and
# decide to trigger a reset later, you have to first set the value
# and then inrement it.
resetCounter: ${ cr.resetCount }
# Forward the cloud-init data if provided
<#if cr.spec.cloudInit??>
cloudInit:

View file

@ -36,7 +36,6 @@ import org.jdrupes.vmoperator.common.K8s;
import static org.jdrupes.vmoperator.manager.Constants.APP_NAME;
import static org.jdrupes.vmoperator.manager.Constants.VM_OP_NAME;
import org.jdrupes.vmoperator.manager.events.VmChannel;
import org.jdrupes.vmoperator.manager.events.VmDefChanged;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;
@ -62,7 +61,6 @@ import org.yaml.snakeyaml.constructor.SafeConstructor;
/**
* Reconcile.
*
* @param event the event
* @param model the model
* @param channel the channel
* @return the dynamic kubernetes object
@ -70,8 +68,8 @@ import org.yaml.snakeyaml.constructor.SafeConstructor;
* @throws TemplateException the template exception
* @throws ApiException the api exception
*/
public DynamicKubernetesObject reconcile(VmDefChanged event,
Map<String, Object> model, VmChannel channel)
public DynamicKubernetesObject reconcile(Map<String, Object> model,
VmChannel channel)
throws IOException, TemplateException, ApiException {
// Get API
DynamicKubernetesApi cmApi = new DynamicKubernetesApi("", "v1",

View file

@ -181,13 +181,12 @@ public class Controller extends Component {
@Handler
public void onModifyVm(ModifyVm event, VmChannel channel)
throws ApiException, IOException {
patchVmSpec(channel.client(), event.name(), event.path(),
patchVmDef(channel.client(), event.name(), "spec/vm/" + event.path(),
event.value());
}
private void patchVmSpec(K8sClient client, String name, String path,
Object value)
throws ApiException, IOException {
private void patchVmDef(K8sClient client, String name, String path,
Object value) throws ApiException, IOException {
var vmStub = K8sDynamicStub.get(client,
new GroupVersionKind(VM_OP_GROUP, "", VM_OP_KIND_VM), namespace,
name);
@ -197,7 +196,7 @@ public class Controller extends Component {
? "\"" + value + "\""
: value.toString();
var res = vmStub.patch(V1Patch.PATCH_FORMAT_JSON_PATCH,
new V1Patch("[{\"op\": \"replace\", \"path\": \"/spec/vm/"
new V1Patch("[{\"op\": \"replace\", \"path\": \"/"
+ path + "\", \"value\": " + valueAsText + "}]"),
client.defaultPatchOptions());
if (!res.isPresent()) {

View file

@ -33,6 +33,7 @@ import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Scanner;
import java.util.logging.Level;
import static org.jdrupes.vmoperator.common.Constants.APP_NAME;
@ -180,7 +181,8 @@ public class DisplaySecretMonitor
// Check validity
var model = stub.model().get();
@SuppressWarnings("PMD.StringInstantiation")
var expiry = new String(model.getData().get(DATA_PASSWORD_EXPIRY));
var expiry = Optional.ofNullable(model.getData()
.get(DATA_PASSWORD_EXPIRY)).map(b -> new String(b)).orElse(null);
if (model.getData().get(DATA_DISPLAY_PASSWORD) != null
&& stillValid(expiry)) {
event.setResult(

View file

@ -64,7 +64,7 @@ import org.jose4j.base64url.Base64;
var display = GsonPtr.to(event.vmDefinition().data()).to("spec", "vm",
"display");
if (!display.get(JsonPrimitive.class, "spice", "generateSecret")
.map(JsonPrimitive::getAsBoolean).orElse(false)) {
.map(JsonPrimitive::getAsBoolean).orElse(true)) {
return;
}

View file

@ -51,6 +51,7 @@ import org.jdrupes.vmoperator.common.K8sDynamicModel;
import org.jdrupes.vmoperator.common.K8sObserver;
import org.jdrupes.vmoperator.common.K8sV1SecretStub;
import static org.jdrupes.vmoperator.manager.Constants.COMP_DISPLAY_SECRET;
import org.jdrupes.vmoperator.manager.events.ResetVm;
import org.jdrupes.vmoperator.manager.events.VmChannel;
import org.jdrupes.vmoperator.manager.events.VmDefChanged;
import org.jdrupes.vmoperator.util.ExtendedObjectWrapper;
@ -209,13 +210,35 @@ public class Reconciler extends Component {
// Reconcile, use "augmented" vm definition for model
Map<String, Object> model
= prepareModel(channel.client(), patchCr(event.vmDefinition()));
var configMap = cmReconciler.reconcile(event, model, channel);
var configMap = cmReconciler.reconcile(model, channel);
model.put("cm", configMap.getRaw());
dsReconciler.reconcile(event, model, channel);
stsReconciler.reconcile(event, model, channel);
lbReconciler.reconcile(event, model, channel);
}
/**
* Reset the VM by incrementing the reset count and doing a
* partial reconcile (configmap only).
*
* @param event the event
* @param channel the channel
* @throws IOException
* @throws ApiException
* @throws TemplateException
*/
@Handler
public void onResetVm(ResetVm event, VmChannel channel)
throws ApiException, IOException, TemplateException {
var defRoot
= GsonPtr.to(channel.vmDefinition().data()).get(JsonObject.class);
defRoot.addProperty("resetCount",
defRoot.get("resetCount").getAsLong() + 1);
Map<String, Object> model
= prepareModel(channel.client(), patchCr(channel.vmDefinition()));
cmReconciler.reconcile(model, channel);
}
private DynamicKubernetesObject patchCr(K8sDynamicModel vmDef) {
var json = vmDef.data().deepCopy();
// Adjust cdromImage path

View file

@ -25,13 +25,13 @@ import io.kubernetes.client.openapi.models.V1ObjectMeta;
import io.kubernetes.client.util.Watch;
import io.kubernetes.client.util.generic.options.ListOptions;
import java.io.IOException;
import java.util.Optional;
import java.util.Set;
import java.util.logging.Level;
import java.util.stream.Collectors;
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.K8sDynamicStub;
import org.jdrupes.vmoperator.common.K8sObserver.ResponseType;
import org.jdrupes.vmoperator.common.K8sV1ConfigMapStub;
@ -121,7 +121,7 @@ public class VmMonitor extends
}
if (vmDef.data() != null) {
// New data, augment and save
addDynamicData(channel.client(), vmDef);
addDynamicData(channel.client(), vmDef, channel.vmDefinition());
channel.setVmDefinition(vmDef);
} else {
// Reuse cached
@ -151,8 +151,16 @@ public class VmMonitor extends
}
}
private void addDynamicData(K8sClient client, K8sDynamicModel vmState) {
private void addDynamicData(K8sClient client, VmDefinitionModel vmState,
VmDefinitionModel prevState) {
var rootNode = GsonPtr.to(vmState.data()).get(JsonObject.class);
// Maintain (or initialize) the resetCount
rootNode.addProperty("resetCount", Optional.ofNullable(prevState)
.map(ps -> GsonPtr.to(ps.data()))
.flatMap(d -> d.getAsLong("resetCount")).orElse(0L));
// Add defaults in case the VM is not running
rootNode.addProperty("nodeName", "");
rootNode.addProperty("nodeAddress", "");

View file

@ -57,7 +57,7 @@
* ```
*
* Developers may also be interested in the usage of channels
* by the application's component:
* by the application's components:
*
* ![Main channels](app-channels.svg)
*
@ -74,6 +74,8 @@
*
* Component NioDispatcher as NioDispatcher <<internal>>
* [Manager] *-up- [NioDispatcher]
* Component HttpConnector as HttpConnector <<internal>>
* [Manager] *-up- [HttpConnector]
* Component FileSystemWatcher as FileSystemWatcher <<internal>>
* [Manager] *-up- [FileSystemWatcher]
* Component YamlConfigurationStore as YamlConfigurationStore <<internal>>
@ -119,6 +121,7 @@
* [WebConsole] *-- [RoleConfigurator]
* [WebConsole] *-- [RoleConletFilter]
* [WebConsole] *-left- [LoginConlet]
* [WebConsole] *-right- [OidcClient]
*
* Component "ComponentCollector\nfor page resources" as cpr <<internal>>
* [WebConsole] *-- [cpr]
@ -147,21 +150,35 @@
* () "guiTransport" as hT
* hT .up. [GuiSocketServer:8080]
* hT .down. [GuiHttpServer]
* hT .right[hidden]. [HttpConnector]
*
* [YamlConfigurationStore] -right[hidden]- hT
*
* () "guiHttp" as http
* http .up. [GuiHttpServer]
* http .up. [HttpConnector]
* note top of [HttpConnector]: transport layer com-\nponents omitted
*
* [PreferencesStore] .right. http
* [PreferencesStore] .. http
* [OidcClient] .up. http
* [LanguageSelector] .left. http
* [InMemorySessionManager] .up. http
* [LanguageSelector] .up. http
*
* package "Conceptual WebConsole" {
* [ConsoleWeblet] .left. http
* [ConsoleWeblet] .right. http
* [ConsoleWeblet] *-down- [WebConsole]
* }
*
* [Controller] .down[hidden]. [ConsoleWeblet]
*
* () "console" as console
* console .. WebConsole
*
* [OidcClient] .. console
* [LoginConlet] .right. console
*
* note right of console: More conlets\nconnect here
*
* @enduml
*/
package org.jdrupes.vmoperator.manager;