Skip to content

Commit

Permalink
Merge pull request #243 from 3scale-ops/refactor/envoyconfig-generati…
Browse files Browse the repository at this point in the history
…on-api

refactor/envoyconfig-generation-api
  • Loading branch information
3scale-robot authored Jan 9, 2023
2 parents 09572b4 + c208cbe commit e4b75b0
Show file tree
Hide file tree
Showing 52 changed files with 1,084 additions and 2,238 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# To re-generate a bundle for another specific version without changing the standard setup, you can:
# - use the VERSION as arg of the bundle target (e.g make bundle VERSION=0.0.2)
# - use environment variables to overwrite this value (e.g export VERSION=0.0.2)
VERSION ?= 0.18.0-alpha.4
VERSION ?= 0.18.0-alpha.8

# CHANNELS define the bundle channels used in the bundle.
# Add a new line here if you would like to change its default config. (E.g CHANNELS = "candidate,fast,stable")
Expand Down
117 changes: 76 additions & 41 deletions api/v1alpha1/marin3r_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package v1alpha1

import (
"reflect"
"sort"

envoyconfig "github.com/3scale/saas-operator/pkg/resource_builders/envoyconfig/descriptor"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
runtime "k8s.io/apimachinery/pkg/runtime"
)

// SidecarPort defines port for the Marin3r sidecar container
Expand Down Expand Up @@ -57,7 +59,7 @@ type Marin3rSidecarSpec struct {
// in the cluster.
// +operator-sdk:csv:customresourcedefinitions:type=spec
// +optional
EnvoyDynamicConfig []EnvoyDynamicConfig `json:"dynamicConfigs,omitempty"`
EnvoyDynamicConfig MapOfEnvoyDynamicConfig `json:"dynamicConfigs,omitempty"`
}

type defaultMarin3rSidecarSpec struct {
Expand Down Expand Up @@ -107,9 +109,37 @@ func InitializeMarin3rSidecarSpec(spec *Marin3rSidecarSpec, def defaultMarin3rSi
return spec
}

// +kubebuilder:validation:MinProperties:=1
// +kubebuilder:validation:MaxProperties:=1
type MapOfEnvoyDynamicConfig map[string]EnvoyDynamicConfig

// AsList transforms from the map in the external API to the list of elements
// that the internal API expects.
func (mapofconfs MapOfEnvoyDynamicConfig) AsList() []envoyconfig.EnvoyDynamicConfigDescriptor {

list := make([]envoyconfig.EnvoyDynamicConfigDescriptor, 0, len(mapofconfs))

for name, conf := range mapofconfs {
list = append(list, conf.DeepCopy().AsEnvoyDynamicConfigDescriptor(name))
}

// ensure consistent order of configs
sort.Slice(list, func(a, b int) bool {
return list[a].GetName() < list[b].GetName()
})

return list
}

// +kubebuilder:validation:MinProperties:=2
// +kubebuilder:validation:MaxProperties:=2
type EnvoyDynamicConfig struct {
// unexported, hidden field
name string `json:"-"`
// GeneratorVersion specifies the version of a given template.
// "v1" is the default.
// +operator-sdk:csv:customresourcedefinitions:type=spec
// +kubebuilder:default:=v1
// +optional
GeneratorVersion *string `json:"generatorVersion,omitempty"`
// ListenerHttp contains options for an HTTP/HTTPS listener
// +operator-sdk:csv:customresourcedefinitions:type=spec
// +optional
Expand All @@ -127,56 +157,53 @@ type EnvoyDynamicConfig struct {
// +operator-sdk:csv:customresourcedefinitions:type=spec
// +optional
Runtime *Runtime `json:"runtime,omitempty"`
}

type EnvoyDynamicConfigMeta struct {
// The name of the configuration/resource. The name is what
// allows a configuration to be used from wihin other configuration.
// +operator-sdk:csv:customresourcedefinitions:type=spec
Name string `json:"name"`
// GeneratorVersion specifies the version of a given template.
// "v1" is the default.
// +operator-sdk:csv:customresourcedefinitions:type=spec
// +kubebuilder:default:=v1
// +optional
GeneratorVersion *string `json:"generatorVersion,omitempty"`
RawConfig *RawConfig `json:"rawConfig,omitempty"`
}

// GetName returns the name
func (meta *EnvoyDynamicConfigMeta) GetName() string {
return meta.Name
// AsEnvoyDynamicConfigDescriptor converts the external API type into the internal EnvoyDynamicConfigDescriptor
// interface. The name field is populated with the parameter passed to the function.
func (config *EnvoyDynamicConfig) AsEnvoyDynamicConfigDescriptor(name string) envoyconfig.EnvoyDynamicConfigDescriptor {
config.name = name
return config
}

// GetGeneratorVersion returns the template's version
func (meta *EnvoyDynamicConfigMeta) GetGeneratorVersion() string {
return *meta.GeneratorVersion
func (config *EnvoyDynamicConfig) GetName() string {
return config.name
}

// EnvoyDynamicConfigRaw is a struct with methods to manage a
// configuration defined using directly the Envoy config API
type EnvoyDynamicConfigRaw struct {
// +operator-sdk:csv:customresourcedefinitions:type=spec
// +optional
// Allows defining configuration using directly envoy's config API.
// WARNING: no validation of this field's value is performed before
// writting the custom resource to etcd.
RawConfig *runtime.RawExtension `json:"rawConfig,omitempty"`
// GetGeneratorVersion returns the template's version
func (config *EnvoyDynamicConfig) GetGeneratorVersion() string {
return *config.GeneratorVersion
}

func (raw *EnvoyDynamicConfigRaw) GetRawConfig() []byte {
if raw != nil && raw.RawConfig != nil && raw.RawConfig.Raw != nil {
return raw.RawConfig.Raw
func (config *EnvoyDynamicConfig) GetOptions() interface{} {
if config.ListenerHttp != nil {
return config.ListenerHttp
} else if config.RouteConfiguration != nil {
return config.RouteConfiguration
} else if config.Cluster != nil {
return config.Cluster
} else if config.Runtime != nil {
return config.Runtime
} else if config.RawConfig != nil {
return config.RawConfig
}

return nil
}

// ListenerHttp contains options for an HTTP/HTTPS listener
type ListenerHttp struct {
EnvoyDynamicConfigMeta `json:",inline"`
EnvoyDynamicConfigRaw `json:",inline"`
// The port where the listener listens for new connections
// +operator-sdk:csv:customresourcedefinitions:type=spec
Port uint32 `json:"port"`
// Whether proxy protocol should be enabled or not. Defaults to true.
// +operator-sdk:csv:customresourcedefinitions:type=spec
// +kubebuilder:default:=true
// +optional
ProxyProtocol *bool `json:"proxyProtocol,omitempty"`
// The name of the RouteConfiguration to use in the listener
// +operator-sdk:csv:customresourcedefinitions:type=spec
RouteConfigName string `json:"routeConfigName"`
Expand Down Expand Up @@ -235,8 +262,6 @@ type RateLimitOptions struct {

// Cluster contains options for an Envoy cluster protobuffer message
type Cluster struct {
EnvoyDynamicConfigMeta `json:",inline"`
EnvoyDynamicConfigRaw `json:",inline"`
// The upstream host
// +operator-sdk:csv:customresourcedefinitions:type=spec
Host string `json:"host"`
Expand All @@ -253,8 +278,6 @@ type Cluster struct {
// RouteConfiguration contains options for an Envoy route_configuration
// protobuffer message
type RouteConfiguration struct {
EnvoyDynamicConfigMeta `json:",inline"`
EnvoyDynamicConfigRaw `json:",inline"`
// The virtual_hosts definitions for this route configuration.
// Virtual hosts must be specified using directly Envoy's API
// +operator-sdk:csv:customresourcedefinitions:type=spec
Expand All @@ -263,9 +286,21 @@ type RouteConfiguration struct {

// Runtime contains options for an Envoy runtime protobuffer message
type Runtime struct {
EnvoyDynamicConfigMeta `json:",inline"`
EnvoyDynamicConfigRaw `json:",inline"`
// The list of listeners to apply overload protection limits to
// +operator-sdk:csv:customresourcedefinitions:type=spec
ListenerNames []string `json:"listenerNames"`
}

// RawConfig is a struct with methods to manage a
// configuration defined using directly the Envoy config API
type RawConfig struct {
// Type is the type url for the protobuf message
// +operator-sdk:csv:customresourcedefinitions:type=spec
// +kubebuilder:validation:Enum=listener;routeConfiguration;cluster;runtime
Type string `json:"type"`
// +operator-sdk:csv:customresourcedefinitions:type=spec
// Allows defining configuration using directly envoy's config API.
// WARNING: no validation of this field's value is performed before
// writting the custom resource to etcd.
Value runtime.RawExtension `json:"value"`
}
54 changes: 29 additions & 25 deletions api/v1alpha1/marin3r_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import (
"reflect"
"testing"

envoyconfig "github.com/3scale/saas-operator/pkg/resource_builders/envoyconfig/descriptor"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/runtime"
)

func TestMarin3rSidecarSpec_Default(t *testing.T) {
Expand Down Expand Up @@ -220,40 +220,44 @@ func TestInitializeMarin3rSidecarSpec(t *testing.T) {
}
}

func TestEnvoyDynamicConfigRaw_GetRawConfig(t *testing.T) {
type fields struct {
RawConfig *runtime.RawExtension
}
func TestMapOfEnvoyDynamicConfig_AsList(t *testing.T) {
tests := []struct {
name string
fields fields
want []byte
name string
mapofconfs MapOfEnvoyDynamicConfig
want []envoyconfig.EnvoyDynamicConfigDescriptor
}{
{
name: "returns the raw config",
fields: fields{
RawConfig: &runtime.RawExtension{
Raw: []byte("whatever"),
Object: nil,
name: "Returns the map as a list of EnvoyDynamicConfigDescriptor",
mapofconfs: map[string]EnvoyDynamicConfig{
"one": {
name: "",
GeneratorVersion: new(string),
ListenerHttp: &ListenerHttp{},
},
"two": {
name: "",
GeneratorVersion: new(string),
Cluster: &Cluster{},
},
},
want: []byte("whatever"),
},
{
name: "returns nil",
fields: fields{
RawConfig: nil,
want: []envoyconfig.EnvoyDynamicConfigDescriptor{
&EnvoyDynamicConfig{
name: "one",
GeneratorVersion: new(string),
ListenerHttp: &ListenerHttp{},
},
&EnvoyDynamicConfig{
name: "two",
GeneratorVersion: new(string),
Cluster: &Cluster{},
},
},
want: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
raw := &EnvoyDynamicConfigRaw{
RawConfig: tt.fields.RawConfig,
}
if got := raw.GetRawConfig(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("EnvoyDynamicConfigRaw.GetRawConfig() = %v, want %v", got, tt.want)
if got := tt.mapofconfs.AsList(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("MapOfEnvoyDynamicConfig.AsList() = %v, want %v", got, tt.want)
}
})
}
Expand Down
Loading

0 comments on commit e4b75b0

Please sign in to comment.