mirror of
https://github.com/outbackdingo/proxmox-cloud-controller-manager.git
synced 2026-01-27 10:20:13 +00:00
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:
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -4,7 +4,7 @@
|
|||||||
## Note to the Contributor
|
## Note to the Contributor
|
||||||
|
|
||||||
We encourage contributors to go through a proposal process to discuss major changes.
|
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)
|
## What? (description)
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import (
|
|||||||
|
|
||||||
pxapi "github.com/Telmate/proxmox-api-go/proxmox"
|
pxapi "github.com/Telmate/proxmox-api-go/proxmox"
|
||||||
|
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/klog/v2"
|
"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)
|
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.
|
// FindVMByName find a VM by name in all Proxmox clusters.
|
||||||
func (c *Cluster) FindVMByName(ctx context.Context, name string) (*pxapi.VmRef, string, error) {
|
func (c *Cluster) FindVMByName(ctx context.Context, name string) (*pxapi.VmRef, string, error) {
|
||||||
for region, px := range c.proxmox {
|
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)
|
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 {
|
func (c *Cluster) getUUID(smbios string) string {
|
||||||
for _, l := range strings.Split(smbios, ",") {
|
for _, l := range strings.Split(smbios, ",") {
|
||||||
if l == "" || l == "base64=1" {
|
if l == "" || l == "base64=1" {
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ func (i *instances) InstanceMetadata(ctx context.Context, node *v1.Node) (*cloud
|
|||||||
|
|
||||||
mc := metrics.NewMetricContext("findVmByName")
|
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 {
|
if mc.ObserveRequest(err) != nil {
|
||||||
mc := metrics.NewMetricContext("findVmByUUID")
|
mc := metrics.NewMetricContext("findVmByUUID")
|
||||||
|
|
||||||
@@ -234,8 +234,10 @@ func (i *instances) getInstance(ctx context.Context, node *v1.Node) (*pxapi.VmRe
|
|||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if vmInfo["name"] != nil && vmInfo["name"].(string) != node.Name { //nolint:errcheck
|
if i.c.GetVMName(vmInfo) != node.Name && i.c.GetVMUUID(vmInfo) != node.Status.NodeInfo.SystemUUID {
|
||||||
return nil, "", fmt.Errorf("instances.getInstance() vm.name(%s) != node.name(%s)", vmInfo["name"].(string), node.Name) //nolint:errcheck
|
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)
|
klog.V(5).Infof("instances.getInstance() vmInfo %+v", vmInfo)
|
||||||
|
|||||||
@@ -66,20 +66,22 @@ clusters:
|
|||||||
return httpmock.NewJsonResponse(200, map[string]interface{}{
|
return httpmock.NewJsonResponse(200, map[string]interface{}{
|
||||||
"data": []interface{}{
|
"data": []interface{}{
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"node": "pve-1",
|
"node": "pve-1",
|
||||||
"type": "qemu",
|
"type": "qemu",
|
||||||
"vmid": 100,
|
"vmid": 100,
|
||||||
"name": "cluster-1-node-1",
|
"name": "cluster-1-node-1",
|
||||||
"maxcpu": 4,
|
"maxcpu": 4,
|
||||||
"maxmem": 10 * 1024 * 1024 * 1024,
|
"maxmem": 10 * 1024 * 1024 * 1024,
|
||||||
|
"smbios1": "uuid=8af7110d-bfad-407a-a663-9527d10a6583",
|
||||||
},
|
},
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"node": "pve-2",
|
"node": "pve-2",
|
||||||
"type": "qemu",
|
"type": "qemu",
|
||||||
"vmid": 101,
|
"vmid": 101,
|
||||||
"name": "cluster-1-node-2",
|
"name": "cluster-1-node-2",
|
||||||
"maxcpu": 2,
|
"maxcpu": 2,
|
||||||
"maxmem": 5 * 1024 * 1024 * 1024,
|
"maxmem": 5 * 1024 * 1024 * 1024,
|
||||||
|
"smbios1": "uuid=5d04cb23-ea78-40a3-af2e-dd54798dc887",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -91,18 +93,58 @@ clusters:
|
|||||||
return httpmock.NewJsonResponse(200, map[string]interface{}{
|
return httpmock.NewJsonResponse(200, map[string]interface{}{
|
||||||
"data": []interface{}{
|
"data": []interface{}{
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"node": "pve-3",
|
"node": "pve-3",
|
||||||
"type": "qemu",
|
"type": "qemu",
|
||||||
"vmid": 100,
|
"vmid": 100,
|
||||||
"name": "cluster-2-node-1",
|
"name": "cluster-2-node-1",
|
||||||
"maxcpu": 1,
|
"maxcpu": 1,
|
||||||
"maxmem": 2 * 1024 * 1024 * 1024,
|
"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",
|
httpmock.RegisterResponder("GET", "https://127.0.0.1:8006/api2/json/nodes/pve-1/qemu/100/status/current",
|
||||||
func(_ *http.Request) (*http.Response, error) {
|
func(_ *http.Request) (*http.Response, error) {
|
||||||
return httpmock.NewJsonResponse(200, map[string]interface{}{
|
return httpmock.NewJsonResponse(200, map[string]interface{}{
|
||||||
@@ -207,9 +249,30 @@ func (ts *ccmTestSuite) TestInstanceExists() {
|
|||||||
Spec: v1.NodeSpec{
|
Spec: v1.NodeSpec{
|
||||||
ProviderID: "proxmox://cluster-1/100",
|
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: true,
|
||||||
expected: false,
|
},
|
||||||
|
{
|
||||||
|
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{
|
Spec: v1.NodeSpec{
|
||||||
ProviderID: "proxmox://cluster-1/100",
|
ProviderID: "proxmox://cluster-1/100",
|
||||||
},
|
},
|
||||||
|
Status: v1.NodeStatus{
|
||||||
|
NodeInfo: v1.NodeSystemInfo{
|
||||||
|
SystemUUID: "8af7110d-bfad-407a-a663-9527d10a6583",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
expected: false,
|
expected: false,
|
||||||
},
|
},
|
||||||
@@ -303,6 +371,40 @@ func (ts *ccmTestSuite) TestInstanceShutdown() {
|
|||||||
},
|
},
|
||||||
expected: true,
|
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 {
|
for _, testCase := range tests {
|
||||||
@@ -398,6 +500,11 @@ func (ts *ccmTestSuite) TestInstanceMetadata() {
|
|||||||
cloudproviderapi.AnnotationAlphaProvidedIPAddr: "1.2.3.4",
|
cloudproviderapi.AnnotationAlphaProvidedIPAddr: "1.2.3.4",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Status: v1.NodeStatus{
|
||||||
|
NodeInfo: v1.NodeSystemInfo{
|
||||||
|
SystemUUID: "8af7110d-bfad-407a-a663-9527d10a6583",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
expected: &cloudprovider.InstanceMetadata{
|
expected: &cloudprovider.InstanceMetadata{
|
||||||
ProviderID: "proxmox://cluster-1/100",
|
ProviderID: "proxmox://cluster-1/100",
|
||||||
@@ -425,6 +532,11 @@ func (ts *ccmTestSuite) TestInstanceMetadata() {
|
|||||||
cloudproviderapi.AnnotationAlphaProvidedIPAddr: "1.2.3.4,2001::1",
|
cloudproviderapi.AnnotationAlphaProvidedIPAddr: "1.2.3.4,2001::1",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Status: v1.NodeStatus{
|
||||||
|
NodeInfo: v1.NodeSystemInfo{
|
||||||
|
SystemUUID: "8af7110d-bfad-407a-a663-9527d10a6583",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
expected: &cloudprovider.InstanceMetadata{
|
expected: &cloudprovider.InstanceMetadata{
|
||||||
ProviderID: "proxmox://cluster-1/100",
|
ProviderID: "proxmox://cluster-1/100",
|
||||||
@@ -456,6 +568,11 @@ func (ts *ccmTestSuite) TestInstanceMetadata() {
|
|||||||
cloudproviderapi.AnnotationAlphaProvidedIPAddr: "1.2.3.4",
|
cloudproviderapi.AnnotationAlphaProvidedIPAddr: "1.2.3.4",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Status: v1.NodeStatus{
|
||||||
|
NodeInfo: v1.NodeSystemInfo{
|
||||||
|
SystemUUID: "3d3db687-89dd-473e-8463-6599f25b36a8",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
expected: &cloudprovider.InstanceMetadata{
|
expected: &cloudprovider.InstanceMetadata{
|
||||||
ProviderID: "proxmox://cluster-2/100",
|
ProviderID: "proxmox://cluster-2/100",
|
||||||
|
|||||||
Reference in New Issue
Block a user