diff --git a/pkg/driver/driver_test.go b/pkg/driver/driver_test.go new file mode 100644 index 00000000..57b42292 --- /dev/null +++ b/pkg/driver/driver_test.go @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: SAP SE or an SAP affiliate company and Gardener contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package driver + +import ( + "errors" + + "github.com/gardener/machine-controller-manager/pkg/util/provider/machinecodes/status" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "github.com/gardener/machine-controller-manager-provider-openstack/pkg/driver/executor" +) + +var _ = Describe("Driver", func() { + + Context("mapErrorToCode", func() { + It("should map executor.ErrFlavorNotFound errors to ResourceExhausted error code", func() { + err1 := executor.ErrFlavorNotFound{Flavor: "flavor"} + err2 := status.Error(mapErrorToCode(err1), err1.Error()) + Expect(err1).To(HaveOccurred()) + Expect(err2).To(HaveOccurred()) + Expect(errors.Is(err2, executor.ErrNotFound)).To(BeFalse()) + }) + }) + +}) diff --git a/pkg/driver/executor/errors.go b/pkg/driver/executor/errors.go index 0c5b7127..391e63b1 100644 --- a/pkg/driver/executor/errors.go +++ b/pkg/driver/executor/errors.go @@ -24,3 +24,14 @@ var ( // OpenStack resources. In case this case, where a unique ID could not be determined an ErrMultipleFound is returned. ErrMultipleFound = fmt.Errorf("multiple resources found") ) + +// ErrFlavorNotFound is returned when there is no flavor can be matched with the specified flavor name. +// It can happen when certain flavor is not available in specified region and needs to be treated as ResourceExhausted +// to allow fallback to other flavors. +type ErrFlavorNotFound struct { + Flavor string +} + +func (e ErrFlavorNotFound) Error() string { + return fmt.Sprintf("Unable to find flavor with name %s", e.Flavor) +} \ No newline at end of file diff --git a/pkg/driver/executor/executor.go b/pkg/driver/executor/executor.go index 5387cbc3..3c05fc7d 100644 --- a/pkg/driver/executor/executor.go +++ b/pkg/driver/executor/executor.go @@ -10,6 +10,7 @@ import ( "fmt" "time" + "github.com/gophercloud/gophercloud/v2" "github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v3/volumes" "github.com/gophercloud/gophercloud/v2/openstack/compute/v2/keypairs" "github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers" @@ -276,7 +277,12 @@ func (ex *Executor) deployServer(ctx context.Context, machineName string, userDa } flavorRef, err := ex.Compute.FlavorIDFromName(ctx, flavorName) if err != nil { - return nil, fmt.Errorf("error resolving flavor ID from flavor name %q: %v", imageName, err) + switch err.(type) { + case gophercloud.ErrResourceNotFound: + return nil, fmt.Errorf("error resolving flavor ID from flavor name %q: %w", flavorName, ErrFlavorNotFound{Flavor: flavorName}) + default: + return nil, fmt.Errorf("error resolving flavor ID from flavor name %q: %v", flavorName, err) + } } createOpts := &servers.CreateOpts{ diff --git a/pkg/driver/executor/executor_test.go b/pkg/driver/executor/executor_test.go index cc639bad..f668d241 100644 --- a/pkg/driver/executor/executor_test.go +++ b/pkg/driver/executor/executor_test.go @@ -209,6 +209,22 @@ var _ = Describe("Executor", func() { Expect(server.ProviderID).To(Equal(encodeProviderID(region, serverID))) }) + It("should raise a ErrResourceNotFound error when called with a missing flavor", func() { + ex := &Executor{ + Compute: compute, + Network: network, + Config: cfg, + } + + compute.EXPECT().ListServers(ctx, &servers.ListOpts{Name: machineName}).Return([]servers.Server{}, nil) + compute.EXPECT().ImageIDFromName(ctx, imageName).Return(images.Image{ID: "imageID"}, nil) + compute.EXPECT().FlavorIDFromName(ctx, flavorName).Return(flavorName, gophercloud.ErrResourceNotFound{Name: flavorName, ResourceType: "flavor"}) + compute.EXPECT().ListServers(ctx, &servers.ListOpts{Name: machineName}).Return([]servers.Server{}, nil) + + _, err := ex.CreateMachine(ctx, machineName, nil) + Expect(err).To(HaveOccurred()) + }) + It("should delete the server on failure", func() { ex := &Executor{ Compute: compute, diff --git a/pkg/driver/utils.go b/pkg/driver/utils.go index 41b9c0d9..1e4c21db 100644 --- a/pkg/driver/utils.go +++ b/pkg/driver/utils.go @@ -63,6 +63,10 @@ func mapErrorToCode(err error) codes.Code { return codes.PermissionDenied } + if errors.Is(err, executor.ErrFlavorNotFound{}) { + return codes.ResourceExhausted + } + return mapErrorMessageToCode(err) }