Skip to content

Commit

Permalink
expose aditional config into serverless cr (#192)
Browse files Browse the repository at this point in the history
Co-authored-by: Damian Badura <[email protected]>
  • Loading branch information
MichalKalke and dbadura authored Aug 11, 2023
1 parent 07c44f8 commit ae1a9af
Show file tree
Hide file tree
Showing 9 changed files with 227 additions and 78 deletions.
2 changes: 1 addition & 1 deletion api/v1alpha1/serverless_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const (
DefaultEnableInternal = false
DefaultRegistryAddress = "k3d-kyma-registry:5000"
DefaultServerAddress = "k3d-kyma-registry:5000"
FeatureDisabled = ""
EndpointDisabled = ""
DefaultEventingEndpoint = "http://eventing-publisher-proxy.kyma-system.svc.cluster.local/publish"
)

Expand Down
25 changes: 22 additions & 3 deletions api/v1alpha1/serverless_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,18 @@ type Endpoint struct {

// ServerlessSpec defines the desired state of Serverless
type ServerlessSpec struct {
Tracing *Endpoint `json:"tracing,omitempty"`
Eventing *Endpoint `json:"eventing,omitempty"`
DockerRegistry *DockerRegistry `json:"dockerRegistry,omitempty"`
Tracing *Endpoint `json:"tracing,omitempty"`
Eventing *Endpoint `json:"eventing,omitempty"`
DockerRegistry *DockerRegistry `json:"dockerRegistry,omitempty"`
TargetCPUUtilizationPercentage string `json:"targetCPUUtilizationPercentage,omitempty"`
FunctionRequeueDuration string `json:"functionRequeueDuration,omitempty"`
FunctionBuildExecutorArgs string `json:"functionBuildExecutorArgs,omitempty"`
FunctionBuildMaxSimultaneousJobs string `json:"functionBuildMaxSimultaneousJobs,omitempty"`
HealthzLivenessTimeout string `json:"healthzLivenessTimeout,omitempty"`
FunctionRequestBodyLimitMb string `json:"functionRequestBodyLimitMb,omitempty"`
FunctionTimeoutSec string `json:"functionTimeoutSec,omitempty"`
DefaultBuildJobPreset string `json:"defaultBuildJobPreset,omitempty"`
DefaultRuntimePodPreset string `json:"defaultRuntimePodPreset,omitempty"`
}

type State string
Expand Down Expand Up @@ -83,6 +92,16 @@ type ServerlessStatus struct {
EventingEndpoint string `json:"eventingEndpoint,omitempty"`
TracingEndpoint string `json:"tracingEndpoint,omitempty"`

CPUUtilizationPercentage string `json:"targetCPUUtilizationPercentage,omitempty"`
RequeueDuration string `json:"functionRequeueDuration,omitempty"`
BuildExecutorArgs string `json:"functionBuildExecutorArgs,omitempty"`
BuildMaxSimultaneousJobs string `json:"functionBuildMaxSimultaneousJobs,omitempty"`
HealthzLivenessTimeout string `json:"healthzLivenessTimeout,omitempty"`
RequestBodyLimitMb string `json:"functionRequestBodyLimitMb,omitempty"`
TimeoutSec string `json:"functionTimeoutSec,omitempty"`
DefaultBuildJobPreset string `json:"defaultBuildJobPreset,omitempty"`
DefaultRuntimePodPreset string `json:"defaultRuntimePodPreset,omitempty"`

// Used registry configuration.
// Contains registry URL or "internal"
DockerRegistry string `json:"dockerRegistry,omitempty"`
Expand Down
36 changes: 36 additions & 0 deletions config/crd/bases/operator.kyma-project.io_serverlesses.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ spec:
spec:
description: ServerlessSpec defines the desired state of Serverless
properties:
defaultBuildJobPreset:
type: string
defaultRuntimePodPreset:
type: string
dockerRegistry:
properties:
enableInternal:
Expand All @@ -65,6 +69,20 @@ spec:
required:
- endpoint
type: object
functionBuildExecutorArgs:
type: string
functionBuildMaxSimultaneousJobs:
type: string
functionRequestBodyLimitMb:
type: string
functionRequeueDuration:
type: string
functionTimeoutSec:
type: string
healthzLivenessTimeout:
type: string
targetCPUUtilizationPercentage:
type: string
tracing:
properties:
endpoint:
Expand Down Expand Up @@ -144,13 +162,29 @@ spec:
- type
type: object
type: array
defaultBuildJobPreset:
type: string
defaultRuntimePodPreset:
type: string
dockerRegistry:
description: Used registry configuration. Contains registry URL or
"internal"
type: string
eventingEndpoint:
description: Used the Eventing endpoint and the Tracing endpoint.
type: string
functionBuildExecutorArgs:
type: string
functionBuildMaxSimultaneousJobs:
type: string
functionRequestBodyLimitMb:
type: string
functionRequeueDuration:
type: string
functionTimeoutSec:
type: string
healthzLivenessTimeout:
type: string
served:
description: Served signifies that current Serverless is managed.
Value can be one of ("True", "False").
Expand All @@ -168,6 +202,8 @@ spec:
- Error
- Warning
type: string
targetCPUUtilizationPercentage:
type: string
tracingEndpoint:
type: string
required:
Expand Down
2 changes: 1 addition & 1 deletion controllers/serverless_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ var _ = Describe("Serverless controller", func() {

var (
serverlessDataDefault = serverlessData{
TraceCollectorURL: pointer.String(v1alpha1.FeatureDisabled),
TraceCollectorURL: pointer.String(v1alpha1.EndpointDisabled),
EnableInternal: pointer.Bool(v1alpha1.DefaultEnableInternal),
registrySecretData: registrySecretData{
ServerAddress: pointer.String(v1alpha1.DefaultServerAddress),
Expand Down
2 changes: 1 addition & 1 deletion controllers/testhelper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ func (h *testHelper) createCheckOptionalDependenciesFunc(deploymentName string,
eventProxyURL = *expected.EventPublisherProxyURL
}

traceCollectorURL := v1alpha1.FeatureDisabled
traceCollectorURL := v1alpha1.EndpointDisabled
if expected.TraceCollectorURL != nil {
traceCollectorURL = *expected.TraceCollectorURL
}
Expand Down
18 changes: 17 additions & 1 deletion internal/chart/flags.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package chart

func AppendContainersFlags(flags map[string]interface{}, publisherURL, traceCollectorURL string) map[string]interface{} {
func AppendContainersFlags(flags map[string]interface{}, publisherURL, traceCollectorURL, CPUUtilizationPercentage, requeueDuration, buildExecutorArgs, maxSimultaneousJobs, healthzLivenessTimeout, requestBodyLimitMb, timeoutSec, defaultBuildJobPreset, defaultRuntimePodPreset string) map[string]interface{} {
flags["containers"] = map[string]interface{}{
"manager": map[string]interface{}{
"envs": map[string]interface{}{
Expand All @@ -10,13 +10,29 @@ func AppendContainersFlags(flags map[string]interface{}, publisherURL, traceColl
"functionPublisherProxyAddress": map[string]interface{}{
"value": publisherURL,
},
"targetCPUUtilizationPercentage": getValueOrEmpty(CPUUtilizationPercentage),
"functionRequeueDuration": getValueOrEmpty(requeueDuration),
"functionBuildExecutorArgs": getValueOrEmpty(buildExecutorArgs),
"functionBuildMaxSimultaneousJobs": getValueOrEmpty(maxSimultaneousJobs),
"healthzLivenessTimeout": getValueOrEmpty(healthzLivenessTimeout),
"functionRequestBodyLimitMb": getValueOrEmpty(requestBodyLimitMb),
"functionTimeoutSec": getValueOrEmpty(timeoutSec),
"defaultBuildJobPreset": getValueOrEmpty(defaultBuildJobPreset),
"defaultRuntimePodPreset": getValueOrEmpty(defaultRuntimePodPreset),
},
},
}

return flags
}

func getValueOrEmpty(value string) map[string]interface{} {
if value == "" {
return map[string]interface{}{}
}
return map[string]interface{}{"value": value}
}

/*
AppendNodePortFlag
nodePort must be int64, because when we compare old Flags with new flags, by default all integers are int64
Expand Down
24 changes: 0 additions & 24 deletions internal/chart/flags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,27 +61,3 @@ func TestAppendExternalRegistryFlags(t *testing.T) {
}, flags)
})
}

func TestAppendContainersFlags(t *testing.T) {
t.Run("append flags", func(t *testing.T) {
publisherURL := "test-proxy-url"
collectorURL := "test-trace-url"

flags := AppendContainersFlags(map[string]interface{}{}, publisherURL, collectorURL)

require.Equal(t, map[string]interface{}{
"containers": map[string]interface{}{
"manager": map[string]interface{}{
"envs": map[string]interface{}{
"functionTraceCollectorEndpoint": map[string]interface{}{
"value": collectorURL,
},
"functionPublisherProxyAddress": map[string]interface{}{
"value": publisherURL,
},
},
},
},
}, flags)
})
}
107 changes: 75 additions & 32 deletions internal/state/optional_dependencies.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ package state
import (
"context"
"fmt"
"github.com/kyma-project/serverless-manager/api/v1alpha1"
"github.com/kyma-project/serverless-manager/internal/chart"
"github.com/kyma-project/serverless-manager/internal/tracing"
"github.com/pkg/errors"
"go.uber.org/zap"
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/kyma-project/serverless-manager/api/v1alpha1"
"github.com/kyma-project/serverless-manager/internal/chart"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
controllerruntime "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"strings"
)

// enable or disable serverless optional dependencies based on the Serverless Spec and installed module on the cluster
Expand All @@ -26,21 +26,22 @@ func sFnOptionalDependencies(ctx context.Context, r *reconciler, s *systemState)
}
eventingURL := getEventingURL(s.instance.Spec)

// update status and condition if status is not up-to-date
if s.instance.Status.EventingEndpoint != eventingURL ||
s.instance.Status.TracingEndpoint != tracingURL ||
!meta.IsStatusConditionPresentAndEqual(s.instance.Status.Conditions, string(v1alpha1.ConditionTypeConfigured), metav1.ConditionTrue) {

s.instance.Status.EventingEndpoint = eventingURL
s.instance.Status.TracingEndpoint = tracingURL
if statusChanged, svlsCfgMsg := updateStatus(&s.instance, eventingURL, tracingURL); statusChanged {
s.setState(v1alpha1.StateProcessing)
s.instance.UpdateConditionTrue(
v1alpha1.ConditionTypeConfigured,
v1alpha1.ConditionReasonConfigured,
fmt.Sprintf(svlsCfgMsg),
)
return nextState(sFnUpdateStatusAndRequeue)
}

if configurationStatusIsNotReady(s.instance.Status.Conditions) {
s.setState(v1alpha1.StateProcessing)
s.instance.UpdateConditionTrue(
v1alpha1.ConditionTypeConfigured,
v1alpha1.ConditionReasonConfigured,
fmt.Sprintf("Configured with %s Publisher Proxy URL and %s Trace Collector URL.",
dependencyState(s.instance.Status.EventingEndpoint),
dependencyState(s.instance.Status.TracingEndpoint)),
"Configuration ready",
)
return nextState(sFnUpdateStatusAndRequeue)
}
Expand All @@ -49,47 +50,89 @@ func sFnOptionalDependencies(ctx context.Context, r *reconciler, s *systemState)
s.chartConfig.Release.Flags,
s.instance.Status.EventingEndpoint,
s.instance.Status.TracingEndpoint,
s.instance.Status.CPUUtilizationPercentage,
s.instance.Status.RequeueDuration,
s.instance.Status.BuildExecutorArgs,
s.instance.Status.BuildMaxSimultaneousJobs,
s.instance.Status.HealthzLivenessTimeout,
s.instance.Status.RequestBodyLimitMb,
s.instance.Status.TimeoutSec,
s.instance.Status.DefaultBuildJobPreset,
s.instance.Status.DefaultRuntimePodPreset,
)

return nextState(sFnApplyResources)
}

func configurationStatusIsNotReady(conditions []metav1.Condition) bool {
if !meta.IsStatusConditionPresentAndEqual(conditions, string(v1alpha1.ConditionTypeConfigured), metav1.ConditionTrue) {
return true
}
return false
}

func getTracingURL(ctx context.Context, log *zap.SugaredLogger, client client.Client, spec v1alpha1.ServerlessSpec) (string, error) {
if spec.Tracing != nil {
if spec.Tracing.Endpoint == "" {
return v1alpha1.FeatureDisabled, nil
}
return spec.Tracing.Endpoint, nil
}

tracingURL, err := tracing.GetTraceCollectorURL(ctx, client)
if err != nil {
return "", errors.Wrap(err, "while getting trace pipeline")
}
if tracingURL == "" {
return v1alpha1.FeatureDisabled, nil
}
return tracingURL, nil
}

func getEventingURL(spec v1alpha1.ServerlessSpec) string {
if spec.Eventing != nil {
if spec.Eventing.Endpoint == "" {
return v1alpha1.FeatureDisabled
}
return spec.Eventing.Endpoint
}
return v1alpha1.DefaultEventingEndpoint
}

// returns "custom" or "no" based on args
func dependencyState(url string) string {
switch {
case url == "" || url == v1alpha1.FeatureDisabled:
return "no"
case url == v1alpha1.DefaultEventingEndpoint:
return "default"
default:
return "custom"
func updateStatus(instance *v1alpha1.Serverless, eventingURL, tracingURL string) (bool, string) {
spec := instance.Spec
status := instance.Status

hasChanged := false

fields := []struct {
specField string
statusField *string
cfgMsg string
}{
{spec.TargetCPUUtilizationPercentage, &status.CPUUtilizationPercentage, "CPU utilization: %s"},
{spec.FunctionRequeueDuration, &status.RequeueDuration, "function requeue duration: %s"},
{spec.FunctionBuildExecutorArgs, &status.BuildExecutorArgs, "function build executor args: %s"},
{spec.FunctionBuildMaxSimultaneousJobs, &status.BuildMaxSimultaneousJobs, "max number of simultaneous jobs: %s"},
{spec.HealthzLivenessTimeout, &status.HealthzLivenessTimeout, "duration of health check: %s"},
{spec.FunctionRequestBodyLimitMb, &status.RequestBodyLimitMb, "max size of request body: %s"},
{spec.FunctionTimeoutSec, &status.TimeoutSec, "timeout: %s"},
{spec.DefaultBuildJobPreset, &status.DefaultBuildJobPreset, "default build job preset: %s"},
{spec.DefaultRuntimePodPreset, &status.DefaultRuntimePodPreset, "default runtime pod preset: %s"},
{eventingURL, &status.EventingEndpoint, "eventing endpoint: %s"},
{tracingURL, &status.TracingEndpoint, "tracing endpoint: %s"},
}

sb := strings.Builder{}
sb.WriteString("Serverless configuration changes: ")
separator := false

for _, field := range fields {
if field.specField != *field.statusField {
if separator {
sb.WriteString(", ")
}
*field.statusField = field.specField
sb.WriteString(fmt.Sprintf(field.cfgMsg, field.specField))
separator = true
hasChanged = true
}
}
if !hasChanged {
sb.WriteString("no changes")
}
instance.Status = status

return hasChanged, sb.String()
}
Loading

0 comments on commit ae1a9af

Please sign in to comment.