2023-10-16 17:55:30 +00:00
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package resource
import (
"fmt"
"strings"
2023-11-02 20:56:02 +00:00
mapset "github.com/deckarep/golang-set/v2"
2024-01-10 16:19:20 +00:00
"github.com/hashicorp/consul/internal/dnsutil"
2023-11-02 20:56:02 +00:00
"github.com/hashicorp/consul/proto-public/pbresource"
2023-10-16 17:55:30 +00:00
)
2023-11-02 20:56:02 +00:00
// MaxNameLength is the maximum length of a resource name.
2023-10-16 17:55:30 +00:00
const MaxNameLength = 63
2023-11-02 20:56:02 +00:00
// DeletionTimestampKey is the key in a resource's metadata that stores the timestamp
// when a resource was marked for deletion. This only applies to resources with finalizers.
const DeletionTimestampKey = "deletionTimestamp"
// FinalizerKey is the key in resource's metadata that stores the whitespace separated
// list of finalizers.
const FinalizerKey = "finalizers"
2023-10-16 17:55:30 +00:00
// ValidateName returns an error a name is not a valid resource name.
// The error will contain reference to what constitutes a valid resource name.
func ValidateName ( name string ) error {
2024-01-10 16:19:20 +00:00
if ! dnsutil . IsValidLabel ( name ) || strings . ToLower ( name ) != name || len ( name ) > MaxNameLength {
2023-10-16 17:55:30 +00:00
return fmt . Errorf ( "a resource name must consist of lower case alphanumeric characters or '-', must start and end with an alphanumeric character and be less than %d characters, got: %q" , MaxNameLength + 1 , name )
}
return nil
}
2023-11-02 20:56:02 +00:00
// IsMarkedForDeletion returns true if a resource has been marked for deletion,
// false otherwise.
func IsMarkedForDeletion ( res * pbresource . Resource ) bool {
if res . Metadata == nil {
return false
}
_ , ok := res . Metadata [ DeletionTimestampKey ]
return ok
}
// HasFinalizers returns true if a resource has one or more finalizers, false otherwise.
func HasFinalizers ( res * pbresource . Resource ) bool {
return GetFinalizers ( res ) . Cardinality ( ) >= 1
}
// HasFinalizer returns true if a resource has a given finalizers, false otherwise.
func HasFinalizer ( res * pbresource . Resource , finalizer string ) bool {
return GetFinalizers ( res ) . Contains ( finalizer )
}
// AddFinalizer adds a finalizer to the given resource.
func AddFinalizer ( res * pbresource . Resource , finalizer string ) {
finalizerSet := GetFinalizers ( res )
finalizerSet . Add ( finalizer )
if res . Metadata == nil {
res . Metadata = map [ string ] string { }
}
res . Metadata [ FinalizerKey ] = strings . Join ( finalizerSet . ToSlice ( ) , " " )
}
// RemoveFinalizer removes a finalizer from the given resource.
func RemoveFinalizer ( res * pbresource . Resource , finalizer string ) {
finalizerSet := GetFinalizers ( res )
finalizerSet . Remove ( finalizer )
2023-11-17 16:51:25 +00:00
if finalizerSet . Cardinality ( ) == 0 {
// Remove key if no finalizers to prevent dual representations of
// the same state.
_ , keyExists := res . Metadata [ FinalizerKey ]
if keyExists {
delete ( res . Metadata , FinalizerKey )
}
} else {
// Add/update key
if res . Metadata == nil {
res . Metadata = map [ string ] string { }
}
res . Metadata [ FinalizerKey ] = strings . Join ( finalizerSet . ToSlice ( ) , " " )
2023-11-02 20:56:02 +00:00
}
}
// GetFinalizers returns the set of finalizers for the given resource.
func GetFinalizers ( res * pbresource . Resource ) mapset . Set [ string ] {
if res . Metadata == nil {
return mapset . NewSet [ string ] ( )
}
finalizers , ok := res . Metadata [ FinalizerKey ]
if ! ok {
return mapset . NewSet [ string ] ( )
}
return mapset . NewSet [ string ] ( strings . Fields ( finalizers ) ... )
}