Skip to content

Commit ca262b1

Browse files
mrIncompetentkubermatic-bot
authored andcommitted
encode openstack quota errors as terminal errors (#369)
1 parent 85f88d8 commit ca262b1

File tree

1 file changed

+38
-15
lines changed

1 file changed

+38
-15
lines changed

pkg/cloudprovider/provider/openstack/provider.go

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package openstack
33
import (
44
"encoding/json"
55
"fmt"
6+
"strings"
67
"sync"
78
"time"
89

@@ -24,7 +25,7 @@ import (
2425
"github.com/kubermatic/machine-controller/pkg/cloudprovider/instance"
2526
"github.com/kubermatic/machine-controller/pkg/providerconfig"
2627

27-
common "sigs.k8s.io/cluster-api/pkg/apis/cluster/common"
28+
"sigs.k8s.io/cluster-api/pkg/apis/cluster/common"
2829
"sigs.k8s.io/cluster-api/pkg/apis/cluster/v1alpha1"
2930
)
3031

@@ -640,23 +641,45 @@ func (d *osInstance) Status() instance.Status {
640641
//
641642
// if the given error doesn't qualify the error passed as an argument will be returned
642643
func osErrorToTerminalError(err error, msg string) error {
643-
prepareAndReturnError := func() error {
644-
return fmt.Errorf("%s, due to %s", msg, err)
644+
if errUnauthorized, ok := err.(gophercloud.ErrDefault401); ok {
645+
return cloudprovidererrors.TerminalError{
646+
Reason: common.InvalidConfigurationMachineError,
647+
Message: fmt.Sprintf("A request has been rejected due to invalid credentials which were taken from the MachineSpec: %v", errUnauthorized),
648+
}
645649
}
646-
if err != nil {
647-
default401 := gophercloud.ErrDefault401{}
648650

649-
switch err.Error() {
650-
case "Authentication failed", default401.Error():
651-
// authorization primitives come from MachineSpec
652-
// thus we are setting InvalidConfigurationMachineError
653-
return cloudprovidererrors.TerminalError{
654-
Reason: common.InvalidConfigurationMachineError,
655-
Message: "A request has been rejected due to invalid credentials which were taken from the MachineSpec",
651+
if errForbidden, ok := err.(gophercloud.ErrDefault403); ok {
652+
terr := cloudprovidererrors.TerminalError{
653+
Reason: common.InvalidConfigurationMachineError,
654+
Message: fmt.Sprintf("%s. The request against the OpenStack API is forbidden: %s", msg, errForbidden.Error()),
655+
}
656+
657+
// The response from OpenStack might contain a more detailed message
658+
info := &forbiddenResponse{}
659+
if err := json.Unmarshal(errForbidden.Body, info); err != nil {
660+
// We just log here as we just do this to make the response more pretty
661+
glog.V(0).Infof("failed to unmarshal response body from 403 response from OpenStack API: %v\n%s", err, errForbidden.Body)
662+
return terr
663+
}
664+
665+
// If we have more details, interpret them
666+
if info.Forbidden.Message != "" {
667+
terr.Message = fmt.Sprintf("%s. The request against the OpenStack API is forbidden: %s", msg, info.Forbidden.Message)
668+
if strings.Contains(info.Forbidden.Message, "Quota exceeded") {
669+
terr.Reason = common.InsufficientResourcesMachineError
656670
}
657-
default:
658-
return prepareAndReturnError()
659671
}
672+
673+
return terr
660674
}
661-
return err
675+
676+
return fmt.Errorf("%s, due to %s", msg, err)
677+
}
678+
679+
// forbiddenResponse is a potential response body from the OpenStack API when the request is forbidden (code: 403)
680+
type forbiddenResponse struct {
681+
Forbidden struct {
682+
Message string `json:"message"`
683+
Code int `json:"code"`
684+
} `json:"forbidden"`
662685
}

0 commit comments

Comments
 (0)