diff --git a/pkg/cloud/services/compute/instance.go b/pkg/cloud/services/compute/instance.go index bc49dc48fa..f6ab5d29e4 100644 --- a/pkg/cloud/services/compute/instance.go +++ b/pkg/cloud/services/compute/instance.go @@ -740,10 +740,15 @@ func (s *Service) deleteAttachInterface(eventObject runtime.Object, instanceID, mc := metrics.NewMetricPrometheusContext("server_os_interface", "delete") err = attachinterfaces.Delete(s.computeClient, instanceID, portID).ExtractErr() - if mc.ObserveRequestIgnoreNotFound(err) != nil { + if mc.ObserveRequestIgnoreNotFoundorConflict(err) != nil { if capoerrors.IsNotFound(err) { return nil } + if capoerrors.IsConflict(err) { + // we don't want to block deletion because of Conflict + // due to instance must be paused/active/shutoff in order to detach interface + return nil + } record.Warnf(eventObject, "FailedDeleteAttachInterface", "Failed to delete attach interface: instance %s, port %s: %v", instance.ID, port.ID, err) return err } diff --git a/pkg/metrics/metrics.go b/pkg/metrics/metrics.go index 0f0d9d0167..fd6e4244da 100644 --- a/pkg/metrics/metrics.go +++ b/pkg/metrics/metrics.go @@ -61,6 +61,19 @@ func (mc *MetricPrometheusContext) ObserveRequestIgnoreNotFound(err error) error return mc.ObserveRequest(err) } +// ObserveRequestIgnoreNotFoundorConflict records the request latency and counts the errors if it's not IsNotFound or IsConflict. +func (mc *MetricPrometheusContext) ObserveRequestIgnoreNotFoundorConflict(err error) error { + if capoerrors.IsNotFound(err) { + _ = mc.ObserveRequest(nil) + return err + } + if capoerrors.IsConflict(err) { + _ = mc.ObserveRequest(nil) + return err + } + return mc.ObserveRequest(err) +} + // Observe records the request latency and counts the errors. func (mc *MetricPrometheusContext) Observe(om *OpenstackPrometheusMetrics, err error) error { if om == nil { diff --git a/pkg/utils/errors/errors.go b/pkg/utils/errors/errors.go index 7d48c8ad72..279e6f3636 100644 --- a/pkg/utils/errors/errors.go +++ b/pkg/utils/errors/errors.go @@ -68,3 +68,19 @@ func IsInvalidError(err error) bool { return false } + +func IsConflict(err error) bool { + var errDefault409 gophercloud.ErrDefault409 + if errors.As(err, &errDefault409) { + return true + } + + var errUnexpectedResponseCode gophercloud.ErrUnexpectedResponseCode + if errors.As(err, &errUnexpectedResponseCode) { + if errUnexpectedResponseCode.Actual == http.StatusConflict { + return true + } + } + + return false +}