@@ -3,6 +3,7 @@ package openstack
33import (
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
642643func 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