package proxmox import ( "hash/fnv" "strconv" "strings" "gitea.home.hrajfrisbee.cz/kacerr/egress-proxies-operator/internal/provider" ) const idPrefix = "vms" // formatProviderID gives vms//: location-free, because VMs can // migrate between nodes (spec entry 1). func formatProviderID(vmid int, name string) string { return idPrefix + "/" + strconv.Itoa(vmid) + "/" + name } // parseProviderID is strict: exactly three segments, the literal "vms", a // decimal VMID without leading zeros in Proxmox's range, and a non-empty // name. Anything else is ErrPermanent. func parseProviderID(id string) (int, string, error) { parts := strings.Split(id, "/") if len(parts) != 3 || parts[0] != idPrefix || parts[2] == "" { return 0, "", permanentf("malformed providerID %q, want vms//", id) } vmid, err := strconv.Atoi(parts[1]) if err != nil || strconv.Itoa(vmid) != parts[1] || vmid < provider.ProxmoxMinVMID || vmid > provider.ProxmoxMaxVMID { return 0, "", permanentf("malformed providerID %q: %q is not a VMID", id, parts[1]) } return vmid, parts[2], nil } // vmidFor is the attempt-th VMID candidate for a Proxy UID: a stable hash of // the UID placed in [min, max], moving forward and wrapping as attempt grows, // so a retry of the same Create lands on the same VMID (spec entry 2). func vmidFor(uid string, min, max, attempt int) int { h := fnv.New64a() _, _ = h.Write([]byte(uid)) span := uint64(max - min + 1) return min + int((h.Sum64()%span+uint64(attempt)%span)%span) }