Wip/viewer link (#24)
Some checks failed
Java CI with Gradle / build (push) Has been cancelled
Some checks failed
Java CI with Gradle / build (push) Has been cancelled
This commit is contained in:
commit
7bd3b172a4
16 changed files with 248 additions and 29 deletions
|
|
@ -1411,6 +1411,11 @@ spec:
|
||||||
Amount of memory in use.
|
Amount of memory in use.
|
||||||
type: string
|
type: string
|
||||||
default: "0"
|
default: "0"
|
||||||
|
displayPasswordSerial:
|
||||||
|
description: >-
|
||||||
|
Counts changes of the display password.
|
||||||
|
type: integer
|
||||||
|
default: 0
|
||||||
conditions:
|
conditions:
|
||||||
description: >-
|
description: >-
|
||||||
List of component conditions observed
|
List of component conditions observed
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ import org.jdrupes.vmoperator.common.K8sDynamicModel;
|
||||||
import org.jdrupes.vmoperator.common.K8sDynamicStub;
|
import org.jdrupes.vmoperator.common.K8sDynamicStub;
|
||||||
import org.jdrupes.vmoperator.runner.qemu.events.BalloonChangeEvent;
|
import org.jdrupes.vmoperator.runner.qemu.events.BalloonChangeEvent;
|
||||||
import org.jdrupes.vmoperator.runner.qemu.events.ConfigureQemu;
|
import org.jdrupes.vmoperator.runner.qemu.events.ConfigureQemu;
|
||||||
|
import org.jdrupes.vmoperator.runner.qemu.events.DisplayPasswordChanged;
|
||||||
import org.jdrupes.vmoperator.runner.qemu.events.Exit;
|
import org.jdrupes.vmoperator.runner.qemu.events.Exit;
|
||||||
import org.jdrupes.vmoperator.runner.qemu.events.HotpluggableCpuStatus;
|
import org.jdrupes.vmoperator.runner.qemu.events.HotpluggableCpuStatus;
|
||||||
import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange;
|
import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange;
|
||||||
|
|
@ -321,6 +322,26 @@ public class StatusUpdater extends Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On ballon change.
|
||||||
|
*
|
||||||
|
* @param event the event
|
||||||
|
* @throws ApiException
|
||||||
|
*/
|
||||||
|
@Handler
|
||||||
|
public void onDisplayPasswordChanged(DisplayPasswordChanged event)
|
||||||
|
throws ApiException {
|
||||||
|
if (vmStub == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
vmStub.updateStatus(from -> {
|
||||||
|
JsonObject status = from.status();
|
||||||
|
status.addProperty("displayPasswordSerial",
|
||||||
|
status.get("displayPasswordSerial").getAsLong() + 1);
|
||||||
|
return status;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On shutdown.
|
* On shutdown.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* 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.runner.qemu.events;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import org.jdrupes.vmoperator.runner.qemu.commands.QmpCommand;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link MonitorResult} that indicates that the display password has changed.
|
||||||
|
*/
|
||||||
|
public class DisplayPasswordChanged extends MonitorResult {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new display password changed.
|
||||||
|
*
|
||||||
|
* @param command the command
|
||||||
|
* @param response the response
|
||||||
|
*/
|
||||||
|
public DisplayPasswordChanged(QmpCommand command, JsonNode response) {
|
||||||
|
super(command, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -25,6 +25,7 @@ import org.jdrupes.vmoperator.runner.qemu.commands.QmpCapabilities;
|
||||||
import org.jdrupes.vmoperator.runner.qemu.commands.QmpCommand;
|
import org.jdrupes.vmoperator.runner.qemu.commands.QmpCommand;
|
||||||
import org.jdrupes.vmoperator.runner.qemu.commands.QmpDelCpu;
|
import org.jdrupes.vmoperator.runner.qemu.commands.QmpDelCpu;
|
||||||
import org.jdrupes.vmoperator.runner.qemu.commands.QmpQueryHotpluggableCpus;
|
import org.jdrupes.vmoperator.runner.qemu.commands.QmpQueryHotpluggableCpus;
|
||||||
|
import org.jdrupes.vmoperator.runner.qemu.commands.QmpSetDisplayPassword;
|
||||||
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;
|
||||||
|
|
@ -57,6 +58,9 @@ public class MonitorResult extends Event<Void> {
|
||||||
if (command instanceof QmpDelCpu) {
|
if (command instanceof QmpDelCpu) {
|
||||||
return new CpuDeleted(command, response);
|
return new CpuDeleted(command, response);
|
||||||
}
|
}
|
||||||
|
if (command instanceof QmpSetDisplayPassword) {
|
||||||
|
return new DisplayPasswordChanged(command, response);
|
||||||
|
}
|
||||||
return new MonitorResult(command, response);
|
return new MonitorResult(command, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ package org.jdrupes.vmoperator.vmconlet;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -30,7 +31,8 @@ import java.util.List;
|
||||||
@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
|
@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
|
||||||
public class TimeSeries {
|
public class TimeSeries {
|
||||||
|
|
||||||
private final List<Entry> data = new LinkedList<>();
|
@SuppressWarnings("PMD.LooseCoupling")
|
||||||
|
private final LinkedList<Entry> data = new LinkedList<>();
|
||||||
private final Duration period;
|
private final Duration period;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -52,25 +54,26 @@ public class TimeSeries {
|
||||||
@SuppressWarnings("PMD.AvoidLiteralsInIfCondition")
|
@SuppressWarnings("PMD.AvoidLiteralsInIfCondition")
|
||||||
public TimeSeries add(Instant time, Number... numbers) {
|
public TimeSeries add(Instant time, Number... numbers) {
|
||||||
var newEntry = new Entry(time, numbers);
|
var newEntry = new Entry(time, numbers);
|
||||||
boolean adjust = false;
|
boolean nothingNew = false;
|
||||||
|
synchronized (data) {
|
||||||
if (data.size() >= 2) {
|
if (data.size() >= 2) {
|
||||||
var lastEntry = data.get(data.size() - 1);
|
var lastEntry = data.get(data.size() - 1);
|
||||||
var lastButOneEntry = data.get(data.size() - 2);
|
var lastButOneEntry = data.get(data.size() - 2);
|
||||||
adjust = lastEntry.valuesEqual(lastButOneEntry)
|
nothingNew = lastEntry.valuesEqual(lastButOneEntry)
|
||||||
&& lastEntry.valuesEqual(newEntry);
|
&& lastEntry.valuesEqual(newEntry);
|
||||||
}
|
}
|
||||||
if (adjust) {
|
if (nothingNew) {
|
||||||
data.get(data.size() - 1).adjustTime(time);
|
data.removeLast();
|
||||||
} else {
|
|
||||||
data.add(new Entry(time, numbers));
|
|
||||||
}
|
}
|
||||||
|
data.add(new Entry(time, numbers));
|
||||||
|
|
||||||
// Purge
|
// Purge
|
||||||
Instant limit = time.minus(period);
|
Instant limit = time.minus(period);
|
||||||
while (data.size() > 2
|
while (data.size() > 2
|
||||||
&& data.get(0).getTime().isBefore(limit)
|
&& data.get(0).getTime().isBefore(limit)
|
||||||
&& data.get(1).getTime().isBefore(limit)) {
|
&& data.get(1).getTime().isBefore(limit)) {
|
||||||
data.remove(0);
|
data.removeFirst();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
@ -81,14 +84,16 @@ public class TimeSeries {
|
||||||
* @return the list
|
* @return the list
|
||||||
*/
|
*/
|
||||||
public List<Entry> entries() {
|
public List<Entry> entries() {
|
||||||
return data;
|
synchronized (data) {
|
||||||
|
return new ArrayList<>(data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Class Entry.
|
* The Class Entry.
|
||||||
*/
|
*/
|
||||||
public static class Entry {
|
public static class Entry {
|
||||||
private Instant timestamp;
|
private final Instant timestamp;
|
||||||
private final Number[] values;
|
private final Number[] values;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -103,15 +108,6 @@ public class TimeSeries {
|
||||||
values = numbers;
|
values = numbers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes the entry's time.
|
|
||||||
*
|
|
||||||
* @param time the time
|
|
||||||
*/
|
|
||||||
public void adjustTime(Instant time) {
|
|
||||||
timestamp = time;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the entry's time.
|
* Returns the entry's time.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -16,3 +16,4 @@ include 'org.jdrupes.vmoperator.vmconlet'
|
||||||
include 'org.jdrupes.vmoperator.runner.qemu'
|
include 'org.jdrupes.vmoperator.runner.qemu'
|
||||||
include 'org.jdrupes.vmoperator.common'
|
include 'org.jdrupes.vmoperator.common'
|
||||||
include 'org.jdrupes.vmoperator.util'
|
include 'org.jdrupes.vmoperator.util'
|
||||||
|
include 'spice-squid'
|
||||||
|
|
|
||||||
10
spice-squid/.checkstyle
Normal file
10
spice-squid/.checkstyle
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<fileset-config file-format-version="1.2.0" simple-config="false" sync-formatter="false">
|
||||||
|
<local-check-config name="Project Checks" location="/VM-Operator/checkstyle.xml" type="project" description="">
|
||||||
|
<additional-data name="protect-config-file" value="false"/>
|
||||||
|
</local-check-config>
|
||||||
|
<fileset name="all" enabled="true" check-config-name="Project Checks" local="true">
|
||||||
|
<file-match-pattern match-pattern="." include-pattern="true"/>
|
||||||
|
</fileset>
|
||||||
|
</fileset-config>
|
||||||
7
spice-squid/.eclipse-pmd
Normal file
7
spice-squid/.eclipse-pmd
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<eclipse-pmd xmlns="http://acanda.ch/eclipse-pmd/0.8" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://acanda.ch/eclipse-pmd/0.8 http://acanda.ch/eclipse-pmd/eclipse-pmd-0.8.xsd">
|
||||||
|
<analysis enabled="true" />
|
||||||
|
<rulesets>
|
||||||
|
<ruleset name="Custom Rules" ref="moodle-tools-console/ruleset.xml" refcontext="workspace" />
|
||||||
|
</rulesets>
|
||||||
|
</eclipse-pmd>
|
||||||
8
spice-squid/.settings/net.sf.jautodoc.prefs
Normal file
8
spice-squid/.settings/net.sf.jautodoc.prefs
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
add_header=true
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
header_text=/*\n * VM-Operator\n * Copyright (C) 2024 Michael N. Lipp\n * \n * This program is free software\: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see <https\://www.gnu.org/licenses/>.\n */
|
||||||
|
project_specific_settings=true
|
||||||
|
replacements=<?xml version\="1.0" standalone\="yes"?>\n\n<replacements>\n<replacement key\="get" scope\="1" mode\="0">Returns the</replacement>\n<replacement key\="set" scope\="1" mode\="0">Sets the</replacement>\n<replacement key\="add" scope\="1" mode\="0">Adds the</replacement>\n<replacement key\="edit" scope\="1" mode\="0">Edits the</replacement>\n<replacement key\="remove" scope\="1" mode\="0">Removes the</replacement>\n<replacement key\="init" scope\="1" mode\="0">Inits the</replacement>\n<replacement key\="parse" scope\="1" mode\="0">Parses the</replacement>\n<replacement key\="create" scope\="1" mode\="0">Creates the</replacement>\n<replacement key\="build" scope\="1" mode\="0">Builds the</replacement>\n<replacement key\="is" scope\="1" mode\="0">Checks if is</replacement>\n<replacement key\="print" scope\="1" mode\="0">Prints the</replacement>\n<replacement key\="has" scope\="1" mode\="0">Checks for</replacement>\n</replacements>\n\n
|
||||||
|
visibility_package=false
|
||||||
|
visibility_private=false
|
||||||
|
visibility_protected=false
|
||||||
13
spice-squid/.settings/org.eclipse.buildship.core.prefs
Normal file
13
spice-squid/.settings/org.eclipse.buildship.core.prefs
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
arguments=
|
||||||
|
auto.sync=false
|
||||||
|
build.scans.enabled=false
|
||||||
|
connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)
|
||||||
|
connection.project.dir=..
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
gradle.user.home=
|
||||||
|
java.home=
|
||||||
|
jvm.arguments=
|
||||||
|
offline.mode=false
|
||||||
|
override.workspace.settings=false
|
||||||
|
show.console.view=false
|
||||||
|
show.executions.view=false
|
||||||
2
spice-squid/.settings/org.eclipse.core.resources.prefs
Normal file
2
spice-squid/.settings/org.eclipse.core.resources.prefs
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
encoding/<project>=UTF-8
|
||||||
2
spice-squid/.settings/org.eclipse.core.runtime.prefs
Normal file
2
spice-squid/.settings/org.eclipse.core.runtime.prefs
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
line.separator=\n
|
||||||
11
spice-squid/Containerfile
Normal file
11
spice-squid/Containerfile
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
FROM alpine:3.19
|
||||||
|
|
||||||
|
RUN apk update &&\
|
||||||
|
apk add --no-cache inotify-tools &&\
|
||||||
|
apk add --no-cache squid
|
||||||
|
|
||||||
|
COPY run.sh /usr/local/bin/run-squid.sh
|
||||||
|
|
||||||
|
CMD ["/usr/local/bin/run-squid.sh"]
|
||||||
|
|
||||||
|
EXPOSE 3128
|
||||||
77
spice-squid/build.gradle
Normal file
77
spice-squid/build.gradle
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
plugins {
|
||||||
|
id 'org.jdrupes.vmoperator.java-application-conventions'
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
}
|
||||||
|
|
||||||
|
task buildImage(type: Exec) {
|
||||||
|
inputs.files 'Containerfile'
|
||||||
|
|
||||||
|
commandLine 'podman', 'build', '--pull',
|
||||||
|
'-t', "${project.name}:${project.version}",\
|
||||||
|
'-f', 'Containerfile', '.'
|
||||||
|
}
|
||||||
|
|
||||||
|
task tagLatestImage(type: Exec) {
|
||||||
|
dependsOn buildImage
|
||||||
|
|
||||||
|
enabled = !project.version.contains("SNAPSHOT")
|
||||||
|
&& !project.version.contains("alpha") \
|
||||||
|
&& !project.version.contains("beta") \
|
||||||
|
|| project.rootProject.properties['docker.testRegistry'] \
|
||||||
|
&& project.rootProject.properties['docker.registry'] \
|
||||||
|
== project.rootProject.properties['docker.testRegistry']
|
||||||
|
|
||||||
|
commandLine 'podman', 'tag', "${project.name}:${project.version}",\
|
||||||
|
"${project.name}:latest"
|
||||||
|
}
|
||||||
|
|
||||||
|
task buildLatestImage {
|
||||||
|
dependsOn buildImage
|
||||||
|
dependsOn tagLatestImage
|
||||||
|
}
|
||||||
|
|
||||||
|
task pushImage(type: Exec) {
|
||||||
|
dependsOn buildImage
|
||||||
|
|
||||||
|
commandLine 'podman', 'push', '--tls-verify=false', \
|
||||||
|
"localhost/${project.name}:${project.version}", \
|
||||||
|
"${project.rootProject.properties['docker.registry']}" \
|
||||||
|
+ "/${project.name}:${project.version}"
|
||||||
|
}
|
||||||
|
|
||||||
|
task pushLatestImage(type: Exec) {
|
||||||
|
dependsOn buildLatestImage
|
||||||
|
|
||||||
|
enabled = !project.version.contains("SNAPSHOT")
|
||||||
|
&& !project.version.contains("alpha") \
|
||||||
|
&& !project.version.contains("beta") \
|
||||||
|
|| project.rootProject.properties['docker.testRegistry'] \
|
||||||
|
&& project.rootProject.properties['docker.registry'] \
|
||||||
|
== project.rootProject.properties['docker.testRegistry']
|
||||||
|
|
||||||
|
commandLine 'podman', 'push', '--tls-verify=false', \
|
||||||
|
"localhost/${project.name}:${project.version}", \
|
||||||
|
"${project.rootProject.properties['docker.registry']}" \
|
||||||
|
+ "/${project.name}:latest"
|
||||||
|
}
|
||||||
|
|
||||||
|
task pushImages {
|
||||||
|
// Don't push without testing first
|
||||||
|
dependsOn pushImage
|
||||||
|
dependsOn pushLatestImage
|
||||||
|
}
|
||||||
|
|
||||||
|
test {
|
||||||
|
enabled = project.hasProperty("k8s.testCluster")
|
||||||
|
|
||||||
|
useJUnitPlatform()
|
||||||
|
|
||||||
|
testLogging {
|
||||||
|
showStandardStreams = true
|
||||||
|
}
|
||||||
|
|
||||||
|
systemProperty "k8s.testCluster", project.hasProperty("k8s.testCluster")
|
||||||
|
? project.getProperty("k8s.testCluster") : null
|
||||||
|
}
|
||||||
19
spice-squid/run.sh
Executable file
19
spice-squid/run.sh
Executable file
|
|
@ -0,0 +1,19 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
CONF_OPT="-f /run/etc/squid/squid.conf"
|
||||||
|
/usr/sbin/squid $CONF_OPT
|
||||||
|
|
||||||
|
inotifywait -m -e create -r /run/etc/squid |
|
||||||
|
while read file_path file_event file_name; do
|
||||||
|
if [ "$file_event" != "CREATE" ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ -r /run/squid/squid.pid ]; then
|
||||||
|
echo "Reconfiguring squid"
|
||||||
|
/usr/sbin/squid $CONF_OPT -k reconfigure
|
||||||
|
else
|
||||||
|
echo "Restarting squid"
|
||||||
|
/usr/sbin/squid $CONF_OPT
|
||||||
|
fi
|
||||||
|
echo "Processed event"
|
||||||
|
done
|
||||||
4
spice-squid/squid.conf
Normal file
4
spice-squid/squid.conf
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
http_access deny all
|
||||||
|
|
||||||
|
# Squid normally listens to port 3128
|
||||||
|
http_port 3128
|
||||||
Loading…
Add table
Add a link
Reference in a new issue