From 178f7d27ea29ffc1832b96e0bf9ecb3cb3b011c8 Mon Sep 17 00:00:00 2001 From: Johannes Edmeier Date: Wed, 10 Jul 2024 11:54:57 +0200 Subject: [PATCH] feat: add http endpoint to alter update/replacement config --- config/config.go | 49 ++++++++++++++++++++++++++++------------ extloadtest/discovery.go | 38 +++++++++++++++++++++++++++++++ main.go | 1 + 3 files changed, 74 insertions(+), 14 deletions(-) diff --git a/config/config.go b/config/config.go index 6735489..e64d187 100644 --- a/config/config.go +++ b/config/config.go @@ -12,6 +12,10 @@ import ( "strings" ) +var ( + Config Specification +) + // Specification is the configuration specification for the extension. Configuration values can be applied // through environment variables. Learn more through the documentation of the envconfig package. // https://github.com/kelseyhightower/envconfig @@ -29,7 +33,7 @@ type Specification struct { ContainerPerPod int `json:"containerPerPod" split_words:"true" required:"false" default:"2"` AttributeUpdates AttributeUpdateSpecifications `split_words:"true" required:"false" default:"[]"` - TargetReplacements TargetReplacementsSpecifications `split_words:"true" required:"false" default:""` + TargetReplacements TargetReplacementsSpecifications `split_words:"true" required:"false" default:"[]"` DiscoveryAttributesExcludesContainer []string `json:"discoveryAttributesExcludesContainer" split_words:"true" required:"false"` DiscoveryAttributesExcludesEc2 []string `json:"discoveryAttributesExcludesEc2" split_words:"true" required:"false"` @@ -64,7 +68,13 @@ func IsPodZero() bool { } type AttributeUpdateSpecifications []AttributeUpdateSpecification -type TargetReplacementsSpecifications []TargetReplacementsSpecification + +type AttributeUpdateSpecification struct { + Type string `json:"type" split_words:"true"` + AttributeName string `json:"attributeName" split_words:"true"` + Rate float64 `json:"rate" split_words:"true"` + Interval int `json:"interval" split_words:"true"` +} func (s *AttributeUpdateSpecifications) Decode(value string) error { var specs []AttributeUpdateSpecification @@ -76,15 +86,8 @@ func (s *AttributeUpdateSpecifications) Decode(value string) error { return nil } -type AttributeUpdateSpecification struct { - Type string `json:"type" split_words:"true"` - AttributeName string `json:"attributeName" split_words:"true"` - Rate float64 `json:"rate" split_words:"true"` - Interval int `json:"interval" split_words:"true"` -} - -func (s *TargetReplacementsSpecification) Decode(value string) error { - var spec TargetReplacementsSpecification +func (s *AttributeUpdateSpecification) Decode(value string) error { + var spec AttributeUpdateSpecification err := json.Unmarshal([]byte(value), &spec) if err != nil { return fmt.Errorf("invalid json: %w", err) @@ -93,15 +96,33 @@ func (s *TargetReplacementsSpecification) Decode(value string) error { return nil } +type TargetReplacementsSpecifications []TargetReplacementsSpecification + type TargetReplacementsSpecification struct { Type string `json:"type" split_words:"true"` Count int `json:"count" split_words:"true"` Interval int `json:"interval" split_words:"true"` } -var ( - Config Specification -) +func (s *TargetReplacementsSpecifications) Decode(value string) error { + var specs []TargetReplacementsSpecification + err := json.Unmarshal([]byte(value), &specs) + if err != nil { + return fmt.Errorf("invalid json: %w", err) + } + *s = specs + return nil +} + +func (s *TargetReplacementsSpecification) Decode(value string) error { + var spec TargetReplacementsSpecification + err := json.Unmarshal([]byte(value), &spec) + if err != nil { + return fmt.Errorf("invalid json: %w", err) + } + *s = spec + return nil +} func ParseConfiguration() { err := envconfig.Process("steadybit_extension", &Config) diff --git a/extloadtest/discovery.go b/extloadtest/discovery.go index 534c1a9..1d98337 100644 --- a/extloadtest/discovery.go +++ b/extloadtest/discovery.go @@ -1,13 +1,19 @@ +// SPDX-License-Identifier: MIT +// SPDX-FileCopyrightText: 2024 Steadybit GmbH + package extloadtest import ( "context" + "encoding/json" "fmt" + "github.com/procyon-projects/chrono" "github.com/rs/zerolog/log" "github.com/steadybit/action-kit/go/action_kit_api/v2" "github.com/steadybit/action-kit/go/action_kit_sdk" "github.com/steadybit/discovery-kit/go/discovery_kit_api" "github.com/steadybit/discovery-kit/go/discovery_kit_sdk" + "github.com/steadybit/extension-kit/exthttp" "github.com/steadybit/extension-kit/extutil" "github.com/steadybit/extension-loadtest/config" "net/http" @@ -302,3 +308,35 @@ func (t *TargetData) RegisterRecreateActions() { }, )) } + +func (t *TargetData) RegisterConfigUpdateHandlers() { + exthttp.RegisterHttpHandler("/config/targetReplacements", t.updateConfigHandler(&config.Config.TargetReplacements)) + exthttp.RegisterHttpHandler("/config/attributeUpdates", t.updateConfigHandler(&config.Config.AttributeUpdates)) +} + +func (t *TargetData) updateConfigHandler(config interface{}) exthttp.Handler { + return func(w http.ResponseWriter, r *http.Request, body []byte) { + if r.Method == http.MethodPost { + clone := extutil.JsonMangle(config) + err := json.Unmarshal(body, clone) + if err != nil { + w.WriteHeader(400) + _, _ = w.Write([]byte(err.Error())) + } + config = clone + t.rescheduleUpdates() + exthttp.WriteBody(w, config) + } else if r.Method == http.MethodGet { + exthttp.WriteBody(w, config) + } else { + w.WriteHeader(405) + } + } +} + +func (t *TargetData) rescheduleUpdates() { + log.Info().Msg("Stopping all scheduled updates") + scheduler.Shutdown() + scheduler = chrono.NewDefaultTaskScheduler() + t.ScheduleUpdates() +} diff --git a/main.go b/main.go index 12d1a3a..85a6406 100644 --- a/main.go +++ b/main.go @@ -44,6 +44,7 @@ func main() { targetData.ScheduleUpdates() targetData.RegisterDiscoveries() targetData.RegisterRecreateActions() + targetData.RegisterConfigUpdateHandlers() discovery_kit_sdk.Register(extloadtest.NewEnrichmentRuleProvider())