forked from LaconicNetwork/kompose
Upgrade OpenShift and its dependencies.
OpenShift version 1.4.0-alpha.0
This commit is contained in:
+19
@@ -0,0 +1,19 @@
|
||||
package api
|
||||
|
||||
// ConvertClusterResourceQuotaToAppliedClusterQuota returns back a converted AppliedClusterResourceQuota which is NOT a deep copy.
|
||||
func ConvertClusterResourceQuotaToAppliedClusterResourceQuota(in *ClusterResourceQuota) *AppliedClusterResourceQuota {
|
||||
return &AppliedClusterResourceQuota{
|
||||
ObjectMeta: in.ObjectMeta,
|
||||
Spec: in.Spec,
|
||||
Status: in.Status,
|
||||
}
|
||||
}
|
||||
|
||||
// ConvertClusterResourceQuotaToAppliedClusterQuota returns back a converted AppliedClusterResourceQuota which is NOT a deep copy.
|
||||
func ConvertAppliedClusterResourceQuotaToClusterResourceQuota(in *AppliedClusterResourceQuota) *ClusterResourceQuota {
|
||||
return &ClusterResourceQuota{
|
||||
ObjectMeta: in.ObjectMeta,
|
||||
Spec: in.Spec,
|
||||
Status: in.Status,
|
||||
}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// +k8s:deepcopy-gen=package,register
|
||||
|
||||
// Package api is the internal version of the API.
|
||||
package api
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package api
|
||||
|
||||
import "k8s.io/kubernetes/pkg/fields"
|
||||
|
||||
func ClusterResourceQuotaToSelectableFields(quota *ClusterResourceQuota) fields.Set {
|
||||
return fields.Set{
|
||||
"metadata.name": quota.Name,
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"k8s.io/kubernetes/pkg/api/meta"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
var accessor = meta.NewAccessor()
|
||||
|
||||
func GetMatcher(selector ClusterResourceQuotaSelector) (func(obj runtime.Object) (bool, error), error) {
|
||||
var labelSelector labels.Selector
|
||||
if selector.LabelSelector != nil {
|
||||
var err error
|
||||
labelSelector, err = unversioned.LabelSelectorAsSelector(selector.LabelSelector)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var annotationSelector map[string]string
|
||||
if len(selector.AnnotationSelector) > 0 {
|
||||
// ensure our matcher has a stable copy of the map
|
||||
annotationSelector = make(map[string]string, len(selector.AnnotationSelector))
|
||||
for k, v := range selector.AnnotationSelector {
|
||||
annotationSelector[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return func(obj runtime.Object) (bool, error) {
|
||||
if labelSelector != nil {
|
||||
objLabels, err := accessor.Labels(obj)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !labelSelector.Matches(labels.Set(objLabels)) {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
if annotationSelector != nil {
|
||||
objAnnotations, err := accessor.Annotations(obj)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
for k, v := range annotationSelector {
|
||||
if objValue, exists := objAnnotations[k]; !exists || objValue != v {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}, nil
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"k8s.io/kubernetes/pkg/api/meta"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
const GroupName = ""
|
||||
|
||||
var SchemeGroupVersion = unversioned.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal}
|
||||
|
||||
// Kind takes an unqualified kind and returns back a Group qualified GroupKind
|
||||
func Kind(kind string) unversioned.GroupKind {
|
||||
return SchemeGroupVersion.WithKind(kind).GroupKind()
|
||||
}
|
||||
|
||||
// Resource takes an unqualified resource and returns back a Group qualified GroupResource
|
||||
func Resource(resource string) unversioned.GroupResource {
|
||||
return SchemeGroupVersion.WithResource(resource).GroupResource()
|
||||
}
|
||||
|
||||
var (
|
||||
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
|
||||
AddToScheme = SchemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
// Adds the list of known types to api.Scheme.
|
||||
func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||
&ClusterResourceQuota{},
|
||||
&ClusterResourceQuotaList{},
|
||||
&AppliedClusterResourceQuota{},
|
||||
&AppliedClusterResourceQuotaList{},
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (obj *AppliedClusterResourceQuotaList) GetObjectKind() unversioned.ObjectKind {
|
||||
return &obj.TypeMeta
|
||||
}
|
||||
func (obj *AppliedClusterResourceQuota) GetObjectKind() unversioned.ObjectKind {
|
||||
return &obj.TypeMeta
|
||||
}
|
||||
|
||||
func (obj *ClusterResourceQuotaList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
|
||||
func (obj *ClusterResourceQuota) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
|
||||
func (obj *ClusterResourceQuota) GetObjectMeta() meta.Object { return &obj.ObjectMeta }
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
)
|
||||
|
||||
// ClusterResourceQuota mirrors ResourceQuota at a cluster scope. This object is easily convertible to
|
||||
// synthetic ResourceQuota object to allow quota evaluation re-use.
|
||||
type ClusterResourceQuota struct {
|
||||
unversioned.TypeMeta
|
||||
// Standard object's metadata.
|
||||
kapi.ObjectMeta
|
||||
|
||||
// Spec defines the desired quota
|
||||
Spec ClusterResourceQuotaSpec
|
||||
|
||||
// Status defines the actual enforced quota and its current usage
|
||||
Status ClusterResourceQuotaStatus
|
||||
}
|
||||
|
||||
// ClusterResourceQuotaSpec defines the desired quota restrictions
|
||||
type ClusterResourceQuotaSpec struct {
|
||||
// Selector is the selector used to match projects.
|
||||
// It should only select active projects on the scale of dozens (though it can select
|
||||
// many more less active projects). These projects will contend on object creation through
|
||||
// this resource.
|
||||
Selector ClusterResourceQuotaSelector
|
||||
|
||||
// Quota defines the desired quota
|
||||
Quota kapi.ResourceQuotaSpec
|
||||
}
|
||||
|
||||
// ClusterResourceQuotaSelector is used to select projects. At least one of LabelSelector or AnnotationSelector
|
||||
// must present. If only one is present, it is the only selection criteria. If both are specified,
|
||||
// the project must match both restrictions.
|
||||
type ClusterResourceQuotaSelector struct {
|
||||
// LabelSelector is used to select projects by label.
|
||||
LabelSelector *unversioned.LabelSelector
|
||||
|
||||
// AnnotationSelector is used to select projects by annotation.
|
||||
AnnotationSelector map[string]string
|
||||
}
|
||||
|
||||
// ClusterResourceQuotaStatus defines the actual enforced quota and its current usage
|
||||
type ClusterResourceQuotaStatus struct {
|
||||
// Total defines the actual enforced quota and its current usage across all projects
|
||||
Total kapi.ResourceQuotaStatus
|
||||
|
||||
// Namespaces slices the usage by project. This division allows for quick resolution of
|
||||
// deletion reconcilation inside of a single project without requiring a recalculation
|
||||
// across all projects. This map can be used to pull the deltas for a given project.
|
||||
Namespaces ResourceQuotasStatusByNamespace
|
||||
}
|
||||
|
||||
// ClusterResourceQuotaList is a collection of ClusterResourceQuotas
|
||||
type ClusterResourceQuotaList struct {
|
||||
unversioned.TypeMeta
|
||||
// Standard object's metadata.
|
||||
unversioned.ListMeta
|
||||
|
||||
// Items is a list of ClusterResourceQuotas
|
||||
Items []ClusterResourceQuota
|
||||
}
|
||||
|
||||
// AppliedClusterResourceQuota mirrors ClusterResourceQuota at a project scope, for projection
|
||||
// into a project. It allows a project-admin to know which ClusterResourceQuotas are applied to
|
||||
// his project and their associated usage.
|
||||
type AppliedClusterResourceQuota struct {
|
||||
unversioned.TypeMeta
|
||||
// Standard object's metadata.
|
||||
kapi.ObjectMeta
|
||||
|
||||
// Spec defines the desired quota
|
||||
Spec ClusterResourceQuotaSpec
|
||||
|
||||
// Status defines the actual enforced quota and its current usage
|
||||
Status ClusterResourceQuotaStatus
|
||||
}
|
||||
|
||||
// AppliedClusterResourceQuotaList is a collection of AppliedClusterResourceQuotas
|
||||
type AppliedClusterResourceQuotaList struct {
|
||||
unversioned.TypeMeta
|
||||
// Standard object's metadata.
|
||||
unversioned.ListMeta
|
||||
|
||||
// Items is a list of AppliedClusterResourceQuota
|
||||
Items []AppliedClusterResourceQuota
|
||||
}
|
||||
|
||||
// ResourceQuotasStatusByNamespace provides type correct methods
|
||||
type ResourceQuotasStatusByNamespace struct {
|
||||
orderedMap orderedMap
|
||||
}
|
||||
|
||||
func (o *ResourceQuotasStatusByNamespace) Insert(key string, value kapi.ResourceQuotaStatus) {
|
||||
o.orderedMap.Insert(key, value)
|
||||
}
|
||||
|
||||
func (o *ResourceQuotasStatusByNamespace) Get(key string) (kapi.ResourceQuotaStatus, bool) {
|
||||
ret, ok := o.orderedMap.Get(key)
|
||||
if !ok {
|
||||
return kapi.ResourceQuotaStatus{}, ok
|
||||
}
|
||||
return ret.(kapi.ResourceQuotaStatus), ok
|
||||
}
|
||||
|
||||
func (o *ResourceQuotasStatusByNamespace) Remove(key string) {
|
||||
o.orderedMap.Remove(key)
|
||||
}
|
||||
|
||||
func (o *ResourceQuotasStatusByNamespace) OrderedKeys() *list.List {
|
||||
return o.orderedMap.OrderedKeys()
|
||||
}
|
||||
|
||||
// orderedMap is a very simple ordering a map tracking insertion order. It allows fast and stable serializations
|
||||
// for our encoding. You could probably do something fancier with pointers to interfaces, but I didn't.
|
||||
type orderedMap struct {
|
||||
backingMap map[string]interface{}
|
||||
orderedKeys *list.List
|
||||
}
|
||||
|
||||
// Insert puts something else in the map. keys are ordered based on first insertion, not last touch.
|
||||
func (o *orderedMap) Insert(key string, value interface{}) {
|
||||
if o.backingMap == nil {
|
||||
o.backingMap = map[string]interface{}{}
|
||||
}
|
||||
if o.orderedKeys == nil {
|
||||
o.orderedKeys = list.New()
|
||||
}
|
||||
|
||||
if _, exists := o.backingMap[key]; !exists {
|
||||
o.orderedKeys.PushBack(key)
|
||||
}
|
||||
o.backingMap[key] = value
|
||||
}
|
||||
|
||||
func (o *orderedMap) Get(key string) (interface{}, bool) {
|
||||
ret, ok := o.backingMap[key]
|
||||
return ret, ok
|
||||
}
|
||||
|
||||
func (o *orderedMap) Remove(key string) {
|
||||
delete(o.backingMap, key)
|
||||
|
||||
if o.orderedKeys == nil {
|
||||
return
|
||||
}
|
||||
for e := o.orderedKeys.Front(); e != nil; e = e.Next() {
|
||||
if e.Value.(string) == key {
|
||||
o.orderedKeys.Remove(e)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// OrderedKeys returns back the ordered keys. This can be used to build a stable serialization
|
||||
func (o *orderedMap) OrderedKeys() *list.List {
|
||||
if o.orderedKeys == nil {
|
||||
o.orderedKeys = list.New()
|
||||
}
|
||||
return o.orderedKeys
|
||||
}
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
// +build !ignore_autogenerated_openshift
|
||||
|
||||
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
pkg_api "k8s.io/kubernetes/pkg/api"
|
||||
unversioned "k8s.io/kubernetes/pkg/api/unversioned"
|
||||
conversion "k8s.io/kubernetes/pkg/conversion"
|
||||
runtime "k8s.io/kubernetes/pkg/runtime"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(RegisterDeepCopies)
|
||||
}
|
||||
|
||||
// RegisterDeepCopies adds deep-copy functions to the given scheme. Public
|
||||
// to allow building arbitrary schemes.
|
||||
func RegisterDeepCopies(scheme *runtime.Scheme) error {
|
||||
return scheme.AddGeneratedDeepCopyFuncs(
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_AppliedClusterResourceQuota, InType: reflect.TypeOf(&AppliedClusterResourceQuota{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_AppliedClusterResourceQuotaList, InType: reflect.TypeOf(&AppliedClusterResourceQuotaList{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ClusterResourceQuota, InType: reflect.TypeOf(&ClusterResourceQuota{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ClusterResourceQuotaList, InType: reflect.TypeOf(&ClusterResourceQuotaList{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ClusterResourceQuotaSelector, InType: reflect.TypeOf(&ClusterResourceQuotaSelector{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ClusterResourceQuotaSpec, InType: reflect.TypeOf(&ClusterResourceQuotaSpec{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ClusterResourceQuotaStatus, InType: reflect.TypeOf(&ClusterResourceQuotaStatus{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ResourceQuotasStatusByNamespace, InType: reflect.TypeOf(&ResourceQuotasStatusByNamespace{})},
|
||||
)
|
||||
}
|
||||
|
||||
func DeepCopy_api_AppliedClusterResourceQuota(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*AppliedClusterResourceQuota)
|
||||
out := out.(*AppliedClusterResourceQuota)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if err := pkg_api.DeepCopy_api_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DeepCopy_api_ClusterResourceQuotaSpec(&in.Spec, &out.Spec, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DeepCopy_api_ClusterResourceQuotaStatus(&in.Status, &out.Status, c); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_AppliedClusterResourceQuotaList(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*AppliedClusterResourceQuotaList)
|
||||
out := out.(*AppliedClusterResourceQuotaList)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]AppliedClusterResourceQuota, len(*in))
|
||||
for i := range *in {
|
||||
if err := DeepCopy_api_AppliedClusterResourceQuota(&(*in)[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_ClusterResourceQuota(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*ClusterResourceQuota)
|
||||
out := out.(*ClusterResourceQuota)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if err := pkg_api.DeepCopy_api_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DeepCopy_api_ClusterResourceQuotaSpec(&in.Spec, &out.Spec, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DeepCopy_api_ClusterResourceQuotaStatus(&in.Status, &out.Status, c); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_ClusterResourceQuotaList(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*ClusterResourceQuotaList)
|
||||
out := out.(*ClusterResourceQuotaList)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]ClusterResourceQuota, len(*in))
|
||||
for i := range *in {
|
||||
if err := DeepCopy_api_ClusterResourceQuota(&(*in)[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_ClusterResourceQuotaSelector(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*ClusterResourceQuotaSelector)
|
||||
out := out.(*ClusterResourceQuotaSelector)
|
||||
if in.LabelSelector != nil {
|
||||
in, out := &in.LabelSelector, &out.LabelSelector
|
||||
*out = new(unversioned.LabelSelector)
|
||||
if err := unversioned.DeepCopy_unversioned_LabelSelector(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.LabelSelector = nil
|
||||
}
|
||||
if in.AnnotationSelector != nil {
|
||||
in, out := &in.AnnotationSelector, &out.AnnotationSelector
|
||||
*out = make(map[string]string)
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
} else {
|
||||
out.AnnotationSelector = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_ClusterResourceQuotaSpec(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*ClusterResourceQuotaSpec)
|
||||
out := out.(*ClusterResourceQuotaSpec)
|
||||
if err := DeepCopy_api_ClusterResourceQuotaSelector(&in.Selector, &out.Selector, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := pkg_api.DeepCopy_api_ResourceQuotaSpec(&in.Quota, &out.Quota, c); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_ClusterResourceQuotaStatus(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*ClusterResourceQuotaStatus)
|
||||
out := out.(*ClusterResourceQuotaStatus)
|
||||
if err := pkg_api.DeepCopy_api_ResourceQuotaStatus(&in.Total, &out.Total, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DeepCopy_api_ResourceQuotasStatusByNamespace(&in.Namespaces, &out.Namespaces, c); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_ResourceQuotasStatusByNamespace(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*ResourceQuotasStatusByNamespace)
|
||||
out := out.(*ResourceQuotasStatusByNamespace)
|
||||
if newVal, err := c.DeepCopy(&in.orderedMap); err != nil {
|
||||
return err
|
||||
} else {
|
||||
out.orderedMap = *newVal.(*orderedMap)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
apierrs "k8s.io/kubernetes/pkg/api/errors"
|
||||
)
|
||||
|
||||
// errMessageString is a part of error message copied from quotaAdmission.Admit() method in
|
||||
// k8s.io/kubernetes/plugin/pkg/admission/resourcequota/admission.go module
|
||||
const errQuotaMessageString = `exceeded quota:`
|
||||
const errQuotaUnknownMessageString = `status unknown for quota:`
|
||||
const errLimitsMessageString = `exceeds the maximum limit`
|
||||
|
||||
// IsErrorQuotaExceeded returns true if the given error stands for a denied request caused by detected quota
|
||||
// abuse.
|
||||
func IsErrorQuotaExceeded(err error) bool {
|
||||
if isForbidden := apierrs.IsForbidden(err); isForbidden || apierrs.IsInvalid(err) {
|
||||
lowered := strings.ToLower(err.Error())
|
||||
// the limit error message can be accompanied only by Invalid reason
|
||||
if strings.Contains(lowered, errLimitsMessageString) {
|
||||
return true
|
||||
}
|
||||
// the quota error message can be accompanied only by Forbidden reason
|
||||
if isForbidden && (strings.Contains(lowered, errQuotaMessageString) || strings.Contains(lowered, errQuotaUnknownMessageString)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsErrorLimitExceeded returns true if the given error is a limit error.
|
||||
func IsErrorLimitExceeded(err error) bool {
|
||||
if isForbidden := apierrs.IsForbidden(err); isForbidden || apierrs.IsInvalid(err) {
|
||||
lowered := strings.ToLower(err.Error())
|
||||
// the limit error message can be accompanied only by Invalid reason
|
||||
if strings.Contains(lowered, errLimitsMessageString) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user