Skip to content
This repository has been archived by the owner on Apr 18, 2024. It is now read-only.

Commit

Permalink
Merge pull request #33 from flanksource/add-annotate-ingress-controller
Browse files Browse the repository at this point in the history
Add annotate ingress controller
  • Loading branch information
moshloop committed Aug 12, 2020
2 parents 05dc462 + 71cf029 commit 12fb8ec
Show file tree
Hide file tree
Showing 11 changed files with 392 additions and 2 deletions.
16 changes: 16 additions & 0 deletions cmd/manager/main.go
Expand Up @@ -28,6 +28,7 @@ import (
platformv1 "github.com/flanksource/platform-operator/pkg/apis/platform/v1"
"github.com/flanksource/platform-operator/pkg/controllers/cleanup"
"github.com/flanksource/platform-operator/pkg/controllers/clusterresourcequota"
"github.com/flanksource/platform-operator/pkg/controllers/ingress"
"github.com/flanksource/platform-operator/pkg/controllers/podannotator"
"k8s.io/apimachinery/pkg/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
Expand Down Expand Up @@ -57,6 +58,9 @@ func main() {
var cleanupInterval, annotationInterval time.Duration
var annotations string
var enableClusterResourceQuota bool
var oauth2ProxySvcName string
var oauth2ProxySvcNamespace string
var domain string

flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")

Expand All @@ -69,6 +73,10 @@ func main() {
flag.StringVar(&annotations, "annotations", "", "Annotations pods inherit from parent namespace")
flag.BoolVar(&enableClusterResourceQuota, "enable-cluster-resource-quota", true, "Enable/Disable cluster resource quota")

flag.StringVar(&oauth2ProxySvcName, "oauth2-proxy-service-name", "", "Name of oauth2-proxy service")
flag.StringVar(&oauth2ProxySvcNamespace, "oauth2-proxy-service-namespace", "", "Name of oauth2-proxy service namespace")
flag.StringVar(&domain, "domain", "", "Domain used by platform")

flag.Parse()

ctrl.SetLogger(zap.New(func(o *zap.Options) {
Expand Down Expand Up @@ -105,6 +113,13 @@ func main() {
os.Exit(1)
}

if oauth2ProxySvcName != "" && oauth2ProxySvcNamespace != "" {
if err := ingress.Add(mgr, annotationInterval, oauth2ProxySvcName, oauth2ProxySvcNamespace, domain); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "IngressAnnotator")
os.Exit(1)
}
}

// Setup webhooks
setupLog.Info("setting up webhook server")
hookServer := mgr.GetWebhookServer()
Expand All @@ -113,6 +128,7 @@ func main() {

setupLog.Info("registering webhooks to the webhook server")
hookServer.Register("/mutate-v1-pod", &webhook.Admission{Handler: platformv1.PodAnnotatorMutateWebhook(mgr.GetClient(), strings.Split(annotations, ","))})
hookServer.Register("/mutate-v1-ingress", &webhook.Admission{Handler: platformv1.IngressAnnotatorMutateWebhook(mgr.GetClient(), oauth2ProxySvcName, oauth2ProxySvcNamespace, domain)})
hookServer.Register("/validate-clusterresourcequota-platform-flanksource-com-v1", platformv1.ClusterResourceQuotaValidatingWebhook(mtx, enableClusterResourceQuota))
hookServer.Register("/validate-resourcequota-v1", platformv1.ResourceQuotaValidatingWebhook(mtx, enableClusterResourceQuota))

Expand Down
37 changes: 36 additions & 1 deletion config/deploy/manifests.yaml
Expand Up @@ -175,6 +175,24 @@ metadata:
name: platform-mutating-webhook-configuration
namespace: platform-system
webhooks:
- clientConfig:
caBundle: Cg==
service:
name: platform-webhook-service
namespace: platform-system
path: /mutate-v1-ingress
failurePolicy: Ignore
name: annotate-ingress-v1.platform.flanksource.com
rules:
- apiGroups:
- extensions
apiVersions:
- v1beta1
operations:
- CREATE
- UPDATE
resources:
- ingresses
- clientConfig:
caBundle: Cg==
service:
Expand Down Expand Up @@ -357,6 +375,23 @@ rules:
- get
- list
- watch
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- extensions
resources:
- ingresses
verbs:
- get
- list
- update
- watch
- apiGroups:
- platform.flanksource.com
resources:
Expand Down Expand Up @@ -440,7 +475,7 @@ spec:
- --annotations=foo.flanksource.com/bar,foo.flanksource.com/baz
command:
- /manager
image: quay.io/toni0/platform-operator:add-pods-annotations
image: docker.io/flanksource/platform-operator:latest
imagePullPolicy: Always
name: manager
ports:
Expand Down
2 changes: 1 addition & 1 deletion config/operator/manager/manager.yaml
Expand Up @@ -29,7 +29,7 @@ spec:
args:
- --enable-leader-election
- --annotations=foo.flanksource.com/bar,foo.flanksource.com/baz
image: quay.io/toni0/platform-operator:add-pods-annotations
image: "docker.io/flanksource/platform-operator:latest"
imagePullPolicy: Always
name: manager
resources:
Expand Down
17 changes: 17 additions & 0 deletions config/operator/rbac/role.yaml
Expand Up @@ -32,6 +32,23 @@ rules:
- get
- list
- watch
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- extensions
resources:
- ingresses
verbs:
- get
- list
- update
- watch
- apiGroups:
- platform.flanksource.com
resources:
Expand Down
18 changes: 18 additions & 0 deletions config/operator/webhook/manifests.yaml
Expand Up @@ -6,6 +6,24 @@ metadata:
creationTimestamp: null
name: mutating-webhook-configuration
webhooks:
- clientConfig:
caBundle: Cg==
service:
name: webhook-service
namespace: system
path: /mutate-v1-ingress
failurePolicy: Ignore
name: annotate-ingress-v1.platform.flanksource.com
rules:
- apiGroups:
- extensions
apiVersions:
- v1beta1
operations:
- CREATE
- UPDATE
resources:
- ingresses
- clientConfig:
caBundle: Cg==
service:
Expand Down
1 change: 1 addition & 0 deletions go.mod
Expand Up @@ -41,4 +41,5 @@ replace (
k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.17.0
k8s.io/metrics => k8s.io/metrics v0.17.0
k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.17.0
vbom.ml/util => github.com/fvbommel/util v0.0.0-20180919145318-efcd4e0f9787
)
1 change: 1 addition & 0 deletions go.sum
Expand Up @@ -149,6 +149,7 @@ github.com/flanksource/yaml v0.0.0-20200322131016-b7b2608b8702/go.mod h1:9oTOzfy
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fvbommel/util v0.0.0-20180919145318-efcd4e0f9787/go.mod h1:AlRx4sdoz6EdWGYPMeunQWYf46cKnq7J4iVvLgyb5cY=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
Expand Down
73 changes: 73 additions & 0 deletions pkg/apis/platform/v1/ingress_annotator_mutewebhook.go
@@ -0,0 +1,73 @@
package v1

import (
"context"
"encoding/json"
"net/http"

utilsk8s "github.com/flanksource/platform-operator/pkg/controllers/utils/k8s"
"k8s.io/api/extensions/v1beta1"
"sigs.k8s.io/controller-runtime/pkg/client"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
)

var ilog = logf.Log.WithName("ingress-annotator")

func IngressAnnotatorMutateWebhook(client client.Client, svcName, svcNamespace, domain string) *admission.Webhook {
return &admission.Webhook{
Handler: NewIngressAnnotatorHandler(client, svcName, svcNamespace, domain),
}
}

type ingressAnnotatorHandler struct {
Client client.Client
decoder *admission.Decoder
ingressAnnotator *utilsk8s.IngressAnnotator
ingressAnnotatorEnabled bool
}

// +kubebuilder:webhook:path=/mutate-v1-ingress,mutating=true,failurePolicy=ignore,groups="extensions",resources=ingresses,verbs=create;update,versions=v1beta1,name=annotate-ingress-v1.platform.flanksource.com

func NewIngressAnnotatorHandler(client client.Client, svcName, svcNamespace, domain string) *ingressAnnotatorHandler {
var ingressAnnotator *utilsk8s.IngressAnnotator = nil
var ingressAnnotatorEnabled = false

if svcName != "" && svcNamespace != "" {
ingressAnnotator = utilsk8s.NewIngressAnnotator(client, svcName, svcNamespace, domain)
ingressAnnotatorEnabled = true
}

return &ingressAnnotatorHandler{Client: client, ingressAnnotator: ingressAnnotator, ingressAnnotatorEnabled: ingressAnnotatorEnabled}
}

func (a *ingressAnnotatorHandler) Handle(ctx context.Context, req admission.Request) admission.Response {
ingress := &v1beta1.Ingress{}
err := a.decoder.Decode(req, ingress)
if err != nil {
return admission.Errored(http.StatusBadRequest, err)
}

if !a.ingressAnnotatorEnabled {
ilog.Info("ingress annotator is not enabled. All requests will be declared valid")
return admission.Allowed("")
}

newIngress, changed, err := a.ingressAnnotator.Annotate(ctx, ingress)
if err != nil {
return admission.Errored(http.StatusInternalServerError, err)
} else if !changed {
return admission.Allowed("not changed")
}

marshaledIngress, err := json.Marshal(newIngress)
if err != nil {
return admission.Errored(http.StatusInternalServerError, err)
}
return admission.PatchResponseFromRaw(req.Object.Raw, marshaledIngress)
}

func (a *ingressAnnotatorHandler) InjectDecoder(d *admission.Decoder) error {
a.decoder = d
return nil
}
38 changes: 38 additions & 0 deletions pkg/controllers/ingress/ingress_annotator_controller.go
@@ -0,0 +1,38 @@
package ingress

import (
"time"

"github.com/pkg/errors"

"sigs.k8s.io/controller-runtime/pkg/event"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
)

const (
name = "ingress-annotator-controller"
)

var log = logf.Log.WithName(name)

func Add(mgr manager.Manager, interval time.Duration, svcName, svcNamespace, domain string) error {
if err := addIngressReconciler(mgr, newIngressReconciler(mgr, svcName, svcNamespace, domain)); err != nil {
return errors.Wrap(err, "failed to add ingress reconciler")
}

return nil
}

var _ reconcile.Reconciler = &IngressReconciler{}

// these functions are passed to the predicate
// objects are queued only in case the label exists
func onCreate(e event.CreateEvent) bool {
return true
}

func onUpdate(e event.UpdateEvent) bool {
return true
}
93 changes: 93 additions & 0 deletions pkg/controllers/ingress/ingress_reconciler.go
@@ -0,0 +1,93 @@
/*
Copyright 2020 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package ingress

import (
"context"

utilsk8s "github.com/flanksource/platform-operator/pkg/controllers/utils/k8s"
"k8s.io/api/extensions/v1beta1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/predicate"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"sigs.k8s.io/controller-runtime/pkg/source"
)

type IngressReconciler struct {
client.Client
Scheme *runtime.Scheme

ingressAnnotator *utilsk8s.IngressAnnotator
}

func newIngressReconciler(mgr manager.Manager, svcName, svcNamespace, domain string) reconcile.Reconciler {
client := mgr.GetClient()
ingressAnnotator := utilsk8s.NewIngressAnnotator(client, svcName, svcNamespace, domain)

return &IngressReconciler{
Client: client,
Scheme: mgr.GetScheme(),
ingressAnnotator: ingressAnnotator,
}
}

func addIngressReconciler(mgr manager.Manager, r reconcile.Reconciler) error {
c, err := controller.New(name, mgr, controller.Options{Reconciler: r})
if err != nil {
return err
}

if err := c.Watch(
&source.Kind{Type: &v1beta1.Ingress{}}, &handler.EnqueueRequestForObject{},
predicate.Funcs{CreateFunc: onCreate, UpdateFunc: onUpdate},
); err != nil {
return err
}

return nil
}

// +kubebuilder:rbac:groups="extensions",resources=ingresses,verbs=get;list;update;watch

func (r *IngressReconciler) Reconcile(request reconcile.Request) (reconcile.Result, error) {
ctx := context.Background()

ingress := &v1beta1.Ingress{}
if err := r.Get(ctx, request.NamespacedName, ingress); err != nil {
if errors.IsNotFound(err) {
return reconcile.Result{}, nil
}
return reconcile.Result{}, err
}

updatedIngress, changed, err := r.ingressAnnotator.Annotate(ctx, ingress)
if err != nil || !changed {
return reconcile.Result{}, err
}

if err := r.Client.Update(ctx, updatedIngress); err != nil {
log.Error(err, "failed to update", "ingress", updatedIngress.Name, "namespace", updatedIngress.Namespace)
return reconcile.Result{}, err
}

return reconcile.Result{}, nil
}

0 comments on commit 12fb8ec

Please sign in to comment.