Skip to content

Commit 5c3cadf

Browse files
author
Pushkar Acharya
committed
Use list VMs with filtering when fetching VMs
Using GET VMs call can result in 403 if the VM is not found or if the credentials are incorrect. To avoid ambiguity use list VMs call with filtering based on name or IDs which will result in empty list if the VM is not found. Also handles mismatch in providerID in case the VM is deleted and recreated with same name again. In such cases, we query crusoe APIs to fetch the VM by name. Updates the deployment to run CCM in host network to remove dependency on a functional CNI
1 parent daa661d commit 5c3cadf

File tree

5 files changed

+46
-13
lines changed

5 files changed

+46
-13
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ tests.xml
99
coverage.xml
1010
.vscode/*
1111
.idea/*
12+
vendor/*

internal/client/client.go

+9-3
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,20 @@ func (a *APIClientImpl) GetInstanceByID(ctx context.Context,
8383
}
8484

8585
klog.Infof("getInstanceByID: %s", instanceID)
86-
instance, response, err := a.CrusoeAPIClient.VMsApi.GetInstance(ctx, projectID, instanceID)
86+
listVMOpts := &crusoeapi.VMsApiListInstancesOpts{
87+
Ids: optional.NewString(instanceID),
88+
}
89+
instances, response, err := a.CrusoeAPIClient.VMsApi.ListInstances(ctx, projectID, listVMOpts)
8790
if err != nil {
8891
return nil, response, fmt.Errorf("failed to list instances: %w", err)
8992
}
9093
if response != nil {
9194
defer response.Body.Close()
9295
}
93-
klog.Infof("getInstanceByID: %v", instance)
96+
klog.Infof("getInstanceByID: %v", instances)
97+
if len(instances.Items) == 0 {
98+
return nil, nil, ErrInstanceNotFound
99+
}
94100

95-
return &instance, response, nil
101+
return &instances.Items[0], response, nil
96102
}

internal/instances/instances.go

+23-4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"errors"
66
"fmt"
7+
"strings"
78
"sync"
89
"time"
910

@@ -168,12 +169,19 @@ func (i *Instances) InstanceExists(ctx context.Context, node *v1.Node) (bool, er
168169

169170
func (i *Instances) InstanceMetadata(ctx context.Context, node *v1.Node) (*cloudprovider.InstanceMetadata, error) {
170171
klog.Infof("Get Instance Metadata for (%v)", node.Name)
171-
currInstance, responseBody, err := i.apiClient.GetInstanceByID(ctx, getInstanceIDFromProviderID(node.Spec.ProviderID))
172+
prefixedProviderID, err := getProviderID(ctx, node, i)
173+
if err != nil {
174+
klog.Errorf("could not get provider ID from Crusoe Cloud %v", err)
175+
176+
return nil, err
177+
}
178+
providerID := getInstanceIDFromProviderID(prefixedProviderID)
179+
currInstance, responseBody, err := i.apiClient.GetInstanceByID(ctx, providerID)
172180
if responseBody != nil {
173181
defer responseBody.Body.Close()
174182
}
175183
if err != nil {
176-
return nil, fmt.Errorf("failed to get instance by ID %s: %w", node.Spec.ProviderID, err)
184+
return nil, fmt.Errorf("failed to get instance by ID %s: %w", providerID, err)
177185
}
178186
klog.Infof("InstanceMetadata for (%v:%v)", node.Name, currInstance)
179187
nodeAddress, err := getNodeAddress(currInstance)
@@ -218,6 +226,17 @@ func NewCrusoeInstances(c client.APIClient) *Instances {
218226

219227
func getProviderID(ctx context.Context, node *v1.Node, i *Instances) (string, error) {
220228
providerID := node.Spec.ProviderID
229+
// While kubelet does not update the node.spec or the node.status.addresses or metadata fields when
230+
// node information changes it is still able to update the nodeInfo field in node.status. Kubelet updates
231+
// node.Status.NodeInfo.SystemUUID to /sys/class/dmi/id/product_uuid which is the correct VM ID in Crusoe Cloud
232+
if node.Status.NodeInfo.SystemUUID != "" &&
233+
getInstanceIDFromProviderID(node.Spec.ProviderID) != node.Status.NodeInfo.SystemUUID {
234+
235+
klog.Warningf("ProviderID and SystemUUID do not match; providerID: "+
236+
"%s; systemUUID: %s. Fetching UUID from Crusoe Cloud directly.",
237+
providerID, node.Status.NodeInfo.SystemUUID)
238+
providerID = ""
239+
}
221240
if providerID == "" {
222241
currInstance, err := i.apiClient.GetInstanceByName(ctx, node.Name)
223242
if err != nil {
@@ -230,7 +249,7 @@ func getProviderID(ctx context.Context, node *v1.Node, i *Instances) (string, er
230249
}
231250

232251
func getInstanceIDFromProviderID(providerID string) string {
233-
return providerID[len(ProviderPrefix):]
252+
return strings.TrimPrefix(providerID, ProviderPrefix)
234253
}
235254

236255
func getNodeAddress(currInstance *crusoeapi.InstanceV1Alpha5) ([]v1.NodeAddress, error) {
@@ -243,7 +262,7 @@ func getNodeAddress(currInstance *crusoeapi.InstanceV1Alpha5) ([]v1.NodeAddress,
243262
Address: currInstance.NetworkInterfaces[0].Ips[0].PublicIpv4.Address,
244263
}, v1.NodeAddress{
245264
Type: v1.NodeHostName,
246-
Address: currInstance.Name,
265+
Address: fmt.Sprintf("%s.%s.compute.internal", currInstance.Name, currInstance.Location),
247266
},
248267
)
249268

internal/instances/instances_test.go

+11-6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package instances_test
22

33
import (
44
"context"
5+
"fmt"
56
"os"
67
"testing"
78

@@ -23,6 +24,7 @@ const (
2324
ProviderIDPrefix = "crusoe://"
2425
CrusoeProjectID = "CRUSOE_PROJECT_ID"
2526
TestProjectID = "1841af90-a4f6-4412-8b23-b7035a6c72ae"
27+
TestLocation = "us-easttesting1-a"
2628
)
2729

2830
func TestNodeAddresses(t *testing.T) {
@@ -47,15 +49,16 @@ func TestNodeAddresses(t *testing.T) {
4749
},
4850
},
4951
},
50-
Name: "node1",
52+
Name: "node1",
53+
Location: TestLocation,
5154
}, nil)
5255

5356
addresses, err := instanceService.NodeAddresses(context.Background(), types.NodeName(TESTNodeName))
5457
require.NoError(t, err)
5558
require.Len(t, addresses, 3)
5659
require.Equal(t, "10.0.0.1", addresses[0].Address)
5760
require.Equal(t, "192.168.0.1", addresses[1].Address)
58-
require.Equal(t, "node1", addresses[2].Address)
61+
require.Equal(t, "node1.us-easttesting1-a.compute.internal", addresses[2].Address)
5962
}
6063

6164
func TestInstanceID(t *testing.T) {
@@ -126,7 +129,8 @@ func TestInstanceMetadata(t *testing.T) {
126129
},
127130
},
128131
},
129-
Name: TESTNodeName,
132+
Name: TESTNodeName,
133+
Location: TestLocation,
130134
}, nil, nil)
131135

132136
node := &v1.Node{
@@ -139,7 +143,7 @@ func TestInstanceMetadata(t *testing.T) {
139143
require.NoError(t, err)
140144
require.NotNil(t, metadata)
141145
require.Equal(t, ProviderIDPrefix+TESTInstanceID, metadata.ProviderID)
142-
require.Equal(t, TESTNodeName, metadata.NodeAddresses[2].Address)
146+
require.Equal(t, fmt.Sprintf("%s.%s.compute.internal", TESTNodeName, TestLocation), metadata.NodeAddresses[2].Address)
143147
}
144148

145149
func TestNodeAddressesByProviderID(t *testing.T) {
@@ -163,15 +167,16 @@ func TestNodeAddressesByProviderID(t *testing.T) {
163167
},
164168
},
165169
},
166-
Name: TESTNodeName,
170+
Name: TESTNodeName,
171+
Location: TestLocation,
167172
}, nil, nil)
168173

169174
addresses, err := instanceService.NodeAddressesByProviderID(context.Background(), ProviderIDPrefix+TESTInstanceID)
170175
require.NoError(t, err)
171176
require.Len(t, addresses, 3)
172177
require.Equal(t, "10.0.0.1", addresses[0].Address)
173178
require.Equal(t, "192.168.0.1", addresses[1].Address)
174-
require.Equal(t, TESTNodeName, addresses[2].Address)
179+
require.Equal(t, fmt.Sprintf("%s.%s.compute.internal", TESTNodeName, TestLocation), addresses[2].Address)
175180
}
176181

177182
func TestGetInstanceType(t *testing.T) {

releases/crusoe-cloud-controller-manager/v0.1.2.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ spec:
5656
values:
5757
- crusoe-cloud-controller-manager
5858
topologyKey: "kubernetes.io/hostname"
59+
# needed to remove dependency on CNI
60+
hostNetwork: true
5961
containers:
6062
- name: crusoe-cloud-controller-manager
6163
image: ghcr.io/crusoecloud/crusoe-cloud-controller-manager:v0.1.0

0 commit comments

Comments
 (0)