agent v0.36.7: isolate shared parent only on create (no peer-group churn)
make-private+make-shared only when first creating the self-bind; re-running it churns the peer group and orphans the guest's slave (propagation dies). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,13 @@
|
|||||||
All notable changes to **felhom-agent** are recorded here. Update on every code
|
All notable changes to **felhom-agent** are recorded here. Update on every code
|
||||||
change that gets pushed.
|
change that gets pushed.
|
||||||
|
|
||||||
|
## v0.36.7 — isolate the shared parent only on CREATE (no peer-group churn) (2026-06-15)
|
||||||
|
|
||||||
|
Follow-up to v0.36.6: make-private+make-shared must run ONLY when the self-bind is first created, not on
|
||||||
|
every reconcile — re-doing it churns the peer-group id and ORPHANS the guest`s already-established slave
|
||||||
|
(propagation silently dies, guest sees empty). Guarded on the mountpoint check; on a fresh boot it runs
|
||||||
|
once before pve-guests so the guest slaves the right group.
|
||||||
|
|
||||||
## v0.36.6 — shared parent gets its OWN peer group (make-private first) — ROOT CAUSE of double-bind (2026-06-15)
|
## v0.36.6 — shared parent gets its OWN peer group (make-private first) — ROOT CAUSE of double-bind (2026-06-15)
|
||||||
|
|
||||||
The shared-parent self-bind INHERITED the root mount`s shared peer group (`/mnt/felhom-drives` was
|
The shared-parent self-bind INHERITED the root mount`s shared peer group (`/mnt/felhom-drives` was
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ import (
|
|||||||
|
|
||||||
// version is the agent version. Overridable at build time with
|
// version is the agent version. Overridable at build time with
|
||||||
// -ldflags "-X main.version=<v>"; defaults to the in-repo CHANGELOG version.
|
// -ldflags "-X main.version=<v>"; defaults to the in-repo CHANGELOG version.
|
||||||
var version = "0.36.6"
|
var version = "0.36.7"
|
||||||
|
|
||||||
// runGuestHook is the PVE pre-start hook body (`felhom-agent guest-hook <vmid> <phase>`). On the
|
// runGuestHook is the PVE pre-start hook body (`felhom-agent guest-hook <vmid> <phase>`). On the
|
||||||
// pre-start phase it creates placeholder dirs for any absent bind-mount source so the guest always boots
|
// pre-start phase it creates placeholder dirs for any absent bind-mount source so the guest always boots
|
||||||
|
|||||||
@@ -32,12 +32,15 @@ const sharedParentScript = `#!/bin/sh
|
|||||||
# the shared peer group (slave). Installed + enabled by felhom-agent. Idempotent.
|
# the shared peer group (slave). Installed + enabled by felhom-agent. Idempotent.
|
||||||
set -e
|
set -e
|
||||||
mkdir -p ` + StableParentDir + `
|
mkdir -p ` + StableParentDir + `
|
||||||
mountpoint -q ` + StableParentDir + ` || mount --bind ` + StableParentDir + ` ` + StableParentDir + `
|
# Isolate + share ONLY when first creating the self-bind (a fresh boot). The self-bind inherits the root
|
||||||
# make-PRIVATE first: the self-bind inherits the root mount's shared peer group, so without detaching it
|
# mount's shared peer group, so make-private detaches it (else binds under it DOUBLE via the root peer),
|
||||||
# every drive bind under the parent would propagate back (and DOUBLE). Then make-shared = its OWN group,
|
# then make-shared gives it its own group whose only slave is the guest's parent bind. Re-running this on
|
||||||
# whose only slave is the guest's parent bind → binds propagate to the guest exactly once.
|
# an existing parent would churn the peer-group id and orphan the guest's slave — so guard on mountpoint.
|
||||||
mount --make-private ` + StableParentDir + `
|
if ! mountpoint -q ` + StableParentDir + `; then
|
||||||
mount --make-shared ` + StableParentDir + `
|
mount --bind ` + StableParentDir + ` ` + StableParentDir + `
|
||||||
|
mount --make-private ` + StableParentDir + `
|
||||||
|
mount --make-shared ` + StableParentDir + `
|
||||||
|
fi
|
||||||
`
|
`
|
||||||
|
|
||||||
const sharedParentUnitPath = "/etc/systemd/system/felhom-shared-parent.service"
|
const sharedParentUnitPath = "/etc/systemd/system/felhom-shared-parent.service"
|
||||||
@@ -94,19 +97,22 @@ func (b *GuestBinder) EnsureSharedParent(ctx context.Context) error {
|
|||||||
if err := b.run(ctx, "mkdir", "-p", StableParentDir); err != nil {
|
if err := b.run(ctx, "mkdir", "-p", StableParentDir); err != nil {
|
||||||
return fmt.Errorf("shared-parent: mkdir %s: %w", StableParentDir, err)
|
return fmt.Errorf("shared-parent: mkdir %s: %w", StableParentDir, err)
|
||||||
}
|
}
|
||||||
|
// Isolate + share the parent ONLY when first creating the self-bind. The self-bind inherits the root
|
||||||
|
// mount's shared peer group, so make-PRIVATE detaches it (else binds under it double via the root
|
||||||
|
// peer); make-SHARED then gives it its OWN group whose only slave is the guest's parent bind. This
|
||||||
|
// must NOT run on every reconcile: re-doing make-private+make-shared churns the peer-group id and
|
||||||
|
// ORPHANS the guest's already-established slave (propagation silently dies). On a fresh host boot the
|
||||||
|
// parent isn't a mountpoint → this runs once, before pve-guests, so the guest slaves the right group.
|
||||||
if !isHostMountpoint(StableParentDir) {
|
if !isHostMountpoint(StableParentDir) {
|
||||||
if err := b.run(ctx, "mount", "--bind", StableParentDir, StableParentDir); err != nil {
|
if err := b.run(ctx, "mount", "--bind", StableParentDir, StableParentDir); err != nil {
|
||||||
return fmt.Errorf("shared-parent: self-bind: %w", err)
|
return fmt.Errorf("shared-parent: self-bind: %w", err)
|
||||||
}
|
}
|
||||||
}
|
if err := b.run(ctx, "mount", "--make-private", StableParentDir); err != nil {
|
||||||
// make-PRIVATE first to detach from the root mount's shared peer group (the self-bind inherits it),
|
return fmt.Errorf("shared-parent: make-private: %w", err)
|
||||||
// THEN make-shared so the parent owns its OWN group — otherwise binds under it propagate back via the
|
}
|
||||||
// root peer and DOUBLE (observed live as 2 stacked binds per drive).
|
if err := b.run(ctx, "mount", "--make-shared", StableParentDir); err != nil {
|
||||||
if err := b.run(ctx, "mount", "--make-private", StableParentDir); err != nil {
|
return fmt.Errorf("shared-parent: make-shared: %w", err)
|
||||||
return fmt.Errorf("shared-parent: make-private: %w", err)
|
}
|
||||||
}
|
|
||||||
if err := b.run(ctx, "mount", "--make-shared", StableParentDir); err != nil {
|
|
||||||
return fmt.Errorf("shared-parent: make-shared: %w", err)
|
|
||||||
}
|
}
|
||||||
// Install the boot-persistence unit only when missing OR its content differs from what we ship (so a
|
// Install the boot-persistence unit only when missing OR its content differs from what we ship (so a
|
||||||
// unit-template fix deploys) — EnsureSharedParent runs on a periodic reconcile, and re-writing files +
|
// unit-template fix deploys) — EnsureSharedParent runs on a periodic reconcile, and re-writing files +
|
||||||
|
|||||||
Reference in New Issue
Block a user