fix: find node by name

We will find the node by name more precisely.
Check the UUID and VM name to determine the VM ID.

Signed-off-by: Serge Logvinov <serge.logvinov@sinextra.dev>
This commit is contained in:
Serge Logvinov
2025-02-13 16:45:52 +02:00
committed by Serge
parent 8a2f51844c
commit 3a34fb960a
4 changed files with 189 additions and 24 deletions

View File

@@ -4,7 +4,7 @@
## Note to the Contributor
We encourage contributors to go through a proposal process to discuss major changes.
Before your PR is allowed to run through CI, the maintainers of Talos CCM will first have to approve the PR.
Before your PR is allowed to run through CI, the maintainers of Proxmox CCM will first have to approve the PR.
-->
## What? (description)

View File

@@ -29,6 +29,7 @@ import (
pxapi "github.com/Telmate/proxmox-api-go/proxmox"
v1 "k8s.io/api/core/v1"
"k8s.io/klog/v2"
)
@@ -106,6 +107,33 @@ func (c *Cluster) GetProxmoxCluster(region string) (*pxapi.Client, error) {
return nil, fmt.Errorf("proxmox cluster %s not found", region)
}
// FindVMByNode find a VM by kubernetes node resource in all Proxmox clusters.
func (c *Cluster) FindVMByNode(ctx context.Context, node *v1.Node) (*pxapi.VmRef, string, error) {
for region, px := range c.proxmox {
vmrs, err := px.GetVmRefsByName(ctx, node.Name)
if err != nil {
if strings.Contains(err.Error(), "not found") {
continue
}
return nil, "", err
}
for _, vmr := range vmrs {
config, err := px.GetVmConfig(ctx, vmr)
if err != nil {
return nil, "", err
}
if c.GetVMUUID(config) == node.Status.NodeInfo.SystemUUID {
return vmr, region, nil
}
}
}
return nil, "", fmt.Errorf("vm '%s' not found", node.Name)
}
// FindVMByName find a VM by name in all Proxmox clusters.
func (c *Cluster) FindVMByName(ctx context.Context, name string) (*pxapi.VmRef, string, error) {
for region, px := range c.proxmox {
@@ -162,6 +190,24 @@ func (c *Cluster) FindVMByUUID(ctx context.Context, uuid string) (*pxapi.VmRef,
return nil, "", fmt.Errorf("vm with uuid '%s' not found", uuid)
}
// GetVMName returns the VM name.
func (c *Cluster) GetVMName(vmInfo map[string]interface{}) string {
if vmInfo["name"] != nil {
return vmInfo["name"].(string) //nolint:errcheck
}
return ""
}
// GetVMUUID returns the VM UUID.
func (c *Cluster) GetVMUUID(vmInfo map[string]interface{}) string {
if vmInfo["smbios1"] != nil {
return c.getUUID(vmInfo["smbios1"].(string)) //nolint:errcheck
}
return ""
}
func (c *Cluster) getUUID(smbios string) string {
for _, l := range strings.Split(smbios, ",") {
if l == "" || l == "base64=1" {

View File

@@ -142,7 +142,7 @@ func (i *instances) InstanceMetadata(ctx context.Context, node *v1.Node) (*cloud
mc := metrics.NewMetricContext("findVmByName")
vmRef, region, err = i.c.FindVMByName(ctx, node.Name)
vmRef, region, err = i.c.FindVMByNode(ctx, node)
if mc.ObserveRequest(err) != nil {
mc := metrics.NewMetricContext("findVmByUUID")
@@ -234,8 +234,10 @@ func (i *instances) getInstance(ctx context.Context, node *v1.Node) (*pxapi.VmRe
return nil, "", err
}
if vmInfo["name"] != nil && vmInfo["name"].(string) != node.Name { //nolint:errcheck
return nil, "", fmt.Errorf("instances.getInstance() vm.name(%s) != node.name(%s)", vmInfo["name"].(string), node.Name) //nolint:errcheck
if i.c.GetVMName(vmInfo) != node.Name && i.c.GetVMUUID(vmInfo) != node.Status.NodeInfo.SystemUUID {
klog.Errorf("instances.getInstance() vm.name(%s) != node.name(%s) with uuid=%s", i.c.GetVMName(vmInfo), node.Name, node.Status.NodeInfo.SystemUUID)
return nil, "", cloudprovider.InstanceNotFound
}
klog.V(5).Infof("instances.getInstance() vmInfo %+v", vmInfo)

View File

@@ -66,20 +66,22 @@ clusters:
return httpmock.NewJsonResponse(200, map[string]interface{}{
"data": []interface{}{
map[string]interface{}{
"node": "pve-1",
"type": "qemu",
"vmid": 100,
"name": "cluster-1-node-1",
"maxcpu": 4,
"maxmem": 10 * 1024 * 1024 * 1024,
"node": "pve-1",
"type": "qemu",
"vmid": 100,
"name": "cluster-1-node-1",
"maxcpu": 4,
"maxmem": 10 * 1024 * 1024 * 1024,
"smbios1": "uuid=8af7110d-bfad-407a-a663-9527d10a6583",
},
map[string]interface{}{
"node": "pve-2",
"type": "qemu",
"vmid": 101,
"name": "cluster-1-node-2",
"maxcpu": 2,
"maxmem": 5 * 1024 * 1024 * 1024,
"node": "pve-2",
"type": "qemu",
"vmid": 101,
"name": "cluster-1-node-2",
"maxcpu": 2,
"maxmem": 5 * 1024 * 1024 * 1024,
"smbios1": "uuid=5d04cb23-ea78-40a3-af2e-dd54798dc887",
},
},
})
@@ -91,18 +93,58 @@ clusters:
return httpmock.NewJsonResponse(200, map[string]interface{}{
"data": []interface{}{
map[string]interface{}{
"node": "pve-3",
"type": "qemu",
"vmid": 100,
"name": "cluster-2-node-1",
"maxcpu": 1,
"maxmem": 2 * 1024 * 1024 * 1024,
"node": "pve-3",
"type": "qemu",
"vmid": 100,
"name": "cluster-2-node-1",
"maxcpu": 1,
"maxmem": 2 * 1024 * 1024 * 1024,
"smbios1": "uuid=3d3db687-89dd-473e-8463-6599f25b36a8",
},
},
})
},
)
httpmock.RegisterResponder("GET", "https://127.0.0.1:8006/api2/json/nodes/pve-1/qemu/100/config",
func(_ *http.Request) (*http.Response, error) {
return httpmock.NewJsonResponse(200, map[string]interface{}{
"data": map[string]interface{}{
"node": "pve-1",
"type": "qemu",
"vmid": 100,
"smbios1": "uuid=8af7110d-bfad-407a-a663-9527d10a6583",
},
})
},
)
httpmock.RegisterResponder("GET", "https://127.0.0.1:8006/api2/json/nodes/pve-2/qemu/101/config",
func(_ *http.Request) (*http.Response, error) {
return httpmock.NewJsonResponse(200, map[string]interface{}{
"data": map[string]interface{}{
"node": "pve-2",
"type": "qemu",
"vmid": 101,
"smbios1": "uuid=5d04cb23-ea78-40a3-af2e-dd54798dc887",
},
})
},
)
httpmock.RegisterResponder("GET", "https://127.0.0.2:8006/api2/json/nodes/pve-3/qemu/100/config",
func(_ *http.Request) (*http.Response, error) {
return httpmock.NewJsonResponse(200, map[string]interface{}{
"data": map[string]interface{}{
"node": "pve-3",
"type": "qemu",
"vmid": 100,
"smbios1": "uuid=3d3db687-89dd-473e-8463-6599f25b36a8",
},
})
},
)
httpmock.RegisterResponder("GET", "https://127.0.0.1:8006/api2/json/nodes/pve-1/qemu/100/status/current",
func(_ *http.Request) (*http.Response, error) {
return httpmock.NewJsonResponse(200, map[string]interface{}{
@@ -207,9 +249,30 @@ func (ts *ccmTestSuite) TestInstanceExists() {
Spec: v1.NodeSpec{
ProviderID: "proxmox://cluster-1/100",
},
Status: v1.NodeStatus{
NodeInfo: v1.NodeSystemInfo{
SystemUUID: "8af7110d-bfad-407a-a663-9527d10a6583",
},
},
},
expectedError: "vm.name(cluster-1-node-1) != node.name(cluster-1-node-3)",
expected: false,
expected: true,
},
{
msg: "NodeExistsWithDifferentNameAndUUID",
node: &v1.Node{
ObjectMeta: metav1.ObjectMeta{
Name: "cluster-1-node-3",
},
Spec: v1.NodeSpec{
ProviderID: "proxmox://cluster-1/100",
},
Status: v1.NodeStatus{
NodeInfo: v1.NodeSystemInfo{
SystemUUID: "8af7110d-0000-0000-0000-9527d10a6583",
},
},
},
expected: false,
},
}
@@ -288,6 +351,11 @@ func (ts *ccmTestSuite) TestInstanceShutdown() {
Spec: v1.NodeSpec{
ProviderID: "proxmox://cluster-1/100",
},
Status: v1.NodeStatus{
NodeInfo: v1.NodeSystemInfo{
SystemUUID: "8af7110d-bfad-407a-a663-9527d10a6583",
},
},
},
expected: false,
},
@@ -303,6 +371,40 @@ func (ts *ccmTestSuite) TestInstanceShutdown() {
},
expected: true,
},
{
msg: "NodeExistsWithDifferentName",
node: &v1.Node{
ObjectMeta: metav1.ObjectMeta{
Name: "cluster-1-node-3",
},
Spec: v1.NodeSpec{
ProviderID: "proxmox://cluster-1/100",
},
Status: v1.NodeStatus{
NodeInfo: v1.NodeSystemInfo{
SystemUUID: "8af7110d-bfad-407a-a663-9527d10a6583",
},
},
},
expected: false,
},
{
msg: "NodeExistsWithDifferentUUID",
node: &v1.Node{
ObjectMeta: metav1.ObjectMeta{
Name: "cluster-1-node-1",
},
Spec: v1.NodeSpec{
ProviderID: "proxmox://cluster-1/100",
},
Status: v1.NodeStatus{
NodeInfo: v1.NodeSystemInfo{
SystemUUID: "8af7110d-0000-0000-0000-9527d10a6583",
},
},
},
expected: false,
},
}
for _, testCase := range tests {
@@ -398,6 +500,11 @@ func (ts *ccmTestSuite) TestInstanceMetadata() {
cloudproviderapi.AnnotationAlphaProvidedIPAddr: "1.2.3.4",
},
},
Status: v1.NodeStatus{
NodeInfo: v1.NodeSystemInfo{
SystemUUID: "8af7110d-bfad-407a-a663-9527d10a6583",
},
},
},
expected: &cloudprovider.InstanceMetadata{
ProviderID: "proxmox://cluster-1/100",
@@ -425,6 +532,11 @@ func (ts *ccmTestSuite) TestInstanceMetadata() {
cloudproviderapi.AnnotationAlphaProvidedIPAddr: "1.2.3.4,2001::1",
},
},
Status: v1.NodeStatus{
NodeInfo: v1.NodeSystemInfo{
SystemUUID: "8af7110d-bfad-407a-a663-9527d10a6583",
},
},
},
expected: &cloudprovider.InstanceMetadata{
ProviderID: "proxmox://cluster-1/100",
@@ -456,6 +568,11 @@ func (ts *ccmTestSuite) TestInstanceMetadata() {
cloudproviderapi.AnnotationAlphaProvidedIPAddr: "1.2.3.4",
},
},
Status: v1.NodeStatus{
NodeInfo: v1.NodeSystemInfo{
SystemUUID: "3d3db687-89dd-473e-8463-6599f25b36a8",
},
},
},
expected: &cloudprovider.InstanceMetadata{
ProviderID: "proxmox://cluster-2/100",