Skip to content

Commit afd0f3f

Browse files
committed
OCPBUGS-55372: Fix regression on ASH with armcompute/v5
The change "Update virtualmachines service to armcompute/v5 SDK" did not update the StackHub implementation of the virtualmachines service, which caused a failure in the machine actuator due to the difference in type returned by Get(). We fix this by moving to a common implementation for both StackHub and public clouds. Having a common implementation in virtualmachines also requires a change to the networkinterfaces Service. The networkinterfaces service Get() method returns different types for StackHub and public clouds, which were previously cast to the anticipated types by different implementations of the virtualmachines service. As we don't require the full type, we add a new type safe method which returns only the ID, meaning a common implementation is now safe.
1 parent edb2a00 commit afd0f3f

File tree

9 files changed

+120
-260
lines changed

9 files changed

+120
-260
lines changed

pkg/cloud/azure/services/networkinterfaces/networkinterfaces.go

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,31 @@ func (s *Service) Get(ctx context.Context, spec azure.Spec) (interface{}, error)
6060
if !ok {
6161
return network.Interface{}, errors.New("invalid network interface specification")
6262
}
63-
nic, err := s.Client.Get(ctx, s.Scope.MachineConfig.ResourceGroup, nicSpec.Name, "")
63+
return s.get(ctx, nicSpec.Name)
64+
}
65+
66+
func (s *Service) get(ctx context.Context, name string) (*network.Interface, error) {
67+
nic, err := s.Client.Get(ctx, s.Scope.MachineConfig.ResourceGroup, name, "")
6468
if err != nil && azure.ResourceNotFound(err) {
65-
return nil, fmt.Errorf("network interface %s not found: %w", nicSpec.Name, err)
69+
return nil, fmt.Errorf("network interface %s not found: %w", name, err)
6670
} else if err != nil {
67-
return nic, err
71+
return nil, err
6872
}
69-
return nic, nil
73+
return &nic, nil
74+
}
75+
76+
// GetID returns the ID of the network interface with the given name
77+
func (s *Service) GetID(ctx context.Context, name string) (string, error) {
78+
nic, err := s.get(ctx, name)
79+
if err != nil {
80+
return "", err
81+
}
82+
83+
if nic.ID == nil {
84+
return "", fmt.Errorf("network interface %s does not have an ID", name)
85+
}
86+
87+
return *nic.ID, nil
7088
}
7189

7290
// CreateOrUpdate creates or updates a network interface.

pkg/cloud/azure/services/networkinterfaces/networkinterfaces_stack.go

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,31 @@ func (s *StackHubService) Get(ctx context.Context, spec azure.Spec) (interface{}
4040
if !ok {
4141
return network.Interface{}, errors.New("invalid network interface specification")
4242
}
43-
nic, err := s.Client.Get(ctx, s.Scope.MachineConfig.ResourceGroup, nicSpec.Name, "")
43+
return s.get(ctx, nicSpec.Name)
44+
}
45+
46+
func (s *StackHubService) get(ctx context.Context, name string) (*network.Interface, error) {
47+
nic, err := s.Client.Get(ctx, s.Scope.MachineConfig.ResourceGroup, name, "")
4448
if err != nil && azure.ResourceNotFound(err) {
45-
return nil, fmt.Errorf("network interface %s not found: %w", nicSpec.Name, err)
49+
return nil, fmt.Errorf("network interface %s not found: %w", name, err)
4650
} else if err != nil {
47-
return nic, err
51+
return nil, err
4852
}
49-
return nic, nil
53+
return &nic, nil
54+
}
55+
56+
// GetID returns the ID of the network interface with the given name
57+
func (s *StackHubService) GetID(ctx context.Context, name string) (string, error) {
58+
nic, err := s.get(ctx, name)
59+
if err != nil {
60+
return "", err
61+
}
62+
63+
if nic.ID == nil {
64+
return "", fmt.Errorf("network interface %s does not have an ID", name)
65+
}
66+
67+
return *nic.ID, nil
5068
}
5169

5270
// CreateOrUpdate creates or updates a network interface.

pkg/cloud/azure/services/networkinterfaces/service.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ limitations under the License.
1717
package networkinterfaces
1818

1919
import (
20+
"context"
21+
2022
"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-02-01/network"
2123
"github.com/Azure/go-autorest/autorest"
2224
"github.com/openshift/machine-api-provider-azure/pkg/cloud/azure"
@@ -29,6 +31,24 @@ type Service struct {
2931
Scope *actuators.MachineScope
3032
}
3133

34+
// ServiceWithGetID implements the azure.Service interface, but additionally
35+
// provides a type safe method to return the ID of an object.
36+
//
37+
// The StackHub implementation of networkinterfaces uses a different API version
38+
// of 'network' to the non-StackHub version, which with the legacy SDK used here
39+
// means they return different types. To avoid potential errors from forgetting
40+
// this difference at the point of use, GetID returns a string and handles type
41+
// differences internally.
42+
//
43+
// This is useful in the virtualmachines service, which references a nic by ID
44+
// and does not require the full object.
45+
type ServiceWithGetID interface {
46+
azure.Service
47+
48+
// GetID returns the ID of the object with the given name
49+
GetID(ctx context.Context, name string) (string, error)
50+
}
51+
3252
// getGroupsClient creates a new groups client from subscriptionid.
3353
func getNetworkInterfacesClient(resourceManagerEndpoint, subscriptionID string, authorizer autorest.Authorizer) network.InterfacesClient {
3454
nicClient := network.NewInterfacesClientWithBaseURI(resourceManagerEndpoint, subscriptionID)
@@ -38,7 +58,7 @@ func getNetworkInterfacesClient(resourceManagerEndpoint, subscriptionID string,
3858
}
3959

4060
// NewService creates a new groups service.
41-
func NewService(scope *actuators.MachineScope) azure.Service {
61+
func NewService(scope *actuators.MachineScope) ServiceWithGetID {
4262
if scope.IsStackHub() {
4363
return NewStackHubService(scope)
4464
}

pkg/cloud/azure/services/networkinterfaces/service_stack.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ func getNetworkInterfacesClientStackHub(resourceManagerEndpoint, subscriptionID
3838
}
3939

4040
// NewStackHubService creates a new groups service.
41-
func NewStackHubService(scope *actuators.MachineScope) azure.Service {
41+
func NewStackHubService(scope *actuators.MachineScope) ServiceWithGetID {
4242
return &StackHubService{
4343
Client: getNetworkInterfacesClientStackHub(scope.ResourceManagerEndpoint, scope.SubscriptionID, scope.Authorizer),
4444
Scope: scope,

pkg/cloud/azure/services/virtualmachines/service.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,17 @@ import (
2323
"github.com/openshift/machine-api-provider-azure/pkg/cloud/azure/actuators"
2424
)
2525

26+
// stackHubAPIVersionVirtualMachines is the API version which will be used when
27+
// connecting to a StackHub cloud.
28+
//
29+
// Bumping this value changes the minimum version requirements of the target
30+
// StackHub deployment. Changes to this value should not be backported, and
31+
// require a release note.
32+
//
33+
// For public cloud deployments, the latest API version supported by the SDK
34+
// will be used.
35+
const stackHubAPIVersionVirtualMachines = "2019-03-01"
36+
2637
// Service provides operations on resource groups
2738
type Service struct {
2839
Client *armcompute.VirtualMachinesClient
@@ -31,11 +42,13 @@ type Service struct {
3142

3243
// NewService creates a new groups service.
3344
func NewService(scope *actuators.MachineScope) azure.Service {
45+
options := scope.ARMClientOptions()
46+
3447
if scope.IsStackHub() {
35-
return NewServiceStackHub(scope)
48+
options.APIVersion = stackHubAPIVersionVirtualMachines
3649
}
3750

38-
vmClient, err := armcompute.NewVirtualMachinesClient(scope.SubscriptionID, scope.Token, scope.ARMClientOptions())
51+
vmClient, err := armcompute.NewVirtualMachinesClient(scope.SubscriptionID, scope.Token, options)
3952
if err != nil {
4053
return azure.NewServiceClientError(err)
4154
}

pkg/cloud/azure/services/virtualmachines/service_stack.go

Lines changed: 0 additions & 46 deletions
This file was deleted.

pkg/cloud/azure/services/virtualmachines/virtualmachines.go

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import (
2727
"strconv"
2828

2929
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5"
30-
"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-02-01/network"
3130
"github.com/Azure/go-autorest/autorest/to"
3231
machinev1 "github.com/openshift/api/machine/v1beta1"
3332
apierrors "github.com/openshift/machine-api-operator/pkg/controller/machine"
@@ -116,20 +115,15 @@ func (s *Service) CreateOrUpdate(ctx context.Context, spec azure.Spec) error {
116115
}
117116

118117
klog.V(2).Infof("getting nic %s", vmSpec.NICName)
119-
nicInterface, err := networkinterfaces.NewService(s.Scope).Get(ctx, &networkinterfaces.Spec{Name: vmSpec.NICName})
118+
nicID, err := networkinterfaces.NewService(s.Scope).GetID(ctx, vmSpec.NICName)
120119
if err != nil {
121120
return err
122121
}
123-
124-
nic, ok := nicInterface.(network.Interface)
125-
if !ok {
126-
return errors.New("error getting network security group")
127-
}
128122
klog.V(2).Infof("got nic %s", vmSpec.NICName)
129123

130124
klog.V(2).Infof("creating vm %s ", vmSpec.Name)
131125

132-
virtualMachine, err := s.deriveVirtualMachineParameters(vmSpec, nic)
126+
virtualMachine, err := s.deriveVirtualMachineParameters(vmSpec, nicID)
133127
if err != nil {
134128
return err
135129
}
@@ -164,7 +158,7 @@ func generateOSProfile(vmSpec *Spec) (*armcompute.OSProfile, error) {
164158
sshKeyData = string(ssh.MarshalAuthorizedKey(publicRsaKey))
165159
}
166160

167-
randomPassword, err := GenerateRandomString(32)
161+
randomPassword, err := generateRandomString(32)
168162
if err != nil {
169163
return nil, fmt.Errorf("failed to generate random string: %w", err)
170164
}
@@ -216,7 +210,11 @@ func generateOSProfile(vmSpec *Spec) (*armcompute.OSProfile, error) {
216210
// Derive virtual machine parameters for CreateOrUpdate API call based
217211
// on the provided virtual machine specification, resource location,
218212
// subscription ID, and the network interface.
219-
func (s *Service) deriveVirtualMachineParameters(vmSpec *Spec, nic network.Interface) (*armcompute.VirtualMachine, error) {
213+
func (s *Service) deriveVirtualMachineParameters(vmSpec *Spec, nicID string) (*armcompute.VirtualMachine, error) {
214+
if s.Scope.IsStackHub() {
215+
return s.deriveVirtualMachineParametersStackHub(vmSpec, nicID)
216+
}
217+
220218
osProfile, err := generateOSProfile(vmSpec)
221219
if err != nil {
222220
return nil, err
@@ -269,7 +267,7 @@ func (s *Service) deriveVirtualMachineParameters(vmSpec *Spec, nic network.Inter
269267
NetworkProfile: &armcompute.NetworkProfile{
270268
NetworkInterfaces: []*armcompute.NetworkInterfaceReference{
271269
{
272-
ID: nic.ID,
270+
ID: &nicID,
273271
Properties: &armcompute.NetworkInterfaceReferenceProperties{
274272
Primary: to.BoolPtr(true),
275273
},
@@ -368,12 +366,12 @@ func (s *Service) Delete(ctx context.Context, spec azure.Spec) error {
368366
return err
369367
}
370368

371-
// GenerateRandomString returns a URL-safe, base64 encoded
369+
// generateRandomString returns a URL-safe, base64 encoded
372370
// securely generated random string.
373371
// It will return an error if the system's secure random
374372
// number generator fails to function correctly, in which
375373
// case the caller should not continue.
376-
func GenerateRandomString(n int) (string, error) {
374+
func generateRandomString(n int) (string, error) {
377375
b := make([]byte, n)
378376
_, err := rand.Read(b)
379377
// Note that err == nil only if we read len(b) bytes.

0 commit comments

Comments
 (0)