From 8b15de8351cca9464b96c5d308614f3f47712926 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 19 Jul 2023 18:03:02 +0200 Subject: [PATCH 1/8] PC-9367 --- agent.go | 1 + direct.go | 1 + manifest/v1alpha/objects.go | 1 + manifest/v1alpha/release_channels.go | 11 +++++++++++ manifest/v1alpha/validator.go | 12 ++++++++++++ 5 files changed, 26 insertions(+) create mode 100644 manifest/v1alpha/release_channels.go diff --git a/agent.go b/agent.go index bdef24e1..9e57146a 100644 --- a/agent.go +++ b/agent.go @@ -26,6 +26,7 @@ type AgentStatus struct { type AgentSpec struct { Description string `json:"description,omitempty"` SourceOf []string `json:"sourceOf" example:"Metrics,Services"` + ReleaseChannel string `json:"releaseChannel,omitempty" example:"beta,stable"` QueryDelay *QueryDelayDuration `json:"queryDelay"` AmazonPrometheus *AmazonPrometheusAgentConfig `json:"amazonPrometheus,omitempty"` AppDynamics *AppDynamicsAgentConfig `json:"appDynamics,omitempty"` diff --git a/direct.go b/direct.go index c51510d7..c7f5f81f 100644 --- a/direct.go +++ b/direct.go @@ -18,6 +18,7 @@ type DirectStatus struct { type DirectSpec struct { Description string `json:"description,omitempty" example:"Datadog description"` //nolint:lll SourceOf []string `json:"sourceOf" example:"Metrics,Services"` + ReleaseChannel string `json:"releaseChannel,omitempty" example:"beta,stable"` LogCollectionEnabled *bool `json:"logCollectionEnabled,omitempty"` HistoricalDataRetrieval *HistoricalDataRetrieval `json:"historicalDataRetrieval"` QueryDelay *QueryDelayDuration `json:"queryDelay"` diff --git a/manifest/v1alpha/objects.go b/manifest/v1alpha/objects.go index 6b2a4dd7..2fc79cb3 100644 --- a/manifest/v1alpha/objects.go +++ b/manifest/v1alpha/objects.go @@ -1153,6 +1153,7 @@ type PublicDirectWithSLOs struct { type DirectSpec struct { Description string `json:"description,omitempty" validate:"description" example:"Datadog description"` //nolint:lll SourceOf []string `json:"sourceOf" example:"Metrics,Services"` + ReleaseChannel string `json:"releaseChannel,omitempty" example:"beta,stable"` Datadog *DatadogDirectConfig `json:"datadog,omitempty"` LogCollectionEnabled *bool `json:"logCollectionEnabled,omitempty"` NewRelic *NewRelicDirectConfig `json:"newRelic,omitempty"` diff --git a/manifest/v1alpha/release_channels.go b/manifest/v1alpha/release_channels.go new file mode 100644 index 00000000..ccbe2fb5 --- /dev/null +++ b/manifest/v1alpha/release_channels.go @@ -0,0 +1,11 @@ +package v1alpha + +const ( + Stable = "stable" + Beta = "beta" + Alpha = "alpha" +) + +func GetAvailableReleaseChannels() map[string]bool { + return map[string]bool{Stable: true, Beta: true, Alpha: false} +} diff --git a/manifest/v1alpha/validator.go b/manifest/v1alpha/validator.go index 3c400a84..b6258f0f 100644 --- a/manifest/v1alpha/validator.go +++ b/manifest/v1alpha/validator.go @@ -1506,6 +1506,10 @@ func agentSpecStructLevelValidation(sl v.StructLevel) { } agentQueryDelayValidation(sa, sl) sourceOfValidation(sa.SourceOf, sl) + + if !isValidReleaseChannel(sa.ReleaseChannel) { + sl.ReportError(sa, "ReleaseChannel", "ReleaseChannel", "unknownReleaseChannel", "") + } } func agentQueryDelayValidation(sa AgentSpec, sl v.StructLevel) { @@ -1874,6 +1878,10 @@ func directSpecStructLevelValidation(sl v.StructLevel) { directTypeValidation(sa, sl) directQueryDelayValidation(sa, sl) sourceOfValidation(sa.SourceOf, sl) + + if !isValidReleaseChannel(sa.ReleaseChannel) { + sl.ReportError(sa, "ReleaseChannel", "ReleaseChannel", "unknownReleaseChannel", "") + } } func directTypeValidation(sa DirectSpec, sl v.StructLevel) { @@ -1993,6 +2001,10 @@ func sourceOfItemsValidation(sourceOf []string, sl v.StructLevel) bool { return true } +func isValidReleaseChannel(releaseChannel string) bool { + return releaseChannel == "" || GetAvailableReleaseChannels()[releaseChannel] +} + // Check performs validation, it accepts all possible structs and perform checks based on tags for structs fields func (val *Validate) Check(s interface{}) error { return val.validate.Struct(s) From 0a72735409ce94290aa1603fc9803e2b06185421 Mon Sep 17 00:00:00 2001 From: David Date: Mon, 24 Jul 2023 16:16:38 +0200 Subject: [PATCH 2/8] PC-9367 --- manifest/v1alpha/release_channel.go | 6 ++ manifest/v1alpha/release_channel_enum.go | 105 +++++++++++++++++++++++ manifest/v1alpha/release_channels.go | 11 --- 3 files changed, 111 insertions(+), 11 deletions(-) create mode 100644 manifest/v1alpha/release_channel.go create mode 100644 manifest/v1alpha/release_channel_enum.go delete mode 100644 manifest/v1alpha/release_channels.go diff --git a/manifest/v1alpha/release_channel.go b/manifest/v1alpha/release_channel.go new file mode 100644 index 00000000..d5d27d40 --- /dev/null +++ b/manifest/v1alpha/release_channel.go @@ -0,0 +1,6 @@ +package v1alpha + +//go:generate ../../bin/go-enum --nocase --lower --names --values --marshal + +// ReleaseChannel /* ENUM(Stable,Beta,Alpha)*/ +type ReleaseChannel int diff --git a/manifest/v1alpha/release_channel_enum.go b/manifest/v1alpha/release_channel_enum.go new file mode 100644 index 00000000..d8877ffc --- /dev/null +++ b/manifest/v1alpha/release_channel_enum.go @@ -0,0 +1,105 @@ +// Code generated by go-enum DO NOT EDIT. +// Version: 0.5.6 +// Revision: 97611fddaa414f53713597918c5e954646cb8623 +// Build Date: 2023-03-26T21:38:06Z +// Built By: goreleaser + +package v1alpha + +import ( + "fmt" + "strings" +) + +const ( + // ReleaseChannelStable is a ReleaseChannel of type Stable. + ReleaseChannelStable ReleaseChannel = iota + // ReleaseChannelBeta is a ReleaseChannel of type Beta. + ReleaseChannelBeta + // ReleaseChannelAlpha is a ReleaseChannel of type Alpha. + ReleaseChannelAlpha +) + +var ErrInvalidReleaseChannel = fmt.Errorf("not a valid ReleaseChannel, try [%s]", strings.Join(_ReleaseChannelNames, ", ")) + +const _ReleaseChannelName = "StableBetaAlpha" + +var _ReleaseChannelNames = []string{ + _ReleaseChannelName[0:6], + _ReleaseChannelName[6:10], + _ReleaseChannelName[10:15], +} + +// ReleaseChannelNames returns a list of possible string values of ReleaseChannel. +func ReleaseChannelNames() []string { + tmp := make([]string, len(_ReleaseChannelNames)) + copy(tmp, _ReleaseChannelNames) + return tmp +} + +// ReleaseChannelValues returns a list of the values for ReleaseChannel +func ReleaseChannelValues() []ReleaseChannel { + return []ReleaseChannel{ + ReleaseChannelStable, + ReleaseChannelBeta, + ReleaseChannelAlpha, + } +} + +var _ReleaseChannelMap = map[ReleaseChannel]string{ + ReleaseChannelStable: _ReleaseChannelName[0:6], + ReleaseChannelBeta: _ReleaseChannelName[6:10], + ReleaseChannelAlpha: _ReleaseChannelName[10:15], +} + +// String implements the Stringer interface. +func (x ReleaseChannel) String() string { + if str, ok := _ReleaseChannelMap[x]; ok { + return str + } + return fmt.Sprintf("ReleaseChannel(%d)", x) +} + +// IsValid provides a quick way to determine if the typed value is +// part of the allowed enumerated values +func (x ReleaseChannel) IsValid() bool { + _, ok := _ReleaseChannelMap[x] + return ok +} + +var _ReleaseChannelValue = map[string]ReleaseChannel{ + _ReleaseChannelName[0:6]: ReleaseChannelStable, + strings.ToLower(_ReleaseChannelName[0:6]): ReleaseChannelStable, + _ReleaseChannelName[6:10]: ReleaseChannelBeta, + strings.ToLower(_ReleaseChannelName[6:10]): ReleaseChannelBeta, + _ReleaseChannelName[10:15]: ReleaseChannelAlpha, + strings.ToLower(_ReleaseChannelName[10:15]): ReleaseChannelAlpha, +} + +// ParseReleaseChannel attempts to convert a string to a ReleaseChannel. +func ParseReleaseChannel(name string) (ReleaseChannel, error) { + if x, ok := _ReleaseChannelValue[name]; ok { + return x, nil + } + // Case insensitive parse, do a separate lookup to prevent unnecessary cost of lowercasing a string if we don't need to. + if x, ok := _ReleaseChannelValue[strings.ToLower(name)]; ok { + return x, nil + } + return ReleaseChannel(0), fmt.Errorf("%s is %w", name, ErrInvalidReleaseChannel) +} + +// MarshalText implements the text marshaller method. +func (x ReleaseChannel) MarshalText() ([]byte, error) { + return []byte(x.String()), nil +} + +// UnmarshalText implements the text unmarshaller method. +func (x *ReleaseChannel) UnmarshalText(text []byte) error { + name := string(text) + tmp, err := ParseReleaseChannel(name) + if err != nil { + return err + } + *x = tmp + return nil +} diff --git a/manifest/v1alpha/release_channels.go b/manifest/v1alpha/release_channels.go deleted file mode 100644 index ccbe2fb5..00000000 --- a/manifest/v1alpha/release_channels.go +++ /dev/null @@ -1,11 +0,0 @@ -package v1alpha - -const ( - Stable = "stable" - Beta = "beta" - Alpha = "alpha" -) - -func GetAvailableReleaseChannels() map[string]bool { - return map[string]bool{Stable: true, Beta: true, Alpha: false} -} From 393385bfe175d7014c378c7e6ad7ada7d10c01b7 Mon Sep 17 00:00:00 2001 From: David Date: Mon, 24 Jul 2023 16:46:02 +0200 Subject: [PATCH 3/8] PC-9367 --- manifest/v1alpha/release_channel.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/manifest/v1alpha/release_channel.go b/manifest/v1alpha/release_channel.go index d5d27d40..71ca51bd 100644 --- a/manifest/v1alpha/release_channel.go +++ b/manifest/v1alpha/release_channel.go @@ -4,3 +4,11 @@ package v1alpha // ReleaseChannel /* ENUM(Stable,Beta,Alpha)*/ type ReleaseChannel int + +func GetAvailableReleaseChannels() map[string]bool { + return map[string]bool{ + ReleaseChannelStable.String(): true, + ReleaseChannelBeta.String(): true, + ReleaseChannelAlpha.String(): false, + } +} From b6aa26e68020233b93f28c7941e1965f3c4143a7 Mon Sep 17 00:00:00 2001 From: David Date: Tue, 25 Jul 2023 10:23:24 +0200 Subject: [PATCH 4/8] PC-9367 --- manifest/v1alpha/release_channel.go | 2 +- manifest/v1alpha/release_channel_enum.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/manifest/v1alpha/release_channel.go b/manifest/v1alpha/release_channel.go index 71ca51bd..2d325fe9 100644 --- a/manifest/v1alpha/release_channel.go +++ b/manifest/v1alpha/release_channel.go @@ -2,7 +2,7 @@ package v1alpha //go:generate ../../bin/go-enum --nocase --lower --names --values --marshal -// ReleaseChannel /* ENUM(Stable,Beta,Alpha)*/ +// ReleaseChannel /* ENUM(stable = 1 ,beta, alpha)*/ type ReleaseChannel int func GetAvailableReleaseChannels() map[string]bool { diff --git a/manifest/v1alpha/release_channel_enum.go b/manifest/v1alpha/release_channel_enum.go index d8877ffc..b38bac1b 100644 --- a/manifest/v1alpha/release_channel_enum.go +++ b/manifest/v1alpha/release_channel_enum.go @@ -13,7 +13,7 @@ import ( const ( // ReleaseChannelStable is a ReleaseChannel of type Stable. - ReleaseChannelStable ReleaseChannel = iota + ReleaseChannelStable ReleaseChannel = iota + 1 // ReleaseChannelBeta is a ReleaseChannel of type Beta. ReleaseChannelBeta // ReleaseChannelAlpha is a ReleaseChannel of type Alpha. @@ -22,7 +22,7 @@ const ( var ErrInvalidReleaseChannel = fmt.Errorf("not a valid ReleaseChannel, try [%s]", strings.Join(_ReleaseChannelNames, ", ")) -const _ReleaseChannelName = "StableBetaAlpha" +const _ReleaseChannelName = "stablebetaalpha" var _ReleaseChannelNames = []string{ _ReleaseChannelName[0:6], From 35adeefebbb7223ed45ae6b39188347387c033b5 Mon Sep 17 00:00:00 2001 From: Mateusz Hawrus Date: Tue, 25 Jul 2023 12:24:53 +0200 Subject: [PATCH 5/8] change direct and agent spec --- manifest/v1alpha/objects.go | 4 ++-- manifest/v1alpha/release_channel.go | 10 +--------- manifest/v1alpha/validator.go | 8 ++------ 3 files changed, 5 insertions(+), 17 deletions(-) diff --git a/manifest/v1alpha/objects.go b/manifest/v1alpha/objects.go index 86a4f2eb..b24fe945 100644 --- a/manifest/v1alpha/objects.go +++ b/manifest/v1alpha/objects.go @@ -993,7 +993,7 @@ type QueryDelay struct { type AgentSpec struct { Description string `json:"description,omitempty" validate:"description" example:"Prometheus description"` //nolint:lll SourceOf []string `json:"sourceOf" example:"Metrics,Services"` - ReleaseChannel string `json:"releaseChannel,omitempty" example:"beta,stable"` + ReleaseChannel ReleaseChannel `json:"releaseChannel,omitempty" example:"beta,stable"` Prometheus *PrometheusAgentConfig `json:"prometheus,omitempty"` Datadog *DatadogAgentConfig `json:"datadog,omitempty"` NewRelic *NewRelicAgentConfig `json:"newRelic,omitempty"` @@ -1121,7 +1121,7 @@ type PublicDirectWithSLOs struct { type DirectSpec struct { Description string `json:"description,omitempty" validate:"description" example:"Datadog description"` //nolint:lll SourceOf []string `json:"sourceOf" example:"Metrics,Services"` - ReleaseChannel string `json:"releaseChannel,omitempty" example:"beta,stable"` + ReleaseChannel ReleaseChannel `json:"releaseChannel,omitempty" example:"beta,stable"` Datadog *DatadogDirectConfig `json:"datadog,omitempty"` LogCollectionEnabled *bool `json:"logCollectionEnabled,omitempty"` NewRelic *NewRelicDirectConfig `json:"newRelic,omitempty"` diff --git a/manifest/v1alpha/release_channel.go b/manifest/v1alpha/release_channel.go index 2d325fe9..35d77ab9 100644 --- a/manifest/v1alpha/release_channel.go +++ b/manifest/v1alpha/release_channel.go @@ -2,13 +2,5 @@ package v1alpha //go:generate ../../bin/go-enum --nocase --lower --names --values --marshal -// ReleaseChannel /* ENUM(stable = 1 ,beta, alpha)*/ +// ReleaseChannel /* ENUM(stable = 1, beta, alpha)*/ type ReleaseChannel int - -func GetAvailableReleaseChannels() map[string]bool { - return map[string]bool{ - ReleaseChannelStable.String(): true, - ReleaseChannelBeta.String(): true, - ReleaseChannelAlpha.String(): false, - } -} diff --git a/manifest/v1alpha/validator.go b/manifest/v1alpha/validator.go index 30b61e2d..4467fabb 100644 --- a/manifest/v1alpha/validator.go +++ b/manifest/v1alpha/validator.go @@ -1507,7 +1507,7 @@ func agentSpecStructLevelValidation(sl v.StructLevel) { agentQueryDelayValidation(sa, sl) sourceOfValidation(sa.SourceOf, sl) - if !isValidReleaseChannel(sa.ReleaseChannel) { + if !sa.ReleaseChannel.IsValid() { sl.ReportError(sa, "ReleaseChannel", "ReleaseChannel", "unknownReleaseChannel", "") } } @@ -1879,7 +1879,7 @@ func directSpecStructLevelValidation(sl v.StructLevel) { directQueryDelayValidation(sa, sl) sourceOfValidation(sa.SourceOf, sl) - if !isValidReleaseChannel(sa.ReleaseChannel) { + if !sa.ReleaseChannel.IsValid() { sl.ReportError(sa, "ReleaseChannel", "ReleaseChannel", "unknownReleaseChannel", "") } } @@ -2001,10 +2001,6 @@ func sourceOfItemsValidation(sourceOf []string, sl v.StructLevel) bool { return true } -func isValidReleaseChannel(releaseChannel string) bool { - return releaseChannel == "" || GetAvailableReleaseChannels()[releaseChannel] -} - // Check performs validation, it accepts all possible structs and perform checks based on tags for structs fields func (val *Validate) Check(s interface{}) error { return val.validate.Struct(s) From a0799cdaafe64acbc766aede55aa1573506e9baa Mon Sep 17 00:00:00 2001 From: Mateusz Hawrus Date: Tue, 25 Jul 2023 12:36:29 +0200 Subject: [PATCH 6/8] fix validation --- manifest/v1alpha/validator.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/manifest/v1alpha/validator.go b/manifest/v1alpha/validator.go index 4467fabb..ce2a3a37 100644 --- a/manifest/v1alpha/validator.go +++ b/manifest/v1alpha/validator.go @@ -1507,7 +1507,7 @@ func agentSpecStructLevelValidation(sl v.StructLevel) { agentQueryDelayValidation(sa, sl) sourceOfValidation(sa.SourceOf, sl) - if !sa.ReleaseChannel.IsValid() { + if !isValidReleaseChannel(sa.ReleaseChannel) { sl.ReportError(sa, "ReleaseChannel", "ReleaseChannel", "unknownReleaseChannel", "") } } @@ -1879,7 +1879,7 @@ func directSpecStructLevelValidation(sl v.StructLevel) { directQueryDelayValidation(sa, sl) sourceOfValidation(sa.SourceOf, sl) - if !sa.ReleaseChannel.IsValid() { + if !isValidReleaseChannel(sa.ReleaseChannel) { sl.ReportError(sa, "ReleaseChannel", "ReleaseChannel", "unknownReleaseChannel", "") } } @@ -2001,6 +2001,10 @@ func sourceOfItemsValidation(sourceOf []string, sl v.StructLevel) bool { return true } +func isValidReleaseChannel(releaseChannel ReleaseChannel) bool { + return releaseChannel == 0 || releaseChannel.IsValid() +} + // Check performs validation, it accepts all possible structs and perform checks based on tags for structs fields func (val *Validate) Check(s interface{}) error { return val.validate.Struct(s) From c7215d950df7477e0fec6d0e3376f5491e31daf3 Mon Sep 17 00:00:00 2001 From: Mateusz Hawrus Date: Tue, 25 Jul 2023 12:52:10 +0200 Subject: [PATCH 7/8] correct parsing logic for alpha channel --- manifest/v1alpha/validator.go | 6 +++++- manifest/v1alpha/validator_test.go | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/manifest/v1alpha/validator.go b/manifest/v1alpha/validator.go index ce2a3a37..f187001b 100644 --- a/manifest/v1alpha/validator.go +++ b/manifest/v1alpha/validator.go @@ -2002,7 +2002,11 @@ func sourceOfItemsValidation(sourceOf []string, sl v.StructLevel) bool { } func isValidReleaseChannel(releaseChannel ReleaseChannel) bool { - return releaseChannel == 0 || releaseChannel.IsValid() + if releaseChannel == 0 { + return true + } + // We do not allow ReleaseChannelAlpha to be set by the user. + return releaseChannel.IsValid() && releaseChannel != ReleaseChannelAlpha } // Check performs validation, it accepts all possible structs and perform checks based on tags for structs fields diff --git a/manifest/v1alpha/validator_test.go b/manifest/v1alpha/validator_test.go index 6fe3f4e2..2204e972 100644 --- a/manifest/v1alpha/validator_test.go +++ b/manifest/v1alpha/validator_test.go @@ -990,3 +990,19 @@ func TestAlertConditionOpSupport(t *testing.T) { }) } } + +func TestIsReleaseChannelValid(t *testing.T) { + for name, test := range map[string]struct { + ReleaseChannel ReleaseChannel + IsValid bool + }{ + "unset release channel, valid": {IsValid: true}, + "beta channel, valid": {ReleaseChannel: ReleaseChannelBeta, IsValid: true}, + "stable channel, valid": {ReleaseChannel: ReleaseChannelStable, IsValid: true}, + "alpha channel, invalid": {ReleaseChannel: ReleaseChannelAlpha}, + } { + t.Run(name, func(t *testing.T) { + assert.Equal(t, test.IsValid, isValidReleaseChannel(test.ReleaseChannel)) + }) + } +} From e3ba61ce09c6066db92461b2136933c4568e4ad2 Mon Sep 17 00:00:00 2001 From: Mateusz Hawrus Date: Tue, 25 Jul 2023 15:24:41 +0200 Subject: [PATCH 8/8] generate custom error during unmarshal --- manifest/v1alpha/release_channel.go | 27 +++++++++++++++++++++++- manifest/v1alpha/release_channel_enum.go | 16 -------------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/manifest/v1alpha/release_channel.go b/manifest/v1alpha/release_channel.go index 35d77ab9..a08a3dd3 100644 --- a/manifest/v1alpha/release_channel.go +++ b/manifest/v1alpha/release_channel.go @@ -1,6 +1,31 @@ package v1alpha -//go:generate ../../bin/go-enum --nocase --lower --names --values --marshal +import ( + "fmt" +) + +//go:generate ../../bin/go-enum --nocase --names --lower --values // ReleaseChannel /* ENUM(stable = 1, beta, alpha)*/ type ReleaseChannel int + +// MarshalText implements the text marshaller method. +func (r ReleaseChannel) MarshalText() ([]byte, error) { + return []byte(r.String()), nil +} + +// UnmarshalText implements the text unmarshaller method. +func (r *ReleaseChannel) UnmarshalText(text []byte) error { + if len(text) == 0 { + *r = 0 + return nil + } + tmp, err := ParseReleaseChannel(string(text)) + if err != nil { + // We're only allowing a subset of valid release channels to be set by the user, inform only on them. + return fmt.Errorf("%s is not a valid ReleaseChannel, try [%s, %s]", + string(text), ReleaseChannelStable, ReleaseChannelBeta) + } + *r = tmp + return nil +} diff --git a/manifest/v1alpha/release_channel_enum.go b/manifest/v1alpha/release_channel_enum.go index b38bac1b..85de193b 100644 --- a/manifest/v1alpha/release_channel_enum.go +++ b/manifest/v1alpha/release_channel_enum.go @@ -87,19 +87,3 @@ func ParseReleaseChannel(name string) (ReleaseChannel, error) { } return ReleaseChannel(0), fmt.Errorf("%s is %w", name, ErrInvalidReleaseChannel) } - -// MarshalText implements the text marshaller method. -func (x ReleaseChannel) MarshalText() ([]byte, error) { - return []byte(x.String()), nil -} - -// UnmarshalText implements the text unmarshaller method. -func (x *ReleaseChannel) UnmarshalText(text []byte) error { - name := string(text) - tmp, err := ParseReleaseChannel(name) - if err != nil { - return err - } - *x = tmp - return nil -}