Skip to content

Commit 6bf4978

Browse files
committed
chore: more changes
Signed-off-by: Ajay Mishra <[email protected]>
1 parent 89a37fc commit 6bf4978

File tree

6 files changed

+110
-24
lines changed

6 files changed

+110
-24
lines changed

tests/data/basic-matching-configmap.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ metadata:
1919
namespace: nvsentinel
2020
data:
2121
config.toml: |
22+
[circuitBreaker]
23+
percentage = 50
24+
duration = "5m"
25+
2226
[[rule-sets]]
2327
name = "Basic-Match-Rule"
2428
[[rule-sets.match.all]]

tests/data/managed-by-nvsentinel-configmap.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ metadata:
1919
namespace: nvsentinel
2020
data:
2121
config.toml: |
22+
[circuitBreaker]
23+
percentage = 50
24+
duration = "5m"
25+
2226
[[rule-sets]]
2327
name = "ManagedByNVSentinel-Rule"
2428
[[rule-sets.match.all]]

tests/go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ go 1.25
55
toolchain go1.25.3
66

77
require (
8+
github.com/BurntSushi/toml v1.5.0
89
github.com/go-logr/logr v1.4.3
910
github.com/nvidia/nvsentinel/commons v0.0.0
1011
github.com/prometheus/client_golang v1.23.2

tests/go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
2+
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
13
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
24
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
35
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=

tests/helpers/fault_quarantine.go

Lines changed: 44 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,17 @@ const (
3737
CELKeyConfigMapBackup
3838
)
3939

40+
type faultQuarantineConfig struct {
41+
LabelPrefix string `toml:"label-prefix"`
42+
CircuitBreaker circuitBreakerConfig `toml:"circuitBreaker"`
43+
RuleSets []map[string]any `toml:"rule-sets"`
44+
}
45+
46+
type circuitBreakerConfig struct {
47+
Percentage int `toml:"percentage"`
48+
Duration string `toml:"duration"`
49+
}
50+
4051
type QuarantineTestContext struct {
4152
NodeName string
4253
ConfigMapBackup []byte
@@ -94,16 +105,11 @@ func SetupQuarantineTest(ctx context.Context, t *testing.T, c *envconf.Config, c
94105

95106
// QuarantineSetupOptions provides options for setting up quarantine tests.
96107
type QuarantineSetupOptions struct {
97-
// CircuitBreakerPercentage sets the CB percentage threshold (0 to skip)
98108
CircuitBreakerPercentage int
99-
// CircuitBreakerDuration sets the CB duration (empty to skip)
100-
CircuitBreakerDuration string
101-
// CircuitBreakerState sets the initial CB state (empty to skip)
102-
CircuitBreakerState string
103-
// DryRun sets dry-run mode (nil to skip, otherwise pointer to bool value)
104-
DryRun *bool
105-
// SkipRestart skips the deployment restart (useful when chaining operations)
106-
SkipRestart bool
109+
CircuitBreakerDuration string
110+
CircuitBreakerState string
111+
DryRun *bool
112+
SkipRestart bool
107113
}
108114

109115
// SetupQuarantineTestWithOptions sets up a quarantine test with additional configuration options.
@@ -118,36 +124,31 @@ func SetupQuarantineTestWithOptions(ctx context.Context, t *testing.T, c *envcon
118124
testCtx := &QuarantineTestContext{}
119125
var originalDeployment *appsv1.Deployment
120126

121-
t.Log("Backing up current fault-quarantine configmap")
122127
backupData, err := BackupConfigMap(ctx, client, "fault-quarantine", NVSentinelNamespace)
123128
require.NoError(t, err)
124-
t.Log("Backup created in memory")
125129
testCtx.ConfigMapBackup = backupData
126130

127131
t.Logf("Applying test configmap: %s", configMapPath)
128132
err = createConfigMapFromFilePath(ctx, client, configMapPath, "fault-quarantine", NVSentinelNamespace)
129133
require.NoError(t, err)
130134

131-
argUpdates := make(map[string]string)
132135
if opts != nil {
133136
if opts.CircuitBreakerPercentage > 0 {
134-
t.Logf("Will set circuit breaker threshold: %d%%, duration: %s",
137+
t.Logf("Updating circuit breaker in ConfigMap: %d%%, duration: %s",
135138
opts.CircuitBreakerPercentage, opts.CircuitBreakerDuration)
136-
argUpdates["--circuit-breaker-percentage="] = fmt.Sprintf("--circuit-breaker-percentage=%d", opts.CircuitBreakerPercentage)
137-
argUpdates["--circuit-breaker-duration="] = fmt.Sprintf("--circuit-breaker-duration=%s", opts.CircuitBreakerDuration)
139+
err = updateCircuitBreakerConfigInConfigMap(ctx, t, client, opts.CircuitBreakerPercentage, opts.CircuitBreakerDuration)
140+
require.NoError(t, err)
138141
}
139142
if opts.DryRun != nil {
140143
t.Logf("Will set dry-run mode to: %v", *opts.DryRun)
141-
argUpdates["--dry-run="] = fmt.Sprintf("--dry-run=%v", *opts.DryRun)
144+
argUpdates := map[string]string{
145+
"--dry-run=": fmt.Sprintf("--dry-run=%v", *opts.DryRun),
146+
}
147+
originalDeployment = modifyFaultQuarantineDeploymentArgs(ctx, t, client, argUpdates)
148+
}
149+
if opts.CircuitBreakerState != "" {
150+
updateCircuitBreakerStateConfigMap(ctx, t, client, opts.CircuitBreakerState)
142151
}
143-
}
144-
145-
if len(argUpdates) > 0 {
146-
originalDeployment = modifyFaultQuarantineDeploymentArgs(ctx, t, client, argUpdates)
147-
}
148-
149-
if opts != nil && opts.CircuitBreakerState != "" {
150-
updateCircuitBreakerStateConfigMap(ctx, t, client, opts.CircuitBreakerState)
151152
}
152153

153154
if opts == nil || !opts.SkipRestart {
@@ -479,3 +480,22 @@ func updateCircuitBreakerStateConfigMap(ctx context.Context, t *testing.T, clien
479480
err := client.Resources().Create(ctx, cm)
480481
require.NoError(t, err, "failed to create CB state configmap")
481482
}
483+
484+
// updateCircuitBreakerConfigInConfigMap updates the circuit breaker percentage and duration in the fault-quarantine ConfigMap.
485+
func updateCircuitBreakerConfigInConfigMap(ctx context.Context, t *testing.T, client klient.Client, percentage int, duration string) error {
486+
t.Helper()
487+
488+
err := UpdateConfigMapTOMLField(ctx, client, "fault-quarantine", NVSentinelNamespace, "config.toml",
489+
func(cfg *faultQuarantineConfig) error {
490+
cfg.CircuitBreaker.Percentage = percentage
491+
cfg.CircuitBreaker.Duration = duration
492+
return nil
493+
})
494+
495+
if err != nil {
496+
return fmt.Errorf("failed to update circuit breaker config: %w", err)
497+
}
498+
499+
t.Logf("Updated circuit breaker config in ConfigMap: percentage=%d, duration=%s", percentage, duration)
500+
return nil
501+
}

tests/helpers/kube.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"testing"
3030
"time"
3131

32+
"github.com/BurntSushi/toml"
3233
"github.com/nvidia/nvsentinel/commons/pkg/statemanager"
3334
"github.com/stretchr/testify/require"
3435
"go.yaml.in/yaml/v2"
@@ -726,6 +727,60 @@ func BackupConfigMap(ctx context.Context, c klient.Client, name, namespace strin
726727
return yamlData, nil
727728
}
728729

730+
// UpdateConfigMapTOMLField updates a TOML ConfigMap using proper TOML parsing.
731+
// The modifier function receives the parsed config and can modify it before it's written back.
732+
//
733+
// Example usage:
734+
//
735+
// err := UpdateConfigMapTOMLField(ctx, client, "fault-quarantine", "nvsentinel", "config.toml",
736+
// func(cfg *map[string]interface{}) error {
737+
// if cb, ok := (*cfg)["circuitBreaker"].(map[string]interface{}); ok {
738+
// cb["percentage"] = 40
739+
// cb["duration"] = "10m"
740+
// }
741+
// return nil
742+
// })
743+
func UpdateConfigMapTOMLField[T any](ctx context.Context, c klient.Client, name, namespace, tomlKey string,
744+
modifier func(*T) error) error {
745+
746+
cm := &v1.ConfigMap{}
747+
err := c.Resources().Get(ctx, name, namespace, cm)
748+
if err != nil {
749+
return fmt.Errorf("failed to get configmap %s/%s: %w", namespace, name, err)
750+
}
751+
752+
if cm.Data == nil {
753+
return fmt.Errorf("configmap %s/%s has no data", namespace, name)
754+
}
755+
756+
tomlData, exists := cm.Data[tomlKey]
757+
if !exists {
758+
return fmt.Errorf("configmap %s/%s missing key %s", namespace, name, tomlKey)
759+
}
760+
761+
var cfg T
762+
if err := toml.Unmarshal([]byte(tomlData), &cfg); err != nil {
763+
return fmt.Errorf("failed to unmarshal TOML: %w", err)
764+
}
765+
766+
if err := modifier(&cfg); err != nil {
767+
return fmt.Errorf("modifier failed: %w", err)
768+
}
769+
770+
var buf strings.Builder
771+
encoder := toml.NewEncoder(&buf)
772+
if err := encoder.Encode(&cfg); err != nil {
773+
return fmt.Errorf("failed to marshal TOML: %w", err)
774+
}
775+
776+
cm.Data[tomlKey] = buf.String()
777+
if err := c.Resources().Update(ctx, cm); err != nil {
778+
return fmt.Errorf("failed to update configmap %s/%s: %w", namespace, name, err)
779+
}
780+
781+
return nil
782+
}
783+
729784
// WaitForDeploymentRollout waits for a deployment rollout to complete.
730785
// This checks the same conditions as `kubectl rollout status` and verifies at least one pod is ready.
731786
func WaitForDeploymentRollout(ctx context.Context, t *testing.T, c klient.Client, name, namespace string) {

0 commit comments

Comments
 (0)