@@ -10,10 +10,13 @@ import (
1010 "encoding/base64"
1111 "errors"
1212 "fmt"
13+ "slices"
14+ "strings"
1315
1416 "github.com/gardener/machine-controller-manager/pkg/util/provider/driver"
1517 "github.com/gardener/machine-controller-manager/pkg/util/provider/machinecodes/codes"
1618 "github.com/gardener/machine-controller-manager/pkg/util/provider/machinecodes/status"
19+ api "github.com/stackitcloud/machine-controller-manager-provider-stackit/pkg/provider/apis"
1720 "github.com/stackitcloud/machine-controller-manager-provider-stackit/pkg/provider/apis/validation"
1821 "k8s.io/klog/v2"
1922)
@@ -182,27 +185,106 @@ func (p *Provider) CreateMachine(ctx context.Context, req *driver.CreateMachineR
182185 createReq .Metadata = providerSpec .Metadata
183186 }
184187
185- // Call STACKIT API to create server
186- server , err := p .client . CreateServer (ctx , projectID , providerSpec .Region , createReq )
188+ // check if server already exists
189+ server , err := p .getServerByName (ctx , projectID , providerSpec .Region , req . Machine . Name )
187190 if err != nil {
188- klog .Errorf ("Failed to create server for machine %q: %v" , req .Machine .Name , err )
189- return nil , status .Error (codes .Internal , fmt .Sprintf ("failed to create server: %v" , err ))
191+ klog .Errorf ("Failed to fetch server for machine %q: %v" , req .Machine .Name , err )
192+ return nil , status .Error (codes .Unavailable , fmt .Sprintf ("failed to fetch server: %v" , err ))
190193 }
191194
192- // Generate ProviderID in format: stackit://<projectId>/<serverId>
193- providerID := fmt .Sprintf ("%s://%s/%s" , StackitProviderName , projectID , server .ID )
195+ if server == nil {
196+ // Call STACKIT API to create server
197+ server , err = p .client .CreateServer (ctx , projectID , providerSpec .Region , createReq )
198+ if err != nil {
199+ klog .Errorf ("Failed to create server for machine %q: %v" , req .Machine .Name , err )
200+ return nil , status .Error (codes .Unavailable , fmt .Sprintf ("failed to create server: %v" , err ))
201+ }
202+ }
194203
195- // NodeName is the machine name (will register with this name in Kubernetes)
196- nodeName := req .Machine .Name
204+ if err := p .patchNetworkInterface (ctx , projectID , server .ID , providerSpec ); err != nil {
205+ klog .Errorf ("Failed to patch network interface for server %q: %v" , req .Machine .Name , err )
206+ return nil , status .Error (codes .Unavailable , fmt .Sprintf ("failed to patch network interface for server: %v" , err ))
207+ }
197208
209+ // Generate ProviderID in format: stackit://<projectId>/<serverId>
210+ providerID := fmt .Sprintf ("%s://%s/%s" , StackitProviderName , projectID , server .ID )
198211 klog .V (2 ).Infof ("Successfully created server %q with ID %q for machine %q" , server .Name , server .ID , req .Machine .Name )
199212
200213 return & driver.CreateMachineResponse {
201214 ProviderID : providerID ,
202- NodeName : nodeName ,
215+ NodeName : req . Machine . Name ,
203216 }, nil
204217}
205218
219+ func (p * Provider ) getServerByName (ctx context.Context , projectID , region , serverName string ) (* Server , error ) {
220+ // 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 )
225+ if err != nil {
226+ return nil , fmt .Errorf ("SDK ListServers with labelSelector: %v failed: %w" , labelSelector , err )
227+ }
228+
229+ if len (servers ) > 1 {
230+ return nil , fmt .Errorf ("%v servers found for server name %v" , len (servers ), serverName )
231+ }
232+
233+ if len (servers ) == 1 {
234+ return servers [0 ], nil
235+ }
236+
237+ // no servers found len == 0
238+ return nil , nil
239+ }
240+
241+ func (p * Provider ) patchNetworkInterface (ctx context.Context , projectID , serverID string , providerSpec * api.ProviderSpec ) error {
242+ if len (providerSpec .AllowedAddresses ) == 0 {
243+ return nil
244+ }
245+
246+ nics , err := p .client .GetNICsForServer (ctx , projectID , providerSpec .Region , serverID )
247+ if err != nil {
248+ return fmt .Errorf ("failed to get NICs for server %q: %w" , serverID , err )
249+ }
250+
251+ if len (nics ) == 0 {
252+ return fmt .Errorf ("failed to find NIC for server %q" , serverID )
253+ }
254+
255+ for _ , nic := range nics {
256+ // if networking is not set, server is inside the default network
257+ // just patch the interface since the server should only have one
258+ if providerSpec .Networking != nil {
259+ // only process interfaces that are either in the configured network (NetworkID) or are defined in NICIDs
260+ if providerSpec .Networking .NetworkID != nic .NetworkID && ! slices .Contains (providerSpec .Networking .NICIDs , nic .ID ) {
261+ continue
262+ }
263+ }
264+
265+ updateNic := false
266+ // check if every cidr in providerspec.allowedAddresses is inside the nic allowedAddresses
267+ for _ , allowedAddress := range providerSpec .AllowedAddresses {
268+ if ! slices .Contains (nic .AllowedAddresses , allowedAddress ) {
269+ nic .AllowedAddresses = append (nic .AllowedAddresses , allowedAddress )
270+ updateNic = true
271+ }
272+ }
273+
274+ if ! updateNic {
275+ continue
276+ }
277+
278+ if _ , err := p .client .UpdateNIC (ctx , projectID , providerSpec .Region , nic .NetworkID , nic .ID , nic .AllowedAddresses ); err != nil {
279+ return fmt .Errorf ("failed to update allowed addresses for NIC %s: %w" , nic .ID , err )
280+ }
281+
282+ klog .V (2 ).Infof ("Updated allowed addresses for NIC %s to %v" , nic .ID , nic .AllowedAddresses )
283+ }
284+
285+ return nil
286+ }
287+
206288// DeleteMachine handles a machine deletion request by deleting the STACKIT server
207289//
208290// This method deletes the server identified by the ProviderID from STACKIT infrastructure.
@@ -216,33 +298,52 @@ func (p *Provider) DeleteMachine(ctx context.Context, req *driver.DeleteMachineR
216298 klog .V (2 ).Infof ("Machine deletion request has been received for %q" , req .Machine .Name )
217299 defer klog .V (2 ).Infof ("Machine deletion request has been processed for %q" , req .Machine .Name )
218300
219- // Validate ProviderID exists
220- if req .Machine .Spec .ProviderID == "" {
221- return nil , status .Error (codes .InvalidArgument , "ProviderID is required" )
222- }
223-
224301 // Extract credentials from Secret
225302 serviceAccountKey := string (req .Secret .Data ["serviceaccount.json" ])
226-
227303 // Initialize client on first use (lazy initialization)
228304 if err := p .ensureClient (serviceAccountKey ); err != nil {
229305 return nil , status .Error (codes .Internal , fmt .Sprintf ("failed to initialize STACKIT client: %v" , err ))
230306 }
231307
232- // Parse ProviderID to extract projectID and serverID
233- projectID , serverID , err := parseProviderID (req .Machine .Spec .ProviderID )
308+ var projectID , serverID string
309+ var err error
310+ if req .Machine .Spec .ProviderID != "" {
311+ if ! strings .HasPrefix (req .Machine .Spec .ProviderID , StackitProviderName ) {
312+ return nil , status .Error (codes .InvalidArgument , "providerID is not empty and does not start with stackit://" )
313+ }
314+
315+ // Parse ProviderID to extract projectID and serverID
316+ projectID , serverID , err = parseProviderID (req .Machine .Spec .ProviderID )
317+ if err != nil {
318+ klog .V (2 ).Infof ("invalid ProviderID format: %v" , err )
319+ }
320+ }
321+
234322 if projectID == "" {
235323 projectID = string (req .Secret .Data ["project-id" ])
236324 }
237- if err != nil {
238- return nil , status .Error (codes .InvalidArgument , fmt .Sprintf ("invalid ProviderID format: %v" , err ))
239- }
240325
241326 providerSpec , err := decodeProviderSpec (req .MachineClass )
242327 if err != nil {
243328 return nil , status .Error (codes .Internal , err .Error ())
244329 }
245330
331+ if serverID == "" {
332+ server , err := p .getServerByName (ctx , projectID , providerSpec .Region , req .Machine .Name )
333+ if err != nil {
334+ return nil , status .Error (codes .Internal , fmt .Sprintf ("failed to find server by name: %v" , err ))
335+ }
336+
337+ if server != nil {
338+ serverID = server .ID
339+ }
340+ }
341+
342+ if serverID == "" {
343+ klog .V (2 ).Infof ("Server is already deleted for machine %q" , req .Machine .Name )
344+ return & driver.DeleteMachineResponse {}, nil
345+ }
346+
246347 // Call STACKIT API to delete server
247348 err = p .client .DeleteServer (ctx , projectID , providerSpec .Region , serverID )
248349 if err != nil {
@@ -364,7 +465,9 @@ func (p *Provider) ListMachines(ctx context.Context, req *driver.ListMachinesReq
364465 }
365466
366467 // Call STACKIT API to list all servers
367- labelSelector := fmt .Sprintf ("%s=%s" , StackitMachineClassLabel , req .MachineClass .Name )
468+ labelSelector := map [string ]string {
469+ StackitMachineClassLabel : req .MachineClass .Name ,
470+ }
368471 servers , err := p .client .ListServers (ctx , projectID , providerSpec .Region , labelSelector )
369472 if err != nil {
370473 klog .Errorf ("Failed to list servers for MachineClass %q: %v" , req .MachineClass .Name , err )
0 commit comments