blob: 791d5617a0f4f34ecc4580a246a8eb0fc58ec58f [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package cloudstack
import (
"strings"
"testing"
"github.com/apache/cloudstack-go/v2/cloudstack"
corev1 "k8s.io/api/core/v1"
)
func TestNodeAddresses(t *testing.T) {
cs := &CSCloud{}
tests := []struct {
name string
instance *cloudstack.VirtualMachine
wantAddrs []corev1.NodeAddress
wantErr bool
errContains string
}{
{
name: "instance with internal IP only",
instance: &cloudstack.VirtualMachine{
Id: "vm-1",
Name: "test-vm",
Nic: []cloudstack.Nic{
{Ipaddress: "10.0.0.1"},
},
},
wantAddrs: []corev1.NodeAddress{
{Type: corev1.NodeInternalIP, Address: "10.0.0.1"},
},
wantErr: false,
},
{
name: "instance with internal IP and hostname",
instance: &cloudstack.VirtualMachine{
Id: "vm-1",
Name: "test-vm",
Hostname: "test-hostname",
Nic: []cloudstack.Nic{
{Ipaddress: "10.0.0.1"},
},
},
wantAddrs: []corev1.NodeAddress{
{Type: corev1.NodeInternalIP, Address: "10.0.0.1"},
{Type: corev1.NodeHostName, Address: "test-hostname"},
},
wantErr: false,
},
{
name: "instance with internal IP and public IP",
instance: &cloudstack.VirtualMachine{
Id: "vm-1",
Name: "test-vm",
Publicip: "203.0.113.1",
Nic: []cloudstack.Nic{
{Ipaddress: "10.0.0.1"},
},
},
wantAddrs: []corev1.NodeAddress{
{Type: corev1.NodeInternalIP, Address: "10.0.0.1"},
{Type: corev1.NodeExternalIP, Address: "203.0.113.1"},
},
wantErr: false,
},
{
name: "instance with all address types",
instance: &cloudstack.VirtualMachine{
Id: "vm-1",
Name: "test-vm",
Hostname: "test-hostname",
Publicip: "203.0.113.1",
Nic: []cloudstack.Nic{
{Ipaddress: "10.0.0.1"},
},
},
wantAddrs: []corev1.NodeAddress{
{Type: corev1.NodeInternalIP, Address: "10.0.0.1"},
{Type: corev1.NodeHostName, Address: "test-hostname"},
{Type: corev1.NodeExternalIP, Address: "203.0.113.1"},
},
wantErr: false,
},
{
name: "instance with no NICs returns error",
instance: &cloudstack.VirtualMachine{
Id: "vm-1",
Name: "test-vm",
Nic: []cloudstack.Nic{},
},
wantAddrs: nil,
wantErr: true,
errContains: "does not have an internal IP",
},
{
name: "instance with nil NICs returns error",
instance: &cloudstack.VirtualMachine{
Id: "vm-1",
Name: "test-vm",
Nic: nil,
},
wantAddrs: nil,
wantErr: true,
errContains: "does not have an internal IP",
},
{
name: "instance with multiple NICs uses first",
instance: &cloudstack.VirtualMachine{
Id: "vm-1",
Name: "test-vm",
Nic: []cloudstack.Nic{
{Ipaddress: "10.0.0.1"},
{Ipaddress: "10.0.0.2"},
},
},
wantAddrs: []corev1.NodeAddress{
{Type: corev1.NodeInternalIP, Address: "10.0.0.1"},
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotAddrs, err := cs.nodeAddresses(tt.instance)
if tt.wantErr {
if err == nil {
t.Errorf("nodeAddresses() expected error, got nil")
return
}
if tt.errContains != "" && !strings.Contains(err.Error(), tt.errContains) {
t.Errorf("nodeAddresses() error = %v, want error containing %q", err, tt.errContains)
}
return
}
if err != nil {
t.Errorf("nodeAddresses() unexpected error: %v", err)
return
}
if len(gotAddrs) != len(tt.wantAddrs) {
t.Errorf("nodeAddresses() returned %d addresses, want %d", len(gotAddrs), len(tt.wantAddrs))
return
}
for i, want := range tt.wantAddrs {
if gotAddrs[i].Type != want.Type || gotAddrs[i].Address != want.Address {
t.Errorf("nodeAddresses()[%d] = {%v, %v}, want {%v, %v}",
i, gotAddrs[i].Type, gotAddrs[i].Address, want.Type, want.Address)
}
}
})
}
}
func TestGetProviderIDFromInstanceID(t *testing.T) {
cs := &CSCloud{}
tests := []struct {
name string
instanceID string
want string
}{
{
name: "valid instance ID",
instanceID: "vm-123",
want: "external-cloudstack://vm-123",
},
{
name: "empty instance ID",
instanceID: "",
want: "external-cloudstack://",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := cs.getProviderIDFromInstanceID(tt.instanceID)
if got != tt.want {
t.Errorf("getProviderIDFromInstanceID(%q) = %q, want %q", tt.instanceID, got, tt.want)
}
})
}
}
func TestGetInstanceIDFromProviderID(t *testing.T) {
cs := &CSCloud{}
tests := []struct {
name string
providerID string
want string
}{
{
name: "full provider ID format",
providerID: "external-cloudstack://vm-123",
want: "vm-123",
},
{
name: "instance ID only - backward compatibility",
providerID: "vm-123",
want: "vm-123",
},
{
name: "empty string",
providerID: "",
want: "",
},
{
name: "invalid format - no separator",
providerID: "external-cloudstack-vm-123",
want: "external-cloudstack-vm-123",
},
{
name: "different provider prefix",
providerID: "aws://i-1234567890abcdef0",
want: "i-1234567890abcdef0",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := cs.getInstanceIDFromProviderID(tt.providerID)
if got != tt.want {
t.Errorf("getInstanceIDFromProviderID(%q) = %q, want %q", tt.providerID, got, tt.want)
}
})
}
}