extension/agenthealth/handler/stats/agent/flag.go (155 lines of code) (raw):
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: MIT
package agent
import (
"encoding"
"errors"
"fmt"
"sync"
"github.com/aws/aws-sdk-go/aws"
)
var (
errUnsupportedFlag = errors.New("unsupported usage flag")
)
const (
FlagIMDSFallbackSuccess Flag = iota
FlagSharedConfigFallback
FlagAppSignal
FlagEnhancedContainerInsights
FlagRunningInContainer
FlagMode
FlagRegionType
flagIMDSFallbackSuccessStr = "imds_fallback_success"
flagSharedConfigFallbackStr = "shared_config_fallback"
flagAppSignalsStr = "application_signals"
flagEnhancedContainerInsightsStr = "enhanced_container_insights"
flagRunningInContainerStr = "running_in_container"
flagModeStr = "mode"
flagRegionTypeStr = "region_type"
)
type Flag int
var _ encoding.TextMarshaler = (*Flag)(nil)
var _ encoding.TextUnmarshaler = (*Flag)(nil)
func (f Flag) String() string {
switch f {
case FlagAppSignal:
return flagAppSignalsStr
case FlagEnhancedContainerInsights:
return flagEnhancedContainerInsightsStr
case FlagIMDSFallbackSuccess:
return flagIMDSFallbackSuccessStr
case FlagMode:
return flagModeStr
case FlagRegionType:
return flagRegionTypeStr
case FlagRunningInContainer:
return flagRunningInContainerStr
case FlagSharedConfigFallback:
return flagSharedConfigFallbackStr
}
return ""
}
func (f Flag) MarshalText() (text []byte, err error) {
s := f.String()
if s == "" {
return nil, fmt.Errorf("%w: %[2]T(%[2]d)", errUnsupportedFlag, f)
}
return []byte(s), nil
}
func (f *Flag) UnmarshalText(text []byte) error {
switch s := string(text); s {
case flagAppSignalsStr:
*f = FlagAppSignal
case flagEnhancedContainerInsightsStr:
*f = FlagEnhancedContainerInsights
case flagIMDSFallbackSuccessStr:
*f = FlagIMDSFallbackSuccess
case flagModeStr:
*f = FlagMode
case flagRegionTypeStr:
*f = FlagRegionType
case flagRunningInContainerStr:
*f = FlagRunningInContainer
case flagSharedConfigFallbackStr:
*f = FlagSharedConfigFallback
default:
return fmt.Errorf("%w: %s", errUnsupportedFlag, s)
}
return nil
}
var (
flagSingleton FlagSet
flagOnce sync.Once
)
// FlagSet is a getter/setter for flag/value pairs. Once a flag key is set, its value is immutable.
type FlagSet interface {
// IsSet returns if the flag is present in the backing map.
IsSet(flag Flag) bool
// GetString if the value stored with the flag is a string. If not, returns nil.
GetString(flag Flag) *string
// Set adds the Flag with an unused value.
Set(flag Flag)
// SetValue adds the Flag with a value.
SetValue(flag Flag, value any)
// SetValues adds each Flag/value pair.
SetValues(flags map[Flag]any)
// OnChange registers a callback that triggers on flag sets.
OnChange(callback func())
}
type flagSet struct {
m sync.Map
mu sync.RWMutex
callbacks []func()
}
var _ FlagSet = (*flagSet)(nil)
func (p *flagSet) IsSet(flag Flag) bool {
_, ok := p.m.Load(flag)
return ok
}
func (p *flagSet) GetString(flag Flag) *string {
value, ok := p.m.Load(flag)
if !ok {
return nil
}
var str string
str, ok = value.(string)
if !ok || str == "" {
return nil
}
return aws.String(str)
}
func (p *flagSet) Set(flag Flag) {
p.SetValue(flag, 1)
}
func (p *flagSet) SetValue(flag Flag, value any) {
if p.setWithValue(flag, value) {
p.notify()
}
}
func (p *flagSet) SetValues(m map[Flag]any) {
var changed bool
for flag, value := range m {
if p.setWithValue(flag, value) {
changed = true
}
}
if changed {
p.notify()
}
}
func (p *flagSet) setWithValue(flag Flag, value any) bool {
if !p.IsSet(flag) {
p.m.Store(flag, value)
return true
}
return false
}
func (p *flagSet) OnChange(f func()) {
p.mu.Lock()
defer p.mu.Unlock()
p.callbacks = append(p.callbacks, f)
}
func (p *flagSet) notify() {
p.mu.RLock()
defer p.mu.RUnlock()
for _, callback := range p.callbacks {
callback()
}
}
func UsageFlags() FlagSet {
flagOnce.Do(func() {
flagSingleton = &flagSet{}
})
return flagSingleton
}