Files
egress-proxies-operator/internal/provider/kvm2/state.go
T
kacerrandClaude Fable 5.1 95768281be kvm2: config block, constructor registration, IDs, state mapping and classify
The kvm2 block reuses KVMConfig; validateKVM gains a block-name variant so
messages say kvm2. The package skeleton has a non-dialing New, strict
providerID parsing, the state table and a 34-row classify test.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 16:38:48 +00:00

50 lines
1.5 KiB
Go

package kvm2
import (
"net/netip"
"github.com/digitalocean/go-libvirt"
"gitea.home.hrajfrisbee.cz/kacerr/egress-proxies-operator/internal/provider"
)
// mapState turns a libvirt domain state plus the discovered address into the
// contract's state. nostate means libvirt could not tell, so the next poll
// decides; an active domain is Running only once it has an address; every
// inactive state, and anything unknown, is Stopped, which the reconciler
// answers by replacing the instance.
func mapState(s libvirt.DomainState, ip string) provider.InstanceState {
switch {
case s == libvirt.DomainNostate:
return provider.StateProvisioning
case isActive(s) && ip == "":
return provider.StateProvisioning
case isActive(s):
return provider.StateRunning
default:
return provider.StateStopped
}
}
func isActive(s libvirt.DomainState) bool {
return s == libvirt.DomainRunning || s == libvirt.DomainBlocked
}
// firstIPv4 picks the first usable IPv4 address from the guest's interfaces:
// not loopback, not link-local, not unspecified. Empty means no address yet.
func firstIPv4(ifaces []libvirt.DomainInterface) string {
for _, iface := range ifaces {
for _, a := range iface.Addrs {
if libvirt.IPAddrType(a.Type) != libvirt.IPAddrTypeIpv4 {
continue
}
addr, err := netip.ParseAddr(a.Addr)
if err != nil || !addr.Is4() || addr.IsLoopback() || addr.IsLinkLocalUnicast() || addr.IsUnspecified() {
continue
}
return addr.String()
}
}
return ""
}