Merge branch 'main' into testing
This commit is contained in:
commit
5d3b19e827
20 changed files with 1209 additions and 131 deletions
|
|
@ -1,4 +1,4 @@
|
|||
# See https://github.com/DavidAnson/markdownlint/blob/main/schema/.markdownlint.yaml
|
||||
# See [rules](https://github.com/DavidAnson/markdownlint/blob/main/schema/.markdownlint.yaml)
|
||||
|
||||
# Default state for all rules
|
||||
default: true
|
||||
|
|
@ -27,12 +27,4 @@ MD036: false
|
|||
|
||||
# MD043/required-headings : Required heading structure :
|
||||
# https://github.com/DavidAnson/markdownlint/blob/v0.37.4/doc/md043.md
|
||||
MD043:
|
||||
# List of headings
|
||||
headings: [
|
||||
"# Head",
|
||||
"## Item",
|
||||
"### Detail"
|
||||
]
|
||||
# Match case of headings
|
||||
match_case: false
|
||||
MD043: false
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ for number in $(seq 1 $count); do
|
|||
if [ -z "$prefix" ]; then
|
||||
prefix=$(basename $template .tpl.yaml)
|
||||
fi
|
||||
name="$prefix$number"
|
||||
name="$prefix$(printf %03d $number)"
|
||||
index=$(($number - 1))
|
||||
esh -o $destination/$name.yaml $template number=$number index=$index
|
||||
done
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ public class K8sDynamicModelsBase<T extends K8sDynamicModel>
|
|||
} catch (InstantiationException | IllegalAccessException
|
||||
| IllegalArgumentException | InvocationTargetException
|
||||
| NoSuchMethodException | SecurityException exc) {
|
||||
throw new IllegalArgumentException(exc);
|
||||
throw new IllegalArgumentException(exc); // NOPMD
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -192,7 +192,7 @@ import org.jgrapes.util.events.WatchFile;
|
|||
*/
|
||||
@SuppressWarnings({ "PMD.ExcessiveImports", "PMD.AvoidPrintStackTrace",
|
||||
"PMD.DataflowAnomalyAnalysis", "PMD.TooManyMethods",
|
||||
"PMD.CouplingBetweenObjects" })
|
||||
"PMD.CouplingBetweenObjects", "PMD.TooManyFields" })
|
||||
public class Runner extends Component {
|
||||
|
||||
private static final String QEMU = "qemu";
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
package org.jdrupes.vmoperator.util;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -157,11 +158,12 @@ public final class DataPath {
|
|||
return (T) copy;
|
||||
}
|
||||
if (object.getClass().isArray()) {
|
||||
var copy = new ArrayList<>();
|
||||
for (var item : (Object[]) object) {
|
||||
copy.add(deepCopy(item));
|
||||
var copy = Array.newInstance(object.getClass().getComponentType(),
|
||||
Array.getLength(object));
|
||||
for (int i = 0; i < Array.getLength(object); i++) {
|
||||
Array.set(copy, i, deepCopy(Array.get(object, i)));
|
||||
}
|
||||
return (T) copy.toArray();
|
||||
return (T) copy;
|
||||
}
|
||||
if (object instanceof Cloneable) {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
package org.jdrupes.vmoperator.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class DataPathTests {
|
||||
|
||||
@Test
|
||||
void testArray() {
|
||||
int[] orig
|
||||
= { Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3) };
|
||||
var copy = DataPath.deepCopy(orig);
|
||||
for (int i = 0; i < orig.length; i++) {
|
||||
assertEquals(orig[i], copy[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,4 +7,4 @@ The VM-operator enables you to easily run Qemu based VMs as pods
|
|||
in Kubernetes. It is built on the
|
||||
[JGrapes](https://mnlipp.github.io/jgrapes/) event driven framework.
|
||||
|
||||
See the project's [home page](https://jdrupes.org/vm-operator/) for details.
|
||||
See the project's [home page](https://vm-operator.jdrupes.org/) for details.
|
||||
|
|
|
|||
1003
package-lock.json
generated
1003
package-lock.json
generated
File diff suppressed because it is too large
Load diff
10
package.json
10
package.json
|
|
@ -7,6 +7,7 @@
|
|||
"documentation": "^14.0.1",
|
||||
"install": "^0.13.0",
|
||||
"jsdoc": "^4.0.2",
|
||||
"markdownlint": "^0.37.4",
|
||||
"node-sass": "^9.0.0",
|
||||
"npm": "^8.11.0",
|
||||
"rollup": "^4.1.5",
|
||||
|
|
@ -22,8 +23,8 @@
|
|||
"typescript": "^5.2.2"
|
||||
},
|
||||
"overrides": {
|
||||
"node-gyp": "^10.1.0",
|
||||
"glob": "^9.0.0"
|
||||
"node-gyp": "^10.1.0",
|
||||
"glob": "^9.0.0"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
|
|
@ -34,5 +35,8 @@
|
|||
},
|
||||
"eslintIgnore": [
|
||||
"node_modules/**"
|
||||
]
|
||||
],
|
||||
"dependencies": {
|
||||
"markdownlint-cli": "^0.44.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
BIN
webpages/ConfigAccess-preview.png
Normal file
BIN
webpages/ConfigAccess-preview.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
BIN
webpages/PoolAccess-preview.png
Normal file
BIN
webpages/PoolAccess-preview.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.9 KiB |
|
|
@ -68,6 +68,11 @@
|
|||
<li><p class="part-entry"><a href="admin-gui.html">For Admins</a></p></li>
|
||||
<li><p class="part-entry"><a href="user-gui.html">For Users</a></p></li>
|
||||
</ul>
|
||||
<p class="part-list-title">Advanced</p>
|
||||
<ul style="margin-bottom: 0;" class="no-bullets">
|
||||
<li><p class="part-entry"><a href="auto-login.html">Auto Login</a></p></li>
|
||||
<li><p class="part-entry"><a href="pools.html">Pools</a></p></li>
|
||||
</ul>
|
||||
<p class="part-list-title"><a href="upgrading.html">Upgrading</a></p>
|
||||
<p class="part-list-title"><a href="https://vm-operator.jdrupes.org/javadoc/index.html">Javadoc</a></p>
|
||||
|
||||
|
|
|
|||
|
|
@ -19,4 +19,3 @@ the VMs and adjust the CPU and RAM usages (modifies the definition
|
|||
in kubernetes).
|
||||
|
||||

|
||||
|
||||
|
|
|
|||
87
webpages/auto-login.md
Normal file
87
webpages/auto-login.md
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
---
|
||||
title: "VM-Operator: Auto login — Login users automatically on the guest"
|
||||
layout: vm-operator
|
||||
---
|
||||
|
||||
# Auto Login
|
||||
|
||||
*Since 4.0.0*
|
||||
|
||||
When users log into the web GUI, they have already authenticated with the
|
||||
VM-Operator. In some environments, requiring an additional login on the
|
||||
guest OS can be cumbersome. To enhance the user experience, the VM-Operator
|
||||
supports automatic login on the guest operating system, thus eliminating
|
||||
the need for multiple logins. However, this feature requires specific
|
||||
support from the guest OS.
|
||||
|
||||
## Prepare the VM
|
||||
|
||||
Automatic login requires an agent running inside the guest OS. Similar
|
||||
to QEMU's standard guest agent, the VM-Operator agent communicates with
|
||||
the host via a tty device (`/dev/virtio-ports/org.jdrupes.vmop_agent.0`). On
|
||||
modern Linux systems, `udev` can detect this device and trigger the start
|
||||
of an associated systemd service.
|
||||
|
||||
Sample configuration files for a VM-Operator agent are available
|
||||
[here](https://github.com/mnlipp/VM-Operator/tree/main/dev-example/vmop-agent).
|
||||
Copy
|
||||
|
||||
* `99-vmop-agent.rules` → `/usr/local/lib/udev/rules.d/99-vmop-agent.rules`,
|
||||
* `vmop-agent` → `/usr/local/libexec/vmop-agent` and
|
||||
* `vmop-agent.service` → `/usr/local/lib/systemd/system/vmop-agent.service`.
|
||||
|
||||
Some of these target directories may not exist by default and must be
|
||||
created manually. If your system uses SELinux, run `restorecon` to apply
|
||||
the correct security contexts.
|
||||
|
||||
Enable the agent:
|
||||
|
||||
```console
|
||||
# systemctl daemon-reload
|
||||
# systemctl enable vmop-agent
|
||||
# udevadm control --reload-rules
|
||||
# udevadm trigger
|
||||
```
|
||||
|
||||
## The VM operator agent
|
||||
|
||||
Communication with the VM-Operator agent follows the pattern established by
|
||||
protocols such as SMTP and FTP. The agent must handle the commands
|
||||
"`login <username>`" and "`logout`" on its input. In response to
|
||||
these commands, the agent sends back lines that start with a three
|
||||
digit number. The first digit determines the type of message: "1" for
|
||||
informational, "2" for success and "4" or "5" for errors. The second
|
||||
digit provides information about the category that a response relates
|
||||
to. The third digit is specific to the command.
|
||||
|
||||
While this describes the general pattern, the [runner](runner.html)
|
||||
only evaluates the following codes:
|
||||
|
||||
| Code | Meaning |
|
||||
| ---- | ------- |
|
||||
| 220 | Sent by the agent on startup |
|
||||
| 201 | Login command executed successfully |
|
||||
| 202 | Logout command executed successfully |
|
||||
|
||||
The provided sample script is written for the gnome desktop environment.
|
||||
It assumes that GDM is running as a service by default. When the agent
|
||||
receives a login command, it stops GDM and starts a gnome-session for
|
||||
the specified user. Upon receiving the logout command, it terminates
|
||||
the session and starts GDM again.
|
||||
|
||||
No attempt has been made to make the script configurable. There are too
|
||||
many possible options. The script should therefore be considered as a
|
||||
starting point that you may need to adapt to your specific needs.
|
||||
|
||||
In addition to starting the desktop for the logged in user, the sample
|
||||
script automatically creates user accounts if they do not already exist.
|
||||
The idea behind this behavior is further explained in the
|
||||
[section about pools](pools.html#vm-pools).
|
||||
|
||||
## Enable auto login for a VM
|
||||
|
||||
To enable auto login for a VM, specify the user to be logged in in the VM's
|
||||
definition with "`spec.vm.display.loggedInUser: user-name`". If everything has been
|
||||
set up correctly, you should be able to open the console and observe the
|
||||
transition from GDM's login screen to the user's desktop when updating the
|
||||
VM's spec.
|
||||
|
|
@ -27,6 +27,7 @@ If you just want to try out things, you can skip the remainder of this
|
|||
page and proceed to "[the manager](manager.html)".
|
||||
|
||||
## Motivation
|
||||
|
||||
The project was triggered by a remark in the discussion about RedHat
|
||||
[dropping SPICE support](https://bugzilla.redhat.com/show_bug.cgi?id=2030592)
|
||||
from the RHEL packages. Which means that you have to run Qemu in a
|
||||
|
|
@ -55,9 +56,11 @@ close to simply deploying the pod (you get the restart and some PVC
|
|||
management "for free").
|
||||
|
||||
A second look, however, reveals that Kubernetes has more to offer.
|
||||
* It has a well defined API for managing resources.
|
||||
* It provides access to different kinds of managed storage for the VMs.
|
||||
* Its managing features *are* useful for running the component that
|
||||
|
||||
* It has a well defined API for managing resources.
|
||||
* It provides access to different kinds of managed storage for the VMs.
|
||||
* Its managing features *are* useful for running the component that
|
||||
|
||||
manages the pods with the VMs.
|
||||
|
||||
And if you use Kubernetes anyway, well then the VMs within Kubernetes
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ default files for creating these resources using the default namespace
|
|||
can be found in the
|
||||
[deploy](https://github.com/mnlipp/VM-Operator/tree/main/deploy)
|
||||
directory. I recommend to use
|
||||
[kustomize](https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization/) to create your own configuration.
|
||||
[kustomize](https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization/)
|
||||
to create your own configuration.
|
||||
|
||||
## Initial Configuration
|
||||
|
||||
|
|
|
|||
|
|
@ -7,67 +7,105 @@ layout: vm-operator
|
|||
|
||||
*Since 4.0.0*
|
||||
|
||||
## Prepare the VM
|
||||
Not all VMs are defined as replacements for carefully maintained
|
||||
individual PCs. In many workplaces, a standardardized VM configuration
|
||||
can be used where all user-specific data is stored in each user's home
|
||||
directory. By using a shared file system for home directories, users
|
||||
can login on any VM and find themselves in their personal
|
||||
environment.
|
||||
|
||||
If only a subset of users require access simultaneously, this makes it
|
||||
possible to define a pool of standardardized VMs and dynamically assign
|
||||
them to users as needed, eliminating the need to define a dedicated VM
|
||||
for each user.
|
||||
|
||||
## Pool definitions
|
||||
|
||||
The VM-operator supports this use case with a CRD for pools.
|
||||
|
||||
```yaml
|
||||
apiVersion: "vmoperator.jdrupes.org/v1"
|
||||
kind: VmPool
|
||||
metadata:
|
||||
namespace: vmop-dev
|
||||
name: test-vms
|
||||
spec:
|
||||
retention: "PT4h"
|
||||
loginOnAssignment: true
|
||||
permissions:
|
||||
- user: admin
|
||||
may:
|
||||
- accessConsole
|
||||
- start
|
||||
- role: user
|
||||
may:
|
||||
- accessConsole
|
||||
- start
|
||||
```
|
||||
|
||||
The `retention` specifies how long the assignment of a VM from the pool to
|
||||
a user remains valid after the user closes the console. This ensures that
|
||||
a user can resume work within this timeframe without the risk of another
|
||||
user taking over the VM. The time is specified as
|
||||
[ISO 8601 duration](https://en.wikipedia.org/wiki/ISO_8601#Durations).
|
||||
|
||||
Setting `loginOnAssignment` to `true` triggers automatic login of the
|
||||
user (as described in [section auto login](auto-login.html)) when
|
||||
the VM is assigned. The `permissions` property specifies the actions
|
||||
that users or roles can perform on assigned VMs.
|
||||
|
||||
VMs become members of one (or more) pools by adding the pool name to
|
||||
the `spec.pools` array, as shown below:
|
||||
|
||||
```yaml
|
||||
apiVersion: "vmoperator.jdrupes.org/v1"
|
||||
kind: VirtualMachine
|
||||
|
||||
spec:
|
||||
pools:
|
||||
- test-vms
|
||||
```
|
||||
|
||||
## Accessing a VM from the pool
|
||||
|
||||
Users can access a VM from a pool using the widget described in
|
||||
[user view](user-gui.html). The widget must be configured to
|
||||
provide access to a pool instead of to a specific VM.
|
||||
|
||||
{: width="500"}
|
||||
|
||||
Assignment happens when the "Start" icon is clicked. If the assigned VM
|
||||
is not already running, it will be started automatically. The assigned
|
||||
VM's name apears in the widget above the action icons.
|
||||
|
||||

|
||||
|
||||
Apart from showing the assigned VM, the widget behaves in the same way
|
||||
as when configured for accessing a specific VM.
|
||||
|
||||
## Guest OS Requirements
|
||||
|
||||
To ensure proper functionality when using VM pools, certain requirements
|
||||
must be met on the guest OS.
|
||||
|
||||
### Shared file system
|
||||
|
||||
Mount a shared file system as home file system on all VMs in the pool.
|
||||
If you want to use the sample script for logging in a user, the filesystem
|
||||
must support POSIX file access control lists (ACLs).
|
||||
All VMs in the pool must mount a shared file system as the home directory.
|
||||
When using the
|
||||
[sample agent](https://github.com/mnlipp/VM-Operator/tree/main/dev-example/vmop-agent),
|
||||
the file system must support POSIX file access control lists (ACLs).
|
||||
|
||||
### Restrict access
|
||||
### User management
|
||||
|
||||
The VMs should only be accessible via a desktop started by the VM-Operator.
|
||||
All VMs in the pool must map a given user name to the same user
|
||||
id. This is typically accomplished by using a central user management,
|
||||
such as LDAP. The drawback of such a solution is that it is rather
|
||||
complicated to configure.
|
||||
|
||||
* Disable the display manager.
|
||||
As an alternative, the sample auto login agent provides a very simple
|
||||
approach that uses the shared home directory for managing the user ids.
|
||||
Simplified, the script searches for a home directory with the given user
|
||||
name and derives the user id from it. It then checks if the user id is
|
||||
known by the guest operating system. If not, the user is added.
|
||||
|
||||
```console
|
||||
# systemctl disable gdm
|
||||
# systemctl stop gdm
|
||||
```
|
||||
|
||||
* Disable `getty` on tty1.
|
||||
|
||||
```console
|
||||
# systemctl mask getty@tty1
|
||||
# systemctl stop getty@tty1
|
||||
```
|
||||
|
||||
You can, of course, disable `getty` completely. If you do this, make sure
|
||||
that you can still access your master VM through `ssh`, else you have
|
||||
locked yourself out.
|
||||
|
||||
Strictly speaking, it is not necessary to disable these services, because
|
||||
the sample script includes a `Conflicts=` directive in the systemd service
|
||||
that starts the desktop for the user. However, this is mainly intended for
|
||||
development purposes and not for production.
|
||||
|
||||
The following should actually be configured for any VM.
|
||||
|
||||
* Prevent suspend/hibernate, because it will lock the VM.
|
||||
|
||||
```console
|
||||
# systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target
|
||||
```
|
||||
|
||||
### Install the VM-Operator agent
|
||||
|
||||
The VM-Operator agent runs as a systemd service. Sample configuration
|
||||
files can be found
|
||||
[here](https://github.com/mnlipp/VM-Operator/tree/main/dev-example/vmop-agent).
|
||||
Copy
|
||||
|
||||
* `99-vmop-agent.rules` to `/usr/local/lib/udev/rules.d/99-vmop-agent.rules`,
|
||||
* `vmop-agent` to `/usr/local/libexec/vmop-agent` and
|
||||
* `vmop-agent.service` to `/usr/local/lib/systemd/system/vmop-agent.service`.
|
||||
|
||||
Note that some of the target directories do not exist by default and have to
|
||||
be created first. Don't forget to run `restorecon` on systems with SELinux.
|
||||
|
||||
Enable everything:
|
||||
|
||||
```console
|
||||
# udevadm control --reload-rules
|
||||
# systemctl enable vmop-agent
|
||||
# udevadm trigger
|
||||
```
|
||||
Details can be found in the comments of the sample script.
|
||||
|
|
|
|||
|
|
@ -44,9 +44,9 @@ A sample configuration file with annotated options can be found
|
|||
As the runner implementation uses the
|
||||
[JGrapes](https://jgrapes.org/) framework, the file
|
||||
follows the framework's
|
||||
[conventions](https://jgrapes.org/latest-release/javadoc/org/jgrapes/util/YamlConfigurationStore.html). The top level "`/Runner`" selects
|
||||
the component to be configured. Nested within is the information
|
||||
to be applied to the component.
|
||||
[conventions](https://jgrapes.org/latest-release/javadoc/org/jgrapes/util/YamlConfigurationStore.html).
|
||||
The top level "`/Runner`" selects the component to be configured. Nested
|
||||
within is the information to be applied to the component.
|
||||
|
||||
The main entries in the configuration file are the "template" and
|
||||
the "vm" information. The runner processes the
|
||||
|
|
@ -58,8 +58,8 @@ defines a particular VM type, i.e. it contains the "nasty details"
|
|||
that do not need to be modified for some given set of VM instances.
|
||||
|
||||
The templates provided with the runner can be found
|
||||
[here](https://github.com/mnlipp/VM-Operator/tree/main/org.jdrupes.vmoperator.runner.qemu/templates). When details
|
||||
of the VM configuration need modification, a new VM type
|
||||
[here](https://github.com/mnlipp/VM-Operator/tree/main/org.jdrupes.vmoperator.runner.qemu/templates).
|
||||
When details of the VM configuration need modification, a new VM type
|
||||
(i.e. a new template) has to be defined. Authoring a new
|
||||
template requires some knowledge about the
|
||||
[qemu invocation](https://www.qemu.org/docs/master/system/invocation.html).
|
||||
|
|
@ -92,7 +92,8 @@ which may be used in a stand-alone development configuration.
|
|||
The runner supports adaption to changes of the RAM size (using the
|
||||
balloon device) and to changes of the number of CPUs. Note that
|
||||
in order to get new CPUs online on Linux guests, you need a
|
||||
[udev rule](https://docs.kernel.org/core-api/cpu_hotplug.html#user-space-notification) which is not installed by default[^simplest].
|
||||
[udev rule](https://docs.kernel.org/core-api/cpu_hotplug.html#user-space-notification)
|
||||
which is not installed by default[^simplest].
|
||||
|
||||
The runner also changes the images loaded in CDROM drives. If the
|
||||
drive is locked, i.e. if it doesn't respond to the "open tray" command
|
||||
|
|
@ -101,7 +102,8 @@ the change will be suspended until the VM opens the tray.
|
|||
Finally, `powerdownTimeout` can be changed while the qemu process runs.
|
||||
|
||||
[^simplest]: The simplest form of the rule is probably:
|
||||
```
|
||||
|
||||
```txt
|
||||
ACTION=="add", SUBSYSTEM=="cpu", ATTR{online}="1"
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ layout: vm-operator
|
|||
## To version 4.0.0
|
||||
|
||||
* The VmViewer conlet has been renamed to VmAccess. This affects the
|
||||
[configuration](https://jdrupes.org/vm-operator/user-gui.html).
|
||||
[configuration](https://vm-operator.jdrupes.org/user-gui.html).
|
||||
Configuration information using the old path
|
||||
`/Manager/GuiHttpServer/ConsoleWeblet/WebConsole/ComponentCollector/VmViewer`
|
||||
is still accepted for backward compatibility until the next major version,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ The idea of the user view is to provide an intuitive widget that
|
|||
allows the users to access their own VMs and to optionally start
|
||||
and stop them.
|
||||
|
||||

|
||||

|
||||
|
||||
The configuration options resulting from this seemingly simple
|
||||
requirement are unexpectedly complex.
|
||||
|
|
@ -77,7 +77,8 @@ objects that either specify a role or a user.
|
|||
## Console access
|
||||
|
||||
Access to the VM's console is implemented by generating a
|
||||
[connection file](https://manpages.debian.org/testing/virt-viewer/remote-viewer.1.en.html#CONNECTION_FILE) for virt-viewer when the user clicks on
|
||||
[connection file](https://manpages.debian.org/testing/virt-viewer/remote-viewer.1.en.html#CONNECTION_FILE)
|
||||
for virt-viewer when the user clicks on
|
||||
the console icon. If automatic open is enabled for this kind of
|
||||
files in the browser, the console opens without further user action.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue