Compare commits

...

373 commits

Author SHA1 Message Date
Thomas Lamprecht
3bf5476b8a bump version to 9.0.11
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-10-06 19:13:44 +02:00
Thomas Lamprecht
360e906d53 pveceph: fix variable name and file ending for deb822 formatted ceph repo
In commit 405fcbc1e ("pveceph: switch repo sources to modern deb822
format") we switched away from single-line repos, but the later
rebased commit 9c0ac59e0 ("fix #5244 pveceph: install: add new
repository for offline installation") seemingly missed that change and
was not re-tested, thus it referenced the previous variable name and
old file ending, as this was already pushed let's fix it as this
follow-up.

Fixes: 9c0ac59e0 ("fix #5244 pveceph: install: add new repository for offline installation")
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-10-06 19:13:44 +02:00
Thomas Lamprecht
6d8d8d567b pveceph: break-up overly long literal strings over multiple lines
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-10-06 17:44:53 +02:00
Aaron Lauterer
e5b2f19060 pveceph: print repo metadata when installing from manual
By printing the site and component, the person installing it manuall has
a final check to see if the correct repository is being used.

Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
Link: https://lore.proxmox.com/20250714083838.68483-3-a.lauterer@proxmox.com
2025-10-06 15:55:54 +02:00
Aaron Lauterer
435004aad4 ui: CephInstallWizard: add option and hint for offline repository
The new 'offline' repository option will not try to configure the Ceph
repositories during installation.

Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
Tested-by: Christoph Heiss <c.heiss@proxmox.com>
Link: https://lore.proxmox.com/20250714083838.68483-2-a.lauterer@proxmox.com
2025-10-06 15:55:54 +02:00
Aaron Lauterer
9c0ac59e09 fix #5244 pveceph: install: add new repository for offline installation
by adding a 4th repository option called 'offline'. If set, the ceph
installation step will not touch the repository configuration.

We add a simple version check to make sure that the latest version
available (and to be installed) does match the selected major Ceph
version.

Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
Tested-by: Christoph Heiss <c.heiss@proxmox.com>
Link: https://lore.proxmox.com/20250714083838.68483-1-a.lauterer@proxmox.com
2025-10-06 15:55:53 +02:00
Nicolas Frey
38ed148a6b ui: guest snapshot: remove excess '}' at the end of window title
Noticed one too many curly braces in the Snapshot window title.

Signed-off-by: Nicolas Frey <n.frey@proxmox.com>
Tested-by: Shan Shaji <s.shaji@proxmox.com>
Link: https://lore.proxmox.com/20251002151609.41473-2-n.frey@proxmox.com
2025-10-03 19:14:12 +02:00
Nicolas Frey
65a80884b0 api: add replication config read return schema
The return props now include programmatically added properties guest,
jobnum, and digest (the latter only being returned in read endpoint)
in addition to the create schema.

Signed-off-by: Nicolas Frey <n.frey@proxmox.com>
Link: https://lore.proxmox.com/20251002124728.103425-3-n.frey@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-10-03 14:19:55 +02:00
Nicolas Frey
6deba095c5 api: add APT versions return schema
The Arch property now includes all officially supported debian
Architectures [0]. These could be extended to include unofficial
ones as well, though I don't see a reason to currently do this.
The CurrentState property now includes all variants according to
the documentation of package AptPkg::Cache.

Also implemented suggestion to clone $apt_package_return_props
instead of modifying, which could've potentially resulted in
unwanted behaviour.

[0] https://wiki.debian.org/SupportedArchitectures

Signed-off-by: Nicolas Frey <n.frey@proxmox.com>
Link: https://lore.proxmox.com/20251002124728.103425-2-n.frey@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-10-03 14:18:38 +02:00
Hannes Laimer
d38659c986 api: cluster: add permission description to log endpoint
Signed-off-by: Hannes Laimer <h.laimer@proxmox.com>
Link: https://lore.proxmox.com/20251003103812.180139-1-h.laimer@proxmox.com
2025-10-03 14:15:40 +02:00
Amin Vakil via pve-devel
3ed06d66d3 close #4248: ui: Add Reset button to VM right click menu
Add the missing 'Reset' action to the VM command menu. All other
actions for managing the VM run state were already present.

Also this patch does not add reset option to containers as they do not
have this option and reboot is already present for containers.

Fixes: https://bugzilla.proxmox.com/show_bug.cgi?id=4248
Signed-off-by: Amin Vakil <info@aminvakil.com>
Link: https://lore.proxmox.com/mailman.631.1754383164.367.pve-devel@lists.proxmox.com
[FE: small improvements to the commit message]
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
2025-10-02 11:20:37 +02:00
Nicolas Frey
35754e078d api: add service state return schema
values for the respective states (active-state, state, unit-state)
were taken from the systemd manpages [0] for ActiveState, SubState,
and UnitFileState. With the addition of unknown and not-found to
account for logic present in the code.

[0] https://manpages.debian.org/trixie/systemd/org.freedesktop.systemd1.5.en.html

Signed-off-by: Nicolas Frey <n.frey@proxmox.com>
Link: https://lore.proxmox.com/20250924115904.122696-4-n.frey@proxmox.com
 [TL: rename variable for more clarity]
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-10-02 10:22:35 +02:00
Nicolas Frey
427e2627c0 api: add ACME plugin return schema
After looking at the code, I don't see any issues with using the
createSchema method. Additionally tested by comparing the output of:
- pvesh usage /cluster/acme/plugins --returns
- pvesh get /cluster/acme/plugins
confirmed that the contents match.

Signed-off-by: Nicolas Frey <n.frey@proxmox.com>
Link: https://lore.proxmox.com/20250924115904.122696-2-n.frey@proxmox.com
 [TL: rename variable used for schema for more clarity]
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-10-02 10:22:35 +02:00
Thomas Lamprecht
55ddbb4647 api: nodes: re-tidy perl code
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-10-02 10:22:35 +02:00
Thomas Lamprecht
035bf934e4 update shipped appliance info index
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-10-01 17:00:42 +02:00
Nicolas Frey
410f25e349 Fix grammar in ifupdown2 version error message
Signed-off-by: Nicolas Frey <n.frey@proxmox.com>
Link: https://lore.proxmox.com/20250919093915.21641-2-n.frey@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-09-22 18:48:42 +02:00
Thomas Lamprecht
deb1ca707e bump version to 9.0.10
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-09-12 18:05:17 +02:00
Thomas Lamprecht
145642be3e api: node shells: avoid nested login for already logged in root@pam
When using the vncshell or xtermjs based shells we use a SSH tunnel if
the requested node is different from the one the request was made too.

Further we special case sessions from the root@pam user, as they
already got verified, so do not need to re-login on the target shell.

With Debian Trixie based releases we had to make a change to make this
shell work again [0], it seems that there is still a race in the
whole interaction, at least if there is a nested login shell. See [1]
for more details.

The Debian Trixie version of the `login` manual page explicitly
mentions a bug related to this:

> A recursive login, as used to be possible in the good old days, no
> longer works; for most purposes su(1) is a satisfactory substitute.
> Indeed, for security reasons, login does a vhangup(2) system call
> to remove any possible listening processes on the tty. This is to
> avoid password sniffing. If one uses the command login, then the
> surrounding shell gets killed by vhangup(2) because it’s no longer
> the true owner of the tty. This can be avoided by using exec login
> in a top-level shell or xterm.
-- man 1 login

IIRC this was checked back when implanting [0], but as it was during
quite eventful bootstrapping times of Debian Trixie releases I'm not
100% certain about that.

If the issues our users sometimes (?) see stem indeed from a race
related to above bug, we should be able to avoid that by dropping the
explicit login call for root@pam when tunneling. Other @pam users
would be still affected, but as the partial fix is so simple and
correct in any way it's still worth roll it out sooner.

To improve this more broadly the following two options seem most
promising:

1. Replace the manual SSH tunnel by our proxy-to-node infrastructure
   and tunnel the websocket of the target nodes termproxy command
   through that.

2. Use a wrapper tool to handle the login command such that it does
   not interferes with the outer login, could potentially even be an
   existing one like dtach, or alternatively something we write
   ourselves.

I did not yet evaluate impact and work required for either option to
happen, but from an experienced gut feeling the first option would be
the better one, especially as we want to drop SSH for tunneling
completely in the mid to long term.

As this is not a complete and certain fix for #6789 [1] and especially
as we cannot really reproduce this ourselves here in any useful way,
I refrained from adding a fix # to the commit message, but it should
be a partial fix.

[0]: https://git.proxmox.com/?p=pve-xtermjs.git;a=commitdiff;h=7b47cca8368e63c30f6227442570f9f35dd7ccf0
[1]: https://bugzilla.proxmox.com/show_bug.cgi?id=6789

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-09-12 17:24:40 +02:00
Thomas Lamprecht
0f38ce3ee6 api: node shells: make helper aware of tunnel command
Rename the not so telling $remcmd to $tunnel_cmd and make the helper
prefix it to the actual command.

This is a preparation of adapting login for proxied (tunneled) shells,
i.e. where the user requests a shell from another node than they
opened the web UI for.

No semantic change intended.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-09-12 17:22:32 +02:00
Dominik Csapak
dbc0ca81d6 ui: fix datacenter notes toolbar visibility
the recent commit
 d2660fc7 (ui: resource tree: improve performance on initial update)
changed how we construct the resource tree, namely outside the
treestore. While it worked fine mostly, the standard
`Ext.data.TreeModel` was used. This lead to problem with the detection
of some things, since we expected all properties that were defined on
the custom `PVETree` model.

To fix this, create an instance of `PVETree` instead.
Note that this might also fix other things that depend on the
PVETree specific properties on the datacenter root node.

Fixes: d2660fc7 (ui: resource tree: improve performance on initial update)
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
Tested-by: Michael Köppl <m.koeppl@proxmox.com>
Link: https://lore.proxmox.com/20250912113242.3139402-1-d.csapak@proxmox.com
2025-09-12 16:08:37 +02:00
Thomas Lamprecht
117b893e0e bump version to 9.0.9
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-09-10 12:52:06 +02:00
Thomas Lamprecht
0984e4c607 ui: pool grid: never submit value of filter field
As this is for the frontend only and the API will fail due to getting
an unknown property.

Reported-by: Alexander Zeidler <a.zeidler@proxmox.com>
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-09-10 12:45:06 +02:00
Stefan Hanreich
20464270a5 cluster: resources: add sdn property to cluster resources schema
SDN entities return their name in the sdn property. Add this property
to the schema so it is shown in the documentation, as well for
generating proper types in proxmox-api-types.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250909155423.526917-2-s.hanreich@proxmox.com
2025-09-10 09:58:17 +02:00
Thomas Lamprecht
1d328910bf api: metrics export: update use statements
Quite a bit was unused while a few others were missing and only worked
because other modules loaded them already.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-09-10 09:53:01 +02:00
Thomas Lamprecht
e09d688c37 ui: cluster dashboard: streamline warning thresholds for memory usage in node table
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-09-09 13:12:12 +02:00
Thomas Lamprecht
2ac4ea1cc7 ui: progress widget: increase default warning threshold from 75% to 80%
This unifies it with other recent changes, as 75% often really is not
a problematic usage, while 80% isn't always problematic either, it's
still closer in practice to a load that might need to be checked out
and use sites can now override this to what makes sense most for their
semantics.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-09-09 13:12:12 +02:00
Thomas Lamprecht
157d5322db ui: progress widget: move warning and critical threshold to config
This allows one to override them on the use site.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-09-09 13:12:12 +02:00
Thomas Lamprecht
24afc8085a ui: cluster dashboard: use higher warning thresholds for memory gauge
Use the same thresholds for warning and critical as we do now for the
node status overview, see commit 6df3a71bd ("ui: node status: increase
warning/critical threshold percentage for memory usage") for details.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-09-09 13:12:12 +02:00
Fabian Grünbichler
21d93bcbab run make-tidy
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
2025-09-09 12:05:53 +02:00
Thomas Lamprecht
2f72b02143 bump version to 9.0.8
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-09-08 22:57:54 +02:00
Thomas Lamprecht
5b6bfa4a16 ui: guests status: increase threshold for warning/critical memory usage
With a similar rationale than commit f70ea8f7c ("ui: node status:
increase warning/critical threshold percentage for memory usage"),
i.e. memory is there to be used and leveraging most of what's
configured is an OK thing to do, so no need to show a warning status
at already 75% of usage.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-09-08 22:48:14 +02:00
Thomas Lamprecht
6df3a71bd4 ui: node status: increase warning/critical threshold percentage for memory usage
Memory is there to be used and unlike with block/file storage it can
be fine, even wanted to use all memory besides a bit of headroom.
As memory is easy to defragment (it's all virtual addresses anyway)
and some usage is also easy to evict (e.g. to SWAP if not really used
at the moment or as it is only an advanced cache like the ZFS ARC).

Without the override the threshold where 75% for warning and 90% for
showing a critical status. For a host with 396 GiB of installed memory
that meant that we warned already on 297 GiB used (99 GiB still
available!) and showed a critical status with ~365 GiB in use (~40 GiB
free), both can be still very OK and warranted usages though.

So increase the thresholds to 90% for warning and 97.5% for critical
usage displays, which provides a less "scare-mongering" display.

Ideally we'd support a callback to make a better decision, as clamping
on totals might be even better, but this simple change makes it
already much better. Add a comment that we might want to split out the
ARC in its own custom bar (I got a prototype around, but that needs
polishing and in-depth review).

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-09-08 22:48:14 +02:00
Thomas Lamprecht
e1a85d845b ui: node summary: use arrow fn for KSM renderer
Code clean-up without any semantic change intended.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-09-08 22:48:14 +02:00
Thomas Lamprecht
da5129fb82 influxdb metrics: explicitly include the SSL_VERIFY_NONE constant
This avoids a "compile" check error (i.e. perl -wc) if no other module
that pulls in that dependency is loaded already.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-09-08 22:48:14 +02:00
Thomas Lamprecht
515549c31f pull metrics: comment the time that the cached old generation includes
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-09-08 22:48:14 +02:00
Thomas Lamprecht
308217e530 api: cluster metrics export: support an explicit node-list
This allows one to query the metrics stats from a specific set of
nodes. This can, e.g., help on batch querying the stats in bigger
clusters, like in a 15 node cluster one could do 3 requests at 5 nodes
each concurrently.

Doing such things can especially help on clusters with many virtual
guests, as there the time required to gather all stats quickly adds
up, more so if the time window is long, and we got a 30s overall
timeout here currently due to being proxied to the privileged API
daemon as we cannot reuse the API ticket and need to generate a new
one.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-09-08 22:48:14 +02:00
Thomas Lamprecht
69b01030f4 api: cluster: metric server: increase timeout when fetching other nodes metrics
5s is rather short, especially if one has many guests on a node and
queries for a (relatively) period, e.g. for a node with 4000 and
querying the last 10 minutes of data needs a bit over 8s on a test
cluster of mine.

So increase the timeout from 5s to 20s as a stop-gap. Note that due to
being a protected API call we are limited by the 30s proxy timeout in
total, which is something that might be revisited but out of the scope
of this change, especially as it would need to be changed in the
pve-http-server git repo anyway.

There are other ideas floating around in making this more reliable,
like making this async here (anyevent or a dedicated executable),
allowing the requester to pass a node-list to allow batching the
queries and so on.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-09-08 22:48:14 +02:00
Thomas Lamprecht
bdecc8191a update shipped appliance info index
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-09-07 19:47:34 +02:00
Thomas Lamprecht
040945d6fe ui: pool members: add filter for name, node or vmid when adding guests
Makes it easier to find specific guests when one got many of them.

I decided to not allow filtering the current pool name, as often there
is none set for the guest the user wants to add and one could
theoretically sort the current pool column to group guests by them,
and finally, we can still add that easily if it gets requested with a
good enough rationale.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-09-06 15:48:12 +02:00
Thomas Lamprecht
ce79e33a14 ui: pool: add members: make virtual guest window bigger and resizeable
It was rather small, i.e. always to narrow for seeing the column
values for somewhat normal name lengths and for more than a handful of
guests the height was rather short too.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-09-06 15:46:19 +02:00
Gabriel Goller
1b37bf06a0 sdn: remove fabrics property correctly from the Vxlan Zone
The missing `deleteEmtpy` attribute caused the fabric property to never
be removed. So when e.g. removing the fabric to add the peers manually,
there would always be an error because you can't have peers *and*
fabrics configured.

Fixes: https://bugzilla.proxmox.com/show_bug.cgi?id=6710
Signed-off-by: Gabriel Goller <g.goller@proxmox.com>
Link: https://lore.proxmox.com/20250821083455.21307-1-g.goller@proxmox.com
2025-09-05 20:40:43 +02:00
Gabriel Goller
146cb84d7c sdn: remove fabrics property correctly from EVPN controller
The missing `deleteEmtpy` attribute caused the fabric property to never
be removed from the EVPN controller. So when e.g. removing the fabric to
add the peers manually, there would always be an error because you can't
have peers *and* fabrics configured.

Signed-off-by: Gabriel Goller <g.goller@proxmox.com>
Link: https://lore.proxmox.com/20250821085015.29401-1-g.goller@proxmox.com
2025-09-05 20:39:51 +02:00
Shannon Sterz
ccccc387fb ui: remove unused pve-itype-icon-itype class
it's based on an old gif icon and should no longer be used anyway, so
remove it.

Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
Link: https://lore.proxmox.com/20250829141219.290626-6-s.sterz@proxmox.com
2025-09-05 20:16:24 +02:00
Maximiliano Sandoval
13cd96a74a cli: pveceph: set use bytes renderer when listing a pool's content
This will make pveceph pool ls report the 'Used' column specifying its
units:

$ pveceph pool ls --noborder
... Used
... 2.07 MiB
... 108.61 KiB

Signed-off-by: Maximiliano Sandoval <m.sandoval@proxmox.com>
Tested-by: Shannon Sterz <s.sterz@proxmox.com>
Reviewed-by: Shannon Sterz <s.sterz@proxmox.com>
Link: https://lore.proxmox.com/20250829094401.223667-2-m.sandoval@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-09-05 20:15:02 +02:00
Maximiliano Sandoval
c83ad9cd49 ui: storage summary: set 'bytes' as unit for metrics graph
This change ensures that the storage unites are displayed consistently
between the graph and the usage label right above.

When setting the unit to `bytes` the graph will now, for example, show
"130 GB" instead of "130 G", which matches the usage displayed above
and removes any ambiguity about whether "G" refers to GiB or GB.

Signed-off-by: Maximiliano Sandoval <m.sandoval@proxmox.com>
Tested-by: Shannon Sterz <s.sterz@proxmox.com>
Reviewed-by: Shannon Sterz <s.sterz@proxmox.com>
Link: https://lore.proxmox.com/20250829094401.223667-1-m.sandoval@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-09-05 20:15:02 +02:00
Maximiliano Sandoval
6121d1126c api: apt: Return valid utf8 on changelog
This was displayed wrongly on the web UI and when calling

    pvesh get /nodes/localhost/apt/changelog

One potential example of such a package was bind9-dnsutils where the
character `ř` was rendered as `Å`.

Reported-by: Lukas Wagner <l.wagner@proxmox.com>
Signed-off-by: Maximiliano Sandoval <m.sandoval@proxmox.com>
Tested-by: Daniel Kral <d.kral@proxmox.com>
Link: https://lore.proxmox.com/20250902145345.500823-1-m.sandoval@proxmox.com
2025-09-05 20:10:33 +02:00
Gabriel Goller
a5250e9e9c make: clean up line continuation backslashes
Some backslashes were not indented correctly and some used spaces
instead of tabs. Most were introduced in the recent fabrics series
(29ebe4e8d4 ("ui: fabrics: add model definitions for fabrics") and
following).

Signed-off-by: Gabriel Goller <g.goller@proxmox.com>
Link: https://lore.proxmox.com/20250905125435.231976-1-g.goller@proxmox.com
2025-09-05 19:47:03 +02:00
Daniel Kral
2ddc4d864b parser: qemu cpu: also allow kebab-cased properties while parsing
There are quite a few kebab-cased properties in the QEMU CPU config,
such as phys-bits and guest-phys-bits. These are currently not exposed
through the web interface, but only the command line.

If the QEMU CPU config is parsed, it will return undefined with an
error and will break the ProcessorEdit component so that changes cannot
be submitted anymore.

Fix that by allowing kebab-cased properties as well.

Signed-off-by: Daniel Kral <d.kral@proxmox.com>
Link: https://lore.proxmox.com/20250905142249.219371-1-d.kral@proxmox.com
 [TL: drop unnecessary escape]
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-09-05 19:04:25 +02:00
Dominik Csapak
e19de81f54 ui: resource tree: fix change detection
when trying to detect changes of resources, we compare a list of
properties of the existing nodes in the tree with the ones we got from
the api call, so that we can update only those that changed.

One of these properties is the 'text' one, which is calculated from e.g.
the vmid and name (or the name and host, depending on the type).

Sadly, when inserting/updating the node, we modified the text property
in every case, at least adding a '<span></span>' around the existing
text. This meant that every resource was updated every time instead of
only when something changed.

To fix this, remote the 'text' property from the to checked ones, and
add all the properties that are used to compile the text one.

This reduces the time of updateTree in my test-setup (~10000 guests)
when nothing changed from ~100ms to ~15ms and reduces scroll stutter
during such an update.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
Link: https://lore.proxmox.com/20250905120627.2585826-5-d.csapak@proxmox.com
2025-09-05 18:52:26 +02:00
Dominik Csapak
d2660fc7a4 ui: resource tree: improve performance on initial update
When we insert nodes into the tree, we use 'insertBefore' of extjs'
NodeInterface. When the node is inside a TreeStore, it calls
'registerNode' to handle some events and accounting. Sadly it does so
not only for the inserted node, but also for the node in which is
inserted too and that calls 'registerNode' again for all of its
children.

So inserting a large number of guests under node this way has (at least)
O(n^2) calls to registerNode.

To workaround this, create the first tree node structure outside the
TreeStore and add it at the end. Further insertions are more likely to
only come in small numbers. (Still have to look into if we can avoid
that behavior there too)

This improves the time spend in 'registerNode' (in my ~10000 guests test
setup) from 4,081.6 ms to about 2.7ms.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
Link: https://lore.proxmox.com/20250905120627.2585826-4-d.csapak@proxmox.com
2025-09-05 18:52:26 +02:00
Dominik Csapak
525738c070 ui: fix O(n^2) calculations when loading /cluster/resources
when we fetch the cluster resources, the ui calculates some fields for
each resource, such as 'hostmem_usage'. This requires the maxmem
attribute from the host which we have to look up in the resource store.
Since the data is not sorted in the store itself, extjs linearly goes
through the records to make the lookup when we use 'findExact'.

So instead of using findExact for every guest (which iterates the whole
resource store again), use a 'nodeCache' there and clear it out before
we load the new data.

This reduces the total time used for 'cacluate_hostmem_usage'
in my test setup (~10000 non-running vms) from 4,408.2 ms to 12.4 ms.
(Measured with the `Performance` tab in Chromium)

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
Link: https://lore.proxmox.com/20250905120627.2585826-3-d.csapak@proxmox.com
2025-09-05 18:52:26 +02:00
Dominik Csapak
695d3b1cb2 API2Tools: rrd: remove O(n^2) lookup for keys
the idea was that we get any of the 'new' versions on lookup, but that
lead to iterating through possibly all keys. Since that was called for
each resource in e.g. /cluster/resources api call, the runtime was
O(n^2) for the number of resources.

To avoid that, simply look up the currently only valid key here which
makes this lookup much cheaper.

In my test setup with ~10000 guests, it reduces the time for a call
to /cluster/resources from ~22s to ~400ms

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
Tested-by: Daniel Kral <d.kral@proxmox.com>
Link: https://lore.proxmox.com/20250905120627.2585826-2-d.csapak@proxmox.com
2025-09-05 18:52:26 +02:00
Wolfgang Bumiller
25bc890152 api: factor out shell command schema
So we only sort the enum keys once and the documentation and API dumps
don't keep reordering them, and to deduplicate the cmd and cmd-opts
schema.

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
Link: https://lore.proxmox.com/20250902125516.346145-1-w.bumiller@proxmox.com
 [TL: use hash directly instead of hash-as-array]
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-09-04 15:46:56 +02:00
Lukas Wagner
be712f0e6a api: apt: add JSON schema for 'list_updates' endpoint
This will be shown in the API viewer. Additionally, this allows us to
automatically generate the appropriate Rust API type automatically.

Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>
Link: https://lore.proxmox.com/20250902151427.425017-2-l.wagner@proxmox.com
2025-09-03 10:00:34 +02:00
Fabian Grünbichler
2bc61ed0de bump version to 9.0.7
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
2025-09-02 14:27:44 +02:00
Lukas Wagner
9a4b04ea49 api: use 'number' instead of 'amount' for countable nouns
Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>
Link: https://lore.proxmox.com/all/20250702114916.138761-1-l.wagner@proxmox.com
2025-09-02 14:25:54 +02:00
Daniel Kral
4008a6472a ha: rule edit: fix enabling ha rules which are disabled
Setting the `disable` property to 0 does not make a HA rule being
enabled anymore since a change in the HA Manager, so explicitly delete
the `disable` property when the HA rule should be enabled.

Reported-by: Friedrich Weber <f.weber@proxmox.com>
Signed-off-by: Daniel Kral <d.kral@proxmox.com>
Link: https://lore.proxmox.com/all/20250901082956.40297-1-d.kral@proxmox.com
2025-09-02 14:25:54 +02:00
Christoph Heiss
b99d14855f fix #6385: ui: pool: members: fix store reload on add/remove
.load() must be called on the underlying UpdateStore, not on the
DiffStore.

Currently, this results in the members list being cleared after
adding/removing an entry, only being reloaded (correctly) during the
next automatic background update.

Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
Link: https://lore.proxmox.com/all/20250827101430.424606-2-c.heiss@proxmox.com

FG: added bug reference to title
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
2025-09-02 14:25:03 +02:00
Max R. Carrara
eecc7a25a5 fix #6747: ceph: osd: swap vg and lv arguments when creating an OSD
... specifically when creating logical volumes for OSD DB / WAL devices,
if the block device wasn't in use beforehand.

The original line was part of a fix for #6652 (92bbc0c89f) and
slipped through during testing.

Fixes: #6747
Fixes: 92bbc0c89f
Signed-off-by: Max R. Carrara <m.carrara@proxmox.com>
Link: https://lore.proxmox.com/all/20250902104119.110464-1-m.carrara@proxmox.com
2025-09-02 14:21:18 +02:00
Wolfgang Bumiller
dc9ef6ae6c api: ceph: add missing type to api schema
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
2025-09-01 15:38:04 +02:00
Wolfgang Bumiller
317b83b078 api: ceph: add missing type to api schema
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
2025-09-01 15:35:53 +02:00
Shannon Sterz
c17f8c7add ui: add ceph logo svg again
this was accidentally dropped when applying this commit:

2348790b (ui: replace the ceph logo png with an svg version)

likely due to line length limits of email. so reformat the svg and add
it back in again.

Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
Tested-by: Maximiliano Sandoval <m.sandoval@proxmox.com>
Link: https://lore.proxmox.com/all/20250829092617.89627-3-s.sterz@proxmox.com
2025-09-01 12:44:35 +02:00
Shannon Sterz
5995877ce2 ui: add virt viewer svg again
this was accidentally dropped when applying:

53cf0269 (ui: use svg version of the virt viewer icon)

likely due mail line length limits. so add the svg again and reformat
it to conform to the limit.

Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
Tested-by: Maximiliano Sandoval <m.sandoval@proxmox.com>
Link: https://lore.proxmox.com/all/20250829092617.89627-2-s.sterz@proxmox.com
2025-09-01 12:44:35 +02:00
Shannon Sterz
ce2f6a8fc5 ui: properly center ceph icon
the container here is 24px tall, the icon itself is rendered with a
height of 14px, so it needs to be rendered 5px from the top to appear
vertically centered.

Reported-by: Christoph Heiss <c.heiss@proxmox.com>
Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
Link: https://lore.proxmox.com/20250827102428.101666-2-s.sterz@proxmox.com
2025-08-28 23:33:05 +02:00
Shannon Sterz
1b061a5d32 ui: remove unused png icons and their asset files
a lot of icons are no longer used, so remove them and, in rare cases,
their accompanying css classes. all of these are png files and would,
thus, appear blurry if used. this should somewhat reduce the size of
the pve-manager package, but more importantly, discourage the use of
icons that would only appear blurry on modern hardware anyway.

Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
Link: https://lore.proxmox.com/20250826145836.302748-10-s.sterz@proxmox.com
2025-08-28 23:31:40 +02:00
Shannon Sterz
2348790ba9 ui: replace the ceph logo png with an svg version
this makes the icon appear sharp on high-res displays

Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
Link: https://lore.proxmox.com/20250826145836.302748-9-s.sterz@proxmox.com
2025-08-28 23:31:40 +02:00
Shannon Sterz
fd40039e7b ui: use the svg version for the cd icon in a storage's treelist
so it does not appear blurry anymore. also removes the now unused png
version.

Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
Link: https://lore.proxmox.com/20250826145836.302748-8-s.sterz@proxmox.com
2025-08-28 23:30:23 +02:00
Shannon Sterz
1b69822949 ui: use svg version of xterm.js logo instead of a png
this allows the icon to look sharp on high-res monitors.

Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
Link: https://lore.proxmox.com/20250826145836.302748-7-s.sterz@proxmox.com
2025-08-28 23:30:23 +02:00
Shannon Sterz
53cf0269a2 ui: use svg version of the virt viewer icon
this should avoid it looking blurry on higher resolution displays

Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
Link: https://lore.proxmox.com/20250826145836.302748-6-s.sterz@proxmox.com
2025-08-28 23:30:23 +02:00
Shannon Sterz
af50fa5836 ui: use svg version of the noVnc icon
this should avoid blury icons on higher resolution displays

Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
Link: https://lore.proxmox.com/20250826145836.302748-5-s.sterz@proxmox.com
2025-08-28 23:28:23 +02:00
Shannon Sterz
61814591bc ui: replace the gif spinner from extjs with an svg
the current spinner gif is quite blurry on modern hardware so use an
svg based spinner instead.

note that by including the css animation in the svg itself, the
animation does not appear to restart when extjs re-renders a table.
this, at least in firefox 128, lead to jerky looking animation when
using font awesome's spinner with the `fa-spin` class. by creating our
own svg, we can also make it look more like the extjs version.

this does not impact the spinners used by extjs's load mask, as that
would require adapting extjs's code itself.

Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
Link: https://lore.proxmox.com/20250826145836.302748-4-s.sterz@proxmox.com
2025-08-28 23:28:23 +02:00
Shannon Sterz
a11f7c02e5 ui: remove all occurences of icon-display.png
and use the font awesome equivalent instead. this way the icons don't
appear blurry and we safe a bit of overhead for storing and loading
the png.

Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
Link: https://lore.proxmox.com/20250826145836.302748-3-s.sterz@proxmox.com
2025-08-28 23:28:23 +02:00
Shannon Sterz
470dd9057f fix #6599: ui: use font-awesome hdd icon instead of png
previously we used custom png rendered for storages in the add menu of
a pool, as well as for mountpoints of containers. these appeared
blurry on high resolution displays and since they were just the same
as the font-awesome icons anyway, use those directly. the ui already
loads font-awesome regardless, so there are no down-sides here.

Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
Link: https://lore.proxmox.com/20250826145836.302748-2-s.sterz@proxmox.com
2025-08-28 23:28:23 +02:00
Christoph Heiss
d9d4cd1f90 configs: drop unused country.dat file from install
I could not find _any_ reference to it in current checkouts of ~every
Proxmox repository.

AFAICT this was copied from pve-installer in pve-installer commit

  f0583fd4e ("copied country.pl form pve-manager")

in 2017 and simply never dropped here afterwards, so it's an unused
leftover.

Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
Link: https://lore.proxmox.com/20250828103621.936206-1-c.heiss@proxmox.com
2025-08-28 23:23:39 +02:00
Stoiko Ivanov
14879e4138 pve8to9: rework systemd-boot checks
This patch replicates the changes done in pbs3to4 from:
https://lore.proxmox.com/pbs-devel/20250821141719.4130062-4-s.ivanov@proxmox.com/T/#u

The check if systemd-boot presence is not problematic (before
upgrade for systems that actually use it) is left in place with a
log_skip,, all other situations where systemd-boot is installed are
marked as failure and point to the upgrade guide in the pve-wiki.

Signed-off-by: Stoiko Ivanov <s.ivanov@proxmox.com>
Link: https://lore.proxmox.com/20250821170007.148854-1-s.ivanov@proxmox.com
2025-08-26 08:52:55 +02:00
Wolfgang Bumiller
49c767b70a bump version to 9.0.6
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
2025-08-20 14:23:01 +02:00
Fiona Ebner
8e84f7d897 ui: ha: rules: fix edit button
As reported in the community forum [0], the 'Edit' button would stay
disabled. Use a proxmoxButton to fix it, which installs a monitor for
selectionchange.

[0]: https://forum.proxmox.com/threads/169258/post-792029

Fixes: fb289b0d ("ha: affinity rules: make edit/remove button declrative configs")
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
2025-08-18 09:53:55 +02:00
Fabian Grünbichler
2012f3eb22 run make tidy
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
2025-08-14 14:17:29 +02:00
Stoiko Ivanov
7e1684537e pve8to9: only allow systemd-boot when it is actually used before upgrade
On some (non-standard) setups having systemd-boot installed, causes
issues, even if the system is using proxmox-boot-tool (p-b-t) for booting.
The currently observed edge-case is:
before the upgrade:
* system is booted with grub (w/o secure boot), using p-b-t, results
  in the ESP not being mounted on /boot/efi

after the upgrade:
* systemd-gpt-auto-generator(8) is active, and mounts the (single) ESP
  on /efi (because grub w/o secure-boot sets the needed efivar+it is
  not mounted)
* the next upgrade of systemd-boot causes systemd-boot to be
  installed on the ESP, but it will not get any kernels configured,
  since we disabled the /etc/kernel/postinst.d/zz-systemd-boot in
  PVE8.

so this patch further restricts the case were having systemd-boot
installed to the cases where p-b-t says it's used for booting.

Additionally raise the level from info to warn in the legacy-boot
case. and add a log_pass message that was added to the equivalent
check in pbs3to4[0]

[0] https://lore.proxmox.com/pbs-devel/20250811091135.127299-1-s.ivanov@proxmox.com/

Signed-off-by: Stoiko Ivanov <s.ivanov@proxmox.com>
Link: https://lore.proxmox.com/all/20250814120807.2653672-1-s.ivanov@proxmox.com
2025-08-14 14:16:31 +02:00
Fabian Grünbichler
4af6d631f4 changelog: fix distro
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
2025-08-14 13:10:51 +02:00
Max R. Carrara
92bbc0c89f fix #6652: ceph: osd: enable autoactivation for OSD LVs on creation
... by adding an inline helper sub for `lvcreate` instead of using the
LVM storage plugin's helper sub.

Autoactivation is required for LVs used by Ceph OSDs, as Ceph
otherwise doesn't activate them by itself.

This is a regression from f296ffc4e4d in pve-storage [0].

[0]: https://git.proxmox.com/?p=pve-storage.git;a=commitdiff;h=f296ffc4e4d64b574c3001dc7cc6af3da1406441

Fixes: #6652
Signed-off-by: Max R. Carrara <m.carrara@proxmox.com>
Link: https://lore.proxmox.com/all/20250813134028.292213-2-m.carrara@proxmox.com
2025-08-13 16:11:35 +02:00
Fabian Grünbichler
9c5600b249 bump version to 9.0.5
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
2025-08-13 13:04:08 +02:00
Dominik Csapak
491f929a60 ui: make sure more datacenter option renderers are html encoded
to avoid interpreting html elements in these options

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
2025-08-13 12:59:52 +02:00
Fiona Ebner
d77a90c471 ui: storage edit: warn about disabling snapshot-as-volume-chain on LVM
Existing qcow2 volumes on a storage won't be handled correctly anymore
after the setting is turned off. The setting is already a fixed
storage setting for directory-based storages, so this is only relevant
for LVM. Could be improved by checking in the backend if there are any
qcow2 images and only allow turning it off if not, but this requires
changes to the on_update_hook() signature. Until then, warn in the
front-end.

Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
Link: https://lore.proxmox.com/all/20250812082824.30625-1-f.ebner@proxmox.com
2025-08-12 11:19:08 +02:00
Dominik Csapak
188ff556cc fix #6657: pveproxy: detect mobile firefox better
in mobile firefox, the text 'Mobile' is not followed by whitespace or a
forward slash, but rather a semicolon (';'). Instead of simply adding
that to the list of characters, change the regex to accept 'Mobile' only
when it's a word boundary, this should include
slashes/whitespace/semicolons and other things browser vendors might use
in their user agent strings.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
Link: https://lore.proxmox.com/20250811131600.2886215-1-d.csapak@proxmox.com
2025-08-12 09:51:55 +02:00
Fabian Grünbichler
39d8a4de7d bump version to 9.0.4
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
2025-08-08 16:42:30 +02:00
Fiona Ebner
adcc7b2083 d/postinst: lvm config: check that --clear-needs-check-flag is set if there is a thin_check_options override
Quoting the commit message from [0] verbatim:

thin_check v1.0.x reveals data block ref count issue that is not being
detected by previous versions, which blocks the pool from activation if
there are any leaked blocks. To reduce potential user complaints on
inactive pools after upgrading and also maintain backward compatibility
between LVM and older thin_check, we decided to adopt the 'auto-repair'
functionality in the --clear-needs-check-flag option, rather than
passing --auto-repair from lvm.conf.

[0]: eb28ab94

Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
Link: https://lore.proxmox.com/all/20250808140419.119992-3-f.ebner@proxmox.com
2025-08-08 16:13:15 +02:00
Fiona Ebner
d038d7d07e 8 to 9: lvm config: check that --clear-needs-check-flag is set if there is a thin_check_options override
Quoting the commit message from [0] verbatim:

thin_check v1.0.x reveals data block ref count issue that is not being
detected by previous versions, which blocks the pool from activation if
there are any leaked blocks. To reduce potential user complaints on
inactive pools after upgrading and also maintain backward compatibility
between LVM and older thin_check, we decided to adopt the 'auto-repair'
functionality in the --clear-needs-check-flag option, rather than
passing --auto-repair from lvm.conf.

[0]: eb28ab94

Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
Link: https://lore.proxmox.com/all/20250808140419.119992-2-f.ebner@proxmox.com
2025-08-08 16:13:15 +02:00
Thomas Lamprecht
8e3e0e08a0 8 to 9 checks: wrap MAC/IPAM files in quotes in log message
Allows simpler selection in most terminals as it clarifies that the
trailing dot of the sentence is not part of the path.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
(cherry picked from commit 2d2d93fcb4c65361584c62ce46a65569d8a7b0ab)
2025-08-08 15:56:59 +02:00
Thomas Lamprecht
4c18e557e7 8 to 9: support single-line repo entries with bracket options
I had a multi-arch setup here where I set an option to make apt check
only for amd64 on the PVE repo, i.e. :

 deb [arch=amd64] http://download.proxmox.com/debian/pve trixie pvetest

This was not detected by our regex and thus the pve8to9 did not
complain about the (for trixie) misspelled pvetest component.

Simply extend the regex to allow arbitrary string inside a bracket,
but do not add a match group for it, we would not do anything with it
for now anyway.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-08 15:55:26 +02:00
Stoiko Ivanov
2d79b567d5 8 to 9 checks: check for removable grub-install
some upgrades result in unbootable systems, which can be traced back
to grub being installed in BOOTX64.efi, but not being upgraded by
grub-install. Refer the cases to the output of
`proxmox-boot-tool refresh` as it has a sensible check logic for those
cases. Some affected systems printed the warning of proxmox-boot-tool,
but it was lost in the large output of the dist-upgrade.

Signed-off-by: Stoiko Ivanov <s.ivanov@proxmox.com>
Link: https://lore.proxmox.com/all/20250808124540.1490294-3-s.ivanov@proxmox.com

FG: rename variable, set boot_ok correctly in last if

Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
2025-08-08 15:31:43 +02:00
Stoiko Ivanov
7cc36772e7 8 to 9 checks: do not ask bootctl if systemd-boot is used.
The current logic of deciding if systemd-boot was manually setup by
the user (without proxmox-boot-tool), by checking
`bootctl is-installed` yields a false-positive after upgrading:
* systems which have the package installed (e.g. from our isos after
  8.0), but do not use proxmox-boot-tool (LVM installs) will get
  systemd-boot installed to /boot/efi upon upgrade
* after upgrading the check says that it's been explicitly setup.

Rather warn if the package is installed (unless proxmox-boot-tool is
used and the upgrade is still not done) in any case - as the number
of systems which have it setup manually are probably far lower than
those that upgrade without explicitly checking pve8to9.

Additionally increase the log from a warn to a fail, as issues with
boot-loaders yield unbootable systems, and move the (probably rare)
case of manual systemd-boot setups to the upgrade-guide
in our wiki, which is also linked in the output.

Finally fix a typo (s/remoing/removing/).

Reported-by: Daniel Herzig <d.herzig@proxmox.com>
Signed-off-by: Stoiko Ivanov <s.ivanov@proxmox.com>
Link: https://lore.proxmox.com/all/20250808124540.1490294-2-s.ivanov@proxmox.com
2025-08-08 15:23:28 +02:00
Fiona Ebner
1f9abf9f01 pve8to9: skip check for running guests if already upgraded
If already upgraded, the suggestion to stop or migrate running guests
is wrong.

Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
Link: https://lore.proxmox.com/all/20250806082926.15848-1-f.ebner@proxmox.com
2025-08-08 10:01:40 +02:00
Shannon Sterz
ea1f252351 8 to 9: use check for unified cgroup v2 support via pve-container
...instead of re-implementing a custom check here. This has the
side-effect that the check implemented by pve-container is much more
robust and is less likely to yield false positive. So users won't get
warnings about containers that actually do have the required unified
cgroup v2 support.

This was reported for an OpenSUSE Slowroll container on the forum:
https://forum.proxmox.com/threads/169302/

Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
Link: https://lore.proxmox.com/20250807142246.341381-1-s.sterz@proxmox.com
[FE: rebase on top of make tidy]
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
2025-08-07 16:27:41 +02:00
Fiona Ebner
bd35fc4555 run make tidy
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
2025-08-07 16:27:21 +02:00
Thomas Lamprecht
23f29d8a61 8 to 9: metric space usage: ignore missing RRD stats directory
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-05 17:08:26 +02:00
Thomas Lamprecht
dc7e07fe35 8 to 9: LVM autoactivation: simplify pass message even further
The context is already established by the initial info log message, so
keep the pass simple to avoid adding more confusion.

Suggested-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-05 17:08:26 +02:00
Friedrich Weber
5bd2666d75 pve8to9: lvm autoactivation: rephrase misleading message and fix typo
Currently, the message implies that *disabling* autoactivation might
cause issues, which is not the case.

While at it, fix a minor typo.

Signed-off-by: Friedrich Weber <f.weber@proxmox.com>
Link: https://lore.proxmox.com/20250805074220.28307-1-f.weber@proxmox.com
2025-08-05 17:08:26 +02:00
Thomas Lamprecht
025864202e bump version to 9.0.3
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-05 12:36:49 +02:00
Thomas Lamprecht
6e2e736367 d/postinst: add snippet to manage systemd-tmpfiles
Copy over manually as we do not use a #DEBHELPER# stanza here.

Suggested-by: Fabian Gründbichler <f.gruenbichler@proxmox.com>
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-05 12:30:25 +02:00
Thomas Lamprecht
cfbd13a083 bump version to 9.0.2
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-05 12:15:42 +02:00
Fiona Ebner
b659334438 d/tmpfiles: fix permission regression for /run/pve directory
There is a regression regarding the permission for the /run/pve
directory. In Proxmox VE 8, the directory had root:root 0755
permissions, being auto-created as the lxc-syscalld runtime directory.
In Proxmox VE 9, the permissions were restricted to root:root 0750,
but this leads to an issue with remote migration, when pveproxy tries
to access the mtunnel socket:

pveproxy[2484]: connect to 'unix/:/run/pve/ct-112.mtunnel' failed: Permission denied

Relax the permissions again by allowing the www-data group
read-access, so that pveproxy can access the socket.

This aligns the permissions with what /run/pve-cluster has.

Reported-by: Hannes Laimer <h.laimer@proxmox.com>
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
Tested-by: Hannes Laimer <h.laimer@proxmox.com>
Link: https://lore.proxmox.com/20250805100556.40874-1-f.ebner@proxmox.com
2025-08-05 12:14:31 +02:00
Thomas Lamprecht
0d706ddeff bump version to 9.0.1
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-05 12:07:10 +02:00
Stefan Hanreich
8f9388f1b2 network: improve reloading logic
The old behavior was *always* reloading the network configuration,
which worked as long as FRR was not pre-installed, but the change in
db03d261 coupled with the fact that we now ship with FRR caused FRR to
be enabled on applying the network configuration via the Web UI.

The stop gap fix in e1b9466d solved this behavior, but had the issue
that we need to possibly regenerate the FRR configuration if the host
configuration changes, since some controllers generate their
configuration based on the host network configuration.

pve-network now always sends the regenerate-frr parameter, so we can
discern whether a request came from SDN or is a manual request that is
requesting a specific behavior. With this information the reloading
logic can be improved as follows:

* Honor the parameter if it is set
* reload only if there are any FRR entities in the SDN configuration

This should handle all cases that we need to consider:

* Do not overwrite existing FRR configurations, unless we need to
  generate our own FRR configuration.

* Do not trigger a FRR enable when reloading the host configuration,
  even though there is no FRR configuration.

* Overwrite the FRR configuration with an empty configuration if all
  SDN entities using FRR got deleted.

* Regenerate the FRR configuration when the host network configuration
  changes, since this might affect the generated FRR configuration.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Tested-by: Hannes Duerr <h.duerr@proxmox.com>
Tested-by: Gabriel Goller <g.goller@proxmox.com>
Reviewed-by: Gabriel Goller <g.goller@proxmox.com>
Link: https://lore.proxmox.com/20250805083504.55378-2-s.hanreich@proxmox.com
2025-08-05 12:03:22 +02:00
Thomas Lamprecht
f1ce32103f pveproxy service: use heuristic to trigger initial appliance update
Our timer won't be triggered automatically on initial boot if the
current date is to near on the next scheduled run, and while it would
be nicer to create a dedicated service with a ConditionFirstBoot, this
seems a bit overkill for now, so just check if the pveam log exists,
and if not trigger a daily update, which will generate such a log.

Do so after pveproxy started in ExecStartPost and allow this to fail
by prefixing the call with -.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-05 11:48:16 +02:00
Thomas Lamprecht
767bac6324 api nodes: drop bogus comment to drop rrddata endpoint, still used for modern graphs
The rrd one is the one that returns a rendered PNG, the rrddata
returns the underlying data to be used by the frontend for modern
graphs, so that we will want to keep.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-05 11:09:14 +02:00
Dominik Csapak
23e19e70d2 ui: node memory RRD: change available color to a green shade
so it's more subtle versus the current gray line.
I used the normal green color from 'total' but increased the lightness
value by 10 points (in HSL color space) to make the color brighter.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
Link: https://lore.proxmox.com/20250805082906.939499-2-d.csapak@proxmox.com
2025-08-05 11:06:23 +02:00
Dominik Csapak
8af0c93162 ui: node memory RRD: change ZFS ARC color to a blue shade
so it's more like the 'used' color. It's a blueish shade from the
default extjs color scheme.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
Link: https://lore.proxmox.com/20250805082906.939499-1-d.csapak@proxmox.com
2025-08-05 11:06:23 +02:00
Thomas Lamprecht
627d9110e4 add symlink to pve-network-pinning-tool into usr/bin
For convenience when one doesn't has the common wrapper tool
installed.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-05 11:01:44 +02:00
Stefan Hanreich
a777811227 network-interface-pinning: move to libexec and rename
In order to avoid conflicts and confusion with the standalone
proxmox-network-interface-pinning standalone tool, rename to
pve-network-interface-pinning. Addtionally, install to the
/usr/libexec/proxmox directory, which is now our preferred location
for shipping custom scripts / CLI tools.

The standalone tool will check for the existence of
pve-network-interface-pinning and invoke the PVE specific script if it
is installed on the host. This makes it possible for the tool to
properly run on hosts where PVE and PBS are both installed.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250730141610.282177-1-s.hanreich@proxmox.com
2025-08-05 10:41:03 +02:00
Thomas Lamprecht
40bbbd26f6 bump version to 9.0.0
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-04 23:13:30 +02:00
Thomas Lamprecht
eaf7bfdc5f d/copyright: update years and drop reference to bootstrap
Bootstrap is now handled by pve-http-server, which uses the debian
provided package, so no need for a entry in d/copyright in pve-manager
in any case.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-04 21:56:40 +02:00
Thomas Lamprecht
e024dc9868 prepare for a time after a beta
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-04 21:52:40 +02:00
Thomas Lamprecht
5adfdb36ef bump version to 9.0.0~22
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-04 21:43:29 +02:00
Stoiko Ivanov
380d2838cb 8 to 9 checks: warn if old udev-mac-pinning still present
We observed this in a host which has been updated through many major
versions (at least since PVE 4). The 70-persistent-net.rules was
used keeping the NICs with 'ethX' names. With the first reboot
into trixie the NICs got their predictable names, and networking was
broken (because the 'ethX' names are not present as altname the
support for this does not help in this case)

I could not reproduce the issue with a VM (there the
70-persistent-net.rules was still active and the NIC remained ethX),
so it might be a race during early boot.

In any case a warning makes sense here as it's becoming a very niche
combination, and thus is likely to cause more issues in the future.

Suggest to manually setup pinning as suggested in our documentation:
https://pve.proxmox.com/pve-docs/pve-admin-guide.html#network_override_device_names
seems sensible.

Signed-off-by: Stoiko Ivanov <s.ivanov@proxmox.com>
Link: https://lore.proxmox.com/20250804183856.773378-1-s.ivanov@proxmox.com
2025-08-04 21:41:52 +02:00
Thomas Lamprecht
ca042b6592 8 to 9 checks: detect if matching CPU microcode package is installed
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-04 21:41:52 +02:00
Thomas Lamprecht
fbe2cd0c4f 8 to 9 checks: perltidy code
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-04 21:41:52 +02:00
Aaron Lauterer
f454b45894 api: backup: remove unneeded call of rrd_dump
$rrd is never used within this function, therefore we can easily remove
it.

Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
Link: https://lore.proxmox.com/20250701121656.1746548-1-a.lauterer@proxmox.com
2025-08-04 20:34:05 +02:00
Thomas Lamprecht
2d7dc01572 bump version to 9.0.0~21
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-04 18:31:00 +02:00
Thomas Lamprecht
0a4bd517ca 8 to 9 checks: rrd metrics space increase: add pass for all-ok case
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-04 18:28:42 +02:00
Thomas Lamprecht
ce1bb644fc 8 to 9 checks: simplify code to check for increased RRD metric space usage
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-04 18:28:42 +02:00
Thomas Lamprecht
60cbcda1ae 8 to 9 checks: perltidy code
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-04 18:28:42 +02:00
Thomas Lamprecht
c053283743 8 to 9 checks: LVM autoactivation: add pass for all-ok case
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-04 18:28:42 +02:00
Fiona Ebner
7eda056e76 pve8to9: rrd migration: mention storage RRD files for which automatic migration doesn't work
The RRD migration tool currently has the limitation of not migrating
RRD files for storages with a '.old' suffix. Mention the list of such
storages below the RRD file list and migration command so that users
can adapt before executing the migration command.

Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
Link: https://lore.proxmox.com/20250804125601.91944-3-f.ebner@proxmox.com
2025-08-04 18:28:42 +02:00
Friedrich Weber
a662ae8f67 pve8to9: bootloader: fix missing period at end of sentence
Signed-off-by: Friedrich Weber <f.weber@proxmox.com>
Link: https://lore.proxmox.com/20250804114017.73932-1-f.weber@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-04 18:28:18 +02:00
Stoiko Ivanov
65ffcdd0c4 cli: pve8to9: rework boot-loader suggestions for trixie
a few things changed in systemd-boot upstream packages we use as
for proxmox-boot-tool systems:
* systemd-boot was split up further into systemd-boot-tools (we need
  `bootctl`) and `systemd-boot`(the meta-package which triggers
  updates
* the ESPs updates now also run upon updates of shim(-signed) and
  probably other boot-related packages. These triggered updated breaks
  apt for systems booted by proxmox-boot-tool (more generally for
  systems which don't have the ESP mounted).

This patch reworks our logic for checking:
* before upgrade the log message just reflects that we need
  systemd-boot in bookworm
* for legacy booted systems we suggest removing `systemd-boot` (so it
  does not cause more issues in the future, and is definitely not
  needed for booting there
* for p-b-t we suggest to remove the meta-package
* for non-p-b-t we suggest to remove it as well, unless the system was
  manually setup to use systemd-boot.

see the changes for proxmox-kernel-helper for further background:
https://lore.proxmox.com/all/20250731114455.995999-1-f.gruenbichler@proxmox.com/

minimally tested on a secure-boot enabled VM, and on one which uses
p-b-t with systemd-boot.

Co-Authored-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
Signed-off-by: Stoiko Ivanov <s.ivanov@proxmox.com>
Reviewed-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
Link: https://lore.proxmox.com/20250801123804.2231830-1-s.ivanov@proxmox.com
2025-08-04 18:24:54 +02:00
Thomas Lamprecht
4a9754bc18 8 to 9 checks: rework log messages for legacy sysctl.conf check
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-04 18:22:40 +02:00
Stoiko Ivanov
aeff9bed42 pve8to9: check for settings in /etc/sysctl.conf
The procps package removed `/etc/sysctl.conf` in version 2:4.0.4-7
[0], as the shipped settings have moved to `linux-sysctl-defaults`[1]
and snippet files in /etc/sysctl.d/ have been favored for a while
now.  Setting them is done by systemd-sysctl.service(8) which only
mentions the snippet-directories (/etc/sysctl.d/*.conf).

Upon upgrading the settings are not set anymore (but are preserved
under /etc/sysctl.conf.dpkg-bak).

As `/etc/sysctl.conf` has been around for a long time (and is present
in most Unixoid systems), and is the default place where e.g. ansible
places settings[2] a warning about lost settings makes sense.

[0] https://metadata.ftp-master.debian.org/changelogs//main/p/procps/procps_4.0.4-9_changelog
[1] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1074156
[2] https://docs.ansible.com/ansible/latest/collections/ansible/posix/sysctl_module.html

Signed-off-by: Stoiko Ivanov <s.ivanov@proxmox.com>
Link: https://lore.proxmox.com/20250804102328.201317-1-s.ivanov@proxmox.com
2025-08-04 18:22:40 +02:00
Thomas Lamprecht
d2dc39a932 drop pve7to8 tool
Neither useful nor tested for PVE 9.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-04 18:11:00 +02:00
Stefan Hanreich
6c5295a1cd api: network: default to not regenerating the frr configuration
Default to not regenerating the FRR configuration, unless explicitly
requested. Otherwise applying the host network configuration would
reload and enable the FRR service. Invert the boolean from skip to
regenerate, since the logic is less convoluted this way.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250804140152.423614-2-s.hanreich@proxmox.com
2025-08-04 18:06:22 +02:00
Thomas Lamprecht
58a0dd085d ui: migration pre-conditions: make lack of support for conntrack state migration only a info
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-04 17:18:15 +02:00
Thomas Lamprecht
1058bdbe2c ui: migration pre-conditions: support info severity
For things that might be good to know but where there's not much that
the user can do in any case.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-04 17:17:07 +02:00
Thomas Lamprecht
edaa2c1e49 bump version to 9.0.0~20
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-04 16:58:49 +02:00
Thomas Lamprecht
3218ff49f9 ui: ignore backend 501 error for migration precondition checks
Avoids a scary error when migrating a CT by using a new UI version but
the CT is currently on an old node.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-04 16:52:29 +02:00
Thomas Lamprecht
2226aab4f5 ui: node summary metrics: only show memory usage without ARC if ARC is more than 1 MiB
It looks rather odd to see the same size twice especially if one isn't
using ZFS in the first place, so use the simple heuristic of ARC
needing to be > 1 MiB to decide if we should render the ARC. Note that
the lowest possible minimum size for the ARC is 64 MiB, so this should
cover all real ZFS setups. FWIW, might also use a test that depends on
the order of magnitude difference between ARC size and memory used.

btw. this is also only theoretical true, with ZFS 2.3 the ARC is
registered for the kernel as reclaimable, so it might or might not
account to used, depending on the calculation and what the kernel
does, which changes frequently. If we get reports about this being odd
we should just remove it completely.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-04 16:18:26 +02:00
Dominik Csapak
f8174b5e49 ui: node memory RRD: make 'Available' a line graph
instead of an area graph. Give it the same color as the 'hostmem' one
from the qemu guests (a neutral color that draws not too much
attraction).

While at it, order it last, since it was just ordered second so the
overlapping colors would not clash.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
Link: https://lore.proxmox.com/20250804132928.1714525-2-d.csapak@proxmox.com
2025-08-04 16:12:37 +02:00
Dominik Csapak
212e43e33e ui: node memory RRD: add 'Available' graph
so one can see how much is available as an explicit graph.
The color is the same as the total, as most other colors produce weird
looking result since the graphs are transparent and overlay each other.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
Link: https://lore.proxmox.com/20250804112842.904286-3-d.csapak@proxmox.com
2025-08-04 13:49:20 +02:00
Dominik Csapak
89ca129203 ui: node memory RRD: add more infos to the tooltips
the stacked graphs had more information, namely how much memory was
available and how much was used without the ZFS ARC. So put this
information into the tooltip where the users most likely want to see it.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
Link: https://lore.proxmox.com/20250804112842.904286-2-d.csapak@proxmox.com
2025-08-04 13:49:20 +02:00
Thomas Lamprecht
bde686c6b4 ui: de-stackify RRD memory graphs
highly confusing if y-axis does not matches the metric and "jumps" if
metrics get toggled via the legend.

Keep the 'host memory' in vm graphs as a line, as otherwise the
overlapping colors make the graph also confusing, and keep it's
'hidden by default' logic.

While at it, use title case for the legend.

Originally-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
Link: https://lore.proxmox.com/20250804112842.904286-1-d.csapak@proxmox.com
2025-08-04 13:49:20 +02:00
Thomas Lamprecht
dbe05420f6 statd: simplify check for if RRD file exists
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-04 10:18:16 +02:00
Thomas Lamprecht
8fd3420bff api: node status: add the available memory to return value
While it's indirectly included in how we calculate memused, it still
can be nice to have as dedicated value.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-04 10:17:18 +02:00
Thomas Lamprecht
6012e29e00 bump version to 9.0.0~19
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-02 19:43:16 +02:00
Thomas Lamprecht
c018b30a9c ui: guest migrate: adapt HA migration checks to new property name also for CTs
This mirrors commit 09d9dd535 ("ui: guest migrate: adapt HA migration
checks to altered property name"), which just fixed it for QEMU..

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-02 19:35:23 +02:00
Thomas Lamprecht
566ec7fdb8 ha: affinity rules: use single data store and mirror it to child grids
This avoids loading the data twice, which is annoying especially on
high-latency links. Further, it ensures both views are always backed
by the exact same data, avoiding inconsistent state and thus e.g.
confusing warnings if something changed in the backend between on of
both loads.

To implement this add a new model that derives from the main one but
uses an in-memory proxy. Then move the "real" store out to the parent
component, where we need to manually initialise it as ExtJS panel are
more generic compared to grids–which always got a backing store.
Anyway, in the parent add a listener to copy any data to the in-memory
stores of the child grids for each affinity rule type. In the child
grid's relay any store load–e.g., after adding/changing/deleting a
rule–to the parent.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-02 19:20:06 +02:00
Thomas Lamprecht
4904453e91 ha: affinity rules: add ID column but hide by default for now
While it's great to auto-generate that by default, it should be still
(optionally) visible and maybe even per default, but then we need to
also allow overriding it on edit.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-02 19:02:47 +02:00
Thomas Lamprecht
b02d0b7c72 ha: affinity rules: give resource rulse some more vertical space
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-02 18:19:59 +02:00
Thomas Lamprecht
d65cbbf389 ha: affinity rules: give resource / node column width a bit more flex ratio
As those normally have most amount of data, so favor giving them a bit
more space.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-02 18:19:59 +02:00
Thomas Lamprecht
9c1fbb4b1a ha: affinity rules: avoid unnecesarry initComponent
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-02 18:19:59 +02:00
Thomas Lamprecht
77772394b4 ha: affinity rules: rework adding child colums
Make it a bit more obvious how the order of columns is.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-02 18:19:59 +02:00
Thomas Lamprecht
f51d3743a4 ha: affinity rules: refactor columns to reduce code bloat
Avoid single-use intermediate variables and make use of arrow function
for simple cases where a ternary works well.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-02 18:19:59 +02:00
Thomas Lamprecht
fb289b0d30 ha: affinity rules: make edit/remove button declrative configs
No benefit in having this pre-created and assigned in a variable, in
our more modern components we normally try to have as much as possible
defined declaratively, and ideally avoid having an initComponent
completely–or at least keep it to the required minimum.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-02 18:19:59 +02:00
Thomas Lamprecht
985a864c6a ha: affinity rules: make store definition declarative
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-02 18:19:59 +02:00
Thomas Lamprecht
ad0bd7192e ui: define HA rules models globally
No real benefit in doing this chained in the RulesView class, and
it causes lots of extra indentation.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-02 18:19:59 +02:00
Thomas Lamprecht
3cc1bcc602 re-tidy code
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-01 19:46:57 +02:00
Thomas Lamprecht
bff166ba36 make: also format/tidy ui JavaScript code from top-level target
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-01 19:46:03 +02:00
Thomas Lamprecht
7eb47686db bump version to 9.0.0~18
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-01 18:41:51 +02:00
Fiona Ebner
732d12184b ui: sdn: ipam/dhcp: allow sorting by guest ID
Previously, sorting would not apply to the leaves of the tree.

Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
Link: https://lore.proxmox.com/20250801092701.48332-1-f.ebner@proxmox.com
2025-08-01 17:31:02 +02:00
Thomas Lamprecht
09d9dd5357 ui: guest migrate: adapt HA migration checks to altered property name
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-01 17:30:41 +02:00
Thomas Lamprecht
8cc5475193 ui: guest migrate: fix logging unexpected errors to developer console
Avoid strignifying the error here, that will most likely just make it
output "[object]", but rather pass it as additional parameter to
console.warn, which the makes it print as nice object that can be
interacted with.

Originally-by: Gabriel Goller <g.goller@proxmox.com>
 [TL: split out of bigger patch that became obsolete]
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-01 17:30:41 +02:00
Thomas Lamprecht
4cc72ba282 8 to 9 checks: note that legacy files can be removed if feature is not used
As otherwise one might be confused about what to do, e.g. if the only
tried the old IPAM once for testing.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-01 16:28:13 +02:00
Thomas Lamprecht
357c41f7c1 8 to 9 checks: fix version for when its ok to clean legacy ipam db/mac state
It's fine since PVE 8.3, as there we replaced those files with a
better system, but use 8.4 as that's required for the upgrade anyway.

Admins that want to clean these things up before the major upgrade can
know that it's safe to do.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-01 16:28:13 +02:00
Stefan Hanreich
152d178e1b pve8to9: check for legacy ipam db or mac cache files
Check if there are any not-yet-migrated ipam / mac cache files in
pmxcfs. Those should have been migrated over in the pve-network
postinst, but if something went wrong during this process we can
explicitly notify users here again to avoid any unpleasant suprises
after the upgrade.

If all nodes are on PVE 9, it is safe to delete the legacy files,
print a notice informing the users.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250801121029.201766-3-s.hanreich@proxmox.com
2025-08-01 16:28:13 +02:00
Thomas Lamprecht
ead55e965a 8 to 9 checks: rrd migration: add pass for all-ok case
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-01 16:21:57 +02:00
Thomas Lamprecht
3eb088c5ca 8 to 9 checks: rrd migration: actually list files, not only count
But cut off after 29 (well 30, I hate it when a list gets cut-off with
an entry like "one additional entry omitted", just print it instead of
that single cut-off entry!) to avoid spamming the log if there–why
ever–are still many files that were not migrated on huge setups.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-01 16:21:51 +02:00
Thomas Lamprecht
2ae80ce143 8 to 9 checks: make full CLI parameter accessible for whole module
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-08-01 16:21:45 +02:00
Shannon Sterz
d73625314f pve8to9: don't report already migrated files as needing to be migrated
the find command previously also found the already migrated rrd files
under `pve-{vm,node,storage}-9.0` and reported them as needing to
migrate them. the provided command to would of course not migrate them
so the warning persisted even after the command was run.

limit the find command to the old `pve2-` prefixed folders to prevent
that.

Reported-by: Friedrich Weber <f.weber@proxmoc.com>
Reported-by: Daniel Herzig <d.herzig@proxmox.com>
Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
Tested-by: Daniel Herzig <d.herzig@proxmox.com>
Tested-by: Michael Köppl <m.koeppl@proxmox.com>
Link: https://lore.proxmox.com/20250801091336.68133-1-s.sterz@proxmox.com
2025-08-01 13:21:07 +02:00
Friedrich Weber
2753e104a1 ui: RRD graphs: display PSI as percent
Pressure stall information are actually in percent. This is not
mentioned explicitly in the documentation, but e.g. in the kernel
source [1]:

> The percentage of wall clock time spent in those compound stall
> states gives pressure numbers between 0 and 100 for each resource,
> where the SOME percentage indicates workload slowdowns and the FULL
> percentage indicates reduced CPU utilization:
>
>	%SOME = time(SOME) / period
>	%FULL = time(FULL) / period

Thus, also display them as percent in the GUI.

This reverts commit 087af55863.

[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/kernel/sched/psi.c?h=v6.16#n52

Signed-off-by: Friedrich Weber <f.weber@proxmox.com>
Link: https://lore.proxmox.com/20250731135147.138187-1-f.weber@proxmox.com
2025-07-31 15:56:29 +02:00
Thomas Lamprecht
60fe557510 use ngettext where other UIs already have plurals
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-31 13:49:04 +02:00
Thomas Lamprecht
d4e9265eea bump version to 9.0.0~17
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-31 11:52:32 +02:00
Thomas Lamprecht
03830d6be5 d/control: bump versioned dependency for ha-manager
For the resource-to-resource affinity rule API to be available.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-31 11:52:32 +02:00
Thomas Lamprecht
57a09b2041 ui: use title-case for affinity selections
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-31 11:52:32 +02:00
Daniel Kral
3b7bbefe73 ui: migrate: vm: display precondition messages for ha resource affinity
Extend the VM precondition check to show whether a migration of a VM
results in any additional migrations because of positive HA resource
affinity rules or if any migrations cannot be completed because of any
negative resource affinity rules.

In the latter case these migrations would be blocked when executing the
migrations anyway by the HA Manager's CLI and it state machine, but this
gives a better heads-up about this. However, additional migrations are
not reported in advance by the CLI yet, so these warnings are crucial to
warn users about the comigrated HA resources.

Signed-off-by: Daniel Kral <d.kral@proxmox.com>
Link: https://lore.proxmox.com/20250730181428.392906-19-d.kral@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-31 11:52:32 +02:00
Daniel Kral
38949914ae ui: migrate: lxc: display precondition messages for ha resource affinity
Extend the container precondition check to show whether a migration of a
container results in any additional migrations because of positive HA
resource affinity rules or if any migrations cannot be completed because
of any negative resource affinity rules.

In the latter case these migrations would be blocked when executing the
migrations anyway by the HA Manager's CLI and it state machine, but this
gives a better heads-up about this. However, additional migrations are
not reported in advance by the CLI yet, so these warnings are crucial to
warn users about the comigrated HA resources.

Signed-off-by: Daniel Kral <d.kral@proxmox.com>
Link: https://lore.proxmox.com/20250730181428.392906-18-d.kral@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-31 11:52:32 +02:00
Daniel Kral
5b927daf3f ui: ha: rules: add ha resource affinity rules
Add HA resource affinity rules as a second rule type to the HA Rules'
tab page as a separate grid so that the columns match the content of
these rules better.

Signed-off-by: Daniel Kral <d.kral@proxmox.com>
Link: https://lore.proxmox.com/20250730181428.392906-17-d.kral@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-31 11:52:32 +02:00
Thomas Lamprecht
91e6d330dd ui: allow hiding some testing artefacts/labels
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-31 11:52:32 +02:00
Thomas Lamprecht
bc214fce67 remove now unreachable sencha touch based mobile UI
got replaced by a modern Yew and Proxmox Yew Widget toolkit based
mobile UI with more features and supporting all modern TFA variants.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-31 10:01:04 +02:00
Thomas Lamprecht
199b18601d make yew based mobile UI required
It beats the ancient sencha-touch UI by light years, so we cannot
really lose here.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-31 09:50:13 +02:00
Thomas Lamprecht
a6b308c5e6 bump version to 9.0.0~16
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-31 09:10:47 +02:00
Thomas Lamprecht
d69320f455 ui: datacenter navigation: mention that the rules are affinity ones
Provide common context of industry standard terminology.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-31 09:09:54 +02:00
Thomas Lamprecht
26e4d922e5 buildsys: allow to opt-out strict online help reference checks
New pve-docs we now depend on supports a --allow-missing flag for the
asciidoc-pve scan-extjs command, which, if set, will silence errors
for missing onlineHelp references to warnings and fallback to a link
to the main single-page admin guide.

One can easily enable this by using `export ALLOW_MISSING=1` before
the build or bass that variable to make like:

 make ALLOW_MISSING=1 OnlineHelpInfo.js

in the www/manager6 source directory.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-31 09:09:54 +02:00
Thomas Lamprecht
69d6ecb768 d/control: bump versioned dependency for pve-docs and pve-ha-manager
to ensure new HA affinity rule infrastructure is available, it will
replace the HA groups.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-31 09:09:54 +02:00
Daniel Kral
a487871d71 ui: ha: replace ha groups with ha node affinity rules
Introduce HA rules and replace the existing HA groups with the new HA
node affinity rules in the web interface.

The HA rules components are designed to be extendible for other new rule
types and allow users to display the errors of contradictory HA rules,
if there are any, in addition to the other basic CRUD operations.

HA rule ids are automatically generated with a 13 character UUID string
in the web interface, as also done for other concepts already, e.g.,
backup jobs, because coming up with future-proof rule ids that cannot be
changed later is not that user friendly. The HA rule's comment field is
meant to store that information instead.

Signed-off-by: Daniel Kral <d.kral@proxmox.com>
Link: https://lore.proxmox.com/20250730175957.386674-30-d.kral@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-31 09:09:54 +02:00
Daniel Kral
1b3daaa28a ui: ha: show failback flag in resources status view
As the HA groups' failback flag is now being part of the HA resources
config, it should also be shown there instead of the previous HA groups
view.

Signed-off-by: Daniel Kral <d.kral@proxmox.com>
Link: https://lore.proxmox.com/20250730175957.386674-29-d.kral@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-31 09:09:54 +02:00
Daniel Kral
decbed80f6 ui: ha: remove ha groups from ha resource components
Remove the HA group column from the HA Resources grid view and the HA
group selector from the HA Resources edit window, as these will be
replaced by semantically equivalent HA node affinity rules in the next
patch.

Add the field 'failback' that is moved to the HA Resources config as
part of the migration from groups to node affinity rules.

Signed-off-by: Daniel Kral <d.kral@proxmox.com>
Link: https://lore.proxmox.com/20250730175957.386674-28-d.kral@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-31 09:09:54 +02:00
Daniel Kral
0196e6f94d api: ha: add ha rules api endpoints
Signed-off-by: Daniel Kral <d.kral@proxmox.com>
Link: https://lore.proxmox.com/20250730175957.386674-27-d.kral@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-31 09:09:54 +02:00
Thomas Lamprecht
c903927c33 bump version to 9.0.0~15
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-31 06:01:49 +02:00
Thomas Lamprecht
a6a0189342 ui: node rrd charts: clarify that the ZFS *ARC* is meant
ZFS is a complex stack, knowing that the metric shows the ARC size can
help understanding this.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-31 05:53:56 +02:00
Thomas Lamprecht
f6e31f7040 ui: rrd charts: drop info tool for now
Avoid rushing this, besides that it could be de-duplicated code-wise,
and might even go into widget-toolkit so that on use-site one only
passes a config option with the respective (get)text along, at least
if this should become a generic concept (which would be good to avoid
making it feel one-off "tacked-on).

It might also look better when being directly besides the title (on
the right side of that), not the legend.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-31 05:50:55 +02:00
Thomas Lamprecht
087af55863 ui: RRD graphs: do not suggest PSI is in percent
It's in amount of processes, which gets a float due do being averaged.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-31 05:40:33 +02:00
Thomas Lamprecht
09e345e8c4 ui: RRD graphs: use title-case for titles
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-31 05:40:16 +02:00
Thomas Lamprecht
e2a3936fba ui: RRD model: use correct memavailable as column name
It was memfree in an earlier revision of the series.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-31 05:39:16 +02:00
Thomas Lamprecht
0a330607de d/postinst: slightly reword output for RRD metric migtraion
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-31 05:38:46 +02:00
Lukas Wagner
43d987e9f2 d/postinst: fix typo
Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>
2025-07-31 03:56:42 +02:00
Lukas Wagner
588e8260c2 d/postinst: use full path for proxmox-rrd-migration-tool
Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>
2025-07-31 03:56:42 +02:00
Lukas Wagner
9fe70d6adc cli: pve8to9: display full path to the proxmox-rrd-migration-tool
It will only be available in /usr/libexec which is usually not in $PATH.

Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>
2025-07-31 03:56:42 +02:00
Lukas Wagner
3447d723d0 cli: pve8to9: fix 'find' call to actually find not migrated rrd files
Also pass arguments individually.

Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>
2025-07-31 03:56:42 +02:00
Aaron Lauterer
0a664efceb pve8to9: add checkfs for RRD migration
As the new RRD files are quite a bit larger than the old ones, we should
check if the estimated required space is actually available and let the
users know if not.

Secondly, it could be possible that a new resource is added while the
node is migrating the RRD files. Therefore, there could be some left not
migrated to the new format. Therefore, check for that too and let the
user know how they can migrate the remaining RRD files.

Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
2025-07-31 03:56:42 +02:00
Aaron Lauterer
68ef7f89c7 d/postinst: run promox-rrd-migration-tool
Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
2025-07-31 03:56:42 +02:00
Aaron Lauterer
646e859725 d/control: require proxmox-rrd-migration-tool >= 1.0.0
Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
2025-07-31 03:56:42 +02:00
Aaron Lauterer
e4ca137de8 fix #6068: ui: utils: calculate and render host memory usage correctly
by adding the new memhost field, which is populated for VMs, and
using it if the guest is of type qemu and the field is numerical.

As a result, if the cluster is in a mixed PVE8 / PVE9 situation, for
example during a migration, we will not report any host memory usage, in
numbers or percent, as we don't get the memhost metric from the older
PVE8 hosts.

Fixes: #6068 (Node Search tab incorrect Host memory usage %)
Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
2025-07-31 03:56:42 +02:00
Aaron Lauterer
112e63671d ui: summaries: use titles for disk and network series
They were missing and just showed the actual field names.

Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
Reviewed-by: Dominik Csapak <d.csapak@proxmox.com>
2025-07-31 03:56:42 +02:00
Aaron Lauterer
a84b66c492 ui: nodesummary: guestsummary: add tooltip info buttons
This way, we can provide a bit more context to what the graph is
showing. Hopefully making it easier for our users to draw useful
conclusions from the provided information.

Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
2025-07-31 03:56:42 +02:00
Aaron Lauterer
8239a37d2a ui: GuestSummary: remember visibility of host memory view
by utilizing the itemclick event of a charts legend and storing it as
state.

Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
2025-07-31 03:56:42 +02:00
Aaron Lauterer
5a9792ec6d ui: GuestSummary: memory switch to stacked and add hostmem
We switch the memory graph to a stacked area graph, similar to what we
have now on the node summary page.

Since the order is important, we need to define the colors manually, as
the default color scheme would switch the colors as we usually have
them.

Additionally we add the host memory view as another data series. But we
keep it as a single line without fill. We chose the grey tone so that is
works for both, bright and dark theme.

Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
2025-07-31 03:56:42 +02:00
Aaron Lauterer
73d70b5c42 ui: GuestStatusView: add memhost for VM guests
With the new memhost field, the vertical space is getting tight. We
therefore reduce the height of the separator boxes.

Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
Reviewed-by: Dominik Csapak <d.csapak@proxmox.com>
2025-07-31 03:56:42 +02:00
Folke Gleumes
615369abf6 ui: add pressure graphs to node and guest summary
Pressures are indicatios that processes needed to wait for their
resources. While 'some' means, that some of the processes on the host
(node summary) or in the guests cgroup had to wait, 'full' means that
all processes couldn't get the resources fast enough.

We set the colors accordingly. For 'some' we use yellow, for 'full' we
use red.
This should make it clear that this is not just another graph, but
indicates performance issues. It also sets the pressure graphs apart
from the other graphs that follow the usual color scheme.

Originally-by: Folke Gleumes <f.gleumes@proxmox.com>
[AL:
    * rebased
    * reworked commit msg
    * set colors
]
Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
Reviewed-by: Dominik Csapak <d.csapak@proxmox.com>
2025-07-31 03:56:42 +02:00
Aaron Lauterer
374ab81628 ui: node summary: use stacked memory graph with zfs arc
To display the used memory and the ZFS arc as a separate data point,
keeping the old line overlapping filled line graphs won't work
anymore. We therefore switch them to area graphs which are stacked by
default.

The order of the fields is important here as it affects the order in the
stacking. This means we also need to override colors manually to keep
them in line as it used to be.
Additionally, we don't use the 3rd color in the default extjs color
scheme, as that would be dark red [0]. We go with a color that is
different enough and not associated as a warning or error: dark-grey.

[0] https://docs.sencha.com/extjs/7.0.0/classic/src/Base.js-6.html#line318

Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
Reviewed-by: Dominik Csapak <d.csapak@proxmox.com>
2025-07-31 03:56:42 +02:00
Aaron Lauterer
b0067575cd ui: rrdmodels: add new columns and update existing
The new columns we get from RRD are added.

Since we are switching the memory graphs to stacked graphs, we need to
handle them a bit different because:
* gaps are not possible, we need to have a value, ideally 'null' when
  there is no data, makes it easier to handle in the tooltip
* calculate some values and not take the ones received from RRD.
  Otherwise the memory graphs can be _wobbly_. For example if we take
  the node memory where we have memused + arcsize + memavailable. Those
  will not always line up perfectly from the gathered data to match the
  total physical memory. Similar for the memory graph for guests.

The values we calculate are for nodes:
* memused-sub-arcsize: because the arcsize is included in memused, but
  we want to show it as a separate part of the graph if we do have that
  information.
  If we don't have the arcsize values (older node for example), we set
  it to 0.
* memfree-capped: instead of memavailable we calculate the free memory
  to avoid memory graphs that have wobbles and spikes due to timing
  differences when gathering the data.

For guests:
* memfree-capped: We cannot just have two line graphs, but will stack
  them as well to match the node graph. Therefore we need to subtract
  the memused from maxmen, so that in total, both data lines will result
  in maxmem.

Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
2025-07-31 03:56:42 +02:00
Aaron Lauterer
e3ac6efa30 api2tools: extract_vm_status add new vm memhost column
as this will also be displayed in the status of VMs

Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
2025-07-31 03:56:42 +02:00
Aaron Lauterer
42bc19a7e7 api: nodes: rrd and rrddata add decade option and use new pve-node-9.0 rrd files
if the new rrd pve-node-9.0 files are present, they contain the current
data and should be used.

'decade' is now possible as timeframe with the new RRD format.

Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
2025-07-31 03:56:42 +02:00
Aaron Lauterer
24ccdc29b3 pvestatd: collect and distribute new pve-{type}-9.0 metrics
If we see that the migration to the new pve-{type}-9.0 rrd format has been done
or is ongoing (new dir exists), we collect and send out the new format with additional
columns for nodes and VMs (guests).

Those are:
Nodes:
* memfree
* arcsize
* pressures:
  * cpu some
  * io some
  * io full
  * mem some
  * mem full

VMs:
* memhost (memory consumption of all processes in the guests cgroup -> host view)
* pressures:
  * cpu some
  * cpu full
  * io some
  * io full
  * mem some
  * mem full

Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
2025-07-31 03:56:42 +02:00
Thomas Lamprecht
193b0f8ec8 bump version to 9.0.0~14
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-31 01:12:01 +02:00
Fabian Grünbichler
ffd144b299 lxc: create: always submit unprivileged field
even if unchecked, since the backend now defaults to unprivileged if not
defined at all.

Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
Link: https://lore.proxmox.com/20250730150013.901666-5-f.gruenbichler@proxmox.com
2025-07-31 01:10:00 +02:00
Thomas Lamprecht
2f31e0e8a2 http server: fix yew mtime path
Was still the old location.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-31 01:09:19 +02:00
Thomas Lamprecht
8b980bbe16 http server: drop legacy yew mobile paths
Those where only used by internally tested versions of the new yew
based UI.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-31 01:08:28 +02:00
Thomas Lamprecht
94fb34bddf bump version to 9.0.0~13
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-31 00:27:27 +02:00
Thomas Lamprecht
eb3063f1aa http server: rework location for yew-mobile UI and provide mtimes
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-31 00:22:21 +02:00
Thomas Lamprecht
ebef4828de http server: fix caching of i18n translation files, use mtime
By using the mtime of the parent directory where all locale i18n files
are located we ensure that every time a file is added/replaced/deleted
we will get a new value.

As both dpkg and install recreate existing files this should always
result in such an mtime update when either installing a new package or
directly installing the build artefacts to the root system
(circumventing dpkg).

While the explicit version would be slightly nicer, it's only relevant
for debugging and can be correlated with the local file and the one
from the debian package – which always has the time stamp from
the current d/changelog entry.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-31 00:14:24 +02:00
Thomas Lamprecht
b5db1334b5 ui: fix indentation in index.tpl
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-31 00:13:00 +02:00
Thomas Lamprecht
ffb9874541 d/control: require qemu-server 9.0.10
To allow adding the API route for the new migration capability API.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-30 23:12:42 +02:00
Christoph Heiss
fa1ab3e999 ui: window: Migrate: add checkbox for migrating VM conntrack state
Adds a new checkbox to the migration dialog, if it is a
live/online-migration and both the source and target nodes have support
for our dbus-vmstate helper.

If the checkbox is active, it passes along the `with-conntrack-state`
parameter to the migrate API call.

Reviewed-by: Stefan Hanreich <s.hanreich@proxmox.com>
Tested-by: Stefan Hanreich <s.hanreich@proxmox.com>
Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
Link: https://lore.proxmox.com/20250730094549.263805-11-c.heiss@proxmox.com
2025-07-30 23:09:22 +02:00
Christoph Heiss
87cbef5cfe api2: capabilities: expose new qemu/migration endpoint
This endpoint provides information about migration capabilities of the
node. Currently, only support for dbus-vmstate is indicated.

Tested-by: Stefan Hanreich <s.hanreich@proxmox.com>
Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
Link: https://lore.proxmox.com/20250730094549.263805-10-c.heiss@proxmox.com
2025-07-30 23:09:19 +02:00
Fiona Ebner
7f4c298e15 ui: drop handling of removed 'maxfiles' setting
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
Link: https://lore.proxmox.com/20250718125408.133376-6-f.ebner@proxmox.com
2025-07-30 20:09:38 +02:00
Fiona Ebner
9b193c4aac backup: drop 'maxfiles' parameter
The 'maxfiles' parameter has been deprecated since the addition of
'prune-backups' in the Proxmox VE 7 beta.

Drop the tests that only had maxfiles or both, but adapt the mixed
tests for CLI/backup/storage precedence.

Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
Link: https://lore.proxmox.com/20250718125408.133376-5-f.ebner@proxmox.com
2025-07-30 20:09:31 +02:00
Fiona Ebner
c81fe5cc08 close #2809: api: replication: use VM.Replicate privilege
Currently, guest replication is guarded with Datastore.Allocate on
'/storage', which is rather surprising. One could require
Datastore.AllocateSpace on all involved storages, but having a
dedicated privilege like for other VM operations like migration and
snapshot seems to be more natural.

Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
FG: add versioned dependency
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
2025-07-30 15:23:35 +02:00
Fiona Ebner
754f8086d1 api: replication: fix usages of RPCEnvironment check method
The RPCEnvironment's check() method is used without $noerr, so it will
already fail and raise a permission exception when the privilege is
missing.

The usage in the job_status endpoint can be simplified, as the
raise_perm_exc() there is dead code.

The other two usages actually want to set the $noerr argument. In
particular, this makes it possible to use the 'status' endpoint, when
the user does not have VM.Audit for all guests with a replication job
and to read the log with only Sys.Audit privilege on the node. Both
would previously fail, because the check for VM.Audit would raise an
exception already.

Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
2025-07-30 14:54:39 +02:00
Fiona Ebner
b3fd2e3d4a api: replication config: remove dead code
The RPCEnvironment's check() method is used without $noerr, so it will
already fail and raise the proper permission exception when the
privilege is missing.

Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
2025-07-30 14:54:39 +02:00
Fiona Ebner
29865e4e44 api: replication config: add missing module imports
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
2025-07-30 14:54:39 +02:00
Fiona Ebner
4ad0a5e711 api: replication config: code style: order module imports
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
2025-07-30 14:54:39 +02:00
Fiona Ebner
ae59bd5cbe api: replication: add missing module imports
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
2025-07-30 14:54:39 +02:00
Fiona Ebner
1f0f148e44 api: replication: code style: order module imports
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
2025-07-30 14:54:39 +02:00
Stefan Hanreich
09f7410dd3 pvestatd: prevent warnings for non-existing network devices
pvestatd runs the update loop for every network device present on the
host. This includes many dynamically created / removed network
interfaces (tap devices, veths, fw bridges). This triggers a warning
if the network device isn't yet in the cached version of the ip link
output:

pvestatd[1011]: Use of uninitialized value in string eq at /usr/share/perl5/PVE/Network.pm line 998.

Silently fail such errors for now, since they should normally affect
only such dynamically created devices and no physical devices. Even
for hotplugged physical devices this should be corrected the next time
the ip link cache gets invalidated. The worst case scenario in this
case is at most 15 minutes of missing netin/out metrics for that link.

Reported-by: Hannes Dürr <h.duerr@proxmox.com>
Reported-by: Max Carrara <m.carrara@proxmox.com>
Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250730124451.184806-1-s.hanreich@proxmox.com
2025-07-30 14:49:56 +02:00
Fiona Ebner
a67037fc69 debian: add tpmfiles.d config to create /run/pve directory
The pve-lxc-syscalld systemd service currently uses /run/pve as a
runtime directory. This means, that when the service is restarted, the
directory will be recreated. But the /run/pve directory is not just
used as the runtime directory of this service, but also for other
things, e.g. storage tunnel and mtunnel sockets, container stderr logs
as well as pull metric cache and lock, which will be lost when the
service is restarted.

The plan is to give the service its own runtime directory that is only
used for that purpose and nothing else. However, this means the
/run/pve directory will not get created automatically anymore (e.g.
pull metric relies on the existence already). Add this tmpfiles.d
configuration to create it automatically again. Note that the
permissions/owner are different now. As the runtime directory, it was
created with 0755 root:root. This tmpfiles configuration
changes this to 0750 root:root.

Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
Link: https://lore.proxmox.com/20250723144131.170616-2-f.ebner@proxmox.com
2025-07-30 13:41:42 +02:00
Thomas Lamprecht
42d9ec4ad5 bump version to 9.0.0~12
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-29 22:19:51 +02:00
Thomas Lamprecht
f24730fdda d/control: require libpve-http-server-perl 6.0.3 or newer
This ensures the installed Perl based http api-server supports WASM
and MO files (for Yew mobile GUI) and understands the new MAX_WORKER
daemon config setting.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-29 21:15:57 +02:00
Friedrich Weber
934305ea1d partially fix #5392: pvedaemon: make number of workers configurable
The number of pvedaemon worker processes is currently hardcoded to 3.
This may not be enough for automation-heavy workloads that trigger a
lot of API requests that are synchronously handled by pvedaemon.

Hence, read /etc/default/pvedaemon when starting pvedaemon and allow
overriding the number of workers by specifying MAX_WORKERS in this
file. All other values are only relevant for pveproxy/spiceproxy and
thus ignored.

Signed-off-by: Friedrich Weber <f.weber@proxmox.com>
Link: https://lore.proxmox.com/20250729155227.157120-4-f.weber@proxmox.com
2025-07-29 21:14:52 +02:00
Friedrich Weber
d7fec8f9ff partially fix #5392: pveproxy: make number of workers configurable
The number of pveproxy worker processes is currently hardcoded to 3.
This may not be enough for automation-heavy workloads that trigger a
lot of API requests that are synchronously handled by pveproxy.

Hence, allow specifying MAX_WORKERS in /etc/default/pveproxy to
override the number of workers.

Signed-off-by: Friedrich Weber <f.weber@proxmox.com>
Link: https://lore.proxmox.com/20250729155227.157120-3-f.weber@proxmox.com
2025-07-29 21:14:49 +02:00
Thomas Lamprecht
c743a51239 d/control: record newer dependency relations for libpve-common-perl
To ensure that, e.g., ip_link_details is available on build and that
the new flexible physical interface naming can work on usage, that's
why it's different versions for build and use.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-29 21:07:51 +02:00
Thomas Lamprecht
03f4d96ee6 udev config: fix style complaints from udevadm verify
Without this a `udevadm verify` execution warns about:

70-virtual-function-pinning.rules:1 style: whitespace after comma is expected.
70-virtual-function-pinning.rules:1 style: whitespace after comma is expected.
70-virtual-function-pinning.rules:1 style: whitespace after comma is expected.
70-virtual-function-pinning.rules: udev rules have style issues.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-29 20:44:59 +02:00
Thomas Lamprecht
5a4d38d6ac statd: re-cache IP link details every 15 minutes
While the commit adding this cache is right in that this data probably
won't change at all that often, adding a simple time based expiration
of the cache is not much extra code, and the normally 96 fork+exec of
ip link per day should really not be noticeable at all.

FWIW, if we wanted to make this more efficient and reduce the latency
on changes, we could hook into udev and touch some in-memory flag file
to signal pvestatd that it should requery this info. As this is an
internal mechanism, we can change it any time, so can still be done in
the future.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-29 20:28:04 +02:00
Stefan Hanreich
57135496ba network-interface-pinning: allow arbitrary names
With the changes to physical interface detection in pve-common and
pve-manager, it is now possible to use arbitrary names for physical
interfaces in our network stack. This allows the removal of the
existing, hardcoded, prefixes.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250729171649.708219-4-s.hanreich@proxmox.com
2025-07-29 20:17:44 +02:00
Stefan Hanreich
83d0b982e6 pvestatd: pull metric: use ip link to detect physical interfaces
pve-common now allows arbitrary names for physical interfaces, without
being restricted by PHYSICAL_NIC_RE. In order to detect physical
interfaces, pvestatd now needs to query 'ip link' for the type of an
interface instead of relying on the regular expression.

On the receiving end, PullMetric cannot consult 'ip link' for
determining which interface is physical or not. To work around that,
introduce a new type key, that carries information about the type of
an interface. When aggregating the metrics, PullMetric can now read
this additional parameter, to infer the type of the interface (either
physical or virtual).

To avoid spawning a process in every update loop of pvestatd, cache
the output once and then use it throughout the lifecycle of pvestatd.
Physical interfaces rarely get added / removed without a reboot, so we
can cache this indefinitely. Users can always restart the service to
refresh the information about physical interfaces.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250729171649.708219-3-s.hanreich@proxmox.com
2025-07-29 20:17:41 +02:00
Thomas Lamprecht
86afa25bb8 make new Yew based UI opt-out for now
Just for initial testing, this way one can relatively easily switch
back to the old UI for comparison (of how bad it's state is).

While I really do not think this is strictly required, it allows
moving along a newer pve-manager without the Yew PVE GUI package, so
can be useful.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-29 19:44:05 +02:00
Dietmar Maurer
a7d469e51c replace sencha touch mobile web UI with new Yew based one written in rust
Use the new mobile web UI written in rust with yew and our yew widget
toolkit as replacement for the old sencha-touch based gui.

The new mobile UI is oriented on our Flutter based app for basic style
an widgets.

Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>
Link: https://lore.proxmox.com/20250722072256.3168428-1-dietmar@proxmox.com
 [TL: raise d/control version to current, reword commit message a bit]
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-29 19:07:23 +02:00
Shannon Sterz
ea9eeaac18 fix #6534: ui: keep displaying help button in backup edit dialog
previously the help button would disappear once either the
"Notifications" or "Retention" tabs was opened. this removes an
unnecessary extra container and sets the value for all tab so that the
help button stays present.

Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
Link: https://lore.proxmox.com/20250718133846.101784-1-s.sterz@proxmox.com
2025-07-29 18:47:34 +02:00
nansen.su
523050865a external metric server: add support for OpenTelemetry
This patch adds OpenTelemetry metrics collection to the PVE manager
to improve observability and monitoring capabilities.

The implementation includes:
- OTLP/HTTP JSON protocol support for OpenTelemetry Collector
- Comprehensive metrics collection for nodes, VMs, containers, and storage
- Batching with configurable size limits and compression
- Full compliance with OpenTelemetry v1 specification

Technical features:
- Server/port configuration with HTTP/HTTPS protocol support
- Gzip compression with configurable body size limits (default 10MB)
- Custom HTTP headers (Bearer tokens, API keys)
- Resource attributes support (Unicode support)
- Timeout control and SSL certificate verification options
- Recursive metrics conversion supporting all PVE data types

This plugin also implements proper metric type classification to
distinguish between:

Counter metrics (cumulative values):
- Network traffic: transmit, receive, netin, netout
- Disk I/O: diskread, diskwrite
- Block operations: *_operations, *_merged
- CPU time (cpustat context): user, system, idle, iowait, etc.

Gauge metrics (instantaneous values):
- Memory usage, CPU percentages, storage space, etc.

It should be also compatible with Prometheus.

Signed-off-by: Nansen Su <nansen.su@sianit.com>
Link: https://lore.proxmox.com/20250722095526.4164885-2-nansen.su@sianit.com
 [TL: re-format code to fix various white space & indentation errors]
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-29 18:39:24 +02:00
Thomas Lamprecht
5731c3cb91 run make tidy
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-29 18:39:24 +02:00
Fiona Ebner
91fb2017df pve8to9: backup retention: increase severity of having 'maxfiles' setting configured
The 'maxfiles' setting is dropped with Proxmox VE 9, so make having
the setting configured a proper error rather than just a warning.

Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
Link: https://lore.proxmox.com/20250718125408.133376-4-f.ebner@proxmox.com
2025-07-29 17:59:34 +02:00
Thomas Lamprecht
00de7bf3b5 8to9 upgrade checks: make it a notice if a keyring does not exist for an RBD storage
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-29 17:10:21 +02:00
Thomas Lamprecht
b6e69f8403 8to9 upgrade checks: add skip logs when applicable
As otherwise one has no feedback from the info levels that the tests
are not applicable for one at all, thus explicitly skip for the case
where there is no RBD storage at all or if there are only
PVE-managed ones.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-29 17:10:21 +02:00
Thomas Lamprecht
cb1127e702 8to9 upgrade checks: external rbd: output storages on new line and separate by space
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-29 17:10:21 +02:00
Thomas Lamprecht
07434e2922 8to9 upgrade checks: external rbd: mark returns that only exit the eval scope
As those can be rather subtle when reading the code.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-29 17:10:21 +02:00
Fiona Ebner
3ac8422322 pve8to9: add check and script to ensure that 'keyring' option for external RBD storages is set
With the switch from QEMU's -drive to -blockdev, it is not possible
anymore to pass along the Ceph 'keyring' option via the QEMU
commandline anymore, as was previously done for externally managed RBD
storages. For such storages, it is now necessary that the 'keyring'
option is correctly configured in the storage's Ceph configuration.

For newly created external RBD storages in Proxmox VE 9, the Ceph
configuration with the 'keyring' option is automatically added, as
well as for existing storages that do not have a Ceph configuration
at all yet. But storages that already got an existing Ceph
configuration are not automatically handled by the storage layer in
Proxmox VE 9, the check and script here covers those as well.

Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
Reviewed-by: Max R. Carrara <m.carrara@proxmox.com>
Tested-by: Max R. Carrara <m.carrara@proxmox.com>
Link: https://lore.proxmox.com/20250716124716.104765-1-f.ebner@proxmox.com
2025-07-29 17:10:21 +02:00
Thomas Lamprecht
58f080d410 interface pinning: use our schema support for marking required property dependencies
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-29 09:37:49 +02:00
Thomas Lamprecht
9a54bda980 interface pinning: fix prefix parameter description
It was just copied and not adapted.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-29 09:35:37 +02:00
Stefan Hanreich
90057e0ab9 network-interface-pinning: add if prefix to list of allowed prefixes
'if' has been added as a possible prefix for physical nics in
pve-common. Add it as a possible prefix for pinning network interfaces
here as well.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250724093459.76397-5-s.hanreich@proxmox.com
2025-07-29 08:30:46 +02:00
Stefan Hanreich
63dddce3cb network-interface-pinning: add target-name parameter
If a specific interface is specified via the interface parameter,
users can now additionally specify a target-name. This makes it easier
for users to assign specific names to specific interfaces, according
to their preferences.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250724093459.76397-4-s.hanreich@proxmox.com
2025-07-29 08:30:46 +02:00
Stefan Hanreich
e19c1f48b5 network-interface-pinning: improve printing mapping
Instead of printing a separate line for each altname, the tool now
only prints one line per physical interface. The primary name is used
as an identifier and the altnames are printed additionally in
parentheses (if they exist). Additionally, the output is now sorted by
ifindex (just as the pin order), so interfaces should now be printed
in ascending order.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250724093459.76397-3-s.hanreich@proxmox.com
2025-07-29 08:30:46 +02:00
Stefan Hanreich
595b69b024 network-interface-pinning: use ifindex as order for pinning
While ifindex is not guaranteed to be stable across reboots, it seems
like a good enough heuristic for making sure interfaces with multiple
ports are clamped together when pinning.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250724093459.76397-2-s.hanreich@proxmox.com
2025-07-29 08:30:46 +02:00
Fiona Ebner
7eadbed6b0 api: create pool: force first character to be a letter for new pools
Currently, the first character can also be a digit, '.', '-', or '_'.
Almost all other configuration IDs in Proxmox VE require starting with
a letter, so force this for new pool names too.

A pool with ID '0' can be added, but not parsed, because it will
evaluate to false in PVE/AccessControl.pm's parse_user_config():

> if (!verify_poolname($pool, 1)) {
>     warn "user config - ignore pool '$pool' - invalid characters in pool name\n";
>     next;
> }

It's likely that it would cause other issues as well if properly
handled there.

Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
Link: https://lore.proxmox.com/20250724083205.15646-1-f.ebner@proxmox.com
2025-07-29 08:28:40 +02:00
Thomas Lamprecht
8177df1d26 8to9 upgrade checks: test pvetest -> pve-test transition
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-29 08:00:15 +02:00
Thomas Lamprecht
be65f0b013 8to9 upgrade checks: improve closure name for parsing repo list files
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-29 08:00:15 +02:00
Friedrich Weber
7f7d0158ec pve8to9: lvm: fix missing space and remove unnecessary line break
Signed-off-by: Friedrich Weber <f.weber@proxmox.com>
Link: https://lore.proxmox.com/20250728152400.972595-2-f.weber@proxmox.com
2025-07-29 08:00:15 +02:00
Friedrich Weber
fae2a201f3 pve8to9: lvm: use consistent spelling for autoactivation
In some cases, autoactivation was spelled as "auto-activation". Remove
the dash for consistency with other occurrences and the LVM
documentation.

Signed-off-by: Friedrich Weber <f.weber@proxmox.com>
Link: https://lore.proxmox.com/20250728152400.972595-1-f.weber@proxmox.com
2025-07-29 08:00:15 +02:00
Thomas Lamprecht
01216ea90c ui index: add fallback ngettext implementation
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-24 17:05:01 +02:00
Fiona Ebner
47fd309d27 run make tidy
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
2025-07-23 13:25:42 +02:00
Thomas Lamprecht
c474e5a0b4 bump version to 9.0.0~11
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-22 23:33:42 +02:00
Stefan Hanreich
8694ab3cea network-interface-pinning: fix pinning for bond members
The key in the ip link output is actually called linkinfo. Before this
patch, members of bond interfaces that inherit the MAC address of the
bond would have a wrong MAC in their generated .link file.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250722151452.378352-1-s.hanreich@proxmox.com
2025-07-22 23:31:01 +02:00
Stefan Hanreich
73ae711ff0 network-interface-pinning: do not generate link files for vfs
Since the renaming of virtual functions is now handled dynamically via
a custom udev rule, proxmox-network-interface-pinning needs to
additionally filter all existing virtual functions when pinning
network interface names, since otherwise they would also get a pinned
name.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250722145223.351778-3-s.hanreich@proxmox.com
2025-07-22 17:30:47 +02:00
Stefan Hanreich
017359f376 configs: add udev helper for pinning virtual function names
This commmit adds a udev rule that triggers for every network device
that gets added. It checks if the network device is a VF and if the
parent device is pinned. If it is pinned, then generate a new name for
the VF which consists of the pinned name of the parent device, as well
as the index of the VF.

It relies on the network device driver exposing the information via
sysfs, which was the case in my tests for mlx5_core, igb and bnxt_en.

Specifically it checks if a device is a virtual function by checking
for the existence of:

  /sys/class/net/<iface>/device/physfn

It then follows that symlink and infers the vf index by looking at the
virtfnX symlinks in the folder above.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250722145223.351778-2-s.hanreich@proxmox.com
2025-07-22 17:30:47 +02:00
Shannon Sterz
5034a93f6d apl: make keyring generation output keys as binary again
sequioa dropped the `--binary` flag for keyring generation and only
outputs ascii armored keyrings. so make it dearmor the key afterward
to keep the key format consistent with the file ending (".gpg") again.

Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
Link: https://lore.proxmox.com/20250722123658.196232-2-s.sterz@proxmox.com
2025-07-22 16:24:55 +02:00
Shannon Sterz
15a67b13e7 fix #6539: apl: use sqv instead of gpgv to verify signatures
debian trixie based installs don't ship with gpgv so take this
opportunity and use sqv directly. sqv can deal with both armored and
dearmored keys. this has the side-effect of closing #6539. which
occured, due to sequioa dropping the `--binary` option for merging
keys into a keyring and would always output them in an armored
formart. gpgv cannot handle armored keys and would therefore fail to
verify signatures.

while sqv is pre-installed, adding it as an explicit dependency should
still avoid problems if it is removed at some point (like gpgv was).

Closes: #6539
Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
Link: https://lore.proxmox.com/20250722123658.196232-1-s.sterz@proxmox.com
2025-07-22 16:24:55 +02:00
Thomas Lamprecht
e1b82fd1b4 ui: base storage: fix outdated wording in tech-preview hint
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-20 13:57:00 +02:00
Thomas Lamprecht
4e285047c8 ui: base storage: add comment for disable logic
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-20 13:56:25 +02:00
Thomas Lamprecht
21a6ed782d fix #6537: api: system services:
Since postfix (3.9.1-7) the postfix@- is gone again and the non-
templated postfix.service is back, so cope with that here.

Closes: #6537
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-19 21:27:38 +02:00
Thomas Lamprecht
f55e789f99 8to9 upgrade checks: machine version: place VMIDs in dedicated line
And the links too, as otherwise this rather easy to overlook, and
there's no downside in using more lines.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-19 20:58:46 +02:00
Thomas Lamprecht
0fef50945c bump version to 9.0.0~10
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-19 20:56:48 +02:00
Thomas Lamprecht
193518f473 8to9 upgrade checks: fix parsing network config for VMs, got moved in PVE 9
Moves not available in oldstable might get annoying...

Report: https://forum.proxmox.com/threads/168628/post-784423
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-19 20:51:06 +02:00
Thomas Lamprecht
2a7093d0dd d/postinst: use proper if-else for adapting lvm.conf always vs as-needed
... and early exit for the odd case that there is no lvm config, no
point in failing the manager postinst then, as nothing can be filtered
anyway.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-19 16:19:09 +02:00
Thomas Lamprecht
2ddac43bf5 d/postinst: improve lvm filter mirgration
The old code worked but used a bit hard to read syntax in the sed
command that even confused my vim syntax highlighting into thinking
the quote is still open for the rest of the file.

Split into single and double quotes as needed, this also separates
backslash escaping for shell and for sed more clearly.

While at it ensure the new marker gets added, as otherwise one might
gain two entries.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-19 14:34:28 +02:00
Thomas Lamprecht
2a0cd96ad9 d/postinst: tell shellcheck to ignore the local keyword, dash supports it
As do most other shells, it's just not defined in POSIX.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-19 13:56:05 +02:00
Thomas Lamprecht
bdf7126caa d/postinst: only set-up pve-test repos for beta on fresh installation
As for upgrades (or installations on top of Debian) a user will
already have a valid PVE 9 test repo setup upfront, as otherwise they
could not do the upgrade anyway.

Report: https://forum.proxmox.com/threads/168619/post-784373
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-19 13:52:11 +02:00
Thomas Lamprecht
1db25b139c bump version to 9.0.0~9
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-18 20:48:20 +02:00
Stefan Hanreich
04ff424388 network-interface-pinning: early exit if nothing to do
We would regenerate all configuration files, even if no interface
would be mapped. While this shouldn't cause an issue, it's
unnecessary, has potential for creating bugs and leads to confusing
output for the users - so just abort in this case instead.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250718162610.443895-3-s.hanreich@proxmox.com
2025-07-18 20:46:58 +02:00
Stefan Hanreich
e569f15af2 network-interface-pinning: fix subsequent invocations
The fix introduced in 5b5db0e67 fixed the scenario where pins were
already applied, but broke the case where they weren't yet applied,
since now not-yet-applied pins would get overwritten again on
subsequent invocations of the pinning tool.

Move the check for the same name to the update_etc_network_interfaces
call, where it is actually required - instead of filtering already in
the resolve_pinned function, which is also used in the generate body
to filter eligible links for pinning.

Fixes: 5b5db0e67
Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250718162610.443895-2-s.hanreich@proxmox.com
2025-07-18 20:46:58 +02:00
Aaron Lauterer
5b4c6ef074 guest metrics: support and prefer new pve-{type}-9.0 RRD files
We add a new function to handle different key names, as it would
otherwise become quite unreadable.

It checks which key format exists for the type and resource:
* the old pve2-{type} / pve2.3-vm
* the new pve-{type}-{version}

and will return the one that was found. Since we will only have one key
per resource, we can return on the first hit.

Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
Link: https://lore.proxmox.com/20250715143218.1548306-16-a.lauterer@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-18 19:38:12 +02:00
Aaron Lauterer
352393b632 guest metrics: drop support for ancient RRD schema
pve2.3-vm has been introduced with commit 3b6ad3ac back in 2013. By now
there should not be any combination of clustered nodes that still send
the old pve2-vm variant.

Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
Link: https://lore.proxmox.com/20250715143218.1548306-15-a.lauterer@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-18 19:37:02 +02:00
Thomas Lamprecht
08dc1724de bump version to 9.0.0~8
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-18 15:39:59 +02:00
Thomas Lamprecht
6738b721f8 ui: add beta text with link to bugtracker
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-18 15:39:14 +02:00
Thomas Lamprecht
07e5c12ca6 bump version to 9.0.0~7
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-18 15:24:32 +02:00
Thomas Lamprecht
8824ceafa2 d/postinst: setup pve-test repo for updates during the beta phase
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-18 15:23:33 +02:00
Thomas Lamprecht
96d5d10aa5 bump version to 9.0.0~6
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-18 14:41:40 +02:00
Stefan Hanreich
3a5ede8acb sdn-commit: only reload ifupdown if sdn configuration changed
Check for any changes between the running config and the currently
applied config and guard against executing pve-sdn-commit if the
configuration is unchanged.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250718123313.208460-4-s.hanreich@proxmox.com
2025-07-18 14:36:51 +02:00
Stefan Hanreich
3aa6c09142 {sdn, firewall}-commit: wait for quorum
Since both one-shot services need to wait for quorum, wait for it at
the beginning of the scripts, before proceeding with the actual logic.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250718123313.208460-3-s.hanreich@proxmox.com
2025-07-18 14:36:51 +02:00
Stefan Hanreich
6f5871f63d network-interface-pinning: avoid comparing undefined string
Controllers do not necessarily have a node defined, so check for
definedness before comparing the value to avoid ugly error messages.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250718123313.208460-2-s.hanreich@proxmox.com
2025-07-18 14:36:51 +02:00
Fiona Ebner
3fb8ce7285 ui: adapt to dropped VM.Monitor privilege
Querying the VM IP requires VM.GuestAgent.Audit now and accessing the
QEMU HMP monitor requires Sys.Audit.

Reported-by: Max Carrara <m.carrara@proxmox.com>
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
Link: https://lore.proxmox.com/20250718115527.105844-1-f.ebner@proxmox.com
2025-07-18 14:35:29 +02:00
Gabriel Goller
9663f410c5 fabrics: add maxLength to fabric name to improve error message
A fabric name has a character limit of 8 characters. (This is due to the
dummy interface, which is named 'dummy_<fabric_name>' which is limited
by the max interface name length in the kernel.) This shows a nicer
error message instead of only "Invalid character".

Signed-off-by: Gabriel Goller <g.goller@proxmox.com>
Link: https://lore.proxmox.com/20250718120213.325141-1-g.goller@proxmox.com
2025-07-18 14:34:57 +02:00
Thomas Lamprecht
bd8bd5b076 8to9 upgrade checks: fix duplicate variable name in same scope
This was overlooked when moving some checks to a new virtual guest
specific section.

Adapt the name for the list of node-local VM & CT IDs to differentiate
them from the cluster wide list.

Fixes: a3b63156a ("8to9 upgrade checks: add dedicated section for virtual guest checks")
Reported-by: Friedrich Weber <f.weber@proxmox.com>
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-18 12:33:15 +02:00
Friedrich Weber
a43d436846 ui: disk storage selector: fix check for disabling format selector
The API returns an object where a format can map to 0 (unsupported) or
1 (supported). However, when deciding whether to disable the format
selector by counting the number of valid formats, the GUI only took
the number of entries into account, not the actual values, so it would
show the format selector even though there is only one entry with
value 1. Fix this by taking the values into account when counting the
number of valid formats.

Signed-off-by: Friedrich Weber <f.weber@proxmox.com>
Link: https://lore.proxmox.com/20250718102532.61149-1-f.weber@proxmox.com
 [TL: run through proxmox-biome format]
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-18 12:30:47 +02:00
Maximiliano Sandoval
2064c0db18 ui: dc/options: allow to edit cluster wide replication settings
Signed-off-by: Maximiliano Sandoval <m.sandoval@proxmox.com>
Link: https://lore.proxmox.com/20250718081349.125228-3-m.sandoval@proxmox.com
2025-07-18 12:11:49 +02:00
Thomas Lamprecht
c6a5c4b43c d/control: require libpve-storage-perl >= 9.0.5
To ensure the change of the snapshot-as-volume-chain option name is
available.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-18 11:06:48 +02:00
Thomas Lamprecht
159c075841 bump version to 9.0.0~5
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-17 23:35:06 +02:00
Thomas Lamprecht
c9e58c2c2d 8to9 upgrade checks: add dedicated section for virtual guest checks
As the Misc. section gets rather crowded and virtual guests are
definitively "worth" their own section.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-17 23:31:31 +02:00
Stefan Hanreich
f860b80c46 pve8to9: add check for interfaces
PVE 9 will automatically set the host_mtu parameter for VMs to the
bridge MTU if the MTU field of the network device is unset. Check for
any interface that would be affected by a change in MTU after the
upgrade.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250717175018.606662-1-s.hanreich@proxmox.com
2025-07-17 23:31:31 +02:00
Thomas Lamprecht
49179625ca 8to9 upgrade checks: add newline+tab in long ACL role notice message
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-17 23:31:31 +02:00
Fiona Ebner
2fb2b8bb50 pve8to9: check for to-be-dropped VM.Monitor privilege in custom roles
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
Link: https://lore.proxmox.com/20250717133711.84715-8-f.ebner@proxmox.com
2025-07-17 23:31:31 +02:00
Fiona Ebner
fbb84c3216 pve8to9: remove outdated checks for user roles
These checks were only relevant for the upgrade to PVE 8 and the
messages talking about a new PVE namespace or dropped
Permission.Modify privilege do not apply anymore.

Keep the infrastructure for checking custom roles intact for future
checks.

Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
Link: https://lore.proxmox.com/20250717133711.84715-7-f.ebner@proxmox.com
2025-07-17 23:31:31 +02:00
Thomas Lamprecht
d694481d7a 8to9 upgrade checks: move GlusterFS check to storage section
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-17 23:31:31 +02:00
Thomas Lamprecht
e83b56a860 8to9 upgrade checks: reword log messages for GlusterFS checks
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-17 23:31:31 +02:00
Max R. Carrara
e417a84b77 pve8to9: check for usage of GlusterFS storages
Starting with PVE 9, we will drop support for GlusterFS entirely [1]
as it is no longer properly maintained upstream [2].

Therefore, scan the storage config and suggest either moving to
different storages or using one's GlusterFS instances as directory
storage if a 'glusterfs' storage is found.

[1]: https://git.proxmox.com/?p=pve-storage.git;a=commit;h=7669a99e97f3fd35cca95d1d1ab8a377f593dccb
[2]: https://marc.info/?l=fedora-devel-list&m=171934833215726

Signed-off-by: Max R. Carrara <m.carrara@proxmox.com>
Link: https://lore.proxmox.com/20250711122342.262727-1-m.carrara@proxmox.com
2025-07-17 23:31:31 +02:00
Christoph Heiss
7830c70718 api2: capabilities: proxy index endpoints to respective nodes
Nodes might have different capabilities, depending on their version.
This ensures that always the requested is actually queryied.

Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
Link: https://lore.proxmox.com/20250717141530.1471199-12-c.heiss@proxmox.com
2025-07-17 23:28:19 +02:00
Christoph Heiss
643ed68a8f api2: capabilities: explicitly import CPU capabilities module
This currently works only by pure chance, as it seems to be already
imported somewhere else.

Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
Link: https://lore.proxmox.com/20250717141530.1471199-11-c.heiss@proxmox.com
2025-07-17 23:28:16 +02:00
Thomas Lamprecht
e48656e3e3 d/control: require libpve-rs-perl >= 0.10.4
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-17 21:25:55 +02:00
Stefan Hanreich
5b5db0e670 proxmox-network-interface-pinning: fix pinning after reboot
We generate a list of existing pins as a reference throughout the
pinning tool. It works by reading the existing link files and looking
up interfaces with the corresponding MAC address. If pins have already
been applied, this would return a mapping of the pinned name to itself
(nic0 => nic0).

We use this list for filtering what we write to the pending
configuration, in order to avoid re-introducing already pinned names
to the pending configuration. This reflexive entry would cause the
interfaces file generation to filter all pinned network interfaces
after reboot, leading to invalid ifupdown2 configuration files. Fix
this by filtering entries in the existing-pins list who are reflexive.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250717152841.397830-7-s.hanreich@proxmox.com
2025-07-17 21:23:22 +02:00
Stefan Hanreich
b94382504f proxmox-network-interface-pinning: die on failing to write interfaces
lock_file sets the error variable in perl, but does not die if it
encounters an error in the callback. All other invocations of
lock_file already die, but it was missing for writing the interfaces
s file, which swallowed errors.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250717152841.397830-6-s.hanreich@proxmox.com
2025-07-17 21:23:19 +02:00
Stefan Hanreich
7f471652dd proxmox-network-interface-pinning: add fabrics support
The fabric configuration references interfaces of nodes, which need to
be updated when pinning network interface names as well. Use the new
helper provided by perlmod for that.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250717152841.397830-5-s.hanreich@proxmox.com
2025-07-17 21:23:16 +02:00
Stefan Hanreich
8b9b41c01b pve-sdn-commit: fix reloading logic
The API for generating the SDN configuration has been changed in the
fabrics patch series ('387cc48'). Use the new API to commit the SDN
configuration on boot, since otherwise the one-shot service fails to
apply the SDN configuration on boot.

The service was also missing an ifreload, since the ifupdown2 config
gets regenerated by SDN and needs to be applied before generating the
FRR configuration in order for the FRR config generation to work
properly.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250717152841.397830-4-s.hanreich@proxmox.com
2025-07-17 21:23:12 +02:00
Gabriel Goller
2a13a2e5d9 fabrics: add emptyText attributes to some input fields
Add default emptyText attributes to OpenFabric and OSPF add/edit
windows. Use the default values on Hello Interval [0], CSNP Interval [1]
and Hello Multiplier [2] inputs. For the OSPF area just use the simplest
area "0" (the backbone).

[0]: f56119ea03/isisd/isis_constants.h (L77)
[1]: f56119ea03/isisd/isis_constants.h (L69)
[2]: f56119ea03/isisd/isis_constants.h (L81)

Suggested-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
Signed-off-by: Gabriel Goller <g.goller@proxmox.com>
Link: https://lore.proxmox.com/20250717120639.401311-2-g.goller@proxmox.com
2025-07-17 20:29:24 +02:00
Gabriel Goller
dd734f2496 fabric: increase width of fabric edit/add window
Increase the width of the OSPF and OpenFabric add and create windows.
This looks more pleasant and the input fields aren't that crammed
anymore.

Suggested-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
Signed-off-by: Gabriel Goller <g.goller@proxmox.com>
Link: https://lore.proxmox.com/20250717120639.401311-1-g.goller@proxmox.com
2025-07-17 20:29:24 +02:00
Stefan Hanreich
2d674676aa qemu: network: adjust MTU emptyText to match new default behavior
Leaving the MTU field unset now defaults to the bridge MTU, rather
than 1500. Reflect this change by indicating the new behavior in the
emptyText of the MTU field. While we're at it, add a gettext call so
it can be translated. I've taken the same text as from the container
dialogue, so it should already use existing translations.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250717175012.606372-3-s.hanreich@proxmox.com
2025-07-17 20:29:24 +02:00
Thomas Lamprecht
7d9066d15b ui: storage base: update to new option name for snapshot-as-volume-chain
We also changed the name of the option itself while we still had the
chance (no public release yet).

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-17 20:28:57 +02:00
Thomas Lamprecht
774c3577dd ui: storage base: rename label to "Allow Snapshots as Volume-Chain"
Coming up with a good and self-explanatory terminology for this is
rather hard, but the previous one was definitively wrong.

So, name it with the following in mind:
1. avoid using "qcow2", as
  - that might confuse users in thinking the feature uses qcow2's
    built-in snapshot support, which it does NOT, it rather uses just
    qcow2's backing chain (layering) capability–simplified–for
    providing a unified view for the different volumes a snapshot
    consists of.
  - this is not strictly bound to qcow2, any format that supports
    layering would be possible to use in theory, e.g. vmdk, it just
    has no upside for us doing so, and qcow2 is one of the best
    supported formats in QEMU, that's .
2. Use somewhat unique terms, if we can stick to them everybody can
   easily know what one is talking about if they are used somewhere,
   or if one encounters a users or potential customer that wants
   basically this feature one can provide them just these terms and
   they can find the relevant docs.

"Volume-Chain Snapshots" or "Snapshots as Volume-Chain" fulfil those
points and are definitively better than the status quo.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-17 18:29:19 +02:00
Thomas Lamprecht
a5ac867ced ui: storage edit: only LVM supports changing ext. snapshots for existing storages
Only allow changing external-snapshots for existing storages when type
is LVM, as for the directory based ones the option is marked as
`fixed` in the schema, which means it cannot be changed for existing
configuration entries.

While at it replace the defaultValue with checked, as the former is
not really used any way when using deleteEmpty.

Reported-by: Lukas Wagner <l.wagner@proxmox.com>
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-17 15:29:28 +02:00
Christian Ebner
bf6d0a5555 api: apt: drop glusterfs-client from package list
Glusterfs has been deprecated with PVE9, so is no longer supposed to
be installed. The output of `pveversion -v` however still lists it.

Therefore, drop it from the list of packages to avoid friction for
users.

Signed-off-by: Christian Ebner <c.ebner@proxmox.com>
Link: https://lore.proxmox.com/20250717072834.119580-1-c.ebner@proxmox.com
2025-07-17 10:15:59 +02:00
Thomas Lamprecht
4840a31941 bump version to 9.0.0~4
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-17 02:33:58 +02:00
Thomas Lamprecht
25efd67c0b ui: storage: reformat code base
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-17 02:15:47 +02:00
Maximiliano Sandoval
6fa317a2f8 ui: login: display error messages when logging
This allows to distinguish, for example, the following three cases:

 - The pvedaemon service is not responding (595)
 - The pveproxy service is not responding (no error status code)
 - The authentication credentials are not correct (401)

Since different combinations of wrong password and/or wrong user all
report the same error message: "authentication failure (401)" this does
not leak login information.

Another consideration is that the code `resp.status` does not match the
HTTP code seen in the API (a failed authentication has a return code 200
from the point of view of the browser) and its information is lost
without this change.

Signed-off-by: Maximiliano Sandoval <m.sandoval@proxmox.com>
Link: https://lore.proxmox.com/20250424134423.364697-1-m.sandoval@proxmox.com
 [TL: resolve merge conflict due to code base reformatting]
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-17 02:15:47 +02:00
Dominik Csapak
5a3c292365 api/ui: show/return alternative interface names
in api listing for all interfaces, and in the GET call for an individual
interface.

For intefaces that are already using an 'altname' in the iface stanza,
we look up the 'legacy' interface name and the remaining altnames and
show those.

If we don't show them, the user might be confused if the bridge ports
and interface names don't correlate.

enables the additional alternative names column in the network view on
the gui.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
Link: https://lore.proxmox.com/20250715090749.1608768-3-d.csapak@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-17 02:15:47 +02:00
Thomas Lamprecht
9e6f672395 d/control: update dependencies to ensure current feature set can work
Not verified and cross-checked in depth, it's rather to much for that,
but rather best-effort.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-17 02:15:47 +02:00
Stefan Hanreich
ee5e3c5ca5 ui: sdn: vxlan: add fabric property
VXLAN zones can now use fabrics instead of having to specify peers
manually. Since the network selector doesn't implement deleteEmpty,
we have to manually handle deleted properties in the VXLAN input
panel.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250716130837.585796-75-g.goller@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-17 02:15:47 +02:00
Stefan Hanreich
2c1a20998d ui: sdn: add evpn controller fabric integration
Expose the new fabric field added to the EVPN controller in the UI.
Users can now select any fabric in the EVPN controller, instead of
having to specify peers manually. This simplifies setting up an EVPN
zone via SDN fabrics considerably.

Since the peers field can now be empty, we have to adapt the existing
field to allow empty values and properly send the delete property when
updating a controller.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250716130837.585796-74-g.goller@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-17 02:15:47 +02:00
Stefan Hanreich
1c1dfb3b73 ui: add sdn networks to ceph / migration
Pass the 'include_sdn' type to the network selectors used in the
datacenter migration settings panel, as well as the ceph wizard, to
enable users to select SDN Vnets, as well as fabrics in the UI.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250716130837.585796-73-g.goller@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-17 02:15:47 +02:00
Stefan Hanreich
174e266eea api: network: add include_sdn / fabric type
In order to be able to show SDN networks in the network selector
dropdowns, we introduce a new type ('include_sdn') to the API endpoint
that lists network interfaces of a node. The return value for existing
parameters stays unchanged to preserve backwards-compatibility.
Callers have to explicitly pass the new type if they want SDN networks
included in the response as well. Only fabrics for which the current
user has any SDN permission (Audit/Use/Modify) are listed.

There is also a new type that only lists fabrics ('fabric'), which
works analogous to the current type filters.

There was a separate type for vnets as well, that is not used anywhere
but was defunct due to a missing check in the endpoint. This has now
been fixed and supplying vnet as the type should now only return
vnets.

This commit is preparation for integrating the fabrics with several
parts in the UI, such as the Ceph installation wizard and the
migration settings, which use the pveNetworkSelector component that
uses this endpoint to query available network interfaces.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250716130837.585796-72-g.goller@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-17 02:15:47 +02:00
Stefan Hanreich
6ffcba6bc9 ui: permissions: add ACL path for fabrics
Expose the newly created ACL path for fabrics in the UI, so users can
configure them.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250716130837.585796-71-g.goller@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-17 02:15:47 +02:00
Gabriel Goller
d30efee621 utils: avoid line-break in pending changes message
Remove line-break when showing the current status of SDN configuration
objects. Otherwise the column would contain an additional newline,
making the row too large.

Co-authored-by: Gabriel Goller <g.goller@proxmox.com>
Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250716130837.585796-70-g.goller@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-17 02:15:47 +02:00
Gabriel Goller
38547fc2cc fabrics: Add main FabricView
TreeView that shows all the fabrics and nodes in a hierarchical
structure. It also shows all the pending changes from the
running-config. From here all entities in the fabrics can be added /
edited and deleted, utilizing the previously created EditWindow
components for Fabrics / Nodes.

We decided against including all the interfaces (as children of nodes
in the tree view) because otherwise the indentation would be too much
and detailed information on the interfaces is rarely needed, so we
only show the names of the configured interfaces instead.

Co-authored-by: Stefan Hanreich <s.hanreich@proxmox.com>
Signed-off-by: Gabriel Goller <g.goller@proxmox.com>
Link: https://lore.proxmox.com/20250716130837.585796-69-g.goller@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-17 02:15:47 +02:00
Stefan Hanreich
e3e3ae51af fabric: add OSPF fabric edit panel
Extends the common FabricEdit component and adds the OSPF-specific
items to it.

Co-authored-by: Stefan Hanreich <s.hanreich@proxmox.com>
Signed-off-by: Gabriel Goller <g.goller@proxmox.com>
Link: https://lore.proxmox.com/20250716130837.585796-68-g.goller@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-17 02:15:47 +02:00
Stefan Hanreich
81bf0378f1 fabric: add OpenFabric fabric edit panel
Add a component that extends the common FabricEdit component and adds
the OpenFabric-specific items to it. Those are currently the Hello
Interval and CSNP interval, which can be configured globally for all
members of the fabric.

Since OSPF currently does not provide IPv6 support (yet), we also move
the IPv6 prefix to the Openfabric edit panel, to avoid showing the
IPv6 prefix input field in the OSPF fabric edit panel.

As we don't enable IPv6 forwarding globally if a IPv6 fabric is created, show
a big warning that a use has to enable it manually.

Co-authored-by: Stefan Hanreich <s.hanreich@proxmox.com>
Signed-off-by: Gabriel Goller <g.goller@proxmox.com>
Link: https://lore.proxmox.com/20250716130837.585796-67-g.goller@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-17 02:15:47 +02:00
Stefan Hanreich
adc9097177 fabric: add generic fabric edit panel
Add generic base component to add and edit Fabrics, which contains the
fields required for every protocol. The properties for every protocol
are stored in different components and each extend this one.

Co-authored-by: Stefan Hanreich <s.hanreich@proxmox.com>
Signed-off-by: Gabriel Goller <g.goller@proxmox.com>
Link: https://lore.proxmox.com/20250716130837.585796-66-g.goller@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-17 02:15:47 +02:00
Stefan Hanreich
95426cd6e7 fabric: add OSPF node edit
Extend the generic NodeEdit panel for OSPF. Currently there are no
node-specific properties for OSPF, so leave the additionalItems empty.

Co-authored-by: Gabriel Goller <g.goller@proxmox.com>
Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250716130837.585796-65-g.goller@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-17 02:15:47 +02:00
Stefan Hanreich
73d66ff8eb fabric: add OpenFabric node edit
Extend the common NodeEdit panel with the Openfabric specific
properties. While IPv6 is a property that can be configured on all
nodes in the config, it is currently not supported for OSPF so we only
show it for Openfabric nodes.

Co-authored-by: Gabriel Goller <g.goller@proxmox.com>
Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250716130837.585796-64-g.goller@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-17 02:15:47 +02:00
Stefan Hanreich
eafa2776ce fabric: add generic node edit panel
This component is the base EditWindow for Nodes of all protocols.
It utilizes the existing network endpoint for getting information on
the interfaces of the nodes, as well as the existing pveNodeSelector
component for displaying a node dropdown. In the future we could
provide a single endpoint that accumulates that information
cluster-wide and returns it, eliminating the need for multiple API
calls.

If the node is configured but currently not in the quorate partition,
we show a read-only panel with the current configuration and a warning.

Co-authored-by: Stefan Hanreich <s.hanreich@proxmox.com>
Signed-off-by: Gabriel Goller <g.goller@proxmox.com>
Link: https://lore.proxmox.com/20250716130837.585796-63-g.goller@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-17 02:15:47 +02:00
Stefan Hanreich
af3e6b400d fabric: add OSPF interface properties
Define an OSPF-specific InterfacePanel for future use (currently there
are no protocol-specific properties for OSPF interfaces).

Co-authored-by: Stefan Hanreich <s.hanreich@proxmox.com>
Signed-off-by: Gabriel Goller <g.goller@proxmox.com>
Link: https://lore.proxmox.com/20250716130837.585796-62-g.goller@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-17 02:15:47 +02:00
Stefan Hanreich
32f74c9371 fabric: add OpenFabric interface properties
This component extends the InterfacePanel and adds Openfabric specific
form fields. Hello Multiplier is hidden by default, but can be
activated in the column settings of the DataGrid.

Co-authored-by: Stefan Hanreich <s.hanreich@proxmox.com>
Signed-off-by: Gabriel Goller <g.goller@proxmox.com>
Link: https://lore.proxmox.com/20250716130837.585796-61-g.goller@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-17 02:15:47 +02:00
Stefan Hanreich
dcf55c8bbf fabric: add common interface panel
Implements a shared interface selector panel for openfabric and ospf
fabrics. This GridPanel combines data from two sources: the node
network interfaces (/nodes/<node>/network) and the fabrics section
configuration, displaying a merged view of both sources.

It implements the following warning states:
- When an interface has an IP address configured in
  /etc/network/interfaces, we display a warning and disable the input
  field, prompting users to configure addresses only via the fabrics
  interface
- When addresses exist in both /etc/network/interfaces and
  /etc/network/interfaces.d/sdn, we show a warning without disabling
  the field, allowing users to remove the SDN interface configuration
  while preserving the underlying one

Co-authored-by: Gabriel Goller <g.goller@proxmox.com>
Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250716130837.585796-60-g.goller@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-17 02:15:47 +02:00
Stefan Hanreich
29ebe4e8d4 ui: fabrics: add model definitions for fabrics
Add the three model definitions for SDN fabrics in a shared Common
module, so they can be accessed by all UI components for the SDN
fabrics.

Co-authored-by: Gabriel Goller <g.goller@proxmox.com>
Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250716130837.585796-59-g.goller@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-17 02:15:47 +02:00
Gabriel Goller
387cc48ac6 api: use new sdn config generation functions
With the introduction of fabrics, frr configuration generation and
etc/network/interfaces generation has been reworked and renamed for
better clarity, since now not only zones / controllers are responsible
for generating the ifupdown / FRR configuration. Switch this endpoint
over to use the new functions.

We also add a new skip_frr parameter that skips FRR config generation
if set. With the old FRR config generation logic, we never wrote an
empty FRR configuration if all controllers got deleted. This meant
that deleting all controllers still left the previous FRR
configuration on the nodes, never disabling BGP / IS-IS. The new logic
now writes an empty configuration if there is no controller / fabric
configured, fixing this behavior. This has a side effect for users
with an existing FRR configuration not managed by SDN, but utilizing
other SDN features (zones, vnets, ...). Their manual FRR configuration
would get overwritten when applying an SDN configuration. This is
particularly an issue with full-mesh Ceph setups, that were set up
according to our Wiki guide [1]. User with such a full-mesh setup
could get their FRR configuration overwritten when using unrelated SDN
features. Since this endpoint is called *after* committing the new SDN
configuration, but handles writing the FRR configuration, we need a
way to signal this endpoint to skip writing the FRR configuration from
the `PUT /cluster/sdn` endpoint, where we can check for this case.

[1] https://pve.proxmox.com/mediawiki/index.php?title=Full_Mesh_Network_for_Ceph_Server&oldid=12146

Co-authored-by: Stefan Hanreich <s.hanreich@proxmox.com>
Signed-off-by: Gabriel Goller <g.goller@proxmox.com>
Link: https://lore.proxmox.com/20250716130837.585796-58-g.goller@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-17 02:15:47 +02:00
Thomas Lamprecht
3b8a56a7ae ui: base storage: add tech-preview hint for storage-managed snapshots
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-16 23:02:18 +02:00
Thomas Lamprecht
13751850ff ui: base storage: refactor out closure to add advanced widgets
To avoid code duplication.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-16 22:44:27 +02:00
Thomas Lamprecht
ec094a8284 ui: base storage: add checkbox for storage-managed snapshots for supported types
This exposes the new feature that allows VMs to create snapshots
without LVM interfering, but rather let the storage handle it
directly, like QCOW2 on LVM.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-16 22:42:51 +02:00
Thomas Lamprecht
2aa148a9bf ui: buildsys: add make tidy target
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-16 22:35:46 +02:00
Thomas Lamprecht
112bd23e1c ui: drop support for adding native GlusterFS storage
As it's unmaintained upstream and will be dropped from QEMU soon.
See commit 7669a99 ("drop support for using GlusterFS directly") in
the pve-storage git repository for more details.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-16 22:13:00 +02:00
Thomas Lamprecht
507eb2821e nic pinning: improve some informational and error output wording/formatting
Mainly add a trailing \n to die invocations to avoid getting a ugly
"at line XY" in the output.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-16 19:39:33 +02:00
Thomas Lamprecht
f3fbf72761 nic pinning: rename 'nic' parameter to 'interface'
Note that we do greedy matching for CLI parameters names and allow
using just a single minus too, so as of now one can stills use shorter
variants like `-i IFACE`.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-16 19:36:27 +02:00
Thomas Lamprecht
5fc92c05e2 nic pinning: update description for generate command
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-16 19:29:24 +02:00
Thomas Lamprecht
cbae8dd073 nic pinning: prompt before continuing if connected to TTY
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-16 19:27:51 +02:00
Thomas Lamprecht
b1f9f28037 firewall on-boot commit: report errors if rename fails
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-16 18:57:33 +02:00
Thomas Lamprecht
a361449763 use kebab-case spelling for new SDN and firewall config-commit services
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-16 18:41:25 +02:00
Stefan Hanreich
7b1ff8e76c services: add pvesdncommit and pvefirewallcommit
Changes to /etc/network/interfaces already get automatically applied
by pvenetcommit. In order to support automatically applying all
configuration files generated by proxmox-network-interface-pinning,
add two additional service that apply the SDN and the firewall
configuration respectively.

If the network configuration gets automatically applied, it makes
sense that the SDN configuration should also get re-applied, since it
relies on the current network configuration for some features (e.g.
SNAT ouput interface, IS-IS interface, ..).

For the firewall, the configuration file that gets automatically
applied is currently only generated by
proxmox-network-interface-pinning, so anyone not using that tool
should see no effect at all.

They are split into their own one-shot services, since pvenetcommit
needs to run before the network configuration gets loaded and applied
by ifupdown2, but pvesdncommit requires the new network configuration
to be already applied in order to work properly. pvefirewallcommit
requires at least pmxcfs to be up and running, since it reads / writes
configuration files there.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250716151815.348161-9-s.hanreich@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-16 18:31:23 +02:00
Stefan Hanreich
7e4efda2fa cli: add proxmox-network-interface-pinning tool
proxmox-network-interface-pinning is a tool for pinning network
interface names. It works by generating a link file in
/usr/local/lib/systemd/network and then updating the following files
by replacing the current name with the pinned name:

* /etc/network/interfaces
* /etc/pve/nodes/nodename/host.fw
* /etc/pve/sdn/controllers.cfg (IS-IS controllers)

In each case the tool creates a pending configuration file, that gets
applied on reboot (via pvenetcommit, pvesdncommit and
pvefirewallcommit respectively).

SDN and /e/n/i already have pending configuration files built in, so
the tool writes to them. For the host firewall we introduce a
host.fw.new file, that is currently only used by the
proxmox-network-interface-pinning tool, but could be used in the
future for creating pending configurations for the firewall stack.

There are still some places where interface names occur, where we do
not update the configuration:

* /etc/pve/firewall/cluster.fw - This is because we cannot update a
cluster-wide file with the locally-generated mappings. In this case a
warning is printed.

* In the node configuration there is a parameter for wakeonlan that
takes an interface as argument.

Otherwise all occurrences of interfaces or interface lists should be
included.

Example invocations of pveeth:

$ proxmox-network-interface-pinning generate --nic enp1s0

Generates a pinning for enp1s0 (if it doesn't exist already) and
updates the configuration file.

$ proxmox-network-interface-pinning generate

Generates a pinning for all physical interfaces, that do not yet have
one.

After rebooting, all pending changes made by the tool should get
automatically applied via the respective systemd one-shot services
(see the following commit).

Currently there is only support for a fixed prefix: 'nic'. This is
because we rely on PHYISCAL_NIC_RE for detecting physical network
interfaces across several places in our codebase. For now, nic has
been added as a valid prefix for NICs in pve-common, so that prefix is
used here.

In order to support custom prefixes, every place in the code relying
on PHYISCAL_NIC_RE (at least) would have to be reworked.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
Link: https://lore.proxmox.com/20250716151815.348161-8-s.hanreich@proxmox.com
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-16 18:31:23 +02:00
Fiona Ebner
a3dd669c4c pve8to9: add check for to-be-dropped QEMU machine versions
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
Link: https://lore.proxmox.com/20250716100320.50736-1-f.ebner@proxmox.com
2025-07-16 18:20:58 +02:00
Thomas Lamprecht
b66857763c pvescheduler: move PID file from aliased /var/run legacy path into the underlying /run
Reported-by: Alexander Zeidler <a.zeidler@proxmox.com>
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-16 16:45:39 +02:00
Lukas Wagner
9011464b78 d/postinst: remove old pvemailforward migration logic
Before the separate proxmox-mail-forward helper was split out into its
own package, pve-manager shipped its own pvemailforward script. Arguably
this is the reason why the code for migrating the path to the helper in
/root/.forward is part of pve-manager's d/postinst script, not
proxmox-mail-forward's.

The pvemailforward -> proxmox-mail-forward migration happened in
pve-manager 7.2-12. Since we don't support skipping major versions (e.g.
7 -> 9), we should be able to drop the migration code for PVE 9.

This also means that proxmox-mail-forward is now fully in charge of the
contents of /root/.forward.

Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>
Reviewed-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
Link: https://lore.proxmox.com/20250716073759.40752-2-l.wagner@proxmox.com
2025-07-16 16:25:03 +02:00
Lukas Wagner
7bc3e05914 ui: oneshot backup: stop shifting UI when selecting 'legacy-sendmail'
The 'protected' checkbox in the left column seems to use slightly less
space than the 'mailto' field in the same row in the right column.
The 'mailto' field is only shown when the 'notification-mode' is set to
legacy-sendmail. Due to the differences in size, the UI shifts by a
couple pixels when the additional field is shown.

As a workaround, the checkbox is padded on the bottom by a tiny amount,
stopping the UI from shifting around when the additional field is
shown.

Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>
Link: https://lore.proxmox.com/20250624120032.153539-3-l.wagner@proxmox.com
2025-07-16 16:22:06 +02:00
Lukas Wagner
70471f13f1 ui: one-shot backup: remove 'auto' notification mode for clarity
The 'auto' mode does not really add any functionality but only adds
confusion about what it actually does, so it is completely removed from
the UI. It is still supported by the backend, but in the UI it is mapped
it to a concrete mode (either notification-system or legacy-sendmail,
depending on whether mailto is set).

The term 'Notification System' is completely dropped from the UI,
instead 'Global Notification Settings' is used.

Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>
Tested-by: Michael Köppl <m.koeppl@proxmox.com>
Reviewed-by: Michael Köppl <m.koeppl@proxmox.com>
Link: https://lore.proxmox.com/20250624120032.153539-2-l.wagner@proxmox.com
2025-07-16 16:22:06 +02:00
Lukas Wagner
b4fbca8148 ui: backup job edit: move notification related settings to separate tab
The notification settings in the 'General' tab were unfortunately a
source of regular confusion for many people. This was primarily due to
the behavior of the 'notification mode'. The notification mode can
one of the following:
  - notification-system: Emit a notification event to the global
    notification system, where it can be matched on by notification
    matchers and then sent to one or more targets.
  - legacy-sendmail: Old-style notifications, where one can directly
    enter some email address. The system uses 'sendmail' to
    send the notification to the specified address, circumventing
    the regular notification stack.
  - auto: Use legacy-sendmail if an email is entered and the
    notification system if not

The 'auto' mode was originally intended to ease migration between the
old and the new system. From a user's perspective however, 'auto' is
quite surprising and unintuitive. The UI preselected 'auto' as a
default, which would, as explained above, favor the new notification
stack with the 'mailto' field empty. However, the UI would still invite
the user to enter their email address, which would then entail the
'legacy-sendmail' mode. Some users were led to believe that this email
address would then be used for a configured email target of the new
notification stack. As a consequence, 'auto' is now completely hidden in
the UI.

In the new 'Notifications' tab one can now choose between
  ( ) Use global notification settings
  (x) Use sendmail to send an email
      Recipients: [              ]
      When:       [Always/On Error]

'Recipients' and 'When' are disabled if the first radio box is selected.

The new tab can later also be used to house other controls. For example,
we could display all matchers that could potentially match this backup
job, or maybe even allow to create a new matcher with a pre-populated
match-field rule.

The term 'Notification System' is altogether from the UI. It is not
necessarily clear to a user that this refers to the settings in
Datacenter > Notifications.

Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>
Tested-by: Michael Köppl <m.koeppl@proxmox.com>
Reviewed-by: Michael Köppl <m.koeppl@proxmox.com>
Link: https://lore.proxmox.com/20250624120032.153539-1-l.wagner@proxmox.com
2025-07-16 16:22:06 +02:00
Thomas Lamprecht
f548db7ea1 bump version to 9.0.0~3
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-07-16 02:48:37 +02:00
Lukas Wagner
9d408183b4 www: backup job detail: style fixups using proxmox-biome
Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>
Reviewed-by: Gabriel Goller <g.goller@proxmox.com>
Link: https://lore.proxmox.com/20250714084553.57147-1-l.wagner@proxmox.com
2025-07-15 21:51:15 +02:00
Aaron Lauterer
85d237042b fix #5894: pvestatd: improve broadcast of node version-info
Until now, the pvestatd did broadcast the pve-manager version only
once after startup of the service. But there are some situations,
where the local pmxcfs (pve-cluster) restarts and loses that
information.
Basically every time we restarted the pmxcfs without restarting
pvestatd too.

While updates involving the pve-cluster packages normally correlate
with updates of libpve-cluster-api-perl, which cause a restart of all
perl based daemons through the "pve-api-updates" package trigger, it
still could happen in other situations, like for example, on a cluster
join, or if the pmxcfs has been restarted manually.

By additionally checking if the local kv-store of the pmxcfs has any
version info for the node, we can decide if another broadcast is
necessary.

Therefore after the next run of pvestatd, which normally happens every
10s, we should have the full version info available again.

Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
Link: https://lore.proxmox.com/20250714082358.56826-1-a.lauterer@proxmox.com
 [TL: mention packaging triggers]
2025-07-15 21:34:40 +02:00
Dominik Csapak
51a75f07eb ui: import storage content: allow importing of vm disk images
By enabling the import button for qcow2/vmdk/raw files, and showing a
window with a VMID selector and the disk edit panel.

Change the edit panel so that when we give an explicit volume id
directly, we don't let the user select one. Instead it show it in a
displayfield.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
Link: https://lore.proxmox.com/20250714122835.3347682-4-d.csapak@proxmox.com
2025-07-15 20:38:37 +02:00
Dominik Csapak
77d70937a7 ui: vm create wizard: allow importing disks
by adding a new 'import' button in the disk tab, which adds the same
input panel as the one we have when doing an 'Import Hard Disk' for an
existing VM.

partially fixes #2424

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
Link: https://lore.proxmox.com/20250714122835.3347682-3-d.csapak@proxmox.com
2025-07-15 20:38:37 +02:00
Dominik Csapak
e44afffab0 ui: qemu hd edit: allow importing a disk from the import storage
from the hardware view of a virtual machine, by adding a new 'Import
Hard Disk' option in the 'Add' menu.

It replaces the standard storage selector by a import storage selector,
the file selector for the image to be imported, and a target storage
selector.

partially fixes #2424

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
Link: https://lore.proxmox.com/20250714122835.3347682-2-d.csapak@proxmox.com
2025-07-15 20:38:37 +02:00
Dominik Csapak
3397634b59 ui: guest importer: use 4m efitype for imported vms
If we omit the 'efitype' property, the legacy 2m images get used, so
explicitly use the 4m variant.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
Link: https://lore.proxmox.com/20250715120851.2825781-1-d.csapak@proxmox.com
2025-07-15 14:51:07 +02:00
211 changed files with 8087 additions and 6839 deletions

View file

@ -19,6 +19,7 @@ all: $(SUBDIRS)
tidy:
git ls-files ':*.p[ml]'| xargs -n4 -P0 proxmox-perltidy
$(MAKE) -C bin tidy
$(MAKE) -C www tidy
.PHONY: check
check: bin test www
@ -74,7 +75,7 @@ distclean: clean
.PHONY: clean
clean:
set -e && for i in $(SUBDIRS); do $(MAKE) -C $$i $@; done
rm -f $(PACKAGE)*.tar* country.dat *.deb *.dsc *.build *.buildinfo *.changes
rm -f $(PACKAGE)*.tar* *.deb *.dsc *.build *.buildinfo *.changes
rm -rf dest $(PACKAGE)-[0-9]*/
.PHONY: dinstall

View file

@ -50,6 +50,8 @@ my $modify_cfg_for_api = sub {
return $plugin_cfg;
};
my $acme_challenge_api_create_and_return_schema = PVE::ACME::Challenge->createSchema();
__PACKAGE__->register_method({
name => 'index',
path => '',
@ -72,12 +74,7 @@ __PACKAGE__->register_method({
},
returns => {
type => 'array',
items => {
type => "object",
properties => {
plugin => get_standard_option('pve-acme-pluginid'),
},
},
items => $acme_challenge_api_create_and_return_schema,
links => [{ rel => 'child', href => "{plugin}" }],
},
code => sub {
@ -111,9 +108,7 @@ __PACKAGE__->register_method({
id => get_standard_option('pve-acme-pluginid'),
},
},
returns => {
type => 'object',
},
returns => $acme_challenge_api_create_and_return_schema,
code => sub {
my ($param) = @_;
@ -131,7 +126,7 @@ __PACKAGE__->register_method({
check => ['perm', '/', ['Sys.Modify']],
},
protected => 1,
parameters => PVE::ACME::Challenge->createSchema(),
parameters => $acme_challenge_api_create_and_return_schema,
returns => {
type => "null",
},

View file

@ -7,6 +7,7 @@ use POSIX;
use File::stat ();
use IO::File;
use File::Basename;
use Encode qw(decode);
use LWP::UserAgent;
@ -199,6 +200,52 @@ my $update_pve_pkgstatus = sub {
return $pkglist;
};
my $apt_package_return_props = {
Arch => {
type => 'string',
description => 'Package Architecture.',
enum => [qw(armhf arm64 amd64 ppc64el risc64 s390x)],
},
Description => {
type => 'string',
description => 'Package description.',
},
NotifyStatus => {
type => 'string',
description => 'Version for which PVE has already sent an update notification for.',
optional => 1,
},
OldVersion => {
type => 'string',
description => 'Old version currently installed.',
optional => 1,
},
Origin => {
type => 'string',
description => "Package origin, e.g., 'Proxmox' or 'Debian'.",
},
Package => {
type => 'string',
description => 'Package name.',
},
Priority => {
type => 'string',
description => 'Package priority.',
},
Section => {
type => 'string',
description => 'Package section.',
},
Title => {
type => 'string',
description => 'Package title.',
},
Version => {
type => 'string',
description => 'New version to be updated to.',
},
};
__PACKAGE__->register_method({
name => 'list_updates',
path => 'update',
@ -219,7 +266,7 @@ __PACKAGE__->register_method({
type => "array",
items => {
type => "object",
properties => {},
properties => $apt_package_return_props,
},
},
code => sub {
@ -418,7 +465,7 @@ __PACKAGE__->register_method({
timeout => 10,
logfunc => sub {
my $line = shift;
$output .= "$line\n";
$output .= decode('UTF-8', $line) . "\n";
},
noerr => 1,
);
@ -743,7 +790,27 @@ __PACKAGE__->register_method({
type => "array",
items => {
type => "object",
properties => {},
properties => {
$apt_package_return_props->%*,
CurrentState => {
type => 'string',
description => 'Current state of the package installed on the system.',
# Possible CurrentState variants according to AptPkg::Cache
enum => [
qw(Installed NotInstalled UnPacked HalfConfigured HalfInstalled ConfigFiles)
],
},
RunningKernel => {
type => 'string',
description => "Kernel release, only for package 'proxmox-ve'.",
optional => 1,
},
ManagerVersion => {
type => 'string',
description => "Version of the currently running pve-manager API server.",
optional => 1,
},
},
},
},
code => sub {
@ -795,7 +862,6 @@ __PACKAGE__->register_method({
my @pkgs = qw(
ceph-fuse
corosync
glusterfs-client
libjs-extjs
libknet1
libproxmox-acme-perl

View file

@ -667,7 +667,6 @@ __PACKAGE__->register_method({
my $vzconf = cfs_read_file('vzdump.cron');
my $all_jobs = $vzconf->{jobs} || [];
my $job;
my $rrd = PVE::Cluster::rrd_dump();
for my $j (@$all_jobs) {
if ($j->{id} eq $param->{id}) {

View file

@ -6,7 +6,9 @@ use warnings;
use PVE::JSONSchema qw(get_standard_option);
use PVE::RESTHandler;
use PVE::API2::Qemu::CPU;
use PVE::API2::Qemu::Machine;
use PVE::API2::NodeCapabilities::Qemu::Migration;
use base qw(PVE::RESTHandler);
@ -20,11 +22,17 @@ __PACKAGE__->register_method({
path => 'qemu/machines',
});
__PACKAGE__->register_method({
subclass => 'PVE::API2::NodeCapabilities::Qemu::Migration',
path => 'qemu/migration',
});
__PACKAGE__->register_method({
name => 'index',
path => '',
method => 'GET',
permissions => { user => 'all' },
proxyto => 'node',
description => "Node capabilities index.",
parameters => {
additionalProperties => 0,
@ -56,6 +64,7 @@ __PACKAGE__->register_method({
path => 'qemu',
method => 'GET',
permissions => { user => 'all' },
proxyto => 'node',
description => "QEMU capabilities index.",
parameters => {
additionalProperties => 0,
@ -75,7 +84,7 @@ __PACKAGE__->register_method({
my ($param) = @_;
my $result = [
{ name => 'cpu' }, { name => 'machines' },
{ name => 'cpu' }, { name => 'machines' }, { name => 'migration' },
];
return $result;

View file

@ -37,6 +37,7 @@ __PACKAGE__->register_method({
properties => {
name => {
description => "The name (ID) for the MDS",
type => 'string',
},
addr => {
type => 'string',

View file

@ -38,6 +38,7 @@ __PACKAGE__->register_method({
properties => {
name => {
description => "The name (ID) for the MGR",
type => 'string',
},
addr => {
type => 'string',

View file

@ -423,6 +423,29 @@ __PACKAGE__->register_method({
# See FIXME below
my @udev_trigger_devs = ();
# $size is in kibibytes
my $osd_lvcreate = sub {
my ($vg, $lv, $size) = @_;
my $cmd = [
'/sbin/lvcreate',
'-aly',
'-Wy',
'--yes',
'--size',
$size . "k",
'--name',
$lv,
# explicitly enable autoactivation, because Ceph never explicitly
# activates LVs by itself
'--setautoactivation',
'y',
$vg,
];
run_command($cmd, errmsg => "lvcreate '$vg/$lv' error");
};
my $create_part_or_lv = sub {
my ($dev, $size, $type) = @_;
@ -443,7 +466,7 @@ __PACKAGE__->register_method({
my $lv = $type . "-" . UUID::uuid();
PVE::Storage::LVMPlugin::lvm_create_volume_group($dev->{devpath}, $vg);
PVE::Storage::LVMPlugin::lvcreate($vg, $lv, "${size}k");
$osd_lvcreate->($vg, $lv, $size);
if (PVE::Diskmanage::is_partition($dev->{devpath})) {
eval { PVE::Diskmanage::change_parttype($dev->{devpath}, '8E00'); };
@ -475,7 +498,7 @@ __PACKAGE__->register_method({
my $lv = $type . "-" . UUID::uuid();
PVE::Storage::LVMPlugin::lvcreate($vg, $lv, "${size}k");
$osd_lvcreate->($vg, $lv, $size);
return "$vg/$lv";

View file

@ -108,6 +108,7 @@ __PACKAGE__->register_method({
bytes_used => {
type => 'integer',
title => 'Used',
renderer => 'bytes',
},
target_size => {
type => 'integer',

View file

@ -178,7 +178,10 @@ __PACKAGE__->register_method({
path => 'log',
method => 'GET',
description => "Read cluster log",
permissions => { user => 'all' },
permissions => {
description => "The user needs 'Sys.Syslog' on '/' in order to get all logs.",
user => 'all',
},
parameters => {
additionalProperties => 0,
properties => {
@ -301,6 +304,14 @@ __PACKAGE__->register_method({
renderer => 'bytes',
minimum => 0,
},
memhost => {
description =>
"Used memory in bytes from the point of view of the host (for types 'qemu').",
type => 'integer',
optional => 1,
renderer => 'bytes',
minimum => 0,
},
maxmem => {
description => "Number of available memory in bytes"
. " (for types 'node', 'qemu' and 'lxc').",
@ -364,7 +375,7 @@ __PACKAGE__->register_method({
},
diskread => {
description =>
"The amount of bytes the guest read from its block devices since"
"The number of bytes the guest read from its block devices since"
. " the guest was started. This info is not available for all storage types."
. " (for types 'qemu' and 'lxc')",
type => 'integer',
@ -373,7 +384,7 @@ __PACKAGE__->register_method({
},
diskwrite => {
description =>
"The amount of bytes the guest wrote to its block devices since"
"The number of bytes the guest wrote to its block devices since"
. " the guest was started. This info is not available for all storage types."
. " (for types 'qemu' and 'lxc')",
type => 'integer',
@ -403,6 +414,11 @@ __PACKAGE__->register_method({
type => 'integer',
optional => 1,
},
sdn => {
description => "The name of an SDN entity (for type 'sdn')",
type => "string",
optional => 1,
},
tags => {
description => "The guest's tags (for types 'qemu' and 'lxc')",
type => "string",

View file

@ -3,16 +3,16 @@ package PVE::API2::Cluster::MetricServer;
use warnings;
use strict;
use PVE::Tools qw(extract_param extract_sensitive_params);
use PVE::Exception qw(raise_perm_exc raise_param_exc);
use PVE::JSONSchema qw(get_standard_option);
use PVE::APIClient::LWP;
use PVE::AccessControl;
use PVE::Cluster;
use PVE::INotify;
use PVE::RPCEnvironment;
use PVE::SafeSyslog;
use PVE::Tools qw(extract_param extract_sensitive_params);
use PVE::ExtMetric;
use PVE::PullMetric;
use PVE::SafeSyslog;
use PVE::RESTHandler;
use base qw(PVE::RESTHandler);
@ -325,6 +325,11 @@ __PACKAGE__->register_method({
optional => 1,
default => 0,
},
'node-list' => {
type => 'string',
description => 'Only return metrics from nodes passed as comma-separated list',
optional => 1,
},
'start-time' => {
type => 'integer',
description => 'Only include metrics with a timestamp > start-time.',
@ -404,21 +409,36 @@ __PACKAGE__->register_method({
$generations = 0;
}
my @metrics = @{ PVE::PullMetric::get_local_metrics($generations) };
if (defined($start)) {
@metrics = grep {
$_->{timestamp} > ($start)
} @metrics;
}
my @node_list =
$param->{'node-list'} ? PVE::Tools::split_list($param->{'node-list'}) : ();
my $nodename = PVE::INotify::nodename();
my $include_local_metrics =
!$param->{'node-list'} || grep { $nodename eq $_ } @node_list;
my @metrics;
if ($include_local_metrics) {
@metrics = @{ PVE::PullMetric::get_local_metrics($generations) };
if (defined($start)) {
@metrics = grep {
$_->{timestamp} > ($start)
} @metrics;
}
}
# Fan out to cluster members
# Do NOT remove this check
if (!$local_only) {
if (!$local_only || @node_list) {
my $members = PVE::Cluster::get_members();
@node_list = keys $members->%* if !@node_list;
if (my @unknown_nodes = grep { !exists($members->{$_}) } @node_list) {
die "Requested node-list contains unknown nodes - "
. join(', ', @unknown_nodes) . "\n";
}
my $rpcenv = PVE::RPCEnvironment::get();
my $authuser = $rpcenv->get_user();
@ -435,7 +455,7 @@ __PACKAGE__->register_method({
$ticket = PVE::AccessControl::assemble_ticket($authuser);
}
for my $name (keys %$members) {
for my $name (@node_list) {
if ($name eq $nodename) {
# Skip own node, for that one we already have the metrics
next;
@ -454,7 +474,7 @@ __PACKAGE__->register_method({
host => $ip,
port => 8006,
ticket => $ticket,
timeout => 5,
timeout => 20,
};
$conn_args->{cached_fingerprints} = { $fingerprint => 1 };

View file

@ -12,6 +12,7 @@ use PVE::JSONSchema qw(get_standard_option);
use PVE::Exception qw(raise_param_exc);
use PVE::API2::HA::Resources;
use PVE::API2::HA::Groups;
use PVE::API2::HA::Rules;
use PVE::API2::HA::Status;
use base qw(PVE::RESTHandler);
@ -26,6 +27,11 @@ __PACKAGE__->register_method({
path => 'groups',
});
__PACKAGE__->register_method({
subclass => "PVE::API2::HA::Rules",
path => 'rules',
});
__PACKAGE__->register_method({
subclass => "PVE::API2::HA::Status",
path => 'status',
@ -57,7 +63,7 @@ __PACKAGE__->register_method({
my ($param) = @_;
my $res = [
{ id => 'status' }, { id => 'resources' }, { id => 'groups' },
{ id => 'status' }, { id => 'resources' }, { id => 'groups' }, { id => 'rules' },
];
return $res;

View file

@ -12,6 +12,7 @@ use PVE::RESTHandler;
use PVE::RPCEnvironment;
use PVE::JSONSchema qw(get_standard_option);
use PVE::AccessControl;
use PVE::Network;
use IO::File;
use base qw(PVE::RESTHandler);
@ -43,6 +44,7 @@ my $network_type_enum = [
'eth',
'alias',
'vlan',
'fabric',
'OVSBridge',
'OVSBond',
'OVSPort',
@ -231,6 +233,32 @@ sub json_config_properties {
return $prop;
}
sub extract_altnames {
my ($iface, $altnames) = @_;
$altnames = PVE::Network::altname_mapping() if !defined($altnames);
my $iface_altnames = [];
my $original_iface;
# when we get an altname, first extract the legacy iface name
if (my $legacy_iface = $altnames->{$iface}) {
push $iface_altnames->@*, $legacy_iface;
$original_iface = $iface;
$iface = $legacy_iface;
}
for my $altname (keys $altnames->%*) {
next if defined($original_iface) && $original_iface eq $altname;
if ($altnames->{$altname} eq $iface) {
push $iface_altnames->@*, $altname;
}
}
return [sort $iface_altnames->@*] if scalar($iface_altnames->@*) > 0;
return undef;
}
__PACKAGE__->register_method({
name => 'index',
path => '',
@ -245,7 +273,7 @@ __PACKAGE__->register_method({
type => {
description => "Only list specific interface types.",
type => 'string',
enum => [@$network_type_enum, 'any_bridge', 'any_local_bridge'],
enum => [@$network_type_enum, 'any_bridge', 'any_local_bridge', 'include_sdn'],
optional => 1,
},
},
@ -390,26 +418,52 @@ __PACKAGE__->register_method({
my $ifaces = $config->{ifaces};
my $altnames = PVE::Network::altname_mapping();
delete $ifaces->{lo}; # do not list the loopback device
if (my $tfilter = $param->{type}) {
my $vnets;
my $fabrics;
if ($have_sdn && $tfilter eq 'any_bridge') {
if ($have_sdn && $tfilter =~ /^(any_bridge|include_sdn|vnet)$/) {
$vnets = PVE::Network::SDN::get_local_vnets(); # returns already access-filtered
}
for my $k (sort keys $ifaces->%*) {
my $type = $ifaces->{$k}->{type};
my $is_bridge = $type eq 'bridge' || $type eq 'OVSBridge';
my $bridge_match = $is_bridge && $tfilter =~ /^any(_local)?_bridge$/;
my $match = $tfilter eq $type || $bridge_match;
delete $ifaces->{$k} if !$match;
if ($have_sdn && $tfilter =~ /^(include_sdn|fabric)$/) {
my $local_node = PVE::INotify::nodename();
$fabrics =
PVE::Network::SDN::Fabrics::config(1)->get_interfaces_for_node($local_node);
}
if ($tfilter ne 'include_sdn') {
for my $k (sort keys $ifaces->%*) {
my $type = $ifaces->{$k}->{type};
my $is_bridge = $type eq 'bridge' || $type eq 'OVSBridge';
my $bridge_match = $is_bridge && $tfilter =~ /^any(_local)?_bridge$/;
my $match = $tfilter eq $type || $bridge_match;
delete $ifaces->{$k} if !$match;
}
}
if (defined($vnets)) {
$ifaces->{$_} = $vnets->{$_} for keys $vnets->%*;
}
if (defined($fabrics)) {
for my $fabric_id (keys %$fabrics) {
next
if !$rpcenv->check_any(
$authuser,
"/sdn/fabrics/$fabric_id",
['SDN.Audit', 'SDN.Use', 'SDN.Allocate'],
1,
);
$ifaces->{$fabric_id} = $fabrics->{$fabric_id};
}
}
}
#always check bridge access
@ -424,6 +478,9 @@ __PACKAGE__->register_method({
my $type = $ifaces->{$k}->{type};
delete $ifaces->{$k}
if ($type eq 'bridge' || $type eq 'OVSBridge') && !$can_access_vnet->($k);
my $iface_altnames = extract_altnames($k, $altnames);
$ifaces->{$k}->{altnames} = $iface_altnames if defined($iface_altnames);
}
return PVE::RESTHandler::hash_to_array($ifaces, 'iface');
@ -789,10 +846,15 @@ __PACKAGE__->register_method({
my $config = PVE::INotify::read_file('interfaces');
my $ifaces = $config->{ifaces};
raise_param_exc({ iface => "interface does not exist" })
if !$ifaces->{ $param->{iface} };
my $iface = $param->{iface};
return $ifaces->{ $param->{iface} };
raise_param_exc({ iface => "interface does not exist" })
if !$ifaces->{$iface};
my $altnames = extract_altnames($iface);
$ifaces->{$iface}->{altnames} = $altnames if defined($altnames);
return $ifaces->{$iface};
},
});
@ -811,7 +873,7 @@ sub assert_ifupdown2_installed {
die "you need ifupdown2 to reload network configuration\n" if !-e '/usr/share/ifupdown2';
my ($v, $pve, $v_str) = ifupdown2_version();
die
"incompatible 'ifupdown2' package version '$v_str'! Did you installed from Proxmox repositories?\n"
"incompatible 'ifupdown2' package version '$v_str'! Did you install from Proxmox repositories?\n"
if $v < (1 * 100000 + 2 * 1000 + 8 * 10) || !$pve;
}
@ -829,6 +891,12 @@ __PACKAGE__->register_method({
additionalProperties => 0,
properties => {
node => get_standard_option('pve-node'),
'regenerate-frr' => {
type => 'boolean',
description => 'Whether FRR config generation should get skipped or not.',
optional => 1,
default => 0,
},
},
},
returns => { type => 'string' },
@ -843,6 +911,8 @@ __PACKAGE__->register_method({
my $current_config_file = "/etc/network/interfaces";
my $new_config_file = "/etc/network/interfaces.new";
my $regenerate_frr = extract_param($param, 'regenerate-frr');
assert_ifupdown2_installed();
my $worker = sub {
@ -850,7 +920,7 @@ __PACKAGE__->register_method({
rename($new_config_file, $current_config_file) if -e $new_config_file;
if ($have_sdn) {
PVE::Network::SDN::generate_zone_config();
PVE::Network::SDN::generate_etc_network_config();
PVE::Network::SDN::generate_dhcp_config();
}
@ -862,8 +932,15 @@ __PACKAGE__->register_method({
};
PVE::Tools::run_command(['ifreload', '-a'], errfunc => $err);
if ($have_sdn) {
PVE::Network::SDN::generate_controller_config(1);
if (defined($regenerate_frr)) {
# SDN (or a manual invocation) is requesting a
# specific behavior, so we abide by the parameter set.
PVE::Network::SDN::generate_frr_config(1) if $regenerate_frr;
} elsif (PVE::Network::SDN::running_config_has_frr()) {
# Reload is coming from the Web UI (or a manual
# invocation requesting no specific behavior), so we
# reload if there are FRR entities in the SDN config.
PVE::Network::SDN::generate_frr_config(1);
}
};
return $rpcenv->fork_worker('srvreload', 'networking', $authuser, $worker);
@ -922,3 +999,5 @@ __PACKAGE__->register_method({
return undef;
},
});
1;

View file

@ -283,7 +283,7 @@ __PACKAGE__->register_method({
{ name => 'replication' },
{ name => 'report' },
{ name => 'rrd' }, # fixme: remove?
{ name => 'rrddata' }, # fixme: remove?
{ name => 'rrddata' },
{ name => 'scan' },
{ name => 'services' },
{ name => 'spiceshell' },
@ -483,6 +483,10 @@ __PACKAGE__->register_method({
type => "integer",
description => "The free memory in bytes.",
},
available => {
type => "integer",
description => "The available memory in bytes.",
},
total => {
type => "integer",
description => "The total memory in bytes.",
@ -550,6 +554,7 @@ __PACKAGE__->register_method({
$res->{memory} = {
free => $meminfo->{memfree},
total => $meminfo->{memtotal},
available => $meminfo->{memavailable},
used => $meminfo->{memused},
};
@ -836,7 +841,7 @@ __PACKAGE__->register_method({
timeframe => {
description => "Specify the time frame you are interested in.",
type => 'string',
enum => ['hour', 'day', 'week', 'month', 'year'],
enum => ['hour', 'day', 'week', 'month', 'year', 'decade'],
},
ds => {
description => "The list of datasources you want to display.",
@ -860,9 +865,10 @@ __PACKAGE__->register_method({
code => sub {
my ($param) = @_;
return PVE::RRD::create_rrd_graph(
"pve2-node/$param->{node}", $param->{timeframe}, $param->{ds}, $param->{cf},
);
my $path = "pve-node-9.0/$param->{node}";
$path = "pve2-node/$param->{node}" if !-e "/var/lib/rrdcached/db/${path}";
return PVE::RRD::create_rrd_graph($path, $param->{timeframe},
$param->{ds}, $param->{cf});
},
});
@ -883,7 +889,7 @@ __PACKAGE__->register_method({
timeframe => {
description => "Specify the time frame you are interested in.",
type => 'string',
enum => ['hour', 'day', 'week', 'month', 'year'],
enum => ['hour', 'day', 'week', 'month', 'year', 'decade'],
},
cf => {
description => "The RRD consolidation function",
@ -903,8 +909,9 @@ __PACKAGE__->register_method({
code => sub {
my ($param) = @_;
return PVE::RRD::create_rrd_data("pve2-node/$param->{node}", $param->{timeframe},
$param->{cf});
my $path = "pve-node-9.0/$param->{node}";
$path = "pve2-node/$param->{node}" if !-e "/var/lib/rrdcached/db/${path}";
return PVE::RRD::create_rrd_data($path, $param->{timeframe}, $param->{cf});
},
});
@ -1096,17 +1103,46 @@ my $shell_cmd_map = {
},
};
my %shell_cmd_params = (
cmd => {
type => 'string',
description => "Run specific command or default to login (requires 'root\@pam')",
enum => [sort keys %$shell_cmd_map],
optional => 1,
default => 'login',
},
'cmd-opts' => {
type => 'string',
description => "Add parameters to a command. Encoded as null terminated strings.",
requires => 'cmd',
optional => 1,
default => '',
},
);
sub get_shell_command {
my ($user, $shellcmd, $args) = @_;
my ($user, $shellcmd, $args, $tunnel_cmd) = @_;
my $is_ssh_tunneling = defined($tunnel_cmd) && scalar(@$tunnel_cmd);
my $cmd;
if ($user eq 'root@pam') {
if (defined($shellcmd) && exists($shell_cmd_map->{$shellcmd})) {
my $def = $shell_cmd_map->{$shellcmd};
$cmd = [@{ $def->{cmd} }]; # clone
if ($is_ssh_tunneling && $cmd eq 'login') {
# stop-gap to avoid running into a racy bug with nested login, i.e. first from SSH
# second would be this command here, likely related to vhangup.
$cmd = [];
} else {
$cmd = [$def->{cmd}->@*]; # clone
}
if (defined($args) && $def->{allow_args}) {
push @$cmd, split("\0", $args);
}
} elsif ($is_ssh_tunneling) {
$cmd = []; # SSH logs us already in as root, and we must not nest login (vhangup).
} else {
$cmd = ['/bin/login', '-f', 'root'];
}
@ -1114,7 +1150,8 @@ sub get_shell_command {
# non-root must always login for now, we do not have a superuser role!
$cmd = ['/bin/login'];
}
return $cmd;
return $is_ssh_tunneling ? [$tunnel_cmd->@*, $cmd->@*] : $cmd;
}
my $get_vnc_connection_info = sub {
@ -1149,22 +1186,7 @@ __PACKAGE__->register_method({
additionalProperties => 0,
properties => {
node => get_standard_option('pve-node'),
cmd => {
type => 'string',
description =>
"Run specific command or default to login (requires 'root\@pam')",
enum => [keys %$shell_cmd_map],
optional => 1,
default => 'login',
},
'cmd-opts' => {
type => 'string',
description =>
"Add parameters to a command. Encoded as null terminated strings.",
requires => 'cmd',
optional => 1,
default => '',
},
%shell_cmd_params,
websocket => {
optional => 1,
type => 'boolean',
@ -1214,9 +1236,9 @@ __PACKAGE__->register_method({
$sslcert = PVE::Tools::file_get_contents("/etc/pve/pve-root-ca.pem", 8192)
if !$sslcert;
my ($port, $remcmd) = $get_vnc_connection_info->($node);
my ($port, $tunnel_cmd) = $get_vnc_connection_info->($node);
my $shcmd = get_shell_command($user, $param->{cmd}, $param->{'cmd-opts'});
my $shcmd = get_shell_command($user, $param->{cmd}, $param->{'cmd-opts'}, $tunnel_cmd);
my $timeout = 10;
@ -1240,7 +1262,7 @@ __PACKAGE__->register_method({
push @$cmd, '-notls', '-listen', 'localhost';
}
push @$cmd, '-c', @$remcmd, @$shcmd;
push @$cmd, '-c', @$shcmd;
my $realcmd = sub {
my $upid = shift;
@ -1300,22 +1322,7 @@ __PACKAGE__->register_method({
additionalProperties => 0,
properties => {
node => get_standard_option('pve-node'),
cmd => {
type => 'string',
description =>
"Run specific command or default to login (requires 'root\@pam')",
enum => [keys %$shell_cmd_map],
optional => 1,
default => 'login',
},
'cmd-opts' => {
type => 'string',
description =>
"Add parameters to a command. Encoded as null terminated strings.",
requires => 'cmd',
optional => 1,
default => '',
},
%shell_cmd_params,
},
},
returns => {
@ -1337,9 +1344,9 @@ __PACKAGE__->register_method({
my $authpath = "/nodes/$node";
my $ticket = PVE::AccessControl::assemble_vnc_ticket($user, $authpath);
my ($port, $remcmd) = $get_vnc_connection_info->($node);
my ($port, $tunnel_cmd) = $get_vnc_connection_info->($node);
my $shcmd = get_shell_command($user, $param->{cmd}, $param->{'cmd-opts'});
my $shcmd = get_shell_command($user, $param->{cmd}, $param->{'cmd-opts'}, $tunnel_cmd);
my $realcmd = sub {
my $upid = shift;
@ -1349,7 +1356,7 @@ __PACKAGE__->register_method({
my $cmd = [
'/usr/bin/termproxy', $port, '--path', $authpath, '--perm', 'Sys.Console', '--',
];
push @$cmd, @$remcmd, @$shcmd;
push @$cmd, @$shcmd;
PVE::Tools::run_command($cmd);
};
@ -1430,22 +1437,7 @@ __PACKAGE__->register_method({
properties => {
node => get_standard_option('pve-node'),
proxy => get_standard_option('spice-proxy', { optional => 1 }),
cmd => {
type => 'string',
description =>
"Run specific command or default to login (requires 'root\@pam')",
enum => [keys %$shell_cmd_map],
optional => 1,
default => 'login',
},
'cmd-opts' => {
type => 'string',
description =>
"Add parameters to a command. Encoded as null terminated strings.",
requires => 'cmd',
optional => 1,
default => '',
},
%shell_cmd_params,
},
},
returns => get_standard_option('remote-viewer-config'),

View file

@ -189,10 +189,13 @@ __PACKAGE__->register_method({
my $pool = $param->{poolid};
die "pool '$pool' already exists\n" if $usercfg->{pools}->{$pool};
if ($pool =~ m!^(.*)/[^/]+$!) {
my $parent = $1;
if ($pool =~ m!^(.*)/([^/]+)$!) {
my ($parent, $leaf) = ($1, $2);
die "parent '$parent' of pool '$pool' does not exist\n"
if !defined($usercfg->{pools}->{$parent});
die "pool name must start with a letter\n" if $leaf !~ m!^[A-Za-z]!;
} else {
die "pool name must start with a letter\n" if $pool !~ m!^[A-Za-z]!;
}
$usercfg->{pools}->{$pool} = {

View file

@ -3,21 +3,23 @@ package PVE::API2::Replication;
use warnings;
use strict;
use PVE::JSONSchema qw(get_standard_option);
use PVE::RPCEnvironment;
use PVE::Cluster;
use PVE::Exception qw(raise_perm_exc);
use PVE::Format qw(render_timestamp);
use PVE::ProcFSTools;
use PVE::ReplicationConfig;
use PVE::ReplicationState;
use PVE::Replication;
use PVE::QemuConfig;
use PVE::QemuServer;
use PVE::INotify;
use PVE::JSONSchema qw(get_standard_option);
use PVE::LXC::Config;
use PVE::LXC;
use PVE::Notify;
use PVE::ProcFSTools;
use PVE::QemuConfig;
use PVE::QemuServer;
use PVE::ReplicationConfig;
use PVE::ReplicationState;
use PVE::Replication;
use PVE::RESTHandler;
use PVE::RPCEnvironment;
use PVE::Tools;
use base qw(PVE::RESTHandler);
@ -234,7 +236,7 @@ __PACKAGE__->register_method({
my $data = $extract_job_status->($jobs->{$id}, $id);
my $guest = $data->{guest};
next if defined($param->{guest}) && $guest != $param->{guest};
next if !$rpcenv->check($authuser, "/vms/$guest", ['VM.Audit']);
next if !$rpcenv->check($authuser, "/vms/$guest", ['VM.Audit'], 1);
push @$res, $data;
}
@ -309,7 +311,7 @@ __PACKAGE__->register_method({
my $data = $extract_job_status->($jobcfg, $jobid);
my $guest = $data->{guest};
raise_perm_exc() if !$rpcenv->check($authuser, "/vms/$guest", ['VM.Audit']);
$rpcenv->check($authuser, "/vms/$guest", ['VM.Audit']);
return $data;
},
@ -379,8 +381,8 @@ __PACKAGE__->register_method({
my $vmid = $data->{guest};
raise_perm_exc()
if (!(
$rpcenv->check($authuser, "/vms/$vmid", ['VM.Audit'])
|| $rpcenv->check($authuser, "/nodes/$node", ['Sys.Audit'])
$rpcenv->check($authuser, "/vms/$vmid", ['VM.Audit'], 1)
|| $rpcenv->check($authuser, "/nodes/$node", ['Sys.Audit'], 1)
));
my ($count, $lines) =
@ -400,7 +402,8 @@ __PACKAGE__->register_method({
proxyto => 'node',
protected => 1,
permissions => {
check => ['perm', '/storage', ['Datastore.Allocate']],
description => "Requires the VM.Replicate permission on /vms/<vmid>.",
user => 'all',
},
parameters => {
additionalProperties => 0,
@ -415,7 +418,12 @@ __PACKAGE__->register_method({
code => sub {
my ($param) = @_;
my $rpcenv = PVE::RPCEnvironment::get();
my $authuser = $rpcenv->get_user();
my $jobid = $param->{id};
my ($vmid) = PVE::ReplicationConfig::parse_replication_job_id($jobid);
$rpcenv->check($authuser, "/vms/$vmid", ['VM.Replicate']);
my $cfg = PVE::ReplicationConfig->new();
my $jobcfg = $cfg->{ids}->{$jobid};

View file

@ -3,17 +3,32 @@ package PVE::API2::ReplicationConfig;
use warnings;
use strict;
use PVE::Tools qw(extract_param);
use PVE::Exception qw(raise_perm_exc raise_param_exc);
use PVE::JSONSchema qw(get_standard_option);
use PVE::RPCEnvironment;
use PVE::ReplicationConfig;
use PVE::Cluster;
use PVE::Exception qw(raise_param_exc);
use PVE::JSONSchema qw(get_standard_option);
use PVE::ReplicationConfig;
use PVE::RESTHandler;
use PVE::RPCEnvironment;
use PVE::SectionConfig;
use PVE::Storage;
use PVE::Tools qw(extract_param);
use PVE::API2::Replication;
use base qw(PVE::RESTHandler);
my $replication_api_return_props = {
PVE::ReplicationConfig->createSchema()->{properties}->%*,
guest => {
type => 'integer',
description => 'Guest ID.',
},
jobnum => {
type => 'integer',
description => 'Unique, sequential ID assigned to each job.',
},
};
__PACKAGE__->register_method({
name => 'index',
path => '',
@ -32,7 +47,7 @@ __PACKAGE__->register_method({
type => 'array',
items => {
type => "object",
properties => {},
properties => $replication_api_return_props,
},
links => [{ rel => 'child', href => "{id}" }],
},
@ -72,7 +87,13 @@ __PACKAGE__->register_method({
id => get_standard_option('pve-replication-id'),
},
},
returns => { type => 'object' },
returns => {
type => 'object',
properties => {
$replication_api_return_props->%*,
digest => get_standard_option('pve-config-digest'),
},
},
code => sub {
my ($param) = @_;
@ -87,7 +108,7 @@ __PACKAGE__->register_method({
my $vmid = $data->{guest};
raise_perm_exc() if !$rpcenv->check($authuser, "/vms/$vmid", ['VM.Audit']);
$rpcenv->check($authuser, "/vms/$vmid", ['VM.Audit']);
$data->{id} = $param->{id};
@ -104,19 +125,24 @@ __PACKAGE__->register_method({
method => 'POST',
description => "Create a new replication job",
permissions => {
check => ['perm', '/storage', ['Datastore.Allocate']],
description => "Requires the VM.Replicate permission on /vms/<vmid>.",
user => 'all',
},
parameters => PVE::ReplicationConfig->createSchema(),
returns => { type => 'null' },
code => sub {
my ($param) = @_;
my $rpcenv = PVE::RPCEnvironment::get();
my $authuser = $rpcenv->get_user();
my $type = extract_param($param, 'type');
my $plugin = PVE::ReplicationConfig->lookup($type);
my $id = extract_param($param, 'id');
# extract guest ID from job ID
my ($guest) = PVE::ReplicationConfig::parse_replication_job_id($id);
$rpcenv->check($authuser, "/vms/$guest", ['VM.Replicate']);
my $nodelist = PVE::Cluster::get_members();
my $vmlist = PVE::Cluster::get_vmlist();
@ -173,17 +199,24 @@ __PACKAGE__->register_method({
method => 'PUT',
description => "Update replication job configuration.",
permissions => {
check => ['perm', '/storage', ['Datastore.Allocate']],
description => "Requires the VM.Replicate permission on /vms/<vmid>.",
user => 'all',
},
parameters => PVE::ReplicationConfig->updateSchema(),
returns => { type => 'null' },
code => sub {
my ($param) = @_;
my $rpcenv = PVE::RPCEnvironment::get();
my $authuser = $rpcenv->get_user();
my $id = extract_param($param, 'id');
my $digest = extract_param($param, 'digest');
my $delete = extract_param($param, 'delete');
my ($vmid) = PVE::ReplicationConfig::parse_replication_job_id($id);
$rpcenv->check($authuser, "/vms/$vmid", ['VM.Replicate']);
my $code = sub {
my $cfg = PVE::ReplicationConfig->new();
@ -228,7 +261,8 @@ __PACKAGE__->register_method({
method => 'DELETE',
description => "Mark replication job for removal.",
permissions => {
check => ['perm', '/storage', ['Datastore.Allocate']],
description => "Requires the VM.Replicate permission on /vms/<vmid>.",
user => 'all',
},
parameters => {
additionalProperties => 0,
@ -253,11 +287,15 @@ __PACKAGE__->register_method({
my ($param) = @_;
my $rpcenv = PVE::RPCEnvironment::get();
my $authuser = $rpcenv->get_user();
my $id = extract_param($param, 'id');
my ($vmid) = PVE::ReplicationConfig::parse_replication_job_id($id);
$rpcenv->check($authuser, "/vms/$vmid", ['VM.Replicate']);
my $code = sub {
my $cfg = PVE::ReplicationConfig->new();
my $id = $param->{id};
if ($param->{force}) {
raise_param_exc({ 'keep' => "conflicts with parameter 'force'" })
if $param->{keep};

View file

@ -50,15 +50,14 @@ my $essential_services = {
# since postfix package 3.1.0-3.1 the postfix unit is only here to
# manage subinstances, of which the default is called "-".
# This is where we look for the daemon status
my $unit_extra_names = {
postfix => 'postfix@-',
};
my $unit_extra_names = {};
my $get_full_service_state = sub {
my ($service) = @_;
$service = $unit_extra_names->{$service} if $unit_extra_names->{$service};
my $res;
$service = $unit_extra_names->{$service} if $unit_extra_names->{$service};
my $res;
my $parser = sub {
my $line = shift;
if ($line =~ m/^([^=\s]+)=(.*)$/) {
@ -138,6 +137,82 @@ my $service_state = sub {
return $res;
};
my $service_state_api_return_schema = {
'active-state' => {
type => 'string',
enum => [
qw(active inactive failed activating deactivating maintenance reloading refreshing unknown)
],
description => 'Current state of the service process (systemd ActiveState).',
},
'desc' => {
type => 'string',
description => 'Description of the service.',
},
'name' => {
type => 'string',
description => 'Short identifier for the service (e.g., "pveproxy").',
},
'service' => {
type => 'string',
description => 'Systemd unit name (e.g., pveproxy).',
},
'state' => {
type => 'string',
# all systemd service unit substates
enum => [qw(
dead
condition
start-pre
start
start-post
running
exited
reload
reload-signal
reload-notify
mounting
stop
stop-watchdog
stop-sigterm
stop-sigkill
stop-post
final-watchdog
final-sigterm
final-sigkill
failed
dead-before-auto-restart
failed-before-auto-restart
dead-resources-pinned
auto-restart
auto-restart-queued
cleaning
unknown
)],
description => 'Execution status of the service (systemd SubState).',
},
'unit-state' => {
type => 'string',
enum => [qw(
enabled
enabled-runtime
linked
linked-runtime
alias
masked
masked-runtime
static
disabled
indirect
generated
transient
bad not-found
unknown
)],
description => 'Whether the service is enabled (systemd UnitFileState).',
},
};
__PACKAGE__->register_method({
name => 'index',
path => '',
@ -158,7 +233,7 @@ __PACKAGE__->register_method({
type => 'array',
items => {
type => "object",
properties => {},
properties => $service_state_api_return_schema,
},
links => [{ rel => 'child', href => "{service}" }],
},
@ -242,7 +317,7 @@ __PACKAGE__->register_method({
},
returns => {
type => "object",
properties => {},
properties => $service_state_api_return_schema,
},
code => sub {
my ($param) = @_;

View file

@ -63,7 +63,7 @@ __PACKAGE__->register_method({
minimum => 0,
default => 50,
optional => 1,
description => "Only list this amount of tasks.",
description => "Only list this number of tasks.",
},
userfilter => {
type => 'string',
@ -358,7 +358,7 @@ __PACKAGE__->register_method({
minimum => 0,
default => 50,
optional => 1,
description => "The amount of lines to read from the tasklog.",
description => "The number of lines to read from the tasklog.",
},
download => {
type => 'boolean',

View file

@ -27,7 +27,7 @@ my sub assert_param_permission_vzdump {
PVE::API2::Backup::assert_param_permission_common($rpcenv, $user, $param);
if (defined($param->{maxfiles}) || defined($param->{'prune-backups'})) {
if (defined($param->{'prune-backups'})) {
if (my $storeid = PVE::VZDump::get_storage_param($param)) {
$rpcenv->check($user, "/storage/$storeid", ['Datastore.Allocate']);
}
@ -40,12 +40,12 @@ __PACKAGE__->register_method({
method => 'POST',
description => "Create backup.",
permissions => {
description => "The user needs 'VM.Backup' permissions on any VM, and "
. "'Datastore.AllocateSpace' on the backup storage (and fleecing storage when fleecing "
. "is used). The 'tmpdir', 'dumpdir', 'script' and 'job-id' parameters are restricted "
. "to the 'root\@pam' user. The 'maxfiles' and 'prune-backups' settings require "
. "'Datastore.Allocate' on the backup storage. The 'bwlimit', 'performance' and "
. "'ionice' parameters require 'Sys.Modify' on '/'.",
description => "The user needs 'VM.Backup' permissions on any VM, and"
. " 'Datastore.AllocateSpace' on the backup storage (and fleecing storage when fleecing"
. " is used). The 'tmpdir', 'dumpdir', 'script' and 'job-id' parameters are restricted"
. " to the 'root\@pam' user. The 'prune-backups' setting requires 'Datastore.Allocate'"
. " on the backup storage. The 'bwlimit', 'performance' and 'ionice' parameters require"
. " 'Sys.Modify' on '/'.",
user => 'all',
},
protected => 1,

View file

@ -41,6 +41,23 @@ sub get_hwaddress {
return $hwaddress;
}
# each rrd key for a resource will only exist once. The key format might be different though. Therefore return on first hit
sub get_rrd_key {
my ($rrd, $type, $id) = @_;
# check for old formats: pve2-{type}/{id}. For VMs and CTs the version number is different than for nodes and storages
if ($type ne "vm" && exists $rrd->{"pve2-${type}/${id}"}) {
return "pve2-${type}/${id}";
} elsif ($type eq "vm" && exists $rrd->{"pve2.3-${type}/${id}"}) {
return "pve2.3-${type}/${id}";
}
my $key = "pve-${type}-9.0/${id}";
if (defined($rrd->{$key})) {
return $key;
}
}
sub extract_node_stats {
my ($node, $members, $rrd, $exclude_stats) = @_;
@ -51,8 +68,8 @@ sub extract_node_stats {
status => 'unknown',
};
if (my $d = $rrd->{"pve2-node/$node"}) {
my $key = get_rrd_key($rrd, "node", $node);
if (my $d = $rrd->{$key}) {
if (
!$members || # no cluster
($members->{$node} && $members->{$node}->{online})
@ -96,24 +113,9 @@ sub extract_vm_stats {
};
my $d;
my $key = get_rrd_key($rrd, "vm", $vmid);
if ($d = $rrd->{"pve2-vm/$vmid"}) {
$entry->{uptime} = ($d->[0] || 0) + 0;
$entry->{name} = $d->[1];
$entry->{status} = $entry->{uptime} ? 'running' : 'stopped';
$entry->{maxcpu} = ($d->[3] || 0) + 0;
$entry->{cpu} = ($d->[4] || 0) + 0;
$entry->{maxmem} = ($d->[5] || 0) + 0;
$entry->{mem} = ($d->[6] || 0) + 0;
$entry->{maxdisk} = ($d->[7] || 0) + 0;
$entry->{disk} = ($d->[8] || 0) + 0;
$entry->{netin} = ($d->[9] || 0) + 0;
$entry->{netout} = ($d->[10] || 0) + 0;
$entry->{diskread} = ($d->[11] || 0) + 0;
$entry->{diskwrite} = ($d->[12] || 0) + 0;
} elsif ($d = $rrd->{"pve2.3-vm/$vmid"}) {
if (my $d = $rrd->{$key}) {
$entry->{uptime} = ($d->[0] || 0) + 0;
$entry->{name} = $d->[1];
@ -130,6 +132,10 @@ sub extract_vm_stats {
$entry->{netout} = ($d->[12] || 0) + 0;
$entry->{diskread} = ($d->[13] || 0) + 0;
$entry->{diskwrite} = ($d->[14] || 0) + 0;
if ($key =~ /^pve-vm-/) {
$entry->{memhost} = ($d->[15] || 0) + 0;
}
}
return $entry;
@ -151,7 +157,8 @@ sub extract_storage_stats {
content => $content,
};
if (my $d = $rrd->{"pve2-storage/$node/$storeid"}) {
my $key = get_rrd_key($rrd, "storage", "${node}/${storeid}");
if (my $d = $rrd->{$key}) {
$entry->{maxdisk} = ($d->[1] || 0) + 0;
$entry->{disk} = ($d->[2] || 0) + 0;
$entry->{status} = 'available';

View file

@ -171,7 +171,7 @@ sub download_aplinfo {
# verify signature
my $trustedkeyring = "/usr/share/doc/pve-manager/trustedkeys.gpg";
my $cmd = "/usr/bin/gpgv -q --keyring $trustedkeyring $sigfn $tmp";
my $cmd = "/usr/bin/sqv --keyring $trustedkeyring $sigfn $tmp";
my $logfunc = sub { logmsg($logfd, "signature verification: $_[0]"); };
eval { run_command($cmd, outfunc => $logfunc, errfunc => $logfunc); };

View file

@ -8,8 +8,8 @@ SOURCES = \
pvesr.pm \
pvenode.pm \
pvesh.pm \
pve7to8.pm \
pve8to9.pm \
pve_network_interface_pinning.pm \
all:

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,494 @@
package PVE::CLI::pve_network_interface_pinning;
use v5.36;
use File::Copy;
use POSIX qw(:errno_h);
use Storable qw(dclone);
use PVE::Firewall;
use PVE::INotify;
use PVE::Network;
use PVE::Network::SDN;
use PVE::Network::SDN::Controllers;
use PVE::Network::SDN::Fabrics;
use PVE::RPCEnvironment;
use PVE::SectionConfig;
use PVE::Tools;
use PVE::CLIHandler;
use base qw(PVE::CLIHandler);
my $PVEETH_LOCK = "/run/lock/proxmox-network-interface-pinning.lck";
sub setup_environment {
PVE::RPCEnvironment->setup_default_cli_env();
}
my sub update_sdn_fabrics {
my ($mapping) = @_;
print "Updating /etc/pve/sdn/fabrics.cfg\n";
my $code = sub {
my $local_node = PVE::INotify::nodename();
my $config = PVE::Network::SDN::Fabrics::config();
$config->map_interfaces($local_node, $mapping);
PVE::Network::SDN::Fabrics::write_config($config);
};
PVE::Network::SDN::lock_sdn_config($code);
}
my sub update_sdn_controllers {
my ($mapping) = @_;
print "Updating /etc/pve/sdn/controllers.cfg\n";
my $code = sub {
my $controllers = PVE::Network::SDN::Controllers::config();
my $local_node = PVE::INotify::nodename();
for my $controller (values $controllers->{ids}->%*) {
next
if ($controller->{node} && $local_node ne $controller->{node})
|| $controller->{type} ne 'isis';
$controller->{'isis-ifaces'} = $mapping->list($controller->{'isis-ifaces'});
}
PVE::Network::SDN::Controllers::write_config($controllers);
};
PVE::Network::SDN::lock_sdn_config($code);
}
my sub update_etc_network_interfaces {
my ($mapping, $existing_pins) = @_;
print "Updating /etc/network/interfaces.new\n";
my $code = sub {
my $config = dclone(PVE::INotify::read_file('interfaces'));
my $old_ifaces = $config->{ifaces};
my $new_ifaces = {};
for my $iface_name (keys $old_ifaces->%*) {
my $iface = $old_ifaces->{$iface_name};
if ($existing_pins->{$iface_name} && $existing_pins->{$iface_name} ne $iface_name) {
# reading the interfaces file adds active interfaces to the
# configuration - we do not want to include already pinned
# interfaces in the new configuration when writing the new
# interface file multiple times, so we skip the interface here
# if there already exists a pin for it.
next;
}
if ($iface->{type} =~ m/^(eth|OVSPort|alias)$/) {
$iface_name = $mapping->name($iface_name);
} elsif ($iface->{type} eq 'vlan') {
$iface_name = $mapping->name($iface_name);
$iface->{'vlan-raw-device'} = $mapping->name($iface->{'vlan-raw-device'});
} elsif ($iface->{type} eq 'bond') {
$iface->{'bond-primary'} = $mapping->name($iface->{'bond-primary'});
$iface->{slaves} = $mapping->list($iface->{slaves});
} elsif ($iface->{type} eq 'bridge') {
$iface->{bridge_ports} = $mapping->list($iface->{bridge_ports});
} elsif ($iface->{type} eq 'OVSBridge') {
$iface->{ovs_ports} = $mapping->list($iface->{ovs_ports});
} elsif ($iface->{type} eq 'OVSBond') {
$iface->{ovs_bonds} = $mapping->list($iface->{ovs_bonds});
}
$new_ifaces->{$iface_name} = $iface;
}
$config->{ifaces} = $new_ifaces;
PVE::INotify::write_file('interfaces', $config, 1);
};
PVE::Tools::lock_file("/etc/network/.pve-interfaces.lock", 10, $code);
die $@ if $@;
}
my sub update_host_fw_config {
my ($mapping) = @_;
my $local_node = PVE::INotify::nodename();
print "Updating /etc/pve/nodes/$local_node/host.fw.new\n";
my $code = sub {
my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
my $temp_fw_file = "/etc/pve/nodes/$local_node/host.fw.new";
my $host_fw_file = (-e $temp_fw_file) ? $temp_fw_file : undef;
my $host_conf = PVE::Firewall::load_hostfw_conf($cluster_conf, $host_fw_file);
for my $rule ($cluster_conf->{rules}->@*) {
next if !$rule->{iface};
warn "found reference to iface $rule->{iface} in cluster config - not updating."
if $mapping->{ $rule->{iface} };
}
for my $rule ($host_conf->{rules}->@*) {
next if !$rule->{iface};
$rule->{iface} = $mapping->name($rule->{iface});
}
PVE::Firewall::save_hostfw_conf($host_conf, "/etc/pve/nodes/$local_node/host.fw.new");
};
PVE::Firewall::run_locked($code);
}
my sub parse_link_file {
my ($file_name) = @_;
my $content = PVE::Tools::file_get_contents($file_name);
my @lines = split(/\n/, $content);
my $section;
my $data = {};
for my $line (@lines) {
next if $line =~ m/^\s*$/;
if ($line =~ m/^\[(Match|Link)\]$/) {
$section = $1;
$data->{$section} = {};
} elsif ($line =~ m/^([a-zA-Z]+)=(.+)$/) {
die "key-value pair before section at line: $line\n" if !$section;
$data->{$section}->{$1} = $2;
} else {
die "unrecognized line: $line\n";
}
}
return $data;
}
my $LINK_DIRECTORY = "/usr/local/lib/systemd/network/";
sub ensure_link_directory_exists {
mkdir '/usr/local/lib/systemd' if !-d '/usr/local/lib/systemd';
mkdir $LINK_DIRECTORY if !-d $LINK_DIRECTORY;
}
my sub get_pinned {
my $link_files = {};
ensure_link_directory_exists();
PVE::Tools::dir_glob_foreach(
$LINK_DIRECTORY,
qr/^50-pve-(.+)\.link$/,
sub {
my $parsed = parse_link_file($LINK_DIRECTORY . $_[0]);
$link_files->{ $parsed->{'Match'}->{'MACAddress'} } = $parsed->{'Link'}->{'Name'};
},
);
return $link_files;
}
my $LINK_FILE_TEMPLATE = <<EOF;
[Match]
MACAddress=%s
Type=ether
[Link]
Name=%s
EOF
my sub link_file_name {
my ($iface_name) = @_;
return "50-pve-$iface_name.link";
}
my sub delete_link_files {
my ($pinned) = @_;
ensure_link_directory_exists();
for my $iface_name (values %$pinned) {
my $link_file = $LINK_DIRECTORY . link_file_name($iface_name);
if (!unlink $link_file) {
return if $! == ENOENT;
warn "failed to delete $link_file";
}
}
}
my sub generate_link_files {
my ($ip_links, $mapping) = @_;
print "Generating link files\n";
ensure_link_directory_exists();
for my $ip_link (values $ip_links->%*) {
my $mapped_name = $mapping->name($ip_link->{ifname});
my $link_file_content =
sprintf($LINK_FILE_TEMPLATE, get_ip_link_mac($ip_link), $mapped_name);
PVE::Tools::file_set_contents(
$LINK_DIRECTORY . link_file_name($mapped_name),
$link_file_content,
);
}
}
package PVE::CLI::pve_network_interface_pinning::InterfaceMapping {
use PVE::CLI::pve_network_interface_pinning;
use PVE::Tools;
sub new {
my ($class, $mapping) = @_;
bless $mapping, $class;
}
sub generate {
my ($class, $ip_links, $pinned, $prefix) = @_;
my $index = 0;
my $mapping = {};
my %existing_names = map { $_ => 1 } values $pinned->%*;
my @sorted_links = sort {
$ip_links->{$a}->{ifindex} <=> $ip_links->{$b}->{ifindex};
} keys $ip_links->%*;
for my $ifname (@sorted_links) {
my $ip_link = $ip_links->{$ifname};
my $generated_name;
do {
$generated_name = $prefix . $index++;
} while ($existing_names{$generated_name});
$mapping->{$ifname} = $generated_name;
for my $altname ($ip_link->{altnames}->@*) {
$mapping->{$altname} = $generated_name;
}
}
bless $mapping, $class;
}
sub name {
my ($self, $iface_name) = @_;
if ($iface_name =~ m/^([a-zA-Z0-9_]+)([:\.]\d+)$/) {
my $mapped_name = $self->{$1} // $1;
my $suffix = $2;
return "$mapped_name$suffix";
}
return $self->{$iface_name} // $iface_name;
}
sub list {
my ($self, $list) = @_;
my @mapped_list = map { $self->name($_) } PVE::Tools::split_list($list);
return join(' ', @mapped_list);
}
}
sub get_ip_link_mac {
my ($ip_link) = @_;
# members of bonds can have a different MAC than the physical interface, so
# we need to check if they're enslaved
return $ip_link->{linkinfo}->{info_slave_data}->{perm_hwaddr} // $ip_link->{address};
}
sub iface_is_vf {
my ($iface_name) = @_;
return -l "/sys/class/net/$iface_name/device/physfn";
}
sub get_ip_links {
my $ip_links = PVE::Network::ip_link_details();
for my $iface_name (keys $ip_links->%*) {
delete $ip_links->{$iface_name}
if !PVE::Network::ip_link_is_physical($ip_links->{$iface_name})
|| iface_is_vf($iface_name);
}
return $ip_links;
}
sub resolve_pinned {
my ($ip_links, $pinned) = @_;
my %mac_lookup = map { get_ip_link_mac($_) => $_->{ifname} } values $ip_links->%*;
my $resolved = {};
for my $mac (keys $pinned->%*) {
if (!$mac_lookup{$mac}) {
warn "could not resolve $mac to an existing interface";
next;
}
$resolved->{ $mac_lookup{$mac} } = $pinned->{$mac};
}
return $resolved;
}
__PACKAGE__->register_method({
name => 'generate',
path => 'generate',
method => 'POST',
description => 'Generate systemd.link files to pin the names of one or more network'
. ' interfaces and update all network-related configuration files.',
parameters => {
additionalProperties => 0,
properties => {
interface => {
description => 'Only pin a specific interface.',
type => 'string',
format => 'pve-iface',
default => '<all>', # just for the docs.
optional => 1,
},
prefix => {
description =>
'Use a specific prefix for automatically choosing the pinned name.',
type => 'string',
pattern => '^[a-zA-Z][a-zA-Z0-9-_]{0,7}$',
default => 'nic', # just for the docs.
optional => 1,
},
'target-name' => {
description => 'Pin the interface to a specific name.',
type => 'string',
format => 'pve-iface',
optional => 1,
requires => 'interface',
},
},
},
returns => {
type => 'null',
},
code => sub {
my ($params) = @_;
my $iface = $params->{interface}; # undef means all.
my $target_name = $params->{'target-name'};
if (-t STDOUT) {
my $target = defined($iface) ? "the interface '$iface'" : 'all interfaces';
say "This will generate name pinning configuration for $target - continue (y/N)? ";
my $answer = <STDIN>;
my $continue = defined($answer) && $answer =~ m/^\s*y(?:es)?\s*$/i;
die "Aborting pinning as requested\n" if !$continue;
}
my $code = sub {
my $prefix = $params->{prefix} // 'nic';
my $ip_links = get_ip_links();
my $pinned = get_pinned();
my $existing_pins = resolve_pinned($ip_links, $pinned);
if ($iface) {
die "Could not find link with name '$iface'\n" if !$ip_links->{$iface};
die "There already exists a pin for NIC '$iface' - aborting.\n"
if $existing_pins->{$iface};
$ip_links = { $iface => $ip_links->{$iface} };
} else {
for my $iface_name (keys $existing_pins->%*) {
delete $ip_links->{$iface_name};
}
}
my $mapping;
if ($target_name) {
die "target-name already exists as link or pin!\n"
if $ip_links->{$target_name} || grep { $target_name eq $_ } values $pinned->%*;
$mapping = PVE::CLI::pve_network_interface_pinning::InterfaceMapping->new({
$iface => $target_name,
});
} else {
$mapping = PVE::CLI::pve_network_interface_pinning::InterfaceMapping->generate(
$ip_links,
$pinned,
$prefix,
);
}
if (!$mapping->%*) {
print "Nothing to do, aborting.\n";
exit 0;
}
my $altnames = PVE::Network::altname_mapping($ip_links);
my @sorted_links = sort {
my $a_name = $altnames->{$a} // $a;
my $b_name = $altnames->{$b} // $b;
$ip_links->{$a_name}->{ifindex} <=> $ip_links->{$b_name}->{ifindex};
} grep {
$ip_links->{$_}
} keys $mapping->%*;
for my $old_name (@sorted_links) {
my $altname_string = '';
if (my $interface_altnames = $ip_links->{$old_name}->{altnames}) {
$altname_string = join(', ', $interface_altnames->@*);
}
print "Name for link '$old_name' ";
print "($altname_string) " if $altname_string;
print "will change to '$mapping->{$old_name}'\n";
}
generate_link_files($ip_links, $mapping);
print "Successfully generated .link files in '/usr/local/lib/systemd/network/'\n";
update_host_fw_config($mapping);
update_etc_network_interfaces($mapping, $existing_pins);
update_sdn_controllers($mapping);
update_sdn_fabrics($mapping);
print "Successfully updated Proxmox VE configuration files.\n";
print "\nPlease reboot to apply the changes to your configuration\n\n";
};
PVE::Tools::lock_file($PVEETH_LOCK, 10, $code);
die $@ if $@;
return;
},
});
our $cmddef = {
generate => [__PACKAGE__, 'generate', [], {}],
};
1;

View file

@ -3,6 +3,7 @@ package PVE::CLI::pveceph;
use strict;
use warnings;
use AptPkg::Cache;
use Data::Dumper;
use Fcntl ':flock';
use File::Path;
@ -136,9 +137,13 @@ __PACKAGE__->register_method({
},
repository => {
type => 'string',
enum => ['enterprise', 'no-subscription', 'test'],
enum => ['enterprise', 'no-subscription', 'test', 'manual'],
default => 'enterprise',
description => "Ceph repository to use.",
description => "Ceph repository to use. The 'manual' option will not configure"
. " any repositories. Use it if the host cannot access the public repositories,"
. " for example if Proxmox Offline Mirror is used. A repository that contains"
. " the Ceph packages for the version needs to be manually configured before"
. " starting the installation!",
optional => 1,
},
'allow-experimental' => {
@ -161,19 +166,23 @@ __PACKAGE__->register_method({
$enterprise_repo ? 'https://enterprise.proxmox.com' : 'http://download.proxmox.com';
if (has_valid_subscription()) {
warn
"\nNOTE: The node has an active subscription but a non-production Ceph repository selected.\n\n"
if !$enterprise_repo;
if (!$enterprise_repo) {
warn "\nNOTE: The node has an active subscription but a non-production Ceph"
. " repository selected.\n\n";
}
} elsif ($enterprise_repo) {
warn "\nWARN: Enterprise repository selected, but no active subscription!\n\n";
} elsif ($repo eq 'no-subscription') {
warn
"\nHINT: The no-subscription repository is not the best choice for production setups.\n"
warn "\nHINT: The no-subscription repository is not the best choice for production"
. " setups.\n"
. "Proxmox recommends using the enterprise repository with a valid subscription.\n";
} elsif ($repo eq 'manual') {
warn "\nHINT: The manual repository option expects that the Ceph repository is"
. " already correctly configured. For example, when used in combination with"
. " Proxmox Offline Mirror.\n";
} else {
warn
"\nWARN: The test repository should only be used for test setups or after consulting"
. " the official Proxmox support!\n\n";
warn "\nWARN: The test repository should only be used for test setups or after"
. " consulting the official Proxmox support!\n\n";
}
my $available_ceph_releases = PVE::Ceph::Releases::get_all_available_ceph_releases();
@ -199,22 +208,24 @@ EOF
die "Aborting installation as requested\n" if !$continue;
}
PVE::Tools::file_set_contents("/etc/apt/sources.list.d/ceph.sources", $repo_source);
if ($repo ne "manual") {
PVE::Tools::file_set_contents("/etc/apt/sources.list.d/ceph.sources", $repo_source);
if ($available_ceph_releases->{$cephver}->{unsupported}) {
if ($param->{'allow-experimental'}) {
warn
"NOTE: installing experimental/tech-preview Ceph release ${rendered_release}!\n";
} elsif (-t STDOUT) {
print
"Ceph ${rendered_release} is currently considered a technology preview for Proxmox VE - continue (y/N)? ";
my $answer = <STDIN>;
my $continue = defined($answer) && $answer =~ m/^\s*y(?:es)?\s*$/i;
if ($available_ceph_releases->{$cephver}->{unsupported}) {
if ($param->{'allow-experimental'}) {
warn
"NOTE: installing experimental/tech-preview Ceph release ${rendered_release}!\n";
} elsif (-t STDOUT) {
print "Ceph ${rendered_release} is currently considered a technology"
. " preview for Proxmox VE - continue (y/N)? ";
my $answer = <STDIN>;
my $continue = defined($answer) && $answer =~ m/^\s*y(?:es)?\s*$/i;
die "Aborting installation as requested\n" if !$continue;
} else {
die
"refusing to install tech-preview Ceph release ${rendered_release} without 'allow-experimental' parameter!\n";
die "Aborting installation as requested\n" if !$continue;
} else {
die "Refusing to install tech-preview Ceph release ${rendered_release}"
. " without 'allow-experimental' parameter!\n";
}
}
}
@ -228,6 +239,25 @@ EOF
);
};
if ($repo eq "manual") {
my $apt_cache = AptPkg::Cache->new() || die "unable to initialize AptPkg::Cache\n";
my @ceph_versions = $apt_cache->{'ceph-common:amd64'}->{'VersionList'}->@*;
my $latest_available = $ceph_versions[0]->{'VerStr'};
my $selected_version =
PVE::Ceph::Releases::get_ceph_release_info($cephver)->{'release'};
if ($latest_available !~ "^$selected_version") {
die "Selected Ceph version '${selected_version}' does not match the available"
. " version in the repository '${latest_available}' \n";
}
my $pkg_infos = $ceph_versions[0]->{'FileList'}->[0]->{'File'};
print "\nUsing the following manual repository:\n"
. "Site:\t\t $pkg_infos->{'Site'}\n"
. "Component:\t $pkg_infos->{'Component'}\n\n";
}
my @apt_install =
qw(apt-get --no-install-recommends -o Dpkg::Options::=--force-confnew install --);
my @ceph_packages = qw(

View file

@ -6,9 +6,11 @@ use warnings;
use PVE::Status::Plugin;
use PVE::Status::Graphite;
use PVE::Status::InfluxDB;
use PVE::Status::OpenTelemetry;
PVE::Status::Graphite->register();
PVE::Status::InfluxDB->register();
PVE::Status::OpenTelemetry->register();
PVE::Status::Plugin->init();
sub foreach_plug($&) {

View file

@ -5,6 +5,7 @@ use warnings;
use Proxmox::RS::SharedCache;
use PVE::Network;
# with the pvestatd 10s update intervall this covers 30 minutes of data.
use constant OLD_GENERATIONS => 180;
use constant LOCK_TIMEOUT => 2;
@ -91,9 +92,18 @@ my sub get_node_metrics {
push @$metrics, gauge($id, $timestamp, "uptime", $data->{uptime});
my ($netin, $netout) = (0, 0);
for my $dev (grep { /^$PVE::Network::PHYSICAL_NIC_RE$/ } keys $data->{nics}->%*) {
$netin += $data->{nics}->{$dev}->{receive};
$netout += $data->{nics}->{$dev}->{transmit};
for my $dev (keys $data->{nics}->%*) {
my $nic_data = $data->{nics}->{$dev};
if ($nic_data->{type}) {
next if $nic_data->{type} ne 'physical';
} else {
next if $dev !~ /^$PVE::Network::PHYSICAL_NIC_RE$/;
}
$netin += $nic_data->{receive};
$netout += $nic_data->{transmit};
}
push @$metrics, derive($id, $timestamp, "net_in", $netin);
push @$metrics, derive($id, $timestamp, "net_out", $netout);

View file

@ -15,7 +15,7 @@ use base qw(PVE::Daemon);
my $cmdline = [$0, @ARGV];
my %daemon_options = (
max_workers => 3,
max_workers => 3, # may be overridden in init
restart_on_error => 5,
stop_wait_time => 15,
leave_children_open_on_reload => 1,
@ -26,6 +26,10 @@ my $daemon = __PACKAGE__->new('pvedaemon', $cmdline, %daemon_options);
sub init {
my ($self) = @_;
# all options other than MAX_WORKERS are ignored
my $proxyconf = PVE::APIServer::Utils::read_proxy_config($self->{name});
$self->{max_workers} = $proxyconf->{MAX_WORKERS} if $proxyconf->{MAX_WORKERS};
my $accept_lock_fn = "/var/lock/pvedaemon.lck";
my $lockfh = IO::File->new(">>${accept_lock_fn}")

View file

@ -29,7 +29,7 @@ use base qw(PVE::Daemon);
my $cmdline = [$0, @ARGV];
my %daemon_options = (
max_workers => 3,
max_workers => 3, # may be overridden in init
restart_on_error => 5,
stop_wait_time => 15,
leave_children_open_on_reload => 1,
@ -54,7 +54,8 @@ my $basedirs = {
i18n => '/usr/share/pve-i18n',
manager => '/usr/share/pve-manager',
novnc => '/usr/share/novnc-pve',
sencha_touch => '/usr/share/javascript/sencha-touch',
yew_mobile => '/usr/share/pve-yew-mobile-gui',
i18n_yew => '/usr/share/pve-yew-mobile-i18n',
widgettoolkit => '/usr/share/javascript/proxmox-widget-toolkit',
xtermjs => '/usr/share/pve-xtermjs',
};
@ -64,6 +65,7 @@ sub init {
# we use same ALLOW/DENY/POLICY as pveproxy
my $proxyconf = PVE::APIServer::Utils::read_proxy_config($self->{name});
$self->{max_workers} = $proxyconf->{MAX_WORKERS} if $proxyconf->{MAX_WORKERS};
my $accept_lock_fn = "/var/lock/pveproxy.lck";
@ -86,12 +88,12 @@ sub init {
add_dirs($dirs, '/pve2/images/' => "$basedirs->{manager}/images/");
add_dirs($dirs, '/pve2/js/' => "$basedirs->{manager}/js/");
add_dirs($dirs, '/pve2/locale/', "$basedirs->{i18n}/");
add_dirs($dirs, '/pve2/sencha-touch/', "$basedirs->{sencha_touch}/");
add_dirs($dirs, '/pve2/touch/', "$basedirs->{manager}/touch/");
add_dirs($dirs, '/pwt/css/' => "$basedirs->{widgettoolkit}/css/");
add_dirs($dirs, '/pwt/images/' => "$basedirs->{widgettoolkit}/images/");
add_dirs($dirs, '/pwt/themes/' => "$basedirs->{widgettoolkit}/themes/");
add_dirs($dirs, '/xtermjs/' => "$basedirs->{xtermjs}/");
add_dirs($dirs, '/yew-mobile/', "$basedirs->{yew_mobile}/");
add_dirs($dirs, '/yew-mobile/i18n/', "$basedirs->{i18n_yew}/");
$self->{server_config} = {
title => 'Proxmox VE API',
@ -183,7 +185,7 @@ sub is_phone {
return 1 if $ua =~ m/(iPhone|iPod|Windows Phone)/;
if ($ua =~ m/Mobile(\/|\s)/) {
if ($ua =~ m/Mobile\b/) {
return 1 if $ua =~ m/(BlackBerry|BB)/;
return 1 if ($ua =~ m/(Android)/) && ($ua !~ m/(Silk)/);
}
@ -191,9 +193,16 @@ sub is_phone {
return 0;
}
# NOTE: Requests to those pages are not authenticated
# so we must be very careful here
my sub get_path_mtime {
my ($path) = @_;
my @stat_res = stat($path) or $!{ENOENT} or die "failed to stat '$path' - $!\n";
my $mtime = $stat_res[9];
return $mtime;
}
# NOTE: Requests to those pages are not authenticated so we must be very careful here
sub get_index {
my ($nodename, $server, $r, $args) = @_;
@ -248,6 +257,13 @@ sub get_index {
my $wtversionraw = PVE::Tools::file_read_firstline("$basedirs->{widgettoolkit}/proxmoxlib.js");
my $wtversion = $wtversionraw =~ m|^// (.*)$| ? $1 : '';
# while we could use the actual pkg version (e.g., shipped as pkg-version file in each
# respective package's /usr/share/<pkg> folder, this way it should also work when using make
# install to directly install to local root filesystem.
my $i18n_js_mtime = get_path_mtime('/usr/share/pve-i18n');
my $i18n_yew_mtime = get_path_mtime('/usr/share/pve-yew-mobile-i18n');
my $ui_yew_mtime = get_path_mtime('/usr/share/pve-yew-mobile-gui');
my $debug = $server->{debug};
if (exists $args->{debug}) {
$debug = !defined($args->{debug}) || $args->{debug};
@ -265,6 +281,10 @@ sub get_index {
wtversion => $wtversion,
theme => $theme,
consenttext => $consent_text,
i18n_js_mtime => $i18n_js_mtime,
i18n_yew_mobile_mtime => $i18n_yew_mtime,
yew_mobile_mtime => $ui_yew_mtime,
yew_mobile_base_path => '/yew-mobile',
};
# by default, load the normal index
@ -275,7 +295,7 @@ sub get_index {
} elsif ($xtermjs) {
$dir = $basedirs->{xtermjs};
} elsif ($mobile) {
$dir = "$basedirs->{manager}/touch";
$dir = "$basedirs->{yew_mobile}";
}
my $page = '';

View file

@ -82,6 +82,12 @@ my $cached_kvm_version = '';
my $next_flag_update_time;
my $failed_flag_update_delay_sec = 120;
# Checks if RRD files exist in the specified location.
my $rrd_dir_exists = sub {
my ($location) = @_;
return -d "/var/lib/rrdcached/db/${location}";
};
sub update_supported_cpuflags {
my $kvm_version = PVE::QemuServer::kvm_user_version();
@ -155,6 +161,9 @@ my sub broadcast_static_node_info {
}
}
my ($cached_ip_links, $cached_ip_link_last_update) = (undef, 0);
my $MAX_IP_LINK_CACHE_AGE_SECONDS = 15 * 60; # every 15 minutes
sub update_node_status {
my ($status_cfg, $pull_txn) = @_;
@ -171,41 +180,94 @@ sub update_node_status {
my $sublevel = $subinfo->{level} || '';
my $netdev = PVE::ProcFSTools::read_proc_net_dev();
my $ctime = time();
if (
!defined($cached_ip_links)
|| ($ctime - $cached_ip_link_last_update) > $MAX_IP_LINK_CACHE_AGE_SECONDS
) {
$cached_ip_links = PVE::Network::ip_link_details();
$cached_ip_link_last_update = $ctime;
}
# traffic from/to physical interface cards
my ($netin, $netout) = (0, 0);
for my $dev (grep { /^$PVE::Network::PHYSICAL_NIC_RE$/ } keys %$netdev) {
for my $dev (keys %$netdev) {
my $ip_link = $cached_ip_links->{$dev};
if ($ip_link && PVE::Network::ip_link_is_physical($ip_link)) {
$netdev->{$dev}->{type} = 'physical';
} else {
$netdev->{$dev}->{type} = 'virtual';
next;
}
$netin += $netdev->{$dev}->{receive};
$netout += $netdev->{$dev}->{transmit};
}
my $meminfo = PVE::ProcFSTools::read_meminfo();
my $pressures = PVE::ProcFSTools::read_pressure();
my $dinfo = df('/', 1); # output is bytes
# everything not free is considered to be used
my $dused = $dinfo->{blocks} - $dinfo->{bfree};
my $ctime = time();
$ctime = time(); # df can need a long time, so requery time.
my $data = $generate_rrd_string->(
[
$uptime,
$sublevel,
$ctime,
$avg1,
$maxcpu,
$stat->{cpu},
$stat->{wait},
$meminfo->{memtotal},
$meminfo->{memused},
$meminfo->{swaptotal},
$meminfo->{swapused},
$dinfo->{blocks},
$dused,
$netin,
$netout,
],
);
PVE::Cluster::broadcast_rrd("pve2-node/$nodename", $data);
my $data;
# TODO: drop old pve2- schema with PVE 10
if ($rrd_dir_exists->("pve-node-9.0")) {
$data = $generate_rrd_string->(
[
$uptime,
$sublevel,
$ctime,
$avg1,
$maxcpu,
$stat->{cpu},
$stat->{wait},
$meminfo->{memtotal},
$meminfo->{memused},
$meminfo->{swaptotal},
$meminfo->{swapused},
$dinfo->{blocks},
$dused,
$netin,
$netout,
$meminfo->{memavailable},
$meminfo->{arcsize},
$pressures->{cpu}->{some}->{avg10},
$pressures->{io}->{some}->{avg10},
$pressures->{io}->{full}->{avg10},
$pressures->{memory}->{some}->{avg10},
$pressures->{memory}->{full}->{avg10},
],
);
PVE::Cluster::broadcast_rrd("pve-node-9.0/$nodename", $data);
} else {
$data = $generate_rrd_string->(
[
$uptime,
$sublevel,
$ctime,
$avg1,
$maxcpu,
$stat->{cpu},
$stat->{wait},
$meminfo->{memtotal},
$meminfo->{memused},
$meminfo->{swaptotal},
$meminfo->{swapused},
$dinfo->{blocks},
$dused,
$netin,
$netout,
],
);
PVE::Cluster::broadcast_rrd("pve2-node/$nodename", $data);
}
my $node_metric = {
uptime => $uptime,
@ -273,44 +335,101 @@ sub update_qemu_status {
my $data;
my $status = $d->{qmpstatus} || $d->{status} || 'stopped';
my $template = $d->{template} ? $d->{template} : "0";
if ($d->{pid}) { # running
$data = $generate_rrd_string->([
$d->{uptime},
$d->{name},
$status,
$template,
$ctime,
$d->{cpus},
$d->{cpu},
$d->{maxmem},
$d->{mem},
$d->{maxdisk},
$d->{disk},
$d->{netin},
$d->{netout},
$d->{diskread},
$d->{diskwrite},
]);
# TODO: drop old pve2.3- schema with PVE 10
if ($rrd_dir_exists->("pve-vm-9.0")) {
if ($d->{pid}) { # running
$data = $generate_rrd_string->([
$d->{uptime},
$d->{name},
$status,
$template,
$ctime,
$d->{cpus},
$d->{cpu},
$d->{maxmem},
$d->{mem},
$d->{maxdisk},
$d->{disk},
$d->{netin},
$d->{netout},
$d->{diskread},
$d->{diskwrite},
$d->{memhost},
$d->{pressurecpusome},
$d->{pressurecpufull},
$d->{pressureiosome},
$d->{pressureiofull},
$d->{pressurememorysome},
$d->{pressurememoryfull},
]);
} else {
$data = $generate_rrd_string->([
0,
$d->{name},
$status,
$template,
$ctime,
$d->{cpus},
undef,
$d->{maxmem},
undef,
$d->{maxdisk},
$d->{disk},
undef,
undef,
undef,
undef,
undef,
undef,
undef,
undef,
undef,
undef,
undef,
]);
}
PVE::Cluster::broadcast_rrd("pve-vm-9.0/$vmid", $data);
} else {
$data = $generate_rrd_string->([
0,
$d->{name},
$status,
$template,
$ctime,
$d->{cpus},
undef,
$d->{maxmem},
undef,
$d->{maxdisk},
$d->{disk},
undef,
undef,
undef,
undef,
]);
if ($d->{pid}) { # running
$data = $generate_rrd_string->([
$d->{uptime},
$d->{name},
$status,
$template,
$ctime,
$d->{cpus},
$d->{cpu},
$d->{maxmem},
$d->{mem},
$d->{maxdisk},
$d->{disk},
$d->{netin},
$d->{netout},
$d->{diskread},
$d->{diskwrite},
]);
} else {
$data = $generate_rrd_string->([
0,
$d->{name},
$status,
$template,
$ctime,
$d->{cpus},
undef,
$d->{maxmem},
undef,
$d->{maxdisk},
$d->{disk},
undef,
undef,
undef,
undef,
]);
}
PVE::Cluster::broadcast_rrd("pve2.3-vm/$vmid", $data);
}
PVE::Cluster::broadcast_rrd("pve2.3-vm/$vmid", $data);
PVE::ExtMetric::update_all($transactions, 'qemu', $vmid, $d, $ctime, $nodename);
}
@ -506,44 +625,100 @@ sub update_lxc_status {
my $d = $vmstatus->{$vmid};
my $template = $d->{template} ? $d->{template} : "0";
my $data;
if ($d->{status} eq 'running') { # running
$data = $generate_rrd_string->([
$d->{uptime},
$d->{name},
$d->{status},
$template,
$ctime,
$d->{cpus},
$d->{cpu},
$d->{maxmem},
$d->{mem},
$d->{maxdisk},
$d->{disk},
$d->{netin},
$d->{netout},
$d->{diskread},
$d->{diskwrite},
]);
# TODO: drop old pve2.3-vm schema with PVE 10
if ($rrd_dir_exists->("pve-vm-9.0")) {
if ($d->{pid}) { # running
$data = $generate_rrd_string->([
$d->{uptime},
$d->{name},
$d->{status},
$template,
$ctime,
$d->{cpus},
$d->{cpu},
$d->{maxmem},
$d->{mem},
$d->{maxdisk},
$d->{disk},
$d->{netin},
$d->{netout},
$d->{diskread},
$d->{diskwrite},
undef,
$d->{pressurecpusome},
$d->{pressurecpufull},
$d->{pressureiosome},
$d->{pressureiofull},
$d->{pressurememorysome},
$d->{pressurememoryfull},
]);
} else {
$data = $generate_rrd_string->([
0,
$d->{name},
$d->{status},
$template,
$ctime,
$d->{cpus},
undef,
$d->{maxmem},
undef,
$d->{maxdisk},
$d->{disk},
undef,
undef,
undef,
undef,
undef,
undef,
undef,
undef,
undef,
undef,
undef,
]);
}
PVE::Cluster::broadcast_rrd("pve-vm-9.0/$vmid", $data);
} else {
$data = $generate_rrd_string->([
0,
$d->{name},
$d->{status},
$template,
$ctime,
$d->{cpus},
undef,
$d->{maxmem},
undef,
$d->{maxdisk},
$d->{disk},
undef,
undef,
undef,
undef,
]);
if ($d->{status} eq 'running') { # running
$data = $generate_rrd_string->([
$d->{uptime},
$d->{name},
$d->{status},
$template,
$ctime,
$d->{cpus},
$d->{cpu},
$d->{maxmem},
$d->{mem},
$d->{maxdisk},
$d->{disk},
$d->{netin},
$d->{netout},
$d->{diskread},
$d->{diskwrite},
]);
} else {
$data = $generate_rrd_string->([
0,
$d->{name},
$d->{status},
$template,
$ctime,
$d->{cpus},
undef,
$d->{maxmem},
undef,
$d->{maxdisk},
$d->{disk},
undef,
undef,
undef,
undef,
]);
}
PVE::Cluster::broadcast_rrd("pve2.3-vm/$vmid", $data);
}
PVE::Cluster::broadcast_rrd("pve2.3-vm/$vmid", $data);
PVE::ExtMetric::update_all($transactions, 'lxc', $vmid, $d, $ctime, $nodename);
}
@ -568,6 +743,7 @@ sub update_storage_status {
my $data = $generate_rrd_string->([$ctime, $d->{total}, $d->{used}]);
my $key = "pve2-storage/${nodename}/$storeid";
$key = "pve-storage-9.0/${nodename}/$storeid" if $rrd_dir_exists->("pve-storage-9.0");
PVE::Cluster::broadcast_rrd($key, $data);
PVE::ExtMetric::update_all($transactions, 'storage', $nodename, $storeid, $d, $ctime);
@ -601,7 +777,10 @@ sub update_sdn_status {
my $broadcast_version_info_done = 0;
my sub broadcast_version_info : prototype() {
if (!$broadcast_version_info_done) {
if (
!$broadcast_version_info_done
|| !scalar(keys PVE::Cluster::get_node_kv('version-info', $nodename)->%*)
) {
PVE::Cluster::broadcast_node_kv(
'version-info', encode_json(PVE::pvecfg::version_info()),
);

View file

@ -6,6 +6,7 @@ use warnings;
use POSIX qw(isnan isinf);
use Scalar::Util 'looks_like_number';
use IO::Socket::IP;
use IO::Socket::SSL qw(SSL_VERIFY_NONE);
use LWP::UserAgent;
use HTTP::Request;
@ -92,7 +93,7 @@ my $set_ssl_opts = sub {
if (!$cert_verify) {
$ua->ssl_opts(
verify_hostname => 0,
SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE,
SSL_verify_mode => SSL_VERIFY_NONE,
);
}

View file

@ -3,6 +3,7 @@ include ../../defines.mk
PERLSOURCE = \
Graphite.pm \
InfluxDB.pm \
OpenTelemetry.pm \
Plugin.pm
all:

712
PVE/Status/OpenTelemetry.pm Normal file
View file

@ -0,0 +1,712 @@
package PVE::Status::OpenTelemetry;
use strict;
use warnings;
use Compress::Zlib;
use Encode;
use HTTP::Request;
use JSON;
use LWP::UserAgent;
use MIME::Base64 qw(decode_base64);
use PVE::Cluster;
use PVE::Status::Plugin;
use PVE::Tools qw(extract_param);
use base qw(PVE::Status::Plugin);
sub type {
return 'opentelemetry';
}
sub properties {
return {
'otel-protocol' => {
type => 'string',
enum => ['http', 'https'],
description => 'HTTP protocol',
default => 'https',
},
'otel-path' => {
type => 'string',
description => 'OTLP endpoint path',
default => '/v1/metrics',
optional => 1,
},
'otel-timeout' => {
type => 'integer',
description => 'HTTP request timeout in seconds',
default => 5,
minimum => 1,
maximum => 10,
},
'otel-headers' => {
type => 'string',
description => 'Custom HTTP headers (JSON format, base64 encoded)',
optional => 1,
maxLength => 1024,
},
'otel-verify-ssl' => {
type => 'boolean',
description => 'Verify SSL certificates',
default => 1,
},
'otel-max-body-size' => {
type => 'integer',
description => 'Maximum request body size in bytes',
default => 10_000_000,
minimum => 1024,
},
'otel-resource-attributes' => {
type => 'string',
description => 'Additional resource attributes as JSON, base64 encoded',
optional => 1,
maxLength => 1024,
},
'otel-compression' => {
type => 'string',
enum => ['none', 'gzip'],
description => 'Compression algorithm for requests',
default => 'gzip',
optional => 1,
},
};
}
sub options {
return {
server => { optional => 0 },
port => { optional => 1 },
disable => { optional => 1 },
'otel-protocol' => { optional => 1 },
'otel-path' => { optional => 1 },
'otel-timeout' => { optional => 1 },
'otel-headers' => { optional => 1 },
'otel-verify-ssl' => { optional => 1 },
'otel-max-body-size' => { optional => 1 },
'otel-resource-attributes' => { optional => 1 },
'otel-compression' => { optional => 1 },
};
}
sub _connect {
my ($class, $cfg, $id) = @_;
my $connection = {
id => $id,
cfg => $cfg,
metrics => [],
stats => {
total_metrics => 0,
successful_batches => 0,
failed_batches => 0,
},
};
return $connection;
}
sub _disconnect {
my ($class, $connection) = @_;
# No persistent connection to cleanup
}
sub _get_otlp_url {
my ($class, $cfg) = @_;
my $proto = $cfg->{'otel-protocol'} || 'https';
my $port = $cfg->{port} || ($proto eq 'https' ? 4318 : 4317);
my $path = $cfg->{'otel-path'} || '/v1/metrics';
return "${proto}://$cfg->{server}:${port}${path}";
}
sub _decode_base64_json {
my ($class, $encoded_str) = @_;
return '' unless defined $encoded_str && $encoded_str ne '';
my $decoded_str = decode_base64($encoded_str);
die "base64 decode failed" if !defined $decoded_str;
return $decoded_str;
}
sub _parse_headers {
my ($class, $headers_str) = @_;
return {} unless defined $headers_str && $headers_str ne '';
my $decoded_str = $class->_decode_base64_json($headers_str);
my $headers = {};
eval {
my $json = JSON->new->decode($decoded_str);
die "headers must be a JSON hash" if ref($json) ne 'HASH';
$headers = $json;
};
if ($@) {
warn "Failed to parse headers '$headers_str' - $@";
}
return $headers;
}
sub _parse_resource_attributes {
my ($class, $json_str) = @_;
return [] unless defined $json_str && $json_str ne '';
my $decoded_str = $class->_decode_base64_json($json_str);
my $attributes = [];
eval {
# Ensure the JSON string is properly decoded as UTF-8
my $utf8_json =
utf8::is_utf8($decoded_str)
? $decoded_str
: Encode::decode('utf-8', $decoded_str);
my $parsed = JSON->new->utf8(0)->decode($utf8_json);
die "resource attributes must be a JSON hash" if ref($parsed) ne 'HASH';
for my $key (keys %$parsed) {
push @$attributes,
{
key => $key,
value => { stringValue => $parsed->{$key} },
};
}
};
if ($@) {
warn "Failed to parse resource attributes '$json_str' - $@";
}
return $attributes;
}
sub _compress_json {
my ($class, $data) = @_;
my $json_str = JSON->new->utf8->encode($data);
my $compressed = Compress::Zlib::memGzip($json_str);
die "gzip compression failed: $Compress::Zlib::gzerrno" if !defined $compressed;
return $compressed;
}
sub _build_otlp_metrics {
my ($class, $metrics_data, $cfg) = @_;
my $cluster_name = 'single-node';
eval {
my $clinfo = PVE::Cluster::get_clinfo();
if ($clinfo && $clinfo->{cluster} && $clinfo->{cluster}->{name}) {
$cluster_name = $clinfo->{cluster}->{name};
}
};
# If reading fails, use default cluster name
my $node_name = PVE::INotify::nodename();
my $pve_version = PVE::pvecfg::version_text();
return {
resourceMetrics => [{
resource => {
attributes => [
{
key => 'service.name',
value => { stringValue => 'proxmox-ve' },
},
{
key => 'service.version',
value => { stringValue => $pve_version },
},
{
key => 'proxmox.cluster',
value => { stringValue => $cluster_name },
},
{
key => 'proxmox.node',
value => { stringValue => $node_name },
},
@{ $class->_parse_resource_attributes($cfg->{'otel-resource-attributes'}) },
],
},
scopeMetrics => [{
scope => {},
metrics => $metrics_data,
}],
}],
};
}
# Classify metric type (counter vs gauge) and determine suffix
sub _classify_metric_type {
my ($class, $key, $metric_prefix) = @_;
# Counter type (cumulative values) - need _total suffix
if (
$key =~ /^(transmit|receive|netin|netout|diskread|diskwrite)$/
|| $key =~ /_operations$/
|| $key =~ /_merged$/
|| $key =~ /^(rd_|wr_|read|write|sent|recv|tx|rx|packets|errors|dropped|collisions)/
|| ($metric_prefix =~ /_cpustat$/
&& $key =~ /^(user|system|idle|nice|steal|guest|irq|softirq|iowait|wait)$/)
|| $metric_prefix =~ /_network$/
) {
return ('counter', '_total');
}
# Gauge type (instantaneous values) - no suffix
return ('gauge', '');
}
sub _convert_node_metrics_recursive {
my ($class, $data, $ctime, $metric_prefix, $attributes) = @_;
my @metrics = ();
# Skip non-metric fields
my $skip_fields = {
name => 1,
tags => 1,
vmid => 1,
type => 1,
status => 1,
template => 1,
pid => 1,
agent => 1,
serial => 1,
ctime => 1,
nics => 1, # Skip nics - handled separately with device labels
storages => 1, # Skip storages - handled separately with storage labels
};
# Unit mapping for common metrics
my $unit_mapping = {
# Memory and storage (bytes)
mem => 'bytes',
memory => 'bytes',
swap => 'bytes',
disk => 'bytes',
size => 'bytes',
used => 'bytes',
free => 'bytes',
total => 'bytes',
avail => 'bytes',
available => 'bytes',
arcsize => 'bytes',
blocks => 'bytes',
bavail => 'bytes',
bfree => 'bytes',
# Network (bytes)
net => 'bytes',
receive => 'bytes',
transmit => 'bytes',
netin => 'bytes',
netout => 'bytes',
diskread => 'bytes',
diskwrite => 'bytes',
# CPU and time
cpu => 'percent',
wait => 'seconds',
iowait => 'seconds',
user => 'seconds',
system => 'seconds',
idle => 'seconds',
nice => 'seconds',
steal => 'seconds',
guest => 'seconds',
irq => 'seconds',
softirq => 'seconds',
uptime => 'seconds',
# Time measurements (nanoseconds)
time_ns => 'seconds',
total_time_ns => 'seconds',
# Load average (dimensionless)
avg => '1',
avg1 => '1',
avg5 => '1',
avg15 => '1',
# Counters and ratios (dimensionless)
cpus => '1',
operations => '1',
merged => '1',
ratio => '1',
count => '1',
# File system (files are counted, not sized)
files => '1',
ffree => '1',
fused => '1',
favail => '1',
# Percentages (dimensionless 0-100 scale)
per => 'percent',
fper => 'percent',
percent => 'percent',
# Boolean-like flags (dimensionless)
enabled => '1',
shared => '1',
active => '1',
};
for my $key (sort keys %$data) {
next if $skip_fields->{$key};
my $value = $data->{$key};
next if !defined($value);
# Classify metric type and get suffix
my ($metric_type, $suffix) = $class->_classify_metric_type($key, $metric_prefix);
my $metric_name = "${metric_prefix}_${key}${suffix}";
if (ref($value) eq 'HASH') {
# Recursive call for nested hashes
push @metrics,
$class->_convert_node_metrics_recursive(
$value, $ctime, "${metric_prefix}_${key}", $attributes,
);
} elsif (
!ref($value)
&& $value ne ''
&& $value =~ /^[+-]?[0-9]*\.?[0-9]+([eE][+-]?[0-9]+)?$/
) {
# Numeric value - create metric
my $unit = '1'; # default unit
# Try to determine unit based on key name
for my $pattern (keys %$unit_mapping) {
if ($key =~ /\Q$pattern\E/) {
$unit = $unit_mapping->{$pattern};
last;
}
}
# Determine if it's an integer or double
my $data_point = {
timeUnixNano => $ctime * 1_000_000_000,
attributes => $attributes,
};
if ($value =~ /\./ || $value =~ /[eE]/) {
$data_point->{asDouble} = $value + 0; # Convert to number
} else {
$data_point->{asInt} = int($value);
}
# Create metric with appropriate type
my $metric = {
name => $metric_name,
unit => $unit,
};
if ($metric_type eq 'counter') {
$metric->{sum} = {
dataPoints => [$data_point],
aggregationTemporality => 2, # AGGREGATION_TEMPORALITY_CUMULATIVE
isMonotonic => \1 # JSON boolean true
};
} else {
$metric->{gauge} = { dataPoints => [$data_point] };
}
push @metrics, $metric;
}
}
return @metrics;
}
sub update_node_status {
my ($class, $txn, $node, $data, $ctime) = @_;
my @metrics = ();
my $base_attributes = [{ key => 'node', value => { stringValue => $node } }];
# Convert all node metrics recursively
push @metrics,
$class->_convert_node_metrics_recursive($data, $ctime, 'proxmox_node', $base_attributes);
# Handle special cases that need different attributes
# Network metrics with device labels
if (defined $data->{nics}) {
for my $iface (keys %{ $data->{nics} }) {
my $nic_attributes = [
{ key => 'node', value => { stringValue => $node } },
{ key => 'device', value => { stringValue => $iface } },
];
# Use recursive processing for network metrics with device-specific attributes
push @metrics,
$class->_convert_node_metrics_recursive(
$data->{nics}->{$iface},
$ctime,
'proxmox_node_network',
$nic_attributes,
);
}
}
# Storage metrics with storage labels
if (defined $data->{storages}) {
for my $storage (keys %{ $data->{storages} }) {
my $storage_attributes = [
{ key => 'node', value => { stringValue => $node } },
{ key => 'storage', value => { stringValue => $storage } },
];
# Use recursive processing for storage metrics with storage-specific attributes
push @metrics,
$class->_convert_node_metrics_recursive(
$data->{storages}->{$storage},
$ctime,
'proxmox_node_storage',
$storage_attributes,
);
}
}
push @{ $txn->{metrics} }, @metrics;
}
sub update_qemu_status {
my ($class, $txn, $vmid, $data, $ctime, $nodename) = @_;
my @metrics = ();
my $vm_attributes = [
{ key => 'vmid', value => { stringValue => $vmid } },
{ key => 'node', value => { stringValue => $nodename } },
{ key => 'name', value => { stringValue => $data->{name} || '' } },
{ key => 'type', value => { stringValue => 'qemu' } },
];
# Use recursive processing for all VM metrics
push @metrics,
$class->_convert_node_metrics_recursive($data, $ctime, 'proxmox_vm', $vm_attributes);
push @{ $txn->{metrics} }, @metrics;
}
sub update_lxc_status {
my ($class, $txn, $vmid, $data, $ctime, $nodename) = @_;
my @metrics = ();
my $vm_attributes = [
{ key => 'vmid', value => { stringValue => $vmid } },
{ key => 'node', value => { stringValue => $nodename } },
{ key => 'name', value => { stringValue => $data->{name} || '' } },
{ key => 'type', value => { stringValue => 'lxc' } },
];
# Use recursive processing for all LXC metrics
push @metrics,
$class->_convert_node_metrics_recursive($data, $ctime, 'proxmox_vm', $vm_attributes);
push @{ $txn->{metrics} }, @metrics;
}
sub update_storage_status {
my ($class, $txn, $nodename, $storeid, $data, $ctime) = @_;
my @metrics = ();
my $storage_attributes = [
{ key => 'node', value => { stringValue => $nodename } },
{ key => 'storage', value => { stringValue => $storeid } },
];
# Use recursive processing for all storage metrics
push @metrics,
$class->_convert_node_metrics_recursive(
$data, $ctime, 'proxmox_storage', $storage_attributes,
);
push @{ $txn->{metrics} }, @metrics;
}
sub flush_data {
my ($class, $txn) = @_;
return if !$txn->{connection};
return if !$txn->{metrics} || !@{ $txn->{metrics} };
my $metrics = delete $txn->{metrics};
$txn->{metrics} = [];
eval {
$class->_send_metrics_batched($txn->{connection}, $metrics, $txn->{cfg});
$txn->{stats}->{successful_batches}++;
};
if (my $err = $@) {
$txn->{stats}->{failed_batches}++;
die "OpenTelemetry export failed '$txn->{id}': $err";
}
}
sub _send_metrics_batched {
my ($class, $connection, $metrics, $cfg) = @_;
my $max_body_size = $cfg->{'otel-max-body-size'} || 10_000_000;
my $total_metrics = @$metrics;
# Estimate metrics per batch based on size heuristics
my $estimated_batch_size = $class->_estimate_batch_size($metrics, $max_body_size, $cfg);
# If estimated batch size covers all metrics, try sending everything at once
if ($estimated_batch_size >= $total_metrics) {
my $otlp_data = $class->_build_otlp_metrics($metrics, $cfg);
my $serialized_size = $class->_get_serialized_size($otlp_data, $cfg);
if ($serialized_size <= $max_body_size) {
$class->send($connection, $otlp_data, $cfg);
return;
}
# If estimation was wrong, fall through to batching
}
# Send in batches
for (my $i = 0; $i < $total_metrics; $i += $estimated_batch_size) {
my $end_idx = $i + $estimated_batch_size - 1;
$end_idx = $total_metrics - 1 if $end_idx >= $total_metrics;
my @batch_metrics = @$metrics[$i .. $end_idx];
my $batch_otlp = $class->_build_otlp_metrics(\@batch_metrics, $cfg);
# Verify batch size is within limits
my $batch_size_bytes = $class->_get_serialized_size($batch_otlp, $cfg);
if ($batch_size_bytes > $max_body_size) {
# Fallback: send metrics one by one
for my $single_metric (@batch_metrics) {
my $single_otlp = $class->_build_otlp_metrics([$single_metric], $cfg);
$class->send($connection, $single_otlp, $cfg);
}
} else {
$class->send($connection, $batch_otlp, $cfg);
}
}
}
sub _estimate_batch_size {
my ($class, $metrics, $max_body_size, $cfg) = @_;
return 1 if @$metrics == 0;
# Sample first few metrics to estimate size per metric
my $sample_size = @$metrics > 10 ? 10 : @$metrics;
my @sample_metrics = @$metrics[0 .. $sample_size - 1];
my $sample_otlp = $class->_build_otlp_metrics(\@sample_metrics, $cfg);
my $sample_bytes = $class->_get_serialized_size($sample_otlp, $cfg);
# Calculate average bytes per metric with overhead
my $bytes_per_metric = $sample_bytes / $sample_size;
# Add 20% safety margin for OTLP structure overhead
$bytes_per_metric *= 1.2;
# Calculate how many metrics fit in max_body_size
my $estimated_count = int($max_body_size / $bytes_per_metric);
# Ensure at least 1 metric per batch, and cap at total metrics
$estimated_count = 1 if $estimated_count < 1;
$estimated_count = @$metrics if $estimated_count > @$metrics;
return $estimated_count;
}
sub _get_serialized_size {
my ($class, $data, $cfg) = @_;
my $serialized;
if (($cfg->{'otel-compression'} // 'gzip') eq 'gzip') {
$serialized = $class->_compress_json($data);
} else {
$serialized = JSON->new->utf8->encode($data);
}
return length($serialized);
}
sub send {
my ($class, $connection, $data, $cfg) = @_;
my $ua = LWP::UserAgent->new(
timeout => $cfg->{'otel-timeout'} || 5,
ssl_opts => { verify_hostname => $cfg->{'otel-verify-ssl'} // 1 },
);
my $url = $class->_get_otlp_url($cfg);
my $request_data;
my %headers = (
'Content-Type' => 'application/json',
);
# Safely add parsed headers
my $parsed_headers = $class->_parse_headers($cfg->{'otel-headers'});
if ($parsed_headers && ref($parsed_headers) eq 'HASH') {
%headers = (%headers, %$parsed_headers);
}
if (($cfg->{'otel-compression'} // 'gzip') eq 'gzip') {
$request_data = $class->_compress_json($data);
$headers{'Content-Encoding'} = 'gzip';
} else {
$request_data = JSON->new->utf8->encode($data);
}
my $req = HTTP::Request->new('POST', $url, [%headers], $request_data);
my $response = $ua->request($req);
die "OTLP request failed: " . $response->status_line unless $response->is_success;
}
sub test_connection {
my ($class, $cfg) = @_;
my $ua = LWP::UserAgent->new(
timeout => $cfg->{'otel-timeout'} || 5,
ssl_opts => { verify_hostname => $cfg->{'otel-verify-ssl'} // 1 },
);
my $url = $class->_get_otlp_url($cfg);
# Send empty metrics payload for testing
my $test_data = {
resourceMetrics => [{
resource => { attributes => [] },
scopeMetrics => [{
scope => {},
metrics => [],
}],
}],
};
my $request_data;
my %headers = (
'Content-Type' => 'application/json',
);
# Safely add parsed headers
my $parsed_headers = $class->_parse_headers($cfg->{'otel-headers'});
if ($parsed_headers && ref($parsed_headers) eq 'HASH') {
%headers = (%headers, %$parsed_headers);
}
if (($cfg->{'otel-compression'} // 'gzip') eq 'gzip') {
$request_data = $class->_compress_json($test_data);
$headers{'Content-Encoding'} = 'gzip';
} else {
$request_data = JSON->new->utf8->encode($test_data);
}
my $req = HTTP::Request->new('POST', $url, [%headers], $request_data);
my $response = $ua->request($req);
die "Connection test failed: " . $response->status_line unless $response->is_success;
return 1;
}
1;

View file

@ -177,28 +177,16 @@ my sub merge_performance {
return $res;
}
my $parse_prune_backups_maxfiles = sub {
my $parse_prune_backups = sub {
my ($param, $kind) = @_;
my $maxfiles = delete $param->{maxfiles};
my $prune_backups = $param->{'prune-backups'};
debugmsg(
'warn',
"both 'maxfiles' and 'prune-backups' defined as ${kind} - ignoring 'maxfiles'",
) if defined($maxfiles) && defined($prune_backups);
if (defined($prune_backups)) {
return $prune_backups if ref($prune_backups) eq 'HASH'; # already parsed
$param->{'prune-backups'} = PVE::JSONSchema::parse_property_string(
'prune-backups', $prune_backups,
);
} elsif (defined($maxfiles)) {
if ($maxfiles) {
$param->{'prune-backups'} = { 'keep-last' => $maxfiles };
} else {
$param->{'prune-backups'} = { 'keep-all' => 1 };
}
}
return $param->{'prune-backups'};
@ -335,7 +323,7 @@ sub read_vzdump_defaults {
defined($default) ? ($_ => $default) : ()
} keys $fleecing_fmt->%*
};
$parse_prune_backups_maxfiles->($defaults, "defaults in VZDump schema");
$parse_prune_backups->($defaults, "defaults in VZDump schema");
my $raw;
eval { $raw = PVE::Tools::file_get_contents($fn); };
@ -360,7 +348,7 @@ sub read_vzdump_defaults {
my @mailto = split_list($res->{mailto});
$res->{mailto} = [@mailto];
}
$parse_prune_backups_maxfiles->($res, "options in '$fn'");
$parse_prune_backups->($res, "options in '$fn'");
parse_fleecing($res);
parse_performance($res);
@ -1548,10 +1536,7 @@ sub verify_vzdump_parameters {
raise_param_exc({ pool => "option conflicts with option 'vmid'" })
if $param->{pool} && $param->{vmid};
raise_param_exc({ 'prune-backups' => "option conflicts with option 'maxfiles'" })
if defined($param->{'prune-backups'}) && defined($param->{maxfiles});
$parse_prune_backups_maxfiles->($param, 'CLI parameters');
$parse_prune_backups->($param, 'CLI parameters');
parse_fleecing($param);
parse_performance($param);

View file

@ -20,7 +20,9 @@ update:
mv aplinfo.dat.tmp aplinfo.dat
trustedkeys.gpg: $(TRUSTED_KEYS)
sq keyring merge --output $@.tmp $(TRUSTED_KEYS)
sq keyring merge --output $(basename $@).asc.tmp $(TRUSTED_KEYS)
sq packet dearmor $(basename $@).asc.tmp --output $@.tmp
rm $(basename $@).asc.tmp
mv $@.tmp $@
.PHONY: clean

View file

@ -4,6 +4,19 @@ Description: News displayed on the admin interface
For more information please visit our homepage at
<a href='https://www.proxmox.com' target='_blank'>www.proxmox.com</a>
Package: almalinux-10-default
Version: 20250930
Type: lxc
OS: almalinux
Section: system
Maintainer: Proxmox Support Team <support@proxmox.com>
Architecture: amd64
Location: system/almalinux-10-default_20250930_amd64.tar.xz
md5sum: 15112c6ccd019b93fb5ab9d91f3f92fc
sha512sum: ba26baea9b73188f1ec308f27a3c3e4efcd7fc8bfca976dc2dfffc89c5681df4ac3a96e136f841d769a8b6a04c6cf0db97ffef70def853a0c3486c90a30e3418
Infopage: https://linuxcontainers.org
Description: LXC default image for almalinux 10 (20250930)
Package: almalinux-9-default
Version: 20240911
Type: lxc
@ -44,18 +57,32 @@ Infopage: https://linuxcontainers.org
Description: LXC default image for centos 9-stream (20240828)
Package: debian-12-standard
Version: 12.7-1
Version: 12.12-1
Type: lxc
OS: debian-12
Section: system
Maintainer: Proxmox Support Team <support@proxmox.com>
Architecture: amd64
Location: system/debian-12-standard_12.7-1_amd64.tar.zst
md5sum: 0b6959720ebd506b5ddb2fbf8780ca6c
sha512sum: 39f6d06e082d6a418438483da4f76092ebd0370a91bad30b82ab6d0f442234d63fe27a15569895e34d6d1e5ca50319f62637f7fb96b98dbde4f6103cf05bff6d
Location: system/debian-12-standard_12.12-1_amd64.tar.zst
md5sum: 4e5a0a7183b6c8ca6867489820961e88
sha512sum: 50c85eaaece677a3ebe01cc909b83872e9da2a22c29ae652838afce71e83222fdf40f6accecd7d52b180e912fc1f85ecdf7b3fc4d3027da4d865e509a9e76597
Infopage: https://pve.proxmox.com/wiki/Linux_Container#pct_supported_distributions
Description: Debian 12 Bookworm (standard)
A small Debian Bullseye system including all standard packages.
A small Debian Bookworm system including all standard packages.
Package: debian-13-standard
Version: 13.1-2
Type: lxc
OS: debian-13
Section: system
Maintainer: Proxmox Support Team <support@proxmox.com>
Architecture: amd64
Location: system/debian-13-standard_13.1-2_amd64.tar.zst
md5sum: 5ee736fbc37d2068ca6695d7686b7d62
sha512sum: 5aec4ab2ac5c16c7c8ecb87bfeeb10213abe96db6b85e2463585cea492fc861d7c390b3f9c95629bf690b95e9dfe1037207fc69c0912429605f208d5cb2621f8
Infopage: https://pve.proxmox.com/wiki/Linux_Container#pct_supported_distributions
Description: Debian 13 Trixie (standard)
A small Debian Trixie system including all standard packages.
Package: devuan-5.0-standard
Version: 5.0
@ -97,19 +124,6 @@ sha512sum: 50495e3c066aa4f4a8886d8eebbb30ecf662bb7bf7209677fa9edfb82ce2d00172ad2
Infopage: https://linuxcontainers.org
Description: LXC openrc image for gentoo current (20250508)
Package: openeuler-24.03-default
Version: 20250507
Type: lxc
OS: openeuler
Section: system
Maintainer: Proxmox Support Team <support@proxmox.com>
Architecture: amd64
Location: system/openeuler-24.03-default_20250507_amd64.tar.xz
md5sum: db93408ef4ac38193ef25ffb0bfc52db
sha512sum: e0267c22e6e9401dac8ce8a6f572c51e23131b0d6b77743385a59a63fedcac36d401e818db3d0e98bac98d020e37926aade5a17de6995015733ade97bdd605be
Infopage: https://linuxcontainers.org
Description: LXC default image for openeuler 24.03 (20250507)
Package: openeuler-25.03-default
Version: 20250507
Type: lxc
@ -150,6 +164,33 @@ Infopage: https://www.proxmox.com/en/proxmox-mail-gateway/overview
Description: Proxmox Mail Gateway 8.2
A full featured mail proxy for spam and virus filtering, optimized for container environment.
Package: proxmox-mail-gateway-9.0-standard
Version: 9.0-1
Type: lxc
OS: debian-13
Section: mail
Maintainer: Proxmox Support Team <support@proxmox.com>
Architecture: amd64
Location: mail/proxmox-mail-gateway-9.0-standard_9.0-1_amd64.tar.zst
md5sum: 2346458e2947248b25ebbe3484086e5c
sha512sum: 8c20d93aa5af8a94526ecedb6b1a18e45ea2dd80d48d1ca9c413fffcd93cccaf4f6767e6326d9fe12e737388a9fbe328ef16e677f7442d7da29b75c5eb9f5b01
Infopage: https://www.proxmox.com/en/proxmox-mail-gateway/overview
Description: Proxmox Mail Gateway 9.0
A full featured mail proxy for spam and virus filtering, optimized for container environment.
Package: rockylinux-10-default
Version: 20251001
Type: lxc
OS: rockylinux
Section: system
Maintainer: Proxmox Support Team <support@proxmox.com>
Architecture: amd64
Location: system/rockylinux-10-default_20251001_amd64.tar.xz
md5sum: 13ef16830a3f62727b8641b041529497
sha512sum: 025d346a9aa9b27b90c28147cece917659cb320508cf248f59c776a00fd3a7009a9e1e0812217c990398588bb11b5a38abca82c0991a161ba3f27e1c6ee190ac
Infopage: https://linuxcontainers.org
Description: LXC default image for rockylinux 10 (20251001)
Package: rockylinux-9-default
Version: 20240912
Type: lxc

View file

@ -12,9 +12,11 @@ CLITOOLS = \
pvesr \
pvenode \
pvesh \
pve7to8 \
pve8to9 \
LIBEXECCLITOOLS = \
pve-network-interface-pinning \
SCRIPTS = \
$(SERVICES) \
@ -28,15 +30,19 @@ SCRIPTS = \
HELPERS = \
pve-startall-delay \
pve-init-ceph-crash
pve-init-ceph-crash \
pve-firewall-commit \
pve-sdn-commit
MIGRATIONS = \
pve-lvm-disable-autoactivation
pve-lvm-disable-autoactivation \
pve-rbd-storage-configure-keyring
SERVICE_MANS = $(addsuffix .8, $(SERVICES))
CLI_MANS = \
$(addsuffix .1, $(CLITOOLS)) \
$(addsuffix .1, $(LIBEXECCLITOOLS)) \
pveversion.1 \
pveupgrade.1 \
pveperf.1 \
@ -45,10 +51,12 @@ CLI_MANS = \
BASH_COMPLETIONS = \
$(addsuffix .service-bash-completion, $(SERVICES)) \
$(addsuffix .bash-completion, $(CLITOOLS)) \
$(addsuffix .bash-completion, $(LIBEXECCLITOOLS)) \
ZSH_COMPLETIONS = \
$(addsuffix .service-zsh-completion, $(SERVICES)) \
$(addsuffix .zsh-completion, $(CLITOOLS)) \
$(addsuffix .zsh-completion, $(LIBEXECCLITOOLS)) \
all: $(SERVICE_MANS) $(CLI_MANS)
@ -61,13 +69,23 @@ all: $(SERVICE_MANS) $(CLI_MANS)
podselect $* > $@.tmp
mv $@.tmp $@
pve7to8.1:
printf ".TH PVE7TO8 1\n.SH NAME\npve7to8 \- Proxmox VE upgrade checker script for 7.4+ to current 8.x\n" > $@.tmp
printf ".SH DESCRIPTION\nThis tool will help you to detect common pitfalls and misconfguration\
before, and during the upgrade of a Proxmox VE system\n" >> $@.tmp
printf "Any failure must be addressed before the upgrade, and any warning must be addressed, \
or at least carefully evaluated, if a false-positive is suspected\n" >> $@.tmp
printf ".SH SYNOPSIS\npve7to8 [--full]\n" >> $@.tmp
pve-network-interface-pinning.1:
printf "pve-network-interface-pinning" > $@.tmp
printf ".TH PVE-NETWORK-INTERFACE-PINNING 1\n.SH NAME\npve-network-interface-pinning \- Assisted interface name pinning.\n" > $@.tmp
printf ".SH DESCRIPTION\nThis tool helps you to configure a network interface name pinning \
and adapting all relevant Proxmox VE config files.\n" >> $@.tmp
mv $@.tmp $@
pve-network-interface-pinning.api-verified:
perl ${PERL_DOC_INC} -T -e "use PVE::CLI::pve_network_interface_pinning; PVE::CLI::pve_network_interface_pinning->verify_api();"
touch 'pve-network-interface-pinning.service-api-verified'
pve-network-interface-pinning.zsh-completion:
perl ${PERL_DOC_INC} -T -e "use PVE::CLI::pve_network_interface_pinning; PVE::CLI::pve_network_interface_pinning->generate_zsh_completions();" >$@.tmp
mv $@.tmp $@
pve-network-interface-pinning.bash-completion:
perl ${PERL_DOC_INC} -T -e "use PVE::CLI::pve_network_interface_pinning; PVE::CLI::pve_network_interface_pinning->generate_bash_completions();" >$@.tmp
mv $@.tmp $@
pve8to9.1:
@ -86,16 +104,18 @@ pvereport.1.pod: pvereport
.PHONY: tidy
tidy:
echo $(SCRIPTS) $(HELPERS) $(MIGRATIONS) | xargs -n4 -P0 proxmox-perltidy
echo $(SCRIPTS) $(HELPERS) $(MIGRATIONS) $(LIBEXECCLITOOLS) | xargs -n4 -P0 proxmox-perltidy
.PHONY: check
check: $(addsuffix .service-api-verified, $(SERVICES)) $(addsuffix .api-verified, $(CLITOOLS))
check: $(addsuffix .service-api-verified, $(SERVICES)) $(addsuffix .api-verified, $(CLITOOLS)) $(addsuffix .api-verified, $(LIBEXECCLITOOLS))
rm -f *.service-api-verified *.api-verified
.PHONY: install
install: $(SCRIPTS) $(CLI_MANS) $(SERVICE_MANS) $(BASH_COMPLETIONS) $(ZSH_COMPLETIONS)
install: $(SCRIPTS) $(LIBEXECCLITOOLS) $(CLI_MANS) $(SERVICE_MANS) $(BASH_COMPLETIONS) $(ZSH_COMPLETIONS)
install -d $(BINDIR)
install -m 0755 $(SCRIPTS) $(BINDIR)
install -d $(LIBEXECDIR)
install -m 0755 $(LIBEXECCLITOOLS) $(LIBEXECDIR)
install -d $(USRSHARE)/helpers
install -m 0755 $(HELPERS) $(USRSHARE)/helpers
install -d $(USRSHARE)/migrations
@ -105,8 +125,10 @@ install: $(SCRIPTS) $(CLI_MANS) $(SERVICE_MANS) $(BASH_COMPLETIONS) $(ZSH_COMPLE
install -d $(MAN8DIR)
install -m 0644 $(SERVICE_MANS) $(MAN8DIR)
for i in $(CLITOOLS); do install -m 0644 -D $$i.bash-completion $(BASHCOMPLDIR)/$$i; done
for i in $(LIBEXECCLITOOLS); do install -m 0644 -D $$i.bash-completion $(BASHCOMPLDIR)/$$i; done
for i in $(SERVICES); do install -m 0644 -D $$i.service-bash-completion $(BASHCOMPLDIR)/$$i; done
for i in $(CLITOOLS); do install -m 0644 -D $$i.zsh-completion $(ZSHCOMPLDIR)/_$$i; done
for i in $(LIBEXECCLITOOLS); do install -m 0644 -D $$i.zsh-completion $(ZSHCOMPLDIR)/_$$i; done
for i in $(SERVICES); do install -m 0644 -D $$i.service-zsh-completion $(ZSHCOMPLDIR)/_$$i; done
.PHONY: clean

27
bin/pve-firewall-commit Normal file
View file

@ -0,0 +1,27 @@
#!/usr/bin/perl
use strict;
use warnings;
use Time::HiRes qw(usleep);
use PVE::Cluster;
use PVE::INotify;
for (my $i = 0; !PVE::Cluster::check_cfs_quorum(1); $i++) {
print "waiting for pmxcfs mount to appear and get quorate...\n"
if $i % 50 == 0;
usleep(100 * 1000);
}
my $local_node = PVE::INotify::nodename();
my $current_fw_config_file = "/etc/pve/nodes/$local_node/host.fw";
my $new_fw_config_file = "/etc/pve/nodes/$local_node/host.fw.new";
if (-e $new_fw_config_file) {
rename($new_fw_config_file, $current_fw_config_file)
or die "failed to commit new local node firewall config '$new_fw_config_file' - $!\n";
}
exit 0;

View file

@ -0,0 +1,8 @@
#!/usr/bin/perl
use strict;
use warnings;
use PVE::CLI::pve_network_interface_pinning;
PVE::CLI::pve_network_interface_pinning->run_cli_handler();

View file

@ -0,0 +1,23 @@
#!/usr/bin/perl
use strict;
use warnings;
use PVE::RPCEnvironment;
use PVE::Storage;
use PVE::CLI::pve8to9;
sub main {
PVE::RPCEnvironment->setup_default_cli_env();
my $cfg = PVE::Storage::config();
print "INFO: Starting with PVE 9, externally managed RBD storages require that the 'keyring'"
. " option is configured in the storage's Ceph configuration. This script creates and"
. " updates the storage's Ceph configurations.\n";
PVE::CLI::pve8to9::check_rbd_storage_keyring($cfg, 0);
}
main();

102
bin/pve-sdn-commit Normal file
View file

@ -0,0 +1,102 @@
#!/usr/bin/perl
use strict;
use warnings;
use Time::HiRes qw(usleep);
use PVE::Cluster;
use PVE::Network::SDN;
use PVE::Network::SDN::Zones;
use PVE::Network::SDN::Vnets;
use PVE::Network::SDN::Subnets;
use PVE::Network::SDN::Controllers;
use PVE::Network::SDN::Fabrics;
use PVE::Tools;
for (my $i = 0; !PVE::Cluster::check_cfs_quorum(1); $i++) {
print "waiting for pmxcfs mount to appear and get quorate...\n"
if $i % 50 == 0;
usleep(100 * 1000);
}
sub has_pending_changes {
my ($pending_config) = @_;
for my $entity (values $pending_config->{ids}->%*) {
return 1 if $entity->{state};
}
return 0;
}
sub fabrics_changed {
my $current_config = PVE::Network::SDN::Fabrics::config();
my $running_config = PVE::Network::SDN::Fabrics::config(1);
my ($running_fabrics, $running_nodes) = $running_config->list_all();
my ($current_fabrics, $current_nodes) = $current_config->list_all();
my $pending_fabrics = PVE::Network::SDN::pending_config(
{ fabrics => { ids => $running_fabrics } },
{ ids => $current_fabrics },
'fabrics',
);
my $pending_nodes = PVE::Network::SDN::pending_config(
{ nodes => { ids => $running_nodes } },
{ ids => $current_nodes },
'nodes',
);
return has_pending_changes($pending_fabrics) || has_pending_changes($pending_nodes);
}
sub sdn_changed {
my $running_config = PVE::Network::SDN::running_config();
my $configs = {
zones => PVE::Network::SDN::Zones::config(),
vnets => PVE::Network::SDN::Vnets::config(),
subnets => PVE::Network::SDN::Subnets::config(),
controllers => PVE::Network::SDN::Controllers::config(),
};
for my $type (keys $configs->%*) {
my $pending_config = PVE::Network::SDN::pending_config(
$running_config, $configs->{$type}, $type,
);
return 1 if has_pending_changes($pending_config);
}
return fabrics_changed();
}
if (!sdn_changed()) {
print "No changes to SDN configuration detected, skipping reload\n";
exit 0;
}
my $previous_config_has_frr = PVE::Network::SDN::running_config_has_frr();
PVE::Network::SDN::commit_config();
my $new_config_has_frr = PVE::Network::SDN::running_config_has_frr();
my $regenerate_frr = ($previous_config_has_frr || $new_config_has_frr);
PVE::Network::SDN::generate_etc_network_config();
PVE::Network::SDN::generate_dhcp_config();
my $err = sub {
my $line = shift;
if ($line =~ /(warning|error): (\S+):/) {
print "$2 : $line \n";
}
};
PVE::Tools::run_command(['ifreload', '-a'], errfunc => $err);
PVE::Network::SDN::generate_frr_config(1) if $regenerate_frr;
exit 0;

View file

@ -1,8 +0,0 @@
#!/usr/bin/perl
use strict;
use warnings;
use PVE::CLI::pve7to8;
PVE::CLI::pve7to8->run_cli_handler();

View file

@ -1,19 +1,16 @@
include ../defines.mk
all: country.dat
country.dat: country.pl
./country.pl > country.dat
all:
.PHONY: install
install: country.dat vzdump.conf pve-sources.sources pve-initramfs.conf pve-blacklist.conf pve.logrotate
install: vzdump.conf pve-sources.sources pve-initramfs.conf pve-blacklist.conf pve.logrotate virtual-function-pinning.rules virtual-function-pinning-helper
install -D -m 0644 pve.logrotate $(DESTDIR)/etc/logrotate.d/pve
install -D -m 0644 pve-sources.sources $(DESTDIR)/etc/apt/sources.list.d/pve-enterprise.sources
install -D -m 0644 pve-blacklist.conf $(DESTDIR)/etc/modprobe.d/pve-blacklist.conf
install -D -m 0644 vzdump.conf $(DESTDIR)/etc/vzdump.conf
install -D -m 0644 pve-initramfs.conf $(DESTDIR)/etc/initramfs-tools/conf.d/pve-initramfs.conf
install -D -m 0644 country.dat $(DESTDIR)/usr/share/$(PACKAGE)/country.dat
install -D -m 0644 proxmox-ve-default.link $(DESTDIR)/usr/lib/systemd/network/99-default.link.d/proxmox-mac-address-policy.conf
install -D -m 0644 virtual-function-pinning.rules $(DESTDIR)/usr/lib/udev/rules.d/70-virtual-function-pinning.rules
install -D -m 0755 virtual-function-pinning-helper $(DESTDIR)/usr/lib/udev/virtual-function-naming-helper
clean:
rm -f country.dat

View file

@ -1,81 +0,0 @@
#!/usr/bin/perl -w
use strict;
use PVE::Tools;
# see also: http://en.wikipedia.org/wiki/Keyboard_layout
#
# country codes from: /usr/share/zoneinfo/iso3166.tab
# timezones from: /usr/share/zoneinfo/zone.tab
# keymaps: find /usr/share/keymaps/i386/ -type f -name '*.kmap.gz'
# x11 layouts: /usr/share/X11/xkb/rules/xorg.lst
my $country = {};
my $line;
open(TMP, "</usr/share/zoneinfo/iso3166.tab");
while (defined($line = <TMP>)) {
if ($line =~ m/^([A-Z][A-Z])\s+(.*\S)\s*$/) {
$country->{ lc($1) } = $2;
}
}
close(TMP);
# we need mappings for X11, console, and kvm vnc
# LC(-LC)? => [DESC, kvm, console, X11, X11variant]
my $keymaps = PVE::Tools::kvmkeymaps();
foreach my $km (sort keys %$keymaps) {
my ($desc, $kvm, $console, $x11, $x11var) = @{ $keymaps->{$km} };
if ($km =~ m/^([a-z][a-z])-([a-z][a-z])$/i) {
defined($country->{$2}) || die "undefined country code '$2'";
} else {
defined($country->{$km}) || die "undefined country code '$km'";
}
$x11var = '' if !defined($x11var);
print "map:$km:$desc:$kvm:$console:$x11:$x11var:\n";
}
my $defmap = {
'us' => 'en-us',
'be' => 'fr-be',
'br' => 'pt-br',
'ca' => 'en-us',
'dk' => 'dk',
'nl' => 'en-us', # most Dutch people us US layout
'fi' => 'fi',
'fr' => 'fr',
'de' => 'de',
'at' => 'de',
'hu' => 'hu',
'is' => 'is',
'it' => 'it',
'va' => 'it',
'jp' => 'jp',
'lt' => 'lt',
'mk' => 'mk',
'no' => 'no',
'pl' => 'pl',
'pt' => 'pt',
'si' => 'si',
'es' => 'es',
'gi' => 'es',
'ch' => 'de-ch',
'gb' => 'en-gb',
'lu' => 'fr-ch',
'li' => 'de-ch',
};
my $mirrors = PVE::Tools::debmirrors();
foreach my $cc (keys %$mirrors) {
die "undefined country code '$cc'" if !defined($country->{$cc});
}
foreach my $cc (sort keys %$country) {
my $map = $defmap->{$cc} || '';
my $mir = $mirrors->{$cc} || '';
print "$cc:$country->{$cc}:$map:$mir:\n";
}

View file

@ -0,0 +1,37 @@
#!/bin/sh
set -eu
DEVICE_SYSFS_PCI_PATH=$(realpath "/sys${DEVPATH}/../..");
if [ ! -L "$DEVICE_SYSFS_PCI_PATH/physfn" ]; then
exit;
fi
PHYSFN_SYSFS_PCI_PATH=$(realpath "${DEVICE_SYSFS_PCI_PATH}/physfn");
PHYSFN_IFACE_NAME=$(ls "${PHYSFN_SYSFS_PCI_PATH}/net")
# interface is not pinned
if [ ! -f "/usr/local/lib/systemd/network/50-pve-${PHYSFN_IFACE_NAME}.link" ]; then
exit;
fi
# pin is not applied - or interface doesn't exist
if ! ip link show "$PHYSFN_IFACE_NAME" > /dev/null 2>&1 ; then
exit;
fi
DEVICE_PCI_ID=$(basename "$DEVICE_SYSFS_PCI_PATH");
for file in $(find "${PHYSFN_SYSFS_PCI_PATH=$}/" -maxdepth 1 -type l -name 'virtfn*' ); do
VF_PCI_ID=$(basename "$(realpath "$file")");
if [ "$DEVICE_PCI_ID" = "$VF_PCI_ID" ]; then
VF_INDEX=$(basename "$file" | grep -Eo '[[:digit:]]+$' -);
echo "${PHYSFN_IFACE_NAME}v${VF_INDEX}";
exit;
fi
done
echo "interface seems to be a VF of ${PHYSFN_IFACE_NAME}, but could not find the VF index" 1>&2;
exit;

View file

@ -0,0 +1 @@
SUBSYSTEM=="net", ACTION=="add", PROGRAM=="/usr/lib/udev/virtual-function-naming-helper", NAME="%c"

524
debian/changelog vendored
View file

@ -1,3 +1,527 @@
pve-manager (9.0.11) trixie; urgency=medium
* close #4248: ui: Add Reset button to right click context menu of virtual
machines, like available in the resource tree or the global search result.
* ui: guest snapshot: remove excess '}' at the end of window title
* fix #5244 pveceph: install: add new 'manual' repository option, which, for
example, can be useful for offline installation
* ui: ceph install wizard: add option and hint for 'manual' repository for,
e.g., offline installation through a Proxmox Offline Mirror managed
repository.
* fix typo in ifupdown2 version error message.
* update shipped appliance info index.
-- Proxmox Support Team <support@proxmox.com> Mon, 06 Oct 2025 19:03:25 +0200
pve-manager (9.0.10) trixie; urgency=medium
* ui: datacenter notes: fix visibility of top toolbar to allow editing the
notes again.
* api: node xterm.js and VNC shells: avoid nested login for already logged
in root@pam when tunneling to another node. This should avoid a race where
the shell hangs on load that seems to very rarely happen in Proxmox VE 9,
but currently the fix only covers the root@pam users. While this makes
this just a partial fix, as the issue is hard to reproduce it should not
only benefit some of the affected users, it will also help in confirming
the underlying root cause.
-- Proxmox Support Team <support@proxmox.com> Fri, 12 Sep 2025 18:05:12 +0200
pve-manager (9.0.9) trixie; urgency=medium
* ui: cluster dashboard: use higher warning thresholds for memory gauge and
the memory widget-column in the node overview table.
* cluster: resources: add sdn property to cluster resources return JSON
schema.
* ui: resource pool: never submit value of filter field when adding guests
to a pool.
-- Proxmox Support Team <support@proxmox.com> Wed, 10 Sep 2025 12:52:03 +0200
pve-manager (9.0.8) trixie; urgency=medium
* api: apt list updates: complete JSON return schema to be used in the API
viewer and API clients like PDM.
* api: cluster resource: fix performance regression causing O(n²) lookups
slowing the API response, and thus also the initial load of the web UI,
significantly down on setups with more than a few hundred, or even
thousands of virtual guests.
* ui: resource tree: various performance improvement for the main resource
tree, making initial load, updates and scrolling significantly more
responsive on setups with thousands of virtual guests.
* ui: VM cpu: recognize kebab-cased properties like while parsing to avoid
loosing the value of such a manually set option on edit.
* api: apt: ensure change log entries are encoded as valid UTF-8.
* ui: storage summary: set 'bytes' as unit for metrics graph.
* cli: pveceph: set use bytes renderer when listing a pool's content.
* ui: SDN: ensure fabrics property gets correctly removed when editing a
EVPN controller or a VXLAN zone.
* ui: pool: add members: make virtual guest window bigger and resizeable.
* ui: pool members: add filter for name, node or vmid when adding guests.
* update shipped appliance info index.
* api: cluster: metric server: increase timeout when fetching other nodes
metrics from 5s to 20s.
* api: cluster metrics export: support requesting the metrics from a
specific set of nodes through a new 'node-list' parameter.
* ui: node and virtual guest status: increase warning/critical threshold
percentage for memory usage from 75% to 90% and 90% to 97.5% percent,
respectively, as leveraging most of the memory installed is fine and often
even wanted.
-- Proxmox Support Team <support@proxmox.com> Mon, 08 Sep 2025 22:57:43 +0200
pve-manager (9.0.7) trixie; urgency=medium
* pve8to9: rework systemd-boot checks
* configs: drop unused country.dat file from install
* fix #6599: ui: use font-awesome hdd icon instead of png
* ui: icons: use svg versions where possible
* ui: properly center ceph icon
* api: ceph: add missing type to api schema
* fix #6747: ceph: osd: swap vg and lv arguments when creating an OSD
* fix #6385: ui: pool: members: fix store reload on add/remove
* ha: rule edit: fix enabling ha rules which are disabled
* api: use 'number' instead of 'amount' for countable nouns
-- Proxmox Support Team <support@proxmox.com> Tue, 02 Sep 2025 14:26:43 +0200
pve-manager (9.0.6) trixie; urgency=medium
* fix #6652: ceph: osd: enable autoactivation for OSD LVs on creation
* pve8to9: only allow systemd-boot when it is actually used before upgrade
* ui: ha: rules: fix edit button
-- Proxmox Support Team <support@proxmox.com> Wed, 20 Aug 2025 14:22:52 +0200
pve-manager (9.0.5) trixie; urgency=medium
* fix #6657: pveproxy: detect mobile firefox better
* ui: storage edit: warn about disabling snapshot-as-volume-chain on LVM
* ui: make sure more datacenter option renderers are html encoded
-- Proxmox Support Team <support@proxmox.com> Wed, 13 Aug 2025 13:00:02 +0200
pve-manager (9.0.4) trixie; urgency=medium
* 8to9 upgrade checks (pve8to9):
- skip check for running guests if already upgraded
- use check for unified cgroup v2 support via pve-container
- rework systemd-boot checks
- add check for removable GRUB entry
- support single-line repo entries with bracket options
- lvm config: check that --clear-needs-check-flag is set if there is a
thin_check_options override
* d/postinst: lvm config: check that --clear-needs-check-flag is set if there
is a thin_check_options override
-- Proxmox Support Team <support@proxmox.com> Fri, 08 Aug 2025 16:40:26 +0200
pve-manager (9.0.3) trixie; urgency=medium
* d/postinst: add snippet to manage systemd-tmpfiles configurations to
ensure they are updated on package upgrade.
-- Proxmox Support Team <support@proxmox.com> Tue, 05 Aug 2025 12:36:45 +0200
pve-manager (9.0.2) trixie; urgency=medium
* fix permission regression for '/run/pve' directory, which is now managed
by systemd's tmpfile mechanism. Ensure it's created with root:www-data
user:group.
-- Proxmox Support Team <support@proxmox.com> Tue, 05 Aug 2025 12:15:38 +0200
pve-manager (9.0.1) trixie; urgency=medium
* network-interface-pinning: move to libexec and rename but add symlink to
pve-network-pinning-tool into usr/bin.
* ui: node memory RRD: change ZFS ARC color to a blue shade and available
memory to a green shade for more visual difference.
* pveproxy service: use heuristic to trigger initial appliance update on
first boot.
* network: improve reloading logic for FFR config, trust flag if set, else
reload only if there is a FRR controller configured.
-- Proxmox Support Team <support@proxmox.com> Tue, 05 Aug 2025 12:07:04 +0200
pve-manager (9.0.0) trixie; urgency=medium
* bump for final Proxmox VE 9.0 release.
-- Proxmox Support Team <support@proxmox.com> Mon, 04 Aug 2025 23:13:26 +0200
pve-manager (9.0.0~22) trixie; urgency=medium
* sync over 8 to 9 upgrade checks from stable-8 branch.
* api: backup: remove unneeded call of rrd_dump method.
-- Proxmox Support Team <support@proxmox.com> Mon, 04 Aug 2025 21:43:25 +0200
pve-manager (9.0.0~21) trixie; urgency=medium
* ui: migration pre-conditions: make lack of support for conntrack state
migration only a info-level severity.
* sync over 8 to 9 upgrade checks from stable-8 branch.
* api: network: default to not regenerating the frr configuration using new
parameter from SDN stack.
-- Proxmox Support Team <support@proxmox.com> Mon, 04 Aug 2025 18:30:55 +0200
pve-manager (9.0.0~20) trixie; urgency=medium
* api: node status: add the available memory to return value.
* ui: avoid stacked graphs for memory usage, can easily lead to confusion as
y-axis does not match the values anymore.
* ui: node memory RRD: add 'Available' graph.
* ui: ignore backend 501 error for migration precondition checks, most
likely stems from using a new web UI version operating on an older node,
e.g., when during the major upgrade.
-- Proxmox Support Team <support@proxmox.com> Mon, 04 Aug 2025 16:58:46 +0200
pve-manager (9.0.0~19) trixie; urgency=medium
* ui: ha affinity rules: use single data store and mirror it to child grids,
this avoids loading the data twice which then also ensures that they both
show the same consistent view of the ruleset.
* ui: ha affinity rules: various small UX polishing:
- give resource rule some more vertical space.
- add ID column but hide by default for now.
- give resource rules some more vertical space.
* ui: guest migrate: adapt HA migration checks to new property name also for
Containers.
-- Proxmox Support Team <support@proxmox.com> Sat, 02 Aug 2025 19:42:57 +0200
pve-manager (9.0.0~18) trixie; urgency=medium
* sync over 8 to 9 upgrade checks from stable-8 branch.
* ui: RRD graphs: display PSI as percent again
* ui: guest migrate: fix logging unexpected errors to developer
console.
* ui: guest migrate: adapt HA migration checks to altered property name
* ui: sdn: allow sorting the IPAM and DHCP view by guest ID.
-- Proxmox Support Team <support@proxmox.com> Fri, 01 Aug 2025 18:41:47 +0200
pve-manager (9.0.0~17) trixie; urgency=medium
* make Yew based mobile UI package a required dependency and completely drop
legacy sencha-touch based mobile UI.
* ui: ha affinity rules: add CRUD ui for resource-to-resource rules.
* ui: VM & CT migration: display precondition messages for HA resource
affinity blockers.
-- Proxmox Support Team <support@proxmox.com> Thu, 31 Jul 2025 11:46:10 +0200
pve-manager (9.0.0~16) trixie; urgency=medium
* ui: replace HA Groups CRUD with new HA Affinity Rules CRUD.
* api: route new ha affinity rules endpoints.
* ui: ha: support new per-resources failback flag.
-- Proxmox Support Team <support@proxmox.com> Thu, 31 Jul 2025 09:10:41 +0200
pve-manager (9.0.0~15) trixie; urgency=medium
* pvestatd: collect and distribute new pve-{type}-9.0 metrics, with new
columns (pressure stall information, ZFS ARC, ...) and higher
time granularity.
* ui: node summary: use stacked memory graph with zfs arc.
* ui: add pressure stall information graphs to node and guest summary views.
* fix #6068: ui: qemu RRD metrics: improve calculation of actual on-host
memory usage by using the sum of the proportional set sizes for all
processes inside a VMs resource cgroup slice.
* post-installation: run promox-rrd-migration-tool to automatically migrate
existing data from previous format to new one.
* 8 to 9 upgrade: add checks for RRD metrics migration and increased on-disk
space usage needs.
* ui: RRD graphs: use title-case for titles.
-- Proxmox Support Team <support@proxmox.com> Thu, 31 Jul 2025 06:01:44 +0200
pve-manager (9.0.0~14) trixie; urgency=medium
* http server: drop legacy yew mobile paths and fix yew mtime path.
* ui: lxc create wizard: always submit unprivileged field.
-- Proxmox Support Team <support@proxmox.com> Thu, 31 Jul 2025 01:11:57 +0200
pve-manager (9.0.0~13) trixie; urgency=medium
* debian: add tpmfiles.d config to create /run/pve directory.
* pvestatd: prevent warnings for non-existing network devices.
* close #2809: replication: use new VM.Replicate privilege.
* backup: drop 'maxfiles' parameter, it was replaced by the more flexible
keep-X prune settings in PVE 7.0 already.
* api: expose new qemu migration capabilities endpoint.
* ui: migrate window: add checkbox for migrating VM conntrack state.
* http server: fix caching of i18n translation files, use mtime.
* http server: rework location for yew-mobile UI and provide mtimes.
-- Proxmox Support Team <support@proxmox.com> Thu, 31 Jul 2025 00:27:24 +0200
pve-manager (9.0.0~12) trixie; urgency=medium
* 8to9 upgrade checks: sync over version from PVE 8.4 stable branch.
* external metric server: add support for OpenTelemetry.
* network-interface-pinning:
- use ifindex as order for pinning.
- improve printing mapping.
- add 'target-name' parameter.
- allow arbitrary target name and prefixes.
* fix #6534: ui: keep displaying help button in backup edit dialog.
* replace sencha touch mobile web UI by default with new Yew based one
written in rust. The new pve-yew-mobile-gui package can still be removed
to get the old package back, but it's planned to drop the outdated sencha
touch based mobile UI completely soon.
* pvestatd: pull metric: use ip link to detect physical interfaces, but
cache the data and update it only every 15 minutes to avoid frequent
polling, physical interfaces are not likely to change frequently.
* fix #5392: pveproxy, pvedaemon: make maximum number of worker configurable.
-- Proxmox Support Team <support@proxmox.com> Tue, 29 Jul 2025 21:17:14 +0200
pve-manager (9.0.0~11) trixie; urgency=medium
* 8to9 upgrade checks: machine version: place VMIDs in dedicated line.
* fix #6537: api: system services: system unit for postfix is again a normal
service in Trixie.
* ui: base storage: fix outdated wording in tech-preview hint.
* fix #6539: apl: use sqv instead of gpgv to verify signatures.
* network-interface-pinning: do not generate link files for virtual
functions (VFs).
* network-interface-pinning: fix pinning for bond members.
-- Proxmox Support Team <support@proxmox.com> Tue, 22 Jul 2025 23:33:37 +0200
pve-manager (9.0.0~10) trixie; urgency=medium
* d/postinst: only set-up pve-test repos for beta on fresh
installation as upgrades must have a valid repo already anyway, otherwise
they could not upgrade in the first place.
* 8to9 upgrade checks: fix calling the method for parsing network defices
from a VM config, it got moved in Proxmox VE 9 into a dedicated module.
-- Proxmox Support Team <support@proxmox.com> Sat, 19 Jul 2025 20:56:45 +0200
pve-manager (9.0.0~9) trixie; urgency=medium
* guest metrics: drop support for ancient RRD schema from before Proxmox VE
2.3 from 2013.
* guest metrics: support and prefer new pve-{type}-9.0 RRD files.
* network-interface-pinning: fix subsequent invocations.
* network-interface-pinning: early exit if nothing to do.
-- Proxmox Support Team <support@proxmox.com> Fri, 18 Jul 2025 20:48:14 +0200
pve-manager (9.0.0~8) trixie; urgency=medium
* ui: add beta text with link to bug tracker
-- Proxmox Support Team <support@proxmox.com> Fri, 18 Jul 2025 15:39:55 +0200
pve-manager (9.0.0~7) trixie; urgency=medium
* d/postinst: setup pve-test repo for updates during the beta phase.
-- Proxmox Support Team <support@proxmox.com> Fri, 18 Jul 2025 15:24:25 +0200
pve-manager (9.0.0~6) trixie; urgency=medium
* ui: dc/options: allow one to edit cluster wide replication settings.
* ui: disk storage selector: fix check for disabling format selector.
* 8to9 upgrade checks: fix duplicate variable name in same scope.
* fabrics: add max-length to fabric name to improve error message.
* ui: adapt to dropped VM.Monitor privilege.
* network-interface-pinning: avoid comparing undefined string.
* sdn-commit, firewall-commit: wait for cluster quorum.
* sdn-commit: only reload ifupdown if sdn configuration changed.
-- Proxmox Support Team <support@proxmox.com> Fri, 18 Jul 2025 14:39:57 +0200
pve-manager (9.0.0~5) trixie; urgency=medium
* pve8to9: sync upgrade checks from stable branch.
* api: apt versions: drop glusterfs-client from package list.
* ui: storage edit: only LVM supports changing ext. snapshots for existing
storages.
* ui: storage base: rename label to "Allow Snapshots as Volume-Chain".
* ui: qemu: network: adjust MTU emptyText to match new default behavior.
* fabric: increase width of fabric edit/add window and add empty text
attributes to some input fields.
* pve-sdn-commit: fix reloading logic.
* proxmox-network-interface-pinning: add fabrics support.
* api: capabilities: proxy index endpoints to respective nodes.
-- Proxmox Support Team <support@proxmox.com> Thu, 17 Jul 2025 23:35:02 +0200
pve-manager (9.0.0~4) trixie; urgency=medium
* ui: backup job edit: move notification related settings to separate tab.
* ui: one-shot backup: remove 'auto' notification mode for clarity.
* ui: oneshot backup: stop shifting UI when selecting 'legacy-sendmail'.
* pvescheduler: move PID file from aliased /var/run legacy path into the
underlying /run directory.
* cli: add proxmox-network-interface-pinning tool.
* services: add pve-sdn-commit and pve-firewall-commit for applying pending
changes on boot.
* ui: drop support for adding native GlusterFS storage, like it was done
already for QEMU and the pve-storage library.
* ui: base storage: add checkbox for storage-managed (external) snapshots
for supported storage types.
* api: use new SDN config generation functions.
* ui: add SDN fabrics management.
* api/ui: show/return alternative interface names for node network
interfaces.
* ui: login: display error messages and status on failure.
-- Proxmox Support Team <support@proxmox.com> Thu, 17 Jul 2025 02:33:52 +0200
pve-manager (9.0.0~3) trixie; urgency=medium
* pve8to9: sync checks from stable branch.
* ui: enable online helplinks for VM audio edit panel and TPM panel.
* ui: enable online helplinks for tag config view.
* api: node services: track lxcfs, proxmox-firewall, pve-lxc-syscalld,
qmeventd units.
* ui: ceph: drop releases that are not available on PVE 9.
* pveceph: switch repo sources to modern deb822 format.
* ui: remove handling of obsolete notification-policy/target settings.
* ui: backup job details: show notification-mode instead of legacy keys.
* ui: guest importer: use modern 4MB EFI-type for imported VMs that use EFI
as firmware.
* ui: qemu disk edit: allow importing a disk from the import storage.
* ui: vm create wizard: allow importing disks directly from an import
storage.
* ui: import storage content: allow importing disks to existing VM disk
images from an import storage.
* fix #5894: pvestatd: always re-broadcast of node version-info if we cannot
find any information for our node.
-- Proxmox Support Team <support@proxmox.com> Wed, 16 Jul 2025 02:48:30 +0200
pve-manager (9.0.0~2) trixie; urgency=medium
* d/control: run all binary tragets under (fake)root to ensure dpkg-deb

36
debian/control vendored
View file

@ -11,7 +11,7 @@ Build-Depends: debhelper-compat (= 13),
libpve-access-control (>= 8.0.7),
libpve-cluster-api-perl,
libpve-cluster-perl (>= 6.1-6),
libpve-common-perl (>= 8.2.3),
libpve-common-perl (>= 9.0.4),
libpve-guest-common-perl (>= 5.1.1),
libpve-http-server-perl (>= 2.0-12),
libpve-notify-perl,
@ -24,8 +24,8 @@ Build-Depends: debhelper-compat (= 13),
proxmox-widget-toolkit (>= 4.1.4),
pve-cluster,
pve-container,
pve-doc-generator (>= 8.3.2),
qemu-server (>= 8.0~~),
pve-doc-generator (>= 9.0.5),
qemu-server (>= 9.0.10~~),
sq,
unzip,
Rules-Requires-Root: binary-targets
@ -51,24 +51,23 @@ Depends: apt (>= 1.5~),
libfilesys-df-perl,
libjs-extjs (>= 7.0.0),
libjs-qrcodejs (>= 1.20201119),
libjs-sencha-touch,
libjson-perl,
liblwp-protocol-https-perl,
libnet-dns-perl,
libproxmox-acme-perl,
libproxmox-acme-plugins,
libproxmox-rs-perl (>= 0.3.4),
libpve-access-control (>= 8.2.0),
libproxmox-rs-perl (>= 0.4~),
libpve-access-control (>= 9.0.3),
libpve-cluster-api-perl (>= 7.0-5),
libpve-cluster-perl (>= 8.1.0),
libpve-common-perl (>= 8.2.6),
libpve-common-perl (>= 9.0.8),
libpve-guest-common-perl (>= 5.1.4),
libpve-http-server-perl (>= 5.1.1),
libpve-network-api-perl (>= 0.9.9~),
libpve-network-perl (>= 0.9~),
libpve-http-server-perl (>= 6.0.3),
libpve-network-api-perl (>= 1.1~),
libpve-network-perl (>= 1.1~),
libpve-notify-perl (>= 8.1.0),
libpve-rs-perl (>= 0.8.12),
libpve-storage-perl (>= 8.3.6),
libpve-rs-perl (>= 0.10.4),
libpve-storage-perl (>= 9.0.5),
librados2-perl (>= 1.3-1),
libtemplate-perl,
libterm-readline-gnu-perl,
@ -83,17 +82,20 @@ Depends: apt (>= 1.5~),
postfix | mail-transport-agent,
proxmox-mail-forward,
proxmox-mini-journalreader (>= 1.3-1),
proxmox-widget-toolkit (>= 4.3.5),
pve-cluster (>= 8.0.5),
proxmox-rrd-migration-tool (>= 1.0.0),
proxmox-widget-toolkit (>= 5.0.2),
pve-cluster (>= 9.0.1),
pve-container (>= 5.2.5),
pve-docs (>= 8.2.4),
pve-docs (>= 9.0.5),
pve-firewall,
pve-ha-manager,
pve-ha-manager (>= 5.0.3),
pve-i18n (>= 3.2.0~),
pve-xtermjs (>= 4.7.0-1),
qemu-server (>= 8.3.11),
pve-yew-mobile-gui (>= 0.5.1),
qemu-server (>= 9.0.10),
rsync,
spiceterm,
sqv,
systemd,
vncterm,
wget,

28
debian/copyright vendored
View file

@ -1,4 +1,4 @@
Copyright (C) 2010-2024 Proxmox Server Solutions GmbH
Copyright (C) 2010-2025 Proxmox Server Solutions GmbH
This software is written by Proxmox Server Solutions GmbH <support@proxmox.com>
@ -41,29 +41,3 @@ open source applications that are distributed under a license other than GPL.
* Open Source License Exception for Development
http://www.sencha.com/products/ux-exception.php
------------------------------
Bootstrap html framework:
The MIT License (MIT)
Copyright (c) 2011-2014 Twitter, Inc
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

2
debian/links vendored Normal file
View file

@ -0,0 +1,2 @@
usr/libexec/proxmox/pve-network-interface-pinning usr/bin/pve-network-interface-pinning

67
debian/postinst vendored
View file

@ -9,9 +9,15 @@ set -e
# installed and configured.
set_lvm_conf() {
# shellcheck disable=SC3043
local FORCE="$1"
LVM_CONF_MARKER="# added by pve-manager to avoid scanning"
if [ ! -e /etc/lvm/lvm.conf ]; then
echo "No /etc/lvm/lvm.conf found - skipping checking the global_filter."
return
fi
# keep user changes afterwards provided marker is still there..
if grep -qLF "$LVM_CONF_MARKER" /etc/lvm/lvm.conf && test -z "$FORCE"; then
return 0 # only do these changes once
@ -46,16 +52,21 @@ set_lvm_conf() {
echo "Backing up lvm.conf before setting pve-manager specific settings.."
cp -vb /etc/lvm/lvm.conf /etc/lvm/lvm.conf.bak
fi
NEW_MARKER="$LVM_CONF_MARKER ZFS zvols and Ceph rbds"
if test -n "$SET_FILTER"; then
echo "Setting 'global_filter' in /etc/lvm/lvm.conf to prevent zvols and rbds from being scanned:"
echo "$OLD_VALUE => $NEW_VALUE"
if test -n "$OLD_VALUE"; then
sed -i -e "s/$LVM_CONF_MARKER ZFS zvols/$LVM_CONF_MARKER ZFS zvols and Ceph rbds/" /etc/lvm/lvm.conf
sed -i -e "s!^\([[:space:]]*\)\(global_filter[[:space:]]*=.*\)\$!\1# \2\n\1$NEW_VALUE!" /etc/lvm/lvm.conf
if grep -qLF "$LVM_CONF_MARKER" /etc/lvm/lvm.conf; then
sed -i -e "s/$LVM_CONF_MARKER ZFS zvols/$NEW_MARKER/" /etc/lvm/lvm.conf
sed -i -e 's!^\([[:space:]]*\)\(global_filter[[:space:]]*=.*\)$!\1# \2\n\1'"$NEW_VALUE"'!' /etc/lvm/lvm.conf
else
sed -i -e 's!^\([[:space:]]*\)\(global_filter[[:space:]]*=.*\)$!\1# \2\n\1'"$NEW_MARKER"'\n\1'"$NEW_VALUE"'!' /etc/lvm/lvm.conf
fi
else
cat >> /etc/lvm/lvm.conf <<EOF
devices {
$LVM_CONF_MARKER ZFS zvols and Ceph rbds
$NEW_MARKER
$NEW_VALUE
}
EOF
@ -122,6 +133,13 @@ migrate_apt_auth_conf() {
fi
}
# Copied from dh_installtmpfiles/13.24.2
if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ] || [ "$1" = "abort-deconfigure" ] || [ "$1" = "abort-remove" ] ; then
if [ -x "$(command -v systemd-tmpfiles)" ]; then
systemd-tmpfiles ${DPKG_ROOT:+--root="$DPKG_ROOT"} --create pve-manager.conf || true
fi
fi
case "$1" in
triggered)
# We don't print a status message here, as dpkg already said
@ -155,22 +173,12 @@ case "$1" in
pveam update || true
fi
# Always try to clean old entry, even when proxmox-mail-forward entry is already present.
# This ensures it will still be cleaned after an upgrade following a downgrade.
if test -f /root/.forward; then
sed -i '\!|/usr/bin/pvemailforward!d' /root/.forward
fi
if ! test -f /root/.forward || ! grep -q '|/usr/bin/proxmox-mail-forward' /root/.forward; then
echo '|/usr/bin/proxmox-mail-forward' >>/root/.forward
fi
systemctl --system daemon-reload >/dev/null || true
# same as dh_systemd_enable (code copied)
UNITS="pvedaemon.service pveproxy.service spiceproxy.service pvestatd.service pvebanner.service pvescheduler.service pve-daily-update.timer"
NO_RESTART_UNITS="pvenetcommit.service pve-guests.service"
NO_RESTART_UNITS="pvenetcommit.service pve-guests.service pve-sdn-commit.service pve-firewall-commit.service"
for unit in ${UNITS} ${NO_RESTART_UNITS}; do
deb-systemd-helper unmask "$unit" >/dev/null || true
@ -187,21 +195,20 @@ case "$1" in
fi
done
# FIXME: remove after beta is over and add hunk to actively remove the repo
BETA_SOURCES="/etc/apt/sources.list.d/pvetest-for-beta.list"
if test -f "$BETA_SOURCES" && dpkg --compare-versions "$2" 'lt' '8.0.2' && dpkg --compare-versions "$2" 'gt' '8.0~'; then
echo "Removing the during beta added pvetest repository file again"
BETA_SOURCES="/etc/apt/sources.list.d/pve-test-for-beta.sources"
if test -f "$BETA_SOURCES" && dpkg --compare-versions "$2" 'lt' '9.0.1' && dpkg --compare-versions "$2" 'gt' '9.0~~'; then
printf "\nNOTE: Remove the pve-test repository, which was added during the beta phase.\nYou can (re-)add repositories on the web UI (Node -> Repositories)\n\n"
rm -v "$BETA_SOURCES" || true
fi
if test ! -e /proxmox_install_mode && test -n "$2" && dpkg --compare-versions "$2" 'lt' '8.1.4~'; then
if test -e /etc/lvm/lvm.conf ; then
set_lvm_conf 1
fi
# TODO: remove with PVE 10
# pass FORCE as we want to ensure the filter for RBDs gets added to our existing one.
set_lvm_conf 1
else
set_lvm_conf
fi
set_lvm_conf
if test -n "$2" && dpkg --compare-versions "$2" 'lt' '8.1.11'; then
update_ceph_conf
fi
@ -225,6 +232,20 @@ case "$1" in
migrate_apt_auth_conf
fi
fi
if test -n "$2" && dpkg --compare-versions "$2" 'lt' '9.0.0~15'; then
printf '\n\nNOTE: Migrating existing RRD metrics data from nodes, storages and virtual guests to new PVE format version - this can take some time!\n\n'
/usr/libexec/proxmox/proxmox-rrd-migration-tool --migrate || \
echo "migration failed, see output above for errors and try to migrate existing data manually by running '/usr/libexec/proxmox/proxmox-rrd-migration-tool --migrate'"
fi
if test -n "$2" && dpkg --compare-versions "$2" 'lt' '9.0.4'; then
if test -e /etc/lvm/lvm.conf && grep "^\s*thin_check_options" /etc/lvm/lvm.conf | grep -qv -- "--clear-needs-check-flag"; then
printf '\nNOTE: Detected override for 'thin_check_options' without '--clear-needs-check-flag' option in /etc/lvm/lvm.conf\n'
printf 'Add the option to the override or thin pools with minor issues might not automatically activate anymore!\n\n'
fi
fi
;;
abort-upgrade|abort-remove|abort-deconfigure)

2
debian/tmpfiles vendored Normal file
View file

@ -0,0 +1,2 @@
#Type Path Mode User Group Age Argument
d /run/pve 0750 root www-data - -

View file

@ -1,6 +1,7 @@
PACKAGE=pve-manager
BINDIR=$(DESTDIR)/usr/bin
LIBEXECDIR=$(DESTDIR)/usr/libexec/proxmox
PERLLIBDIR=$(DESTDIR)/usr/share/perl5
MAN1DIR=$(DESTDIR)/usr/share/man/man1
MAN8DIR=$(DESTDIR)/usr/share/man/man8

View file

@ -13,7 +13,9 @@ SERVICES= \
pve-storage.target \
pve-daily-update.service\
pve-daily-update.timer \
pvescheduler.service
pvescheduler.service \
pve-sdn-commit.service \
pve-firewall-commit.service
.PHONY: install
install: $(SERVICES)

View file

@ -0,0 +1,13 @@
[Unit]
Description=Commit Proxmox VE Firewall changes
DefaultDependencies=no
Wants=pve-cluster.service
After=corosync.service
[Service]
ExecStart=/usr/share/pve-manager/helpers/pve-firewall-commit
Type=oneshot
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,13 @@
[Unit]
Description=Commit Proxmox VE SDN changes
DefaultDependencies=no
Wants=pve-cluster.service network.target
After=frr.service network.target corosync.service
[Service]
ExecStart=/usr/share/pve-manager/helpers/pve-sdn-commit
Type=oneshot
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target

View file

@ -13,6 +13,7 @@ After=ssh.service
[Service]
ExecStartPre=-/usr/bin/pvecm updatecerts --silent
ExecStart=/usr/bin/pveproxy start
ExecStartPost=-sh -c '[ ! -e /var/log/pveam.log ] && /usr/bin/pveupdate'
ExecStop=/usr/bin/pveproxy stop
ExecReload=/usr/bin/pveproxy restart
PIDFile=/run/pveproxy/pveproxy.pid

View file

@ -10,7 +10,7 @@ After=pve-storage.target
ExecStart=/usr/bin/pvescheduler start
ExecStop=/usr/bin/pvescheduler stop
ExecReload=/usr/bin/pvescheduler restart
PIDFile=/var/run/pvescheduler.pid
PIDFile=/run/pvescheduler.pid
KillMode=process
Type=forking

View file

@ -2,7 +2,7 @@
Description=PVE Status Daemon
ConditionPathExists=/usr/bin/pvestatd
Wants=pve-cluster.service
After=pve-cluster.service
After=pve-cluster.service pvenetcommit.service
[Service]
ExecStart=/usr/bin/pvestatd start

View file

@ -105,78 +105,6 @@ my @tests = (
},
},
# TODO make parse error critical?
{
description => 'maxfiles vzdump 1',
vzdump_param => {
maxfiles => 0,
},
expected => {
'prune-backups' => {
'keep-all' => 1,
},
remove => 0,
},
},
{
description => 'maxfiles vzdump 2',
vzdump_param => {
maxfiles => 7,
},
expected => {
'prune-backups' => {
'keep-last' => 7,
},
remove => 1,
},
},
{
description => 'maxfiles storage 1',
storage_param => {
maxfiles => 0,
},
expected => {
'prune-backups' => {
'keep-all' => 1,
},
remove => 0,
},
},
{
description => 'maxfiles storage 2',
storage_param => {
maxfiles => 7,
},
expected => {
'prune-backups' => {
'keep-last' => 7,
},
remove => 1,
},
},
{
description => 'maxfiles CLI 1',
cli_param => {
maxfiles => 0,
},
expected => {
'prune-backups' => {
'keep-all' => 1,
},
remove => 0,
},
},
{
description => 'maxfiles CLI 2',
cli_param => {
maxfiles => 7,
},
expected => {
'prune-backups' => {
'keep-last' => 7,
},
remove => 1,
},
},
{
description => 'prune-backups vzdump 1',
vzdump_param => {
@ -219,19 +147,6 @@ my @tests = (
remove => 0,
},
},
{
description => 'both vzdump 1',
vzdump_param => {
'prune-backups' => 'keep-all=1',
maxfiles => 7,
},
expected => {
'prune-backups' => {
'keep-all' => 1,
},
remove => 0,
},
},
{
description => 'prune-backups storage 1',
storage_param => {
@ -275,21 +190,6 @@ my @tests = (
remove => 0,
},
},
{
description => 'both storage 1',
storage_param => {
'prune-backups' => 'keep-hourly=1,keep-monthly=2,keep-yearly=3',
maxfiles => 0,
},
expected => {
'prune-backups' => {
'keep-hourly' => 1,
'keep-monthly' => 2,
'keep-yearly' => 3,
},
remove => 1,
},
},
{
description => 'prune-backups CLI 1',
cli_param => {
@ -329,19 +229,10 @@ my @tests = (
expected => "format error\n"
. "foo: property is not defined in schema and the schema does not allow additional properties\n",
},
{
description => 'both CLI 1',
cli_param => {
'prune-backups' => 'keep-hourly=1,keep-monthly=2,keep-yearly=3',
maxfiles => 4,
},
expected => "400 Parameter verification failed.\n"
. "prune-backups: option conflicts with option 'maxfiles'\n",
},
{
description => 'mixed 1',
vzdump_param => {
maxfiles => 7,
'prune-backups' => 'keep-last=7',
},
storage_param => {
'prune-backups' => 'keep-hourly=24',
@ -357,7 +248,7 @@ my @tests = (
{
description => 'mixed 2',
vzdump_param => {
maxfiles => 7,
'prune-backups' => 'keep-last=7',
},
storage_param => {
'prune-backups' => 'keephourly=24',
@ -372,7 +263,7 @@ my @tests = (
{
description => 'mixed 3',
vzdump_param => {
maxfiles => 7,
'prune-backups' => 'keep-last=7',
},
cli_param => {
'prune-backups' => 'keep-all=1',
@ -387,7 +278,7 @@ my @tests = (
{
description => 'mixed 4',
vzdump_param => {
maxfiles => 7,
'prune-backups' => 'keep-last=7',
},
storage_param => {
'prune-backups' => 'keep-all=0,keep-last=10',
@ -405,7 +296,7 @@ my @tests = (
{
description => 'mixed 5',
vzdump_param => {
maxfiles => 7,
'prune-backups' => 'keep-last=7',
},
storage_param => {
'prune-backups' => 'keep-all=0,keep-last=10',
@ -650,7 +541,6 @@ foreach my $test (@tests) {
my $vzdump = PVE::VZDump->new('fake cmdline', $test->{cli_param}, undef);
my $opts = $vzdump->{opts} or die "did not get options\n";
die "maxfiles is defined" if defined($opts->{maxfiles});
my $res = {};
foreach my $opt (@{$tested_options}) {

View file

@ -1,5 +1,5 @@
include ../defines.mk
SUBDIRS = images css manager6 mobile
SUBDIRS = images css manager6
all:
@ -14,6 +14,10 @@ install:
check:
$(MAKE) -C manager6 $@
.PHONY: tidy
tidy:
$(MAKE) -C manager6 $@
.PHONY: clean
clean:
set -e && for i in $(SUBDIRS); do $(MAKE) -C $$i $@; done

View file

@ -92,13 +92,7 @@
/* loading in task list */
.x-grid-row-loading {
background: no-repeat center center;
background-image: url(../ext6/theme-crisp/resources/images/loadmask/loading.gif);
}
/* console icon in task list */
.x-grid-row-console {
background: no-repeat center center;
background-image: url(../images/icon-display.png);
background-image: url(../images/spinner.svg);
}
/* for font-awesome colors */
@ -256,7 +250,7 @@
.pve-itype-treelist-item-icon-cdrom {
top: 50%;
transform: translateY(-50%);
content: url(../images/icon-cd.png);
content: url(../images/icon-cd-drive.svg);
}
/* the lxc template */
@ -296,27 +290,15 @@
}
.pve-itype-icon-virt-viewer,
.pve-itype-icon-tigervnc,
.pve-itype-icon-novnc,
.pve-itype-icon-xtermjs,
.pve-itype-icon-display,
.pve-itype-icon-network,
.pve-itype-icon-network-server,
.pve-itype-icon-keyboard,
.pve-itype-icon-cdrom,
.pve-itype-icon-qemu,
.pve-itype-icon-qemu-template,
.pve-itype-icon-qemu-running,
.pve-itype-icon-lxc,
.pve-itype-icon-lxc-template,
.pve-itype-icon-lxc-running,
.pve-itype-icon-swap,
.pve-itype-icon-node,
.pve-itype-icon-node-running,
.pve-itype-icon-storage,
.pve-itype-icon-pool,
.pve-itype-icon-itype,
.pve-itype-icon-usb,
.pve-itype-icon-serial,
.pve-itype-icon-cloud,
.pve-itype-icon-pci,
@ -342,84 +324,24 @@
font-size: 14px;
}
.pve-itype-icon-qemu,
.x-tree-node-computer,
.x-grid-tree-node-expanded .x-tree-node-computer {
background-image: url(../images/icon-display.png);
}
.pve-itype-icon-lxc,
.x-tree-node-lxc,
.x-grid-tree-node-expanded .x-tree-node-lxc {
background-image: url(../images/lxc-off.png);
}
.pve-itype-icon-swap,
.x-tree-node-lxc-swap,
.x-grid-tree-node-expanded .x-tree-lxc-swap {
background-image: url(../images/icon-swap.png);
}
.pve-itype-icon-lxc-running,
.x-tree-node-lxc-running,
.x-grid-tree-node-expanded .x-tree-node-lxc-running {
background-image: url(../images/lxc-on.png);
}
.pve-itype-icon-storage,
.x-tree-node-harddisk,
.x-grid-tree-node-expanded .x-tree-node-harddisk {
background-image: url(../images/icon-harddisk.png);
}
.x-tree-node-snapshot,
.x-grid-tree-node-expanded .x-tree-node-snapshot {
background-image: url(../images/snapshot.png);
}
.pve-itype-icon-itype {
background-image: url(../ext6/theme-classic/resources/images/tree/folder.gif);
}
.pve-itype-icon-network-server {
background-image: url(../images/network-server.png);
}
.pve-itype-icon-network {
background-image: url(../images/icon-network.png);
}
.pve-itype-icon-keyboard {
background-image: url(../images/icon-keyboard.png);
}
.pve-itype-icon-cdrom {
background-size: 16px;
background-image: url(../images/icon-cd-drive.svg);
}
.pve-itype-icon-display {
background-image: url(../images/icon-display.png);
}
.pve-itype-icon-tigervnc {
background-image: url(../images/tigervnc.png);
}
.pve-itype-icon-novnc {
background-image: url(../images/novnc.png);
background-size: 16px;
background-image: url(../images/novnc.svg);
}
.pve-itype-icon-virt-viewer {
background-image: url(../images/virt-viewer.png);
background-size: 16px;
background-image: url(../images/virt-viewer.svg);
}
.pve-itype-icon-xtermjs {
background-image: url(../images/xtermjs.png);
}
.pve-itype-icon-usb {
background-image: url(../images/icon-usb.png);
background-size: 16px;
background-image: url(../images/xtermjs.svg);
}
.pve-itype-icon-pci {
@ -522,8 +444,8 @@ div.right-aligned {
height: 14px;
position: absolute;
left: 1px;
top: 4px;
background-image: url(../images/logo-ceph.png);
top: 5px;
background-image: url(../images/logo-ceph.svg);
background-size: 14px 14px;
content: " ";
}

View file

@ -2,93 +2,50 @@ include ../../defines.mk
all:
# start.png /usr/share/icons/gnome/16x16/actions/media-playback-start.png
# stop.png /usr/share/icons/gnome/16x16/actions/media-playback-stop.png
# computer-template.png /usr/share/icons/gnome/16x16/mimetypes/gnome-mime-application-vnd.sun.xml.calc.template.png
# virt-viewer.svg copied from virt-viewer source (and reformatted):
# https://github.com/webrulon/virt-viewer/blob/master/icons/virt-viewer.svg
#
# novnc.svg copied from the noVnc source:
# https://github.com/novnc/noVNC/blob/master/app/images/icons/novnc-icon-sm.svg
# virt-viewer.png copied from virt-viewer sources
# tigervnc.png converted from tigervnc sources
# (tigervnc.org/media/tigervnc_16.svg)
# checked.png converted from extjs examples/ux/css/images/checked.gif
# unchecked.png converted from extjs examples/ux/css/images/unchecked.gif
# swap.png downloaded from https://www.iconfinder.com/icons/17009/arrows_exchange_interact_refresh_reload_swap_sync_update_icon#size=16
# icon-cd, icon-pci
# icon-cd-drive and icon-pci
# are self made (sources as .xcf)
# icon-swap, icon-display, icon-harddisk, icon-keyboard, icon-network, icon-usb, icon-cloud
# come from fontawesome (respective fa-refresh, fa-desktop, fa-hdd-o, fa-keyboard-o, fa-exchange, fa-usb, fa-ellipsis-h, fa-cloud)
# icon-cloud
# come from fontawesome (respective fa-cloud)
# icon-serial is a modified version of
# https://commons.wikimedia.org/wiki/File:DE9_Diagram.svg
# (public domain)
# ceph logos are from
# http://ceph.com/logos/
# logo-ceph is adapted and reformatted from Ceph_Logo.svg:
# https://github.com/ceph/ceph/blob/main/src/pybind/mgr/dashboard/frontend/src/assets/Ceph_Logo.svg
# xtermjs.png is a cropped version of the logo found on
# https://github.com/xtermjs/xterm.js
# xtermjs.svg was copied from the xtermjs-branding sources:
# https://github.com/xtermjs/xtermjs-branding/blob/master/logo.svg
GNOME_IMAGES = \
checked.png \
unchecked.png \
start.png \
stop.png \
gtk-stop.png \
forward.png \
display.png \
keyboard.png \
cdrom.png \
network.png \
drive-harddisk.png \
network-server.png \
connect_established.png \
computer-template.png \
computer.png
IMAGES = $(GNOME_IMAGES) \
virt-viewer.png \
tigervnc.png \
novnc.png \
xtermjs.png \
IMAGES = \
virt-viewer.svg \
novnc.svg \
xtermjs.svg \
favicon.ico \
snapshot.png \
computer-on.png \
memory.png \
processor.png \
proxmox_logo.png \
network-server-on.png \
network-server-off.png \
lxc-on.png \
lxc-off.png \
openvz-on.png \
openvz-off.png \
blank.gif \
swap.png \
icon-swap.png \
icon-cd.png \
icon-network.png \
icon-display.png \
icon-harddisk.png \
icon-keyboard.png \
logo-ceph.png \
logo-ceph.svg \
logo-128.png \
icon-serial.svg \
icon-cloud.svg \
icon-pci.svg \
icon-usb.png \
icon-die.svg \
icon-sdn.svg \
icon-fa-network-wired.svg\
icon-cpu.svg \
icon-memory.svg \
icon-cd-drive.svg \
spinner.svg \
icon-sdn.svg: icon-sdn.dot
fdp -Tsvg $< > $@
.PHONY: install
.PHONY: install
install: $(IMAGES)
install -d $(WWWIMAGEDIR)
install -m 0644 $(IMAGES) $(WWWIMAGEDIR)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 960 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 585 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 994 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 723 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 741 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 847 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 641 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 664 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 309 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 221 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 293 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 309 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 245 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 324 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 367 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 590 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 488 B

129
www/images/logo-ceph.svg Normal file
View file

@ -0,0 +1,129 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
sodipodi:docname="Ceph_Logo.svg"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
id="svg27"
version="1.1"
viewBox="0 0 22.93428 22.4424"
height="22.4424mm"
width="22.93428mm">
<defs
id="defs21">
<color-profile
xlink:href="file:///usr/share/color/icc/krita/sRGB-elle-V2-g10.icc"
name="sRGB-elle-V2-g10.icc"
id="color-profile35" />
</defs>
<sodipodi:namedview
inkscape:window-maximized="1"
inkscape:window-y="1080"
inkscape:window-x="3840"
inkscape:window-height="1051"
inkscape:window-width="1920"
fit-margin-bottom="0"
fit-margin-right="0"
fit-margin-left="0"
fit-margin-top="0"
showgrid="false"
inkscape:document-rotation="0"
inkscape:current-layer="layer1"
inkscape:document-units="mm"
inkscape:cy="39.499381"
inkscape:cx="29.58201"
inkscape:zoom="5.6"
inkscape:pageshadow="2"
inkscape:pageopacity="0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base" />
<metadata
id="metadata24">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="translate(-111.75311,-212.54075)"
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Ebene 1">
<path
style="fill:#000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.264583"
d="m 123.18096,212.54075 c -1.54244,0 -3.03889,0.30198 -4.44866,0.89818
-1.36085,0.57588 -2.58333,1.3995 -3.63198,2.44903 -1.04982,1.04891
-1.87352,2.27125 -2.44969,3.63166 -0.59614,1.41006 -0.89752,2.90769
-0.89752,4.44931 0,0.88089 0.0998,1.75881 0.29917,2.60975 0.19372,0.82789
0.48107,1.63557 0.85432,2.40026 0.68819,1.40905 1.80379,2.81384
3.06538,3.86536 0.82281,-0.4498 1.28965,-0.94572 1.38884,-1.47622
0.0956,-0.50956 -0.12815,-1.05842 -0.7044,-1.72565 -1.36741,-1.56892
-2.12041,-3.58324 -2.12041,-5.6735 0,-4.76667 3.87763,-8.6456
8.64495,-8.6456 0.008,0 0.0393,6.6e-4 0.0393,6.6e-4 0,0 0.0305,-6.6e-4
0.0383,-6.6e-4 4.76715,0 8.64527,3.87893 8.64527,8.6456 0,2.09026
-0.75283,4.1046 -2.11975,5.67284 -0.57201,0.66284 -0.80153,1.23499
-0.70211,1.74922 0.10311,0.53107 0.56896,1.02002 1.38458,1.45397
1.26331,-1.05177 2.3782,-2.4564 3.06637,-3.86602 0.37372,-0.76469
0.66107,-1.57237 0.85464,-2.40026 0.1988,-0.85094 0.29983,-1.72886
0.29983,-2.60975 0,-1.54162 -0.30231,-3.03925 -0.89851,-4.44931
-0.57588,-1.36041 -1.40013,-2.58275 -2.44904,-3.63166 -1.04913,-1.04953
-2.27155,-1.87315 -3.63198,-2.44903 -1.40995,-0.5962 -2.90688,-0.89818
-4.44931,-0.89818 h -0.0393 z m -0.004,4.62214 c -0.32192,0 -0.64417,0.0219
-0.95873,0.0671 -0.92883,0.1324 -1.8401,0.46397 -2.63525,0.96004
-0.75897,0.47323 -1.43426,1.1087 -1.95215,1.83792 -0.53535,0.75374
-0.91954,1.62985 -1.10963,2.53316 -0.20655,0.97977 -0.19361,2.01224
0.0376,2.98552 0.21276,0.89514 0.61602,1.75703 1.16626,2.49191
0.14746,0.19797 0.31251,0.37855 0.48673,0.56987 0.058,0.063 0.11717,0.12782
0.17675,0.19411 0.002,0.002 0.003,0.003 0.005,0.005 0.007,0.007
0.0162,0.0158 0.0252,0.0265 0.60646,0.70473 0.91421,1.46388 0.91421,2.25525
0,1.19597 -0.66414,2.29315 -1.70895,2.85525 0.60776,0.33731 1.24734,0.61904
1.90404,0.83925 0.21816,0.0731 0.44001,0.13985 0.6625,0.19934
0.13296,-0.0835 0.58624,-0.42093 1.02943,-1.03369 0.42381,-0.58551
0.92331,-1.55674 0.89687,-2.85753 -0.0155,-0.78287 -0.17316,-1.54536
-0.46709,-2.26507 -0.29199,-0.71355 -0.71021,-1.36743 -1.24449,-1.94268 l
-0.002,-0.004 c -0.04,-0.0456 -0.0786,-0.0911 -0.11816,-0.13613
-0.20138,-0.23358 -0.40932,-0.47459 -0.57609,-0.75677 -0.20417,-0.34691
-0.35302,-0.71154 -0.44123,-1.08442 -0.13724,-0.57588 -0.1445,-1.18703
-0.0229,-1.76689 0.1135,-0.53315 0.3392,-1.04985 0.65563,-1.49522
0.30638,-0.43154 0.70637,-0.80806 1.15578,-1.08835 0.46898,-0.29265
1.00724,-0.48855 1.55511,-0.56627 0.18502,-0.0266 0.37651,-0.0403
0.56824,-0.0403 h 0.0409 0.0412 c 0.19212,0 0.38328,0.0137 0.56889,0.0403
0.54819,0.0777 1.08631,0.27362 1.55479,0.56627 0.44949,0.28029
0.84882,0.65681 1.15545,1.08835 0.31651,0.44537 0.54311,0.96207
0.65563,1.49522 0.12194,0.57986 0.11399,1.19101 -0.0222,1.76689
-0.0886,0.37288 -0.23731,0.73751 -0.44189,1.08442 -0.16594,0.28218
-0.37412,0.52319 -0.57544,0.75677 -0.0397,0.045 -0.0786,0.0905
-0.11783,0.13617 l -0.003,0.004 c -0.53338,0.57525 -0.9522,1.22913
-1.24416,1.94267 -0.29412,0.71971 -0.45106,1.4822 -0.46742,2.26507
-0.0261,1.30079 0.47323,2.27202 0.89753,2.85754 0.44229,0.61275
0.89596,0.95014 1.02877,1.03369 0.22233,-0.0595 0.44541,-0.12627
0.66349,-0.19934 0.6567,-0.22022 1.29635,-0.50194 1.90436,-0.83926
-1.04596,-0.5621 -1.70993,-1.65928 -1.70993,-2.85524 0,-0.78066
0.29884,-1.5183 0.91356,-2.25395 0.008,-0.0117 0.0182,-0.0208 0.0252,-0.0278
0.002,-0.002 0.004,-0.003 0.006,-0.005 0.0597,-0.0663 0.1185,-0.1311
0.17577,-0.19411 0.17488,-0.19132 0.33935,-0.3719 0.48706,-0.56987
0.55097,-0.73488 0.95359,-1.59677 1.16691,-2.49191 0.2306,-0.97328
0.24377,-2.00575 0.038,-2.98552 -0.19086,-0.90335 -0.57496,-1.77946
-1.10998,-2.5332 -0.51797,-0.72922 -1.19318,-1.36469 -1.95215,-1.83792
-0.79523,-0.49606 -1.70641,-0.82764 -2.63561,-0.96004 -0.31415,-0.0452
-0.63706,-0.0671 -0.95906,-0.0671 h -0.0409 -0.0452 z m 0.0429,4.65814 c
-1.24383,0 -2.25624,1.01222 -2.25624,2.25657 0,1.24414 1.01241,2.25624
2.25624,2.25624 1.24382,0 2.25591,-1.0121 2.25591,-2.25624 0,-1.24435
-1.01209,-2.25657 -2.25591,-2.25657 z"
id="path3043-5"
inkscape:connector-curvature="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 891 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 872 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 349 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 833 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 845 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 832 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 703 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 453 B

163
www/images/novnc.svg Normal file
View file

@ -0,0 +1,163 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
viewBox="0 0 16 16"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="novnc-icon-sm.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="45.254834"
inkscape:cx="9.722703"
inkscape:cy="5.5311896"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:object-nodes="true"
inkscape:snap-smooth-nodes="true"
inkscape:snap-midpoints="true"
inkscape:window-width="1920"
inkscape:window-height="1136"
inkscape:window-x="1920"
inkscape:window-y="27"
inkscape:window-maximized="1">
<inkscape:grid
type="xygrid"
id="grid4169" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-1036.3621)">
<rect
style="opacity:1;fill:#494949;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect4167"
width="16"
height="15.999992"
x="0"
y="1036.3622"
ry="2.6666584" />
<path
style="opacity:1;fill:#313131;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="M 2.6666667,1036.3621 C 1.1893373,1036.3621 0,1037.5515 0,1039.0288 l 0,10.6666 c 0,1.4774 1.1893373,2.6667 2.6666667,2.6667 l 4,0 C 11.837333,1052.3621 16,1046.7128 16,1039.6955 l 0,-0.6667 c 0,-1.4773 -1.189337,-2.6667 -2.666667,-2.6667 l -10.6666663,0 z"
id="rect4173"
inkscape:connector-curvature="0" />
<g
id="g4381">
<g
transform="translate(0.25,0.25)"
style="fill:#000000;fill-opacity:1"
id="g4365">
<g
style="fill:#000000;fill-opacity:1"
id="g4367">
<path
inkscape:connector-curvature="0"
id="path4369"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 4.3289754,1039.3621 c 0.1846149,0 0.3419956,0.071 0.4716623,0.2121 C 4.933546,1039.7121 5,1039.8793 5,1040.0759 l 0,3.2862 -1,0 0,-2.964 c 0,-0.024 -0.011592,-0.036 -0.034038,-0.036 l -1.931924,0 C 2.011349,1040.3621 2,1040.3741 2,1040.3981 l 0,2.964 -1,0 0,-4 z"
sodipodi:nodetypes="scsccsssscccs" />
<path
inkscape:connector-curvature="0"
id="path4371"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 6.6710244,1039.3621 2.6579513,0 c 0.184775,0 0.3419957,0.071 0.471662,0.2121 C 9.933546,1039.7121 10,1039.8793 10,1040.0759 l 0,2.5724 c 0,0.1966 -0.066454,0.3655 -0.1993623,0.5069 -0.1296663,0.1379 -0.286887,0.2069 -0.471662,0.2069 l -2.6579513,0 c -0.184775,0 -0.3436164,-0.069 -0.4765247,-0.2069 C 6.0648334,1043.0138 6,1042.8449 6,1042.6483 l 0,-2.5724 c 0,-0.1966 0.064833,-0.3638 0.1944997,-0.5017 0.1329083,-0.1414 0.2917497,-0.2121 0.4765247,-0.2121 z m 2.2949386,1 -1.931926,0 C 7.011344,1040.3621 7,1040.3741 7,1040.3981 l 0,1.928 c 0,0.024 0.011347,0.036 0.034037,0.036 l 1.931926,0 c 0.02269,0 0.034037,-0.012 0.034037,-0.036 l 0,-1.928 c 0,-0.024 -0.011347,-0.036 -0.034037,-0.036 z"
sodipodi:nodetypes="sscsscsscsscssssssssss" />
</g>
<g
style="fill:#000000;fill-opacity:1"
id="g4373">
<path
inkscape:connector-curvature="0"
id="path4375"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 3,1047.1121 1,-2.75 1,0 -1.5,4 -1,0 -1.5,-4 1,0 z"
sodipodi:nodetypes="cccccccc" />
<path
inkscape:connector-curvature="0"
id="path4377"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 9,1046.8621 0,-2.5 1,0 0,4 -1,0 -2,-2.5 0,2.5 -1,0 0,-4 1,0 z"
sodipodi:nodetypes="ccccccccccc" />
<path
inkscape:connector-curvature="0"
id="path4379"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 15,1045.3621 -2.96596,0 c -0.02269,0 -0.03404,0.012 -0.03404,0.036 l 0,1.928 c 0,0.024 0.01135,0.036 0.03404,0.036 l 2.96596,0 0,1 -3.324113,0 c -0.188017,0 -0.348479,-0.068 -0.481388,-0.2037 C 11.064833,1048.0192 11,1047.8511 11,1047.6542 l 0,-2.5842 c 0,-0.1969 0.06483,-0.3633 0.194499,-0.4991 0.132909,-0.1392 0.293371,-0.2088 0.481388,-0.2088 l 3.324113,0 z"
sodipodi:nodetypes="cssssccscsscscc" />
</g>
</g>
<g
id="g4356">
<g
id="g4347">
<path
sodipodi:nodetypes="scsccsssscccs"
d="m 4.3289754,1039.3621 c 0.1846149,0 0.3419956,0.071 0.4716623,0.2121 C 4.933546,1039.7121 5,1039.8793 5,1040.0759 l 0,3.2862 -1,0 0,-2.964 c 0,-0.024 -0.011592,-0.036 -0.034038,-0.036 l -1.931924,0 c -0.022689,0 -0.034038,0.012 -0.034038,0.036 l 0,2.964 -1,0 0,-4 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#008000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="path4143"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="sscsscsscsscssssssssss"
d="m 6.6710244,1039.3621 2.6579513,0 c 0.184775,0 0.3419957,0.071 0.471662,0.2121 C 9.933546,1039.7121 10,1039.8793 10,1040.0759 l 0,2.5724 c 0,0.1966 -0.066454,0.3655 -0.1993623,0.5069 -0.1296663,0.1379 -0.286887,0.2069 -0.471662,0.2069 l -2.6579513,0 c -0.184775,0 -0.3436164,-0.069 -0.4765247,-0.2069 C 6.0648334,1043.0138 6,1042.8449 6,1042.6483 l 0,-2.5724 c 0,-0.1966 0.064833,-0.3638 0.1944997,-0.5017 0.1329083,-0.1414 0.2917497,-0.2121 0.4765247,-0.2121 z m 2.2949386,1 -1.931926,0 C 7.011344,1040.3621 7,1040.3741 7,1040.3981 l 0,1.928 c 0,0.024 0.011347,0.036 0.034037,0.036 l 1.931926,0 c 0.02269,0 0.034037,-0.012 0.034037,-0.036 l 0,-1.928 c 0,-0.024 -0.011347,-0.036 -0.034037,-0.036 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#008000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="path4145"
inkscape:connector-curvature="0" />
</g>
<g
id="g4351">
<path
sodipodi:nodetypes="cccccccc"
d="m 3,1047.1121 1,-2.75 1,0 -1.5,4 -1,0 -1.5,-4 1,0 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffff00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="path4147"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="ccccccccccc"
d="m 9,1046.8621 0,-2.5 1,0 0,4 -1,0 -2,-2.5 0,2.5 -1,0 0,-4 1,0 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffff00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="path4149"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="cssssccscsscscc"
d="m 15,1045.3621 -2.96596,0 c -0.02269,0 -0.03404,0.012 -0.03404,0.036 l 0,1.928 c 0,0.024 0.01135,0.036 0.03404,0.036 l 2.96596,0 0,1 -3.324113,0 c -0.188017,0 -0.348479,-0.068 -0.481388,-0.2037 C 11.064833,1048.0192 11,1047.8511 11,1047.6542 l 0,-2.5842 c 0,-0.1969 0.06483,-0.3633 0.194499,-0.4991 0.132909,-0.1392 0.293371,-0.2088 0.481388,-0.2088 l 3.324113,0 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffff00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="path4151"
inkscape:connector-curvature="0" />
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 516 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 527 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 635 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 570 B

Some files were not shown because too many files have changed in this diff Show more