-
Notifications
You must be signed in to change notification settings - Fork 1
Cleanup NICs when migrate from openstack MCM #89
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
7e0a67c
6be6d0a
6999aa0
fe038e0
17def4f
95cc8ce
297978b
bd1f1ff
5e8df25
b47d91d
e776b6d
54cba9a
b8fb2b0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -6,6 +6,7 @@ import ( | |||||||||
| "fmt" | ||||||||||
| "maps" | ||||||||||
| "slices" | ||||||||||
| "strconv" | ||||||||||
|
|
||||||||||
| "github.com/gardener/machine-controller-manager/pkg/util/provider/driver" | ||||||||||
| "github.com/gardener/machine-controller-manager/pkg/util/provider/machinecodes/codes" | ||||||||||
|
|
@@ -41,74 +42,116 @@ func (p *Provider) CreateMachine(ctx context.Context, req *driver.CreateMachineR | |||||||||
| klog.V(2).Infof("Machine creation request has been received for %q", req.Machine.Name) | ||||||||||
| defer klog.V(2).Infof("Machine creation request has been processed for %q", req.Machine.Name) | ||||||||||
|
|
||||||||||
| // Check if incoming provider in the MachineClass is a provider we support | ||||||||||
| providerSpec, projectID, err := p.prepareMachineCreation(req) | ||||||||||
| if err != nil { | ||||||||||
| return nil, err | ||||||||||
| } | ||||||||||
|
|
||||||||||
| server, err := p.getOrCreateServer(ctx, req, projectID, providerSpec) | ||||||||||
| if err != nil { | ||||||||||
| return nil, err | ||||||||||
| } | ||||||||||
|
|
||||||||||
| if err := p.waitForServer(ctx, req.Machine.Name, projectID, providerSpec.Region, server.ID); err != nil { | ||||||||||
| return nil, err | ||||||||||
| } | ||||||||||
|
|
||||||||||
| nics, err := p.patchNetworkInterfaces(ctx, projectID, server.ID, providerSpec) | ||||||||||
| if err != nil { | ||||||||||
| klog.Errorf("Failed to patch NICs for server %q: %v", req.Machine.Name, err) | ||||||||||
| return nil, status.Error(codes.Unavailable, fmt.Sprintf("failed to patch NICs for server: %v", err)) | ||||||||||
| } | ||||||||||
|
|
||||||||||
| // Generate ProviderID in format: stackit://<projectId>/<serverId> | ||||||||||
| providerID := fmt.Sprintf("%s://%s/%s", StackitProviderName, projectID, server.ID) | ||||||||||
| klog.V(2).Infof("Successfully created server %q with ID %q for machine %q", server.Name, server.ID, req.Machine.Name) | ||||||||||
|
|
||||||||||
| return &driver.CreateMachineResponse{ | ||||||||||
| ProviderID: providerID, | ||||||||||
| NodeName: req.Machine.Name, | ||||||||||
| Addresses: nicAddresses(nics), | ||||||||||
| }, nil | ||||||||||
| } | ||||||||||
|
|
||||||||||
| func (p *Provider) prepareMachineCreation(req *driver.CreateMachineRequest) (*api.ProviderSpec, string, error) { | ||||||||||
| if req.MachineClass.Provider != StackitProviderName { | ||||||||||
| err := fmt.Errorf("requested for Provider '%s', we only support '%s'", req.MachineClass.Provider, StackitProviderName) | ||||||||||
| return nil, status.Error(codes.InvalidArgument, err.Error()) | ||||||||||
| return nil, "", status.Error(codes.InvalidArgument, err.Error()) | ||||||||||
| } | ||||||||||
|
|
||||||||||
| if m, _ := strconv.ParseBool(req.Machine.Annotations[migratedMachineAnnotation]); m { | ||||||||||
| return nil, "", status.Error(codes.AlreadyExists, fmt.Errorf("create for migrated machine %s will not work", req.Machine.Name).Error()) | ||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Avoid allocating an intermediate error object solely to call |
||||||||||
| } | ||||||||||
|
aniruddha2000 marked this conversation as resolved.
|
||||||||||
|
|
||||||||||
| // Decode ProviderSpec from MachineClass | ||||||||||
| providerSpec, err := decodeProviderSpec(req.MachineClass) | ||||||||||
| if err != nil { | ||||||||||
| return nil, status.Error(codes.Internal, err.Error()) | ||||||||||
| return nil, "", status.Error(codes.Internal, err.Error()) | ||||||||||
| } | ||||||||||
|
|
||||||||||
| // Validate ProviderSpec and Secret | ||||||||||
| validationErrs := validation.ValidateProviderSpecNSecret(providerSpec, req.Secret) | ||||||||||
| if len(validationErrs) > 0 { | ||||||||||
| return nil, status.Error(codes.InvalidArgument, validationErrs[0].Error()) | ||||||||||
| return nil, "", status.Error(codes.InvalidArgument, validationErrs[0].Error()) | ||||||||||
| } | ||||||||||
|
|
||||||||||
| // Extract credentials from Secret | ||||||||||
| projectID, serviceAccountKey := extractSecretCredentials(req.Secret.Data) | ||||||||||
|
|
||||||||||
| // Initialize client on first use (lazy initialization) | ||||||||||
| if err := p.ensureClient(serviceAccountKey); err != nil { | ||||||||||
| return nil, status.Error(codes.Internal, fmt.Sprintf("failed to initialize STACKIT client: %v", err)) | ||||||||||
| return nil, "", status.Error(codes.Internal, fmt.Sprintf("failed to initialize STACKIT client: %v", err)) | ||||||||||
| } | ||||||||||
| return providerSpec, projectID, nil | ||||||||||
| } | ||||||||||
|
|
||||||||||
| // check if server already exists | ||||||||||
| server, err := p.getServerByName(ctx, projectID, providerSpec.Region, req.Machine.Name) | ||||||||||
| func (p *Provider) getOrCreateServer(ctx context.Context, req *driver.CreateMachineRequest, projectID string, providerSpec *api.ProviderSpec) (*client.Server, error) { | ||||||||||
| servers, err := p.getServersByLabelSelector(ctx, projectID, providerSpec.Region, map[string]string{ | ||||||||||
| StackitMachineLabel: req.Machine.Name, | ||||||||||
| }) | ||||||||||
| if err != nil { | ||||||||||
| klog.Errorf("Failed to fetch server for machine %q: %v", req.Machine.Name, err) | ||||||||||
| return nil, status.Error(codes.Unavailable, fmt.Sprintf("failed to fetch server: %v", err)) | ||||||||||
| } | ||||||||||
|
|
||||||||||
| if server == nil { | ||||||||||
| // Call STACKIT API to create server | ||||||||||
| server, err = p.client.CreateServer(ctx, projectID, providerSpec.Region, p.createServerRequest(req, providerSpec)) | ||||||||||
| if err != nil { | ||||||||||
| klog.Errorf("Failed to create server for machine %q: %v", req.Machine.Name, err) | ||||||||||
| if isResourceExhaustedError(err) { | ||||||||||
| return nil, status.Error(codes.ResourceExhausted, fmt.Sprintf("failed to create server: %v", err)) | ||||||||||
| } | ||||||||||
| return nil, status.Error(codes.Unavailable, fmt.Sprintf("failed to create server: %v", err)) | ||||||||||
| if len(servers) > 1 { | ||||||||||
| serverNames := make([]string, len(servers)) | ||||||||||
| for i, server := range servers { | ||||||||||
| serverNames[i] = server.Name | ||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Include |
||||||||||
| } | ||||||||||
|
|
||||||||||
| klog.Errorf( | ||||||||||
| "Multiple servers already exist for this machine %q: servers=%v", | ||||||||||
| req.Machine.Name, | ||||||||||
| serverNames, | ||||||||||
| ) | ||||||||||
| return nil, status.Error(codes.AlreadyExists, fmt.Sprintf("Multiple servers: %v already exists for the machine: %v", serverNames, req.Machine.Name)) | ||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Fix grammar ("already exist") and use lowercase initial character consistent with standard error message styling. |
||||||||||
| } | ||||||||||
|
|
||||||||||
| if err := p.WaitUntilServerRunning(ctx, projectID, providerSpec.Region, server.ID); err != nil { | ||||||||||
| klog.Errorf("Failed waiting for server %q to reach ACTIVE state: %v", req.Machine.Name, err) | ||||||||||
| if isResourceExhaustedError(err) { | ||||||||||
| return nil, status.Error(codes.ResourceExhausted, fmt.Sprintf("failed waiting for server to be ACTIVE: %v", err)) | ||||||||||
| } | ||||||||||
| return nil, status.Error(codes.DeadlineExceeded, fmt.Sprintf("failed waiting for server to be ACTIVE: %v", err)) | ||||||||||
| if len(servers) == 1 { | ||||||||||
| return servers[0], nil | ||||||||||
| } | ||||||||||
|
|
||||||||||
| nics, err := p.patchNetworkInterfaces(ctx, projectID, server.ID, providerSpec) | ||||||||||
| server, err := p.client.CreateServer(ctx, projectID, providerSpec.Region, p.createServerRequest(req, providerSpec)) | ||||||||||
| if err != nil { | ||||||||||
| klog.Errorf("Failed to patch NICs for server %q: %v", req.Machine.Name, err) | ||||||||||
| return nil, status.Error(codes.Unavailable, fmt.Sprintf("failed to patch NICs for server: %v", err)) | ||||||||||
| klog.Errorf("Failed to create server for machine %q: %v", req.Machine.Name, err) | ||||||||||
| if isResourceExhaustedError(err) { | ||||||||||
| return nil, status.Error(codes.ResourceExhausted, fmt.Sprintf("failed to create server: %v", err)) | ||||||||||
| } | ||||||||||
| return nil, status.Error(codes.Unavailable, fmt.Sprintf("failed to create server: %v", err)) | ||||||||||
| } | ||||||||||
| return server, nil | ||||||||||
| } | ||||||||||
|
|
||||||||||
| // Generate ProviderID in format: stackit://<projectId>/<serverId> | ||||||||||
| providerID := fmt.Sprintf("%s://%s/%s", StackitProviderName, projectID, server.ID) | ||||||||||
| klog.V(2).Infof("Successfully created server %q with ID %q for machine %q", server.Name, server.ID, req.Machine.Name) | ||||||||||
|
|
||||||||||
| return &driver.CreateMachineResponse{ | ||||||||||
| ProviderID: providerID, | ||||||||||
| NodeName: req.Machine.Name, | ||||||||||
| Addresses: nicAddresses(nics), | ||||||||||
| }, nil | ||||||||||
| func (p *Provider) waitForServer(ctx context.Context, machineName, projectID, region, serverID string) error { | ||||||||||
| if err := p.WaitUntilServerRunning(ctx, projectID, region, serverID); err != nil { | ||||||||||
| klog.Errorf("Failed waiting for server %q to reach ACTIVE state: %v", machineName, err) | ||||||||||
| if isResourceExhaustedError(err) { | ||||||||||
| return status.Error(codes.ResourceExhausted, fmt.Sprintf("failed waiting for server to be ACTIVE: %v", err)) | ||||||||||
| } | ||||||||||
| return status.Error(codes.DeadlineExceeded, fmt.Sprintf("failed waiting for server to be ACTIVE: %v", err)) | ||||||||||
| } | ||||||||||
| return nil | ||||||||||
| } | ||||||||||
|
|
||||||||||
| // nolint: gocyclo // this function is already pretty simple | ||||||||||
|
|
@@ -233,26 +276,18 @@ func nicAddresses(nics []*client.NIC) []corev1.NodeAddress { | |||||||||
| return addresses | ||||||||||
| } | ||||||||||
|
|
||||||||||
| func (p *Provider) getServerByName(ctx context.Context, projectID, region, serverName string) (*client.Server, error) { | ||||||||||
| func (p *Provider) getServersByLabelSelector(ctx context.Context, projectID, region string, selector map[string]string) ([]*client.Server, error) { | ||||||||||
| // Check if the server got already created | ||||||||||
| labelSelector := map[string]string{ | ||||||||||
| StackitMachineLabel: serverName, | ||||||||||
| } | ||||||||||
| servers, err := p.client.ListServers(ctx, projectID, region, labelSelector) | ||||||||||
| servers, err := p.client.ListServers(ctx, projectID, region, selector) | ||||||||||
| if err != nil { | ||||||||||
| return nil, fmt.Errorf("SDK ListServers with labelSelector: %v failed: %w", labelSelector, err) | ||||||||||
| return nil, fmt.Errorf("SDK ListServers with labelSelector: %v failed: %w", selector, err) | ||||||||||
| } | ||||||||||
|
|
||||||||||
| if len(servers) > 1 { | ||||||||||
| return nil, fmt.Errorf("%v servers found for server name %v", len(servers), serverName) | ||||||||||
| } | ||||||||||
|
|
||||||||||
| if len(servers) == 1 { | ||||||||||
| return servers[0], nil | ||||||||||
| if len(servers) == 0 { | ||||||||||
| return nil, nil | ||||||||||
| } | ||||||||||
|
|
||||||||||
| // no servers found len == 0 | ||||||||||
| return nil, nil | ||||||||||
| return servers, nil | ||||||||||
| } | ||||||||||
|
|
||||||||||
| func (p *Provider) patchNetworkInterfaces(ctx context.Context, projectID, serverID string, providerSpec *api.ProviderSpec) ([]*client.NIC, error) { | ||||||||||
|
|
||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix error message to reference
ListNICsinstead ofListServerNICs.