feat: find node by uuid

In some setups, the Proxmox VM name may differ from the Linux hostname.
To reliably identify a VM within a Proxmox cluster, we can use the system's UUID

Signed-off-by: Serge Logvinov <serge.logvinov@sinextra.dev>
This commit is contained in:
Serge Logvinov
2024-09-13 15:05:49 +03:00
committed by Serge
parent b81ad1406d
commit 5876cd4c7b
3 changed files with 89 additions and 10 deletions

10
go.sum
View File

@@ -135,8 +135,6 @@ github.com/prometheus/client_golang v1.20.3 h1:oPksm4K8B+Vt35tUhw6GbSNSgVlVSBH0q
github.com/prometheus/client_golang v1.20.3/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
github.com/prometheus/common v0.59.1 h1:LXb1quJHWm1P6wq/U824uxYi4Sg0oGvNeUm1z5dJoX0=
github.com/prometheus/common v0.59.1/go.mod h1:GpWM7dewqmVYcd7SmRaiWVe9SSqjf0UrwnYnpEZNuT0=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
@@ -216,8 +214,6 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI=
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk=
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@@ -228,8 +224,6 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA=
golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -255,8 +249,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE=
golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@@ -19,8 +19,10 @@ package cluster
import (
"crypto/tls"
"encoding/base64"
"fmt"
"net/http"
"net/url"
"os"
"strings"
@@ -107,3 +109,67 @@ func (c *Cluster) FindVMByName(name string) (*pxapi.VmRef, string, error) {
return nil, "", fmt.Errorf("vm '%s' not found", name)
}
// FindVMByUUID find a VM by uuid in all Proxmox clusters.
func (c *Cluster) FindVMByUUID(uuid string) (*pxapi.VmRef, string, error) {
for region, px := range c.proxmox {
vms, err := px.GetResourceList("vm")
if err != nil {
return nil, "", fmt.Errorf("error get resources %v", err)
}
for vmii := range vms {
vm, ok := vms[vmii].(map[string]interface{})
if !ok {
return nil, "", fmt.Errorf("failed to cast response to map, vm: %v", vm)
}
if vm["type"].(string) != "qemu" {
continue
}
vmr := pxapi.NewVmRef(int(vm["vmid"].(float64)))
vmr.SetNode(vm["node"].(string))
vmr.SetVmType("qemu")
config, err := px.GetVmConfig(vmr)
if err != nil {
return nil, "", err
}
if config["smbios1"] != nil {
if c.getUUID(config["smbios1"].(string)) == uuid {
return vmr, region, nil
}
}
}
}
return nil, "", fmt.Errorf("vm with uuid '%s' not found", uuid)
}
func (c *Cluster) getUUID(smbios string) string {
for _, l := range strings.Split(smbios, ",") {
if l == "" || l == "base64=1" {
continue
}
parsedParameter, err := url.ParseQuery(l)
if err != nil {
return ""
}
for k, v := range parsedParameter {
if k == "uuid" {
decodedString, err := base64.StdEncoding.DecodeString(v[0])
if err != nil {
decodedString = []byte(v[0])
}
return string(decodedString)
}
}
}
return ""
}

View File

@@ -48,6 +48,12 @@ func newInstances(client *cluster.Cluster) *instances {
func (i *instances) InstanceExists(_ context.Context, node *v1.Node) (bool, error) {
klog.V(4).InfoS("instances.InstanceExists() called", "node", klog.KRef("", node.Name))
if node.Spec.ProviderID == "" {
klog.V(4).InfoS("instances.InstanceExists() empty providerID, omitting unmanaged node", "node", klog.KObj(node))
return true, nil
}
if !strings.HasPrefix(node.Spec.ProviderID, provider.ProviderName) {
klog.V(4).InfoS("instances.InstanceExists() omitting unmanaged node", "node", klog.KObj(node), "providerID", node.Spec.ProviderID)
@@ -73,6 +79,12 @@ func (i *instances) InstanceExists(_ context.Context, node *v1.Node) (bool, erro
func (i *instances) InstanceShutdown(_ context.Context, node *v1.Node) (bool, error) {
klog.V(4).InfoS("instances.InstanceShutdown() called", "node", klog.KRef("", node.Name))
if node.Spec.ProviderID == "" {
klog.V(4).InfoS("instances.InstanceShutdown() empty providerID, omitting unmanaged node", "node", klog.KObj(node))
return false, nil
}
if !strings.HasPrefix(node.Spec.ProviderID, provider.ProviderName) {
klog.V(4).InfoS("instances.InstanceShutdown() omitting unmanaged node", "node", klog.KObj(node), "providerID", node.Spec.ProviderID)
@@ -122,13 +134,20 @@ func (i *instances) InstanceMetadata(_ context.Context, node *v1.Node) (*cloudpr
providerID := node.Spec.ProviderID
if providerID == "" {
klog.V(4).InfoS("instances.InstanceMetadata() empty providerID, trying find by Name", "node", klog.KObj(node))
uuid := node.Status.NodeInfo.SystemUUID
klog.V(4).InfoS("instances.InstanceMetadata() empty providerID, trying find node", "node", klog.KObj(node), "uuid", uuid)
mc := metrics.NewMetricContext("findVmByName")
vmRef, region, err = i.c.FindVMByName(node.Name)
if mc.ObserveRequest(err) != nil {
return nil, fmt.Errorf("instances.InstanceMetadata() - failed to find instance by name %s: %v, skipped", node.Name, err)
mc := metrics.NewMetricContext("findVmByUUID")
vmRef, region, err = i.c.FindVMByUUID(uuid)
if mc.ObserveRequest(err) != nil {
return nil, fmt.Errorf("instances.InstanceMetadata() - failed to find instance by name/uuid %s: %v, skipped", node.Name, err)
}
}
} else if !strings.HasPrefix(node.Spec.ProviderID, provider.ProviderName) {
klog.V(4).InfoS("instances.InstanceMetadata() omitting unmanaged node", "node", klog.KObj(node), "providerID", node.Spec.ProviderID)