Skip to content

Commit

Permalink
Enable safe handling of range limits for replicas
Browse files Browse the repository at this point in the history
Correct drift within limits available for community (hobbyist)
users.

Signed-off-by: Alex Ellis (OpenFaaS Ltd) <[email protected]>
  • Loading branch information
alexellis committed Mar 14, 2023
1 parent 9874b8a commit 8cbe374
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ RUN GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build \
--ldflags "-s -w \
-X github.com/openfaas/faas-netes/version.GitCommit=${GIT_COMMIT}\
-X github.com/openfaas/faas-netes/version.Version=${VERSION}" \
-a -installsuffix cgo -o faas-netes .
-o faas-netes .

FROM --platform=${TARGETPLATFORM:-linux/amd64} alpine:3.17 as ship
LABEL org.label-schema.license="MIT" \
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ ${CODEGEN_PKG}: $(TOOLS_DIR)/code-generator.mod
@cd $(TOOLS_DIR) && go mod download -modfile=code-generator.mod

local:
CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o faas-netes
CGO_ENABLED=0 GOOS=linux go build -o faas-netes

build-docker:
docker build \
Expand Down
2 changes: 2 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
informers "github.com/openfaas/faas-netes/pkg/client/informers/externalversions"
v1 "github.com/openfaas/faas-netes/pkg/client/informers/externalversions/openfaas/v1"
"github.com/openfaas/faas-netes/pkg/config"
"github.com/openfaas/faas-netes/pkg/controller"
"github.com/openfaas/faas-netes/pkg/handlers"
"github.com/openfaas/faas-netes/pkg/k8s"
"github.com/openfaas/faas-netes/pkg/signals"
Expand Down Expand Up @@ -197,6 +198,7 @@ func runController(setup serverSetup) {
stopCh := signals.SetupSignalHandler()
operator := false
listers := startInformers(setup, stopCh, operator)
controller.RegisterEventHandlers(listers.DeploymentInformer, kubeClient, config.DefaultFunctionNamespace)

functionLookup := k8s.NewFunctionLookup(config.DefaultFunctionNamespace, listers.EndpointsInformer.Lister())

Expand Down
1 change: 1 addition & 0 deletions pkg/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@ func (c *Controller) handleObject(obj interface{}) {
}
glog.V(4).Infof("Recovered deleted object '%s' from tombstone", object.GetName())
}

glog.V(4).Infof("Processing object: %s", object.GetName())
if ownerRef := metav1.GetControllerOf(object); ownerRef != nil {
// If this object is not owned by a function, we should not do anything more
Expand Down
85 changes: 85 additions & 0 deletions pkg/controller/informers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package controller

import (
"context"
"fmt"

"github.com/openfaas/faas-netes/pkg/handlers"
appsv1 "k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
v1apps "k8s.io/client-go/informers/apps/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"
"k8s.io/klog"
)

func RegisterEventHandlers(deploymentInformer v1apps.DeploymentInformer, kubeClient *kubernetes.Clientset, namespace string) {
deploymentInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
deployment, ok := obj.(*appsv1.Deployment)
if !ok || deployment == nil {
return
}
if err := applyValidation(deployment, kubeClient); err != nil {
klog.Info(err)
}
},
UpdateFunc: func(oldObj, newObj interface{}) {
deployment, ok := newObj.(*appsv1.Deployment)
if !ok || deployment == nil {
return
}
if err := applyValidation(deployment, kubeClient); err != nil {
klog.Info(err)
}
},
})

list, err := deploymentInformer.Lister().Deployments(namespace).List(labels.Everything())
if err != nil {
klog.Info(err)
return
}

for _, deployment := range list {
if err := applyValidation(deployment, kubeClient); err != nil {
klog.Info(err)
}
}
}

func applyValidation(deployment *appsv1.Deployment, kubeClient *kubernetes.Clientset) error {
if deployment.Spec.Replicas == nil {
return nil
}

if _, ok := deployment.Spec.Template.Labels["faas_function"]; !ok {
return nil
}

current := *deployment.Spec.Replicas
var target int
if current == 0 {
target = 1
} else if current > handlers.MaxReplicas {
target = handlers.MaxReplicas
} else {
return nil
}
clone := deployment.DeepCopy()

value := int32(target)
clone.Spec.Replicas = &value

if _, err := kubeClient.AppsV1().Deployments(deployment.Namespace).
Update(context.Background(), clone, metav1.UpdateOptions{}); err != nil {
if errors.IsConflict(err) {
return nil
}
return fmt.Errorf("error scaling %s to %d replicas: %w", deployment.Name, value, err)
}

return nil
}

0 comments on commit 8cbe374

Please sign in to comment.