Add Ingress host, path and annotations support (#1325)
For each ingress controller, the format of ingress host,
path and annotations are different. To support different
kinds of controller, this PR adds new ingress config field
to http trigger spec. A user can set annotations, host and
path based on the type of underlying ingress controller
with CLI.
Command example:
fission route create --name foo \
--url /foo/{bar} --function foofn --createingress \
--ingressannotation "nginx.ingress.kubernetes.io/ssl-redirect=false" \
--ingressannotation "nginx.ingress.kubernetes.io/use-regex=true" \
--ingressrule "*=/foo/*"
This commit is contained in:
+43
-70
@@ -18,16 +18,15 @@ package router
|
||||
|
||||
import (
|
||||
"os"
|
||||
"reflect"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"k8s.io/api/extensions/v1beta1"
|
||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
|
||||
fv1 "github.com/fission/fission/pkg/apis/fission.io/v1"
|
||||
"github.com/fission/fission/pkg/router/util"
|
||||
)
|
||||
|
||||
var podNamespace string
|
||||
@@ -43,61 +42,14 @@ func createIngress(logger *zap.Logger, trigger *fv1.HTTPTrigger, kubeClient *kub
|
||||
if !trigger.Spec.CreateIngress {
|
||||
return
|
||||
}
|
||||
_, err := kubeClient.ExtensionsV1beta1().Ingresses(podNamespace).Get(trigger.Metadata.Name, v1.GetOptions{})
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
ing := &v1beta1.Ingress{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: getDeployLabels(trigger),
|
||||
Name: trigger.Metadata.Name,
|
||||
// The Ingress NS MUST be same as Router NS, check long discussion:
|
||||
// https://github.com/kubernetes/kubernetes/issues/17088
|
||||
// We need to revisit this in future, once Kubernetes supports cross namespace ingress
|
||||
Namespace: podNamespace,
|
||||
},
|
||||
Spec: v1beta1.IngressSpec{
|
||||
Rules: []v1beta1.IngressRule{
|
||||
{
|
||||
Host: trigger.Spec.Host,
|
||||
IngressRuleValue: v1beta1.IngressRuleValue{
|
||||
HTTP: &v1beta1.HTTPIngressRuleValue{
|
||||
Paths: []v1beta1.HTTPIngressPath{
|
||||
{
|
||||
Backend: v1beta1.IngressBackend{
|
||||
ServiceName: "router",
|
||||
ServicePort: intstr.IntOrString{
|
||||
Type: intstr.Int,
|
||||
IntVal: 80,
|
||||
},
|
||||
},
|
||||
Path: trigger.Spec.RelativeURL,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
_, err = kubeClient.ExtensionsV1beta1().Ingresses(podNamespace).Create(ing)
|
||||
if err != nil {
|
||||
_, err := kubeClient.ExtensionsV1beta1().Ingresses(podNamespace).Create(util.GetIngressSpec(podNamespace, trigger))
|
||||
if err != nil && !k8serrors.IsAlreadyExists(err) {
|
||||
logger.Error("failed to create ingress", zap.Error(err))
|
||||
return
|
||||
}
|
||||
logger.Debug("created ingress successfully for trigger", zap.String("trigger", trigger.Metadata.Name))
|
||||
}
|
||||
|
||||
func getDeployLabels(trigger *fv1.HTTPTrigger) map[string]string {
|
||||
return map[string]string{
|
||||
"triggerName": trigger.Metadata.Name,
|
||||
"functionName": trigger.Spec.FunctionReference.Name,
|
||||
"triggerNamespace": trigger.Metadata.Namespace,
|
||||
}
|
||||
}
|
||||
|
||||
func deleteIngress(logger *zap.Logger, trigger *fv1.HTTPTrigger, kubeClient *kubernetes.Clientset) {
|
||||
if !trigger.Spec.CreateIngress {
|
||||
return
|
||||
@@ -130,25 +82,46 @@ func updateIngress(logger *zap.Logger, oldT *fv1.HTTPTrigger, newT *fv1.HTTPTrig
|
||||
return
|
||||
}
|
||||
|
||||
if newT.Spec.Host != oldT.Spec.Host || newT.Spec.RelativeURL != oldT.Spec.RelativeURL {
|
||||
ingress, err := kubeClient.ExtensionsV1beta1().Ingresses(podNamespace).Get(oldT.Metadata.Name, v1.GetOptions{})
|
||||
oldIngress, err := kubeClient.ExtensionsV1beta1().Ingresses(podNamespace).Get(oldT.Metadata.Name, v1.GetOptions{})
|
||||
if err != nil {
|
||||
if k8serrors.IsNotFound(err) {
|
||||
createIngress(logger, newT, kubeClient)
|
||||
}
|
||||
logger.Error("failed to get ingress when updating trigger",
|
||||
zap.Error(err),
|
||||
zap.String("trigger", oldT.Metadata.Name))
|
||||
return
|
||||
}
|
||||
newIngress := util.GetIngressSpec(podNamespace, newT)
|
||||
|
||||
changes := false
|
||||
|
||||
if !reflect.DeepEqual(oldIngress.Annotations, newIngress.Annotations) {
|
||||
logger.Debug("ingress annotation",
|
||||
zap.Any("old_trigger", oldIngress.Annotations), zap.Any("new_trigger", newIngress.Annotations))
|
||||
|
||||
if oldIngress.Annotations == nil || newIngress.Annotations == nil {
|
||||
oldIngress.Annotations = newIngress.Annotations
|
||||
} else {
|
||||
for k, v := range newIngress.Annotations {
|
||||
oldIngress.Annotations[k] = v
|
||||
}
|
||||
}
|
||||
changes = true
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(oldIngress.Spec, newIngress.Spec) {
|
||||
logger.Debug("ingress spec",
|
||||
zap.Any("old_trigger", oldIngress.Spec), zap.Any("new_trigger", newIngress.Spec))
|
||||
|
||||
oldIngress.Spec = newIngress.Spec
|
||||
changes = true
|
||||
}
|
||||
|
||||
if changes {
|
||||
_, err = kubeClient.ExtensionsV1beta1().Ingresses(podNamespace).Update(oldIngress)
|
||||
if err != nil {
|
||||
logger.Error("failed to get ingress when updating trigger",
|
||||
zap.Error(err),
|
||||
zap.String("trigger", oldT.Metadata.Name))
|
||||
}
|
||||
|
||||
if newT.Spec.Host != oldT.Spec.Host {
|
||||
ingress.Spec.Rules[0].Host = newT.Spec.Host
|
||||
}
|
||||
|
||||
if newT.Spec.RelativeURL != oldT.Spec.RelativeURL {
|
||||
ingress.Spec.Rules[0].HTTP.Paths[0].Path = newT.Spec.RelativeURL
|
||||
}
|
||||
|
||||
_, err = kubeClient.ExtensionsV1beta1().Ingresses(podNamespace).Update(ingress)
|
||||
if err != nil {
|
||||
logger.Error("failed to update ingress for trigger", zap.String("trigger", oldT.Metadata.Name))
|
||||
logger.Error("failed to update ingress for trigger", zap.Error(err), zap.String("trigger", oldT.Metadata.Name))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user