Skip to content

Commit cf02b5c

Browse files
committed
WIP
1 parent ab9c7bd commit cf02b5c

File tree

3 files changed

+118
-35
lines changed

3 files changed

+118
-35
lines changed

pkg/provider/core.go

Lines changed: 81 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"errors"
1212
"fmt"
1313
"slices"
14+
"strconv"
1415
"strings"
1516

1617
"github.com/gardener/machine-controller-manager/pkg/util/provider/driver"
@@ -28,6 +29,8 @@ const (
2829
StackitRoleLabel = "mcm.gardener.cloud/role"
2930
)
3031

32+
const migratedMachineAnnotation = "stackit.cloud/migrated-machine"
33+
3134
// CreateMachine handles a machine creation request by creating a STACKIT server
3235
//
3336
// This method creates a new server in STACKIT infrastructure based on the ProviderSpec
@@ -54,6 +57,10 @@ func (p *Provider) CreateMachine(ctx context.Context, req *driver.CreateMachineR
5457
return nil, status.Error(codes.InvalidArgument, err.Error())
5558
}
5659

60+
if m, _ := strconv.ParseBool(req.Machine.Annotations[migratedMachineAnnotation]); m {
61+
return nil, status.Error(codes.AlreadyExists, fmt.Errorf("create for migrated machine %s will not work", req.Machine.Name).Error())
62+
}
63+
5764
// Decode ProviderSpec from MachineClass
5865
providerSpec, err := decodeProviderSpec(req.MachineClass)
5966
if err != nil {
@@ -186,12 +193,25 @@ func (p *Provider) CreateMachine(ctx context.Context, req *driver.CreateMachineR
186193
}
187194

188195
// check if server already exists
189-
server, err := p.getServerByName(ctx, projectID, providerSpec.Region, req.Machine.Name)
196+
servers, err := p.getServersByName(ctx, projectID, providerSpec.Region, map[string]string{
197+
StackitMachineLabel: req.Machine.Name,
198+
})
190199
if err != nil {
191200
klog.Errorf("Failed to fetch server for machine %q: %v", req.Machine.Name, err)
192201
return nil, status.Error(codes.Unavailable, fmt.Sprintf("failed to fetch server: %v", err))
193202
}
194203

204+
if len(servers) > 1 {
205+
klog.Errorf("Multiple servers already exists for this machine %q: %v", req.Machine.Name, err)
206+
return nil, status.Error(codes.AlreadyExists, fmt.Sprintf("failed to fetch server: %v", err))
207+
}
208+
209+
var server *Server
210+
211+
if len(servers) == 1 {
212+
server = servers[0]
213+
}
214+
195215
if server == nil {
196216
// Call STACKIT API to create server
197217
server, err = p.client.CreateServer(ctx, projectID, providerSpec.Region, createReq)
@@ -216,26 +236,18 @@ func (p *Provider) CreateMachine(ctx context.Context, req *driver.CreateMachineR
216236
}, nil
217237
}
218238

219-
func (p *Provider) getServerByName(ctx context.Context, projectID, region, serverName string) (*Server, error) {
239+
func (p *Provider) getServersByName(ctx context.Context, projectID, region string, selector map[string]string) ([]*Server, error) {
220240
// Check if the server got already created
221-
labelSelector := map[string]string{
222-
StackitMachineLabel: serverName,
223-
}
224-
servers, err := p.client.ListServers(ctx, projectID, region, labelSelector)
241+
servers, err := p.client.ListServers(ctx, projectID, region, selector)
225242
if err != nil {
226-
return nil, fmt.Errorf("SDK ListServers with labelSelector: %v failed: %w", labelSelector, err)
243+
return nil, fmt.Errorf("SDK ListServers with labelSelector: %v failed: %w", selector, err)
227244
}
228245

229-
if len(servers) > 1 {
230-
return nil, fmt.Errorf("%v servers found for server name %v", len(servers), serverName)
246+
if len(servers) == 0 {
247+
return nil, nil
231248
}
232249

233-
if len(servers) == 1 {
234-
return servers[0], nil
235-
}
236-
237-
// no servers found len == 0
238-
return nil, nil
250+
return servers, nil
239251
}
240252

241253
func (p *Provider) patchNetworkInterface(ctx context.Context, projectID, serverID string, providerSpec *api.ProviderSpec) error {
@@ -305,9 +317,11 @@ func (p *Provider) DeleteMachine(ctx context.Context, req *driver.DeleteMachineR
305317
return nil, status.Error(codes.Internal, fmt.Sprintf("failed to initialize STACKIT client: %v", err))
306318
}
307319

308-
var projectID, serverID string
320+
var projectID string
321+
var serverIDs []string
309322
var err error
310323
if req.Machine.Spec.ProviderID != "" {
324+
var serverID string
311325
if !strings.HasPrefix(req.Machine.Spec.ProviderID, StackitProviderName) {
312326
return nil, status.Error(codes.InvalidArgument, "providerID is not empty and does not start with stackit://")
313327
}
@@ -317,6 +331,7 @@ func (p *Provider) DeleteMachine(ctx context.Context, req *driver.DeleteMachineR
317331
if err != nil {
318332
klog.V(2).Infof("invalid ProviderID format: %v", err)
319333
}
334+
serverIDs = append(serverIDs, serverID)
320335
}
321336

322337
if projectID == "" {
@@ -328,36 +343,67 @@ func (p *Provider) DeleteMachine(ctx context.Context, req *driver.DeleteMachineR
328343
return nil, status.Error(codes.Internal, err.Error())
329344
}
330345

331-
if serverID == "" {
332-
server, err := p.getServerByName(ctx, projectID, providerSpec.Region, req.Machine.Name)
346+
if len(serverIDs) == 0 {
347+
selector := map[string]string{
348+
StackitMachineLabel: req.Machine.Name,
349+
}
350+
351+
if m, _ := strconv.ParseBool(req.Machine.Annotations[migratedMachineAnnotation]); m {
352+
selector = nil
353+
}
354+
355+
servers, err := p.getServersByName(ctx, projectID, providerSpec.Region, selector)
333356
if err != nil {
334357
return nil, status.Error(codes.Internal, fmt.Sprintf("failed to find server by name: %v", err))
335358
}
336359

337-
if server != nil {
338-
serverID = server.ID
360+
for _, server := range servers {
361+
if server.Name != req.Machine.Name {
362+
continue
363+
}
364+
serverIDs = append(serverIDs, server.ID)
339365
}
340366
}
341367

342-
if serverID == "" {
343-
klog.V(2).Infof("Server is already deleted for machine %q", req.Machine.Name)
344-
return &driver.DeleteMachineResponse{}, nil
368+
for _, id := range serverIDs {
369+
// Call STACKIT API to delete server
370+
err = p.client.DeleteServer(ctx, projectID, providerSpec.Region, id)
371+
if err != nil {
372+
// Check if server was not found (404) - this is OK for idempotency
373+
if errors.Is(err, ErrServerNotFound) {
374+
klog.V(2).Infof("Server %q already deleted for machine %q (idempotent)", id, req.Machine.Name)
375+
return &driver.DeleteMachineResponse{}, nil
376+
}
377+
// All other errors are internal errors
378+
klog.Errorf("Failed to delete server for machine %q: %v", req.Machine.Name, err)
379+
return nil, status.Error(codes.Internal, fmt.Sprintf("failed to delete server: %v", err))
380+
}
345381
}
346382

347-
// Call STACKIT API to delete server
348-
err = p.client.DeleteServer(ctx, projectID, providerSpec.Region, serverID)
349-
if err != nil {
350-
// Check if server was not found (404) - this is OK for idempotency
351-
if errors.Is(err, ErrServerNotFound) {
352-
klog.V(2).Infof("Server %q already deleted for machine %q (idempotent)", serverID, req.Machine.Name)
353-
return &driver.DeleteMachineResponse{}, nil
383+
if m, _ := strconv.ParseBool(req.Machine.Annotations[migratedMachineAnnotation]); m {
384+
nics, err := p.client.ListNICs(ctx, projectID, providerSpec.Region, providerSpec.Networking.NetworkID)
385+
if err != nil {
386+
return nil, err
387+
}
388+
for _, nic := range nics {
389+
if nic.Name != req.Machine.Name {
390+
continue
391+
}
392+
err = p.client.DeleteNIC(ctx, projectID, providerSpec.Region, nic.NetworkID, nic.ID)
393+
if err != nil {
394+
// Check if server was not found (404) - this is OK for idempotency
395+
if errors.Is(err, ErrNicNotFound) {
396+
klog.V(2).Infof("Nic %q already deleted for machine %q (idempotent)", nic.ID, req.Machine.Name)
397+
return &driver.DeleteMachineResponse{}, nil
398+
}
399+
// All other errors are internal errors
400+
klog.Errorf("Failed to delete nic for machine %q: %v", req.Machine.Name, err)
401+
return nil, status.Error(codes.Internal, fmt.Sprintf("failed to delete nic: %v", err))
402+
}
354403
}
355-
// All other errors are internal errors
356-
klog.Errorf("Failed to delete server for machine %q: %v", req.Machine.Name, err)
357-
return nil, status.Error(codes.Internal, fmt.Sprintf("failed to delete server: %v", err))
358-
}
359404

360-
klog.V(2).Infof("Successfully deleted server %q for machine %q", serverID, req.Machine.Name)
405+
}
406+
klog.V(2).Infof("Successfully deleted server for machine %q", req.Machine.Name)
361407

362408
return &driver.DeleteMachineResponse{}, nil
363409
}

pkg/provider/sdk_client.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ func NewStackitClient(serviceAccountKey string) (*SdkStackitClient, error) {
4141
var (
4242
// ErrServerNotFound indicates the server was not found (404)
4343
ErrServerNotFound = errors.New("server not found")
44+
ErrNicNotFound = errors.New("nic not found")
4445
)
4546

4647
// createIAASClient creates a new STACKIT SDK IAAS API client
@@ -320,6 +321,36 @@ func (c *SdkStackitClient) GetNICsForServer(ctx context.Context, projectID, regi
320321
return nics, nil
321322
}
322323

324+
func (c *SdkStackitClient) ListNICs(ctx context.Context, projectID, region, networkID string) ([]*NIC, error) {
325+
res, err := c.iaasClient.ListNics(ctx, projectID, region, networkID).Execute()
326+
if err != nil {
327+
return nil, fmt.Errorf("SDK ListServerNICs failed: %w", err)
328+
}
329+
330+
if res.Items == nil {
331+
return []*NIC{}, nil
332+
}
333+
334+
nics := make([]*NIC, 0)
335+
for _, nic := range *res.Items {
336+
nics = append(nics, convertSDKNICtoNIC(&nic))
337+
}
338+
339+
return nics, nil
340+
}
341+
342+
func (c *SdkStackitClient) DeleteNIC(ctx context.Context, projectID, region, networkID, nicID string) error {
343+
err := c.iaasClient.DeleteNic(ctx, projectID, region, networkID, nicID).Execute()
344+
if err != nil {
345+
// Check if error is 404 Not Found - this is OK (idempotent)
346+
if isNotFoundError(err) {
347+
return fmt.Errorf("%w: %v", ErrNicNotFound, err)
348+
}
349+
return fmt.Errorf("SDK DeleteNic failed: %w", err)
350+
}
351+
return nil
352+
}
353+
323354
func (c *SdkStackitClient) UpdateNIC(ctx context.Context, projectID, region, networkID, nicID string, allowedAddresses []string) (*NIC, error) {
324355
addresses := make([]iaas.AllowedAddressesInner, len(allowedAddresses))
325356

@@ -361,6 +392,7 @@ func convertSDKNICtoNIC(nic *iaas.NIC) *NIC {
361392
ID: getStringValue(nic.Id),
362393
NetworkID: getStringValue(nic.NetworkId),
363394
AllowedAddresses: addresses,
395+
Name: getStringValue(nic.Name),
364396
}
365397
}
366398

pkg/provider/stackit_client.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ type StackitClient interface {
3030
ListServers(ctx context.Context, projectID, region string, labelSelector map[string]string) ([]*Server, error)
3131
// GetNICsForServer retrieves a network interfaces for a given server
3232
GetNICsForServer(ctx context.Context, projectID, region, serverID string) ([]*NIC, error)
33+
// ListNics list all nics for a network
34+
ListNICs(ctx context.Context, projectID, region, networkID string) ([]*NIC, error)
35+
// DeleteNIC delete a given nic by ID
36+
DeleteNIC(ctx context.Context, projectID, region, networkID, nicID string) error
3337
// UpdateNIC updates a network interface
3438
UpdateNIC(ctx context.Context, projectID, region, networkID, nicID string, allowedAddresses []string) (*NIC, error)
3539
}
@@ -97,4 +101,5 @@ type NIC struct {
97101
ID string
98102
NetworkID string
99103
AllowedAddresses []string
104+
Name string
100105
}

0 commit comments

Comments
 (0)