Custom resource definition
Co-authored-by: Mathieu Lonjaret <mathieu.lonjaret@gmail.com>
This commit is contained in:
parent
cfaf47c8a2
commit
4c060a78cc
1348 changed files with 92364 additions and 55766 deletions
|
@ -41,6 +41,10 @@ func NewProviderAggregator(conf static.Providers) ProviderAggregator {
|
|||
p.quietAddProvider(conf.Kubernetes)
|
||||
}
|
||||
|
||||
if conf.KubernetesCRD != nil {
|
||||
p.quietAddProvider(conf.KubernetesCRD)
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
|
|
|
@ -1,158 +0,0 @@
|
|||
package kubernetes
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
func buildEndpoint(opts ...func(*corev1.Endpoints)) *corev1.Endpoints {
|
||||
e := &corev1.Endpoints{}
|
||||
for _, opt := range opts {
|
||||
opt(e)
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
func eNamespace(value string) func(*corev1.Endpoints) {
|
||||
return func(i *corev1.Endpoints) {
|
||||
i.Namespace = value
|
||||
}
|
||||
}
|
||||
|
||||
func eName(value string) func(*corev1.Endpoints) {
|
||||
return func(i *corev1.Endpoints) {
|
||||
i.Name = value
|
||||
}
|
||||
}
|
||||
|
||||
func eUID(value types.UID) func(*corev1.Endpoints) {
|
||||
return func(i *corev1.Endpoints) {
|
||||
i.UID = value
|
||||
}
|
||||
}
|
||||
|
||||
func subset(opts ...func(*corev1.EndpointSubset)) func(*corev1.Endpoints) {
|
||||
return func(e *corev1.Endpoints) {
|
||||
s := &corev1.EndpointSubset{}
|
||||
for _, opt := range opts {
|
||||
opt(s)
|
||||
}
|
||||
e.Subsets = append(e.Subsets, *s)
|
||||
}
|
||||
}
|
||||
|
||||
func eAddresses(opts ...func(*corev1.EndpointAddress)) func(*corev1.EndpointSubset) {
|
||||
return func(subset *corev1.EndpointSubset) {
|
||||
for _, opt := range opts {
|
||||
a := &corev1.EndpointAddress{}
|
||||
opt(a)
|
||||
subset.Addresses = append(subset.Addresses, *a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func eAddress(ip string) func(*corev1.EndpointAddress) {
|
||||
return func(address *corev1.EndpointAddress) {
|
||||
address.IP = ip
|
||||
}
|
||||
}
|
||||
|
||||
func eAddressWithTargetRef(targetRef, ip string) func(*corev1.EndpointAddress) {
|
||||
return func(address *corev1.EndpointAddress) {
|
||||
address.TargetRef = &corev1.ObjectReference{Name: targetRef}
|
||||
address.IP = ip
|
||||
}
|
||||
}
|
||||
|
||||
func ePorts(opts ...func(port *corev1.EndpointPort)) func(*corev1.EndpointSubset) {
|
||||
return func(spec *corev1.EndpointSubset) {
|
||||
for _, opt := range opts {
|
||||
p := &corev1.EndpointPort{}
|
||||
opt(p)
|
||||
spec.Ports = append(spec.Ports, *p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ePort(port int32, name string) func(*corev1.EndpointPort) {
|
||||
return func(sp *corev1.EndpointPort) {
|
||||
sp.Port = port
|
||||
sp.Name = name
|
||||
}
|
||||
}
|
||||
|
||||
// Test
|
||||
|
||||
func TestBuildEndpoint(t *testing.T) {
|
||||
actual := buildEndpoint(
|
||||
eNamespace("testing"),
|
||||
eName("service3"),
|
||||
eUID("3"),
|
||||
subset(
|
||||
eAddresses(eAddress("10.15.0.1")),
|
||||
ePorts(
|
||||
ePort(8080, "http"),
|
||||
ePort(8443, "https"),
|
||||
),
|
||||
),
|
||||
subset(
|
||||
eAddresses(eAddress("10.15.0.2")),
|
||||
ePorts(
|
||||
ePort(9080, "http"),
|
||||
ePort(9443, "https"),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
assert.EqualValues(t, sampleEndpoint1(), actual)
|
||||
}
|
||||
|
||||
func sampleEndpoint1() *corev1.Endpoints {
|
||||
return &corev1.Endpoints{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "service3",
|
||||
UID: "3",
|
||||
Namespace: "testing",
|
||||
},
|
||||
Subsets: []corev1.EndpointSubset{
|
||||
{
|
||||
Addresses: []corev1.EndpointAddress{
|
||||
{
|
||||
IP: "10.15.0.1",
|
||||
},
|
||||
},
|
||||
Ports: []corev1.EndpointPort{
|
||||
{
|
||||
Name: "http",
|
||||
Port: 8080,
|
||||
},
|
||||
{
|
||||
Name: "https",
|
||||
Port: 8443,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Addresses: []corev1.EndpointAddress{
|
||||
{
|
||||
IP: "10.15.0.2",
|
||||
},
|
||||
},
|
||||
Ports: []corev1.EndpointPort{
|
||||
{
|
||||
Name: "http",
|
||||
Port: 9080,
|
||||
},
|
||||
{
|
||||
Name: "https",
|
||||
Port: 9443,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
|
@ -1,223 +0,0 @@
|
|||
package kubernetes
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
)
|
||||
|
||||
func buildIngress(opts ...func(*extensionsv1beta1.Ingress)) *extensionsv1beta1.Ingress {
|
||||
i := &extensionsv1beta1.Ingress{}
|
||||
for _, opt := range opts {
|
||||
opt(i)
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
func iNamespace(value string) func(*extensionsv1beta1.Ingress) {
|
||||
return func(i *extensionsv1beta1.Ingress) {
|
||||
i.Namespace = value
|
||||
}
|
||||
}
|
||||
|
||||
func iAnnotation(name string, value string) func(*extensionsv1beta1.Ingress) {
|
||||
return func(i *extensionsv1beta1.Ingress) {
|
||||
if i.Annotations == nil {
|
||||
i.Annotations = make(map[string]string)
|
||||
}
|
||||
i.Annotations[name] = value
|
||||
}
|
||||
}
|
||||
|
||||
func iRules(opts ...func(*extensionsv1beta1.IngressSpec)) func(*extensionsv1beta1.Ingress) {
|
||||
return func(i *extensionsv1beta1.Ingress) {
|
||||
s := &extensionsv1beta1.IngressSpec{}
|
||||
for _, opt := range opts {
|
||||
opt(s)
|
||||
}
|
||||
i.Spec = *s
|
||||
}
|
||||
}
|
||||
|
||||
func iSpecBackends(opts ...func(*extensionsv1beta1.IngressSpec)) func(*extensionsv1beta1.Ingress) {
|
||||
return func(i *extensionsv1beta1.Ingress) {
|
||||
s := &extensionsv1beta1.IngressSpec{}
|
||||
for _, opt := range opts {
|
||||
opt(s)
|
||||
}
|
||||
i.Spec = *s
|
||||
}
|
||||
}
|
||||
|
||||
func iSpecBackend(opts ...func(*extensionsv1beta1.IngressBackend)) func(*extensionsv1beta1.IngressSpec) {
|
||||
return func(s *extensionsv1beta1.IngressSpec) {
|
||||
p := &extensionsv1beta1.IngressBackend{}
|
||||
for _, opt := range opts {
|
||||
opt(p)
|
||||
}
|
||||
s.Backend = p
|
||||
}
|
||||
}
|
||||
|
||||
func iIngressBackend(name string, port intstr.IntOrString) func(*extensionsv1beta1.IngressBackend) {
|
||||
return func(p *extensionsv1beta1.IngressBackend) {
|
||||
p.ServiceName = name
|
||||
p.ServicePort = port
|
||||
}
|
||||
}
|
||||
|
||||
func iRule(opts ...func(*extensionsv1beta1.IngressRule)) func(*extensionsv1beta1.IngressSpec) {
|
||||
return func(spec *extensionsv1beta1.IngressSpec) {
|
||||
r := &extensionsv1beta1.IngressRule{}
|
||||
for _, opt := range opts {
|
||||
opt(r)
|
||||
}
|
||||
spec.Rules = append(spec.Rules, *r)
|
||||
}
|
||||
}
|
||||
|
||||
func iHost(name string) func(*extensionsv1beta1.IngressRule) {
|
||||
return func(rule *extensionsv1beta1.IngressRule) {
|
||||
rule.Host = name
|
||||
}
|
||||
}
|
||||
|
||||
func iPaths(opts ...func(*extensionsv1beta1.HTTPIngressRuleValue)) func(*extensionsv1beta1.IngressRule) {
|
||||
return func(rule *extensionsv1beta1.IngressRule) {
|
||||
rule.HTTP = &extensionsv1beta1.HTTPIngressRuleValue{}
|
||||
for _, opt := range opts {
|
||||
opt(rule.HTTP)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func onePath(opts ...func(*extensionsv1beta1.HTTPIngressPath)) func(*extensionsv1beta1.HTTPIngressRuleValue) {
|
||||
return func(irv *extensionsv1beta1.HTTPIngressRuleValue) {
|
||||
p := &extensionsv1beta1.HTTPIngressPath{}
|
||||
for _, opt := range opts {
|
||||
opt(p)
|
||||
}
|
||||
irv.Paths = append(irv.Paths, *p)
|
||||
}
|
||||
}
|
||||
|
||||
func iPath(name string) func(*extensionsv1beta1.HTTPIngressPath) {
|
||||
return func(p *extensionsv1beta1.HTTPIngressPath) {
|
||||
p.Path = name
|
||||
}
|
||||
}
|
||||
|
||||
func iBackend(name string, port intstr.IntOrString) func(*extensionsv1beta1.HTTPIngressPath) {
|
||||
return func(p *extensionsv1beta1.HTTPIngressPath) {
|
||||
p.Backend = extensionsv1beta1.IngressBackend{
|
||||
ServiceName: name,
|
||||
ServicePort: port,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func iTLSes(opts ...func(*extensionsv1beta1.IngressTLS)) func(*extensionsv1beta1.Ingress) {
|
||||
return func(i *extensionsv1beta1.Ingress) {
|
||||
for _, opt := range opts {
|
||||
iTLS := extensionsv1beta1.IngressTLS{}
|
||||
opt(&iTLS)
|
||||
i.Spec.TLS = append(i.Spec.TLS, iTLS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func iTLS(secret string, hosts ...string) func(*extensionsv1beta1.IngressTLS) {
|
||||
return func(i *extensionsv1beta1.IngressTLS) {
|
||||
i.SecretName = secret
|
||||
i.Hosts = hosts
|
||||
}
|
||||
}
|
||||
|
||||
// Test
|
||||
|
||||
func TestBuildIngress(t *testing.T) {
|
||||
i := buildIngress(
|
||||
iNamespace("testing"),
|
||||
iRules(
|
||||
iRule(iHost("foo"), iPaths(
|
||||
onePath(iPath("/bar"), iBackend("service1", intstr.FromInt(80))),
|
||||
onePath(iPath("/namedthing"), iBackend("service4", intstr.FromString("https")))),
|
||||
),
|
||||
iRule(iHost("bar"), iPaths(
|
||||
onePath(iBackend("service3", intstr.FromString("https"))),
|
||||
onePath(iBackend("service2", intstr.FromInt(802))),
|
||||
),
|
||||
),
|
||||
),
|
||||
iTLSes(
|
||||
iTLS("tls-secret", "foo"),
|
||||
),
|
||||
)
|
||||
|
||||
assert.EqualValues(t, sampleIngress(), i)
|
||||
}
|
||||
|
||||
func sampleIngress() *extensionsv1beta1.Ingress {
|
||||
return &extensionsv1beta1.Ingress{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "testing",
|
||||
},
|
||||
Spec: extensionsv1beta1.IngressSpec{
|
||||
Rules: []extensionsv1beta1.IngressRule{
|
||||
{
|
||||
Host: "foo",
|
||||
IngressRuleValue: extensionsv1beta1.IngressRuleValue{
|
||||
HTTP: &extensionsv1beta1.HTTPIngressRuleValue{
|
||||
Paths: []extensionsv1beta1.HTTPIngressPath{
|
||||
{
|
||||
Path: "/bar",
|
||||
Backend: extensionsv1beta1.IngressBackend{
|
||||
ServiceName: "service1",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "/namedthing",
|
||||
Backend: extensionsv1beta1.IngressBackend{
|
||||
ServiceName: "service4",
|
||||
ServicePort: intstr.FromString("https"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Host: "bar",
|
||||
IngressRuleValue: extensionsv1beta1.IngressRuleValue{
|
||||
HTTP: &extensionsv1beta1.HTTPIngressRuleValue{
|
||||
Paths: []extensionsv1beta1.HTTPIngressPath{
|
||||
{
|
||||
Backend: extensionsv1beta1.IngressBackend{
|
||||
ServiceName: "service3",
|
||||
ServicePort: intstr.FromString("https"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Backend: extensionsv1beta1.IngressBackend{
|
||||
ServiceName: "service2",
|
||||
ServicePort: intstr.FromInt(802),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
TLS: []extensionsv1beta1.IngressTLS{
|
||||
{
|
||||
Hosts: []string{"foo"},
|
||||
SecretName: "tls-secret",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
|
@ -1,232 +0,0 @@
|
|||
package kubernetes
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
func buildService(opts ...func(*corev1.Service)) *corev1.Service {
|
||||
s := &corev1.Service{}
|
||||
for _, opt := range opts {
|
||||
opt(s)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func sNamespace(value string) func(*corev1.Service) {
|
||||
return func(i *corev1.Service) {
|
||||
i.Namespace = value
|
||||
}
|
||||
}
|
||||
|
||||
func sName(value string) func(*corev1.Service) {
|
||||
return func(i *corev1.Service) {
|
||||
i.Name = value
|
||||
}
|
||||
}
|
||||
|
||||
func sUID(value types.UID) func(*corev1.Service) {
|
||||
return func(i *corev1.Service) {
|
||||
i.UID = value
|
||||
}
|
||||
}
|
||||
|
||||
func sAnnotation(name string, value string) func(*corev1.Service) {
|
||||
return func(s *corev1.Service) {
|
||||
if s.Annotations == nil {
|
||||
s.Annotations = make(map[string]string)
|
||||
}
|
||||
s.Annotations[name] = value
|
||||
}
|
||||
}
|
||||
|
||||
func sSpec(opts ...func(*corev1.ServiceSpec)) func(*corev1.Service) {
|
||||
return func(s *corev1.Service) {
|
||||
spec := &corev1.ServiceSpec{}
|
||||
for _, opt := range opts {
|
||||
opt(spec)
|
||||
}
|
||||
s.Spec = *spec
|
||||
}
|
||||
}
|
||||
|
||||
func sLoadBalancerStatus(opts ...func(*corev1.LoadBalancerStatus)) func(service *corev1.Service) {
|
||||
return func(s *corev1.Service) {
|
||||
loadBalancer := &corev1.LoadBalancerStatus{}
|
||||
for _, opt := range opts {
|
||||
if opt != nil {
|
||||
opt(loadBalancer)
|
||||
}
|
||||
}
|
||||
s.Status = corev1.ServiceStatus{
|
||||
LoadBalancer: *loadBalancer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func sLoadBalancerIngress(ip string, hostname string) func(*corev1.LoadBalancerStatus) {
|
||||
return func(status *corev1.LoadBalancerStatus) {
|
||||
ingress := corev1.LoadBalancerIngress{
|
||||
IP: ip,
|
||||
Hostname: hostname,
|
||||
}
|
||||
status.Ingress = append(status.Ingress, ingress)
|
||||
}
|
||||
}
|
||||
|
||||
func clusterIP(ip string) func(*corev1.ServiceSpec) {
|
||||
return func(spec *corev1.ServiceSpec) {
|
||||
spec.ClusterIP = ip
|
||||
}
|
||||
}
|
||||
|
||||
func sType(value corev1.ServiceType) func(*corev1.ServiceSpec) {
|
||||
return func(spec *corev1.ServiceSpec) {
|
||||
spec.Type = value
|
||||
}
|
||||
}
|
||||
|
||||
func sExternalName(name string) func(*corev1.ServiceSpec) {
|
||||
return func(spec *corev1.ServiceSpec) {
|
||||
spec.ExternalName = name
|
||||
}
|
||||
}
|
||||
|
||||
func sPorts(opts ...func(*corev1.ServicePort)) func(*corev1.ServiceSpec) {
|
||||
return func(spec *corev1.ServiceSpec) {
|
||||
for _, opt := range opts {
|
||||
p := &corev1.ServicePort{}
|
||||
opt(p)
|
||||
spec.Ports = append(spec.Ports, *p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func sPort(port int32, name string) func(*corev1.ServicePort) {
|
||||
return func(sp *corev1.ServicePort) {
|
||||
sp.Port = port
|
||||
sp.Name = name
|
||||
}
|
||||
}
|
||||
|
||||
// Test
|
||||
|
||||
func TestBuildService(t *testing.T) {
|
||||
actual1 := buildService(
|
||||
sName("service1"),
|
||||
sNamespace("testing"),
|
||||
sUID("1"),
|
||||
sSpec(
|
||||
clusterIP("10.0.0.1"),
|
||||
sPorts(sPort(80, "")),
|
||||
),
|
||||
)
|
||||
|
||||
assert.EqualValues(t, sampleService1(), actual1)
|
||||
|
||||
actual2 := buildService(
|
||||
sName("service2"),
|
||||
sNamespace("testing"),
|
||||
sUID("2"),
|
||||
sSpec(
|
||||
clusterIP("10.0.0.2"),
|
||||
sType("ExternalName"),
|
||||
sExternalName("example.com"),
|
||||
sPorts(
|
||||
sPort(80, "http"),
|
||||
sPort(443, "https"),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
assert.EqualValues(t, sampleService2(), actual2)
|
||||
|
||||
actual3 := buildService(
|
||||
sName("service3"),
|
||||
sNamespace("testing"),
|
||||
sUID("3"),
|
||||
sSpec(
|
||||
clusterIP("10.0.0.3"),
|
||||
sType("ExternalName"),
|
||||
sExternalName("example.com"),
|
||||
sPorts(
|
||||
sPort(8080, "http"),
|
||||
sPort(8443, "https"),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
assert.EqualValues(t, sampleService3(), actual3)
|
||||
}
|
||||
|
||||
func sampleService1() *corev1.Service {
|
||||
return &corev1.Service{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "service1",
|
||||
UID: "1",
|
||||
Namespace: "testing",
|
||||
},
|
||||
Spec: corev1.ServiceSpec{
|
||||
ClusterIP: "10.0.0.1",
|
||||
Ports: []corev1.ServicePort{
|
||||
{
|
||||
Port: 80,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func sampleService2() *corev1.Service {
|
||||
return &corev1.Service{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "service2",
|
||||
UID: "2",
|
||||
Namespace: "testing",
|
||||
},
|
||||
Spec: corev1.ServiceSpec{
|
||||
ClusterIP: "10.0.0.2",
|
||||
Type: "ExternalName",
|
||||
ExternalName: "example.com",
|
||||
Ports: []corev1.ServicePort{
|
||||
{
|
||||
Name: "http",
|
||||
Port: 80,
|
||||
},
|
||||
{
|
||||
Name: "https",
|
||||
Port: 443,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func sampleService3() *corev1.Service {
|
||||
return &corev1.Service{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "service3",
|
||||
UID: "3",
|
||||
Namespace: "testing",
|
||||
},
|
||||
Spec: corev1.ServiceSpec{
|
||||
ClusterIP: "10.0.0.3",
|
||||
Type: "ExternalName",
|
||||
ExternalName: "example.com",
|
||||
Ports: []corev1.ServicePort{
|
||||
{
|
||||
Name: "http",
|
||||
Port: 8080,
|
||||
},
|
||||
{
|
||||
Name: "https",
|
||||
Port: 8443,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
362
provider/kubernetes/crd/client.go
Normal file
362
provider/kubernetes/crd/client.go
Normal file
|
@ -0,0 +1,362 @@
|
|||
package crd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"time"
|
||||
|
||||
"github.com/containous/traefik/old/log"
|
||||
"github.com/containous/traefik/provider/kubernetes/crd/generated/clientset/versioned"
|
||||
"github.com/containous/traefik/provider/kubernetes/crd/generated/informers/externalversions"
|
||||
"github.com/containous/traefik/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
"github.com/containous/traefik/provider/kubernetes/k8s"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
|
||||
kubeerror "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/informers"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
)
|
||||
|
||||
const resyncPeriod = 10 * time.Minute
|
||||
|
||||
type resourceEventHandler struct {
|
||||
ev chan<- interface{}
|
||||
}
|
||||
|
||||
func (reh *resourceEventHandler) OnAdd(obj interface{}) {
|
||||
eventHandlerFunc(reh.ev, obj)
|
||||
}
|
||||
|
||||
func (reh *resourceEventHandler) OnUpdate(oldObj, newObj interface{}) {
|
||||
eventHandlerFunc(reh.ev, newObj)
|
||||
}
|
||||
|
||||
func (reh *resourceEventHandler) OnDelete(obj interface{}) {
|
||||
eventHandlerFunc(reh.ev, obj)
|
||||
}
|
||||
|
||||
// Client is a client for the Provider master.
|
||||
// WatchAll starts the watch of the Provider resources and updates the stores.
|
||||
// The stores can then be accessed via the Get* functions.
|
||||
type Client interface {
|
||||
WatchAll(namespaces k8s.Namespaces, stopCh <-chan struct{}) (<-chan interface{}, error)
|
||||
|
||||
GetIngressRoutes() []*v1alpha1.IngressRoute
|
||||
GetMiddlewares() []*v1alpha1.Middleware
|
||||
|
||||
GetIngresses() []*extensionsv1beta1.Ingress
|
||||
GetService(namespace, name string) (*corev1.Service, bool, error)
|
||||
GetSecret(namespace, name string) (*corev1.Secret, bool, error)
|
||||
GetEndpoints(namespace, name string) (*corev1.Endpoints, bool, error)
|
||||
UpdateIngressStatus(namespace, name, ip, hostname string) error
|
||||
}
|
||||
|
||||
// TODO: add tests for the clientWrapper (and its methods) itself.
|
||||
type clientWrapper struct {
|
||||
csCrd *versioned.Clientset
|
||||
csKube *kubernetes.Clientset
|
||||
|
||||
factoriesCrd map[string]externalversions.SharedInformerFactory
|
||||
factoriesKube map[string]informers.SharedInformerFactory
|
||||
|
||||
ingressLabelSelector labels.Selector
|
||||
|
||||
isNamespaceAll bool
|
||||
watchedNamespaces k8s.Namespaces
|
||||
}
|
||||
|
||||
func createClientFromConfig(c *rest.Config) (*clientWrapper, error) {
|
||||
csCrd, err := versioned.NewForConfig(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
csKube, err := kubernetes.NewForConfig(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newClientImpl(csKube, csCrd), nil
|
||||
}
|
||||
|
||||
func newClientImpl(csKube *kubernetes.Clientset, csCrd *versioned.Clientset) *clientWrapper {
|
||||
return &clientWrapper{
|
||||
csCrd: csCrd,
|
||||
csKube: csKube,
|
||||
factoriesCrd: make(map[string]externalversions.SharedInformerFactory),
|
||||
factoriesKube: make(map[string]informers.SharedInformerFactory),
|
||||
}
|
||||
}
|
||||
|
||||
// newInClusterClient returns a new Provider client that is expected to run
|
||||
// inside the cluster.
|
||||
func newInClusterClient(endpoint string) (*clientWrapper, error) {
|
||||
config, err := rest.InClusterConfig()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create in-cluster configuration: %s", err)
|
||||
}
|
||||
|
||||
if endpoint != "" {
|
||||
config.Host = endpoint
|
||||
}
|
||||
|
||||
return createClientFromConfig(config)
|
||||
}
|
||||
|
||||
func newExternalClusterClientFromFile(file string) (*clientWrapper, error) {
|
||||
configFromFlags, err := clientcmd.BuildConfigFromFlags("", file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return createClientFromConfig(configFromFlags)
|
||||
}
|
||||
|
||||
// newExternalClusterClient returns a new Provider client that may run outside
|
||||
// of the cluster.
|
||||
// The endpoint parameter must not be empty.
|
||||
func newExternalClusterClient(endpoint, token, caFilePath string) (*clientWrapper, error) {
|
||||
if endpoint == "" {
|
||||
return nil, errors.New("endpoint missing for external cluster client")
|
||||
}
|
||||
|
||||
config := &rest.Config{
|
||||
Host: endpoint,
|
||||
BearerToken: token,
|
||||
}
|
||||
|
||||
if caFilePath != "" {
|
||||
caData, err := ioutil.ReadFile(caFilePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read CA file %s: %s", caFilePath, err)
|
||||
}
|
||||
|
||||
config.TLSClientConfig = rest.TLSClientConfig{CAData: caData}
|
||||
}
|
||||
|
||||
return createClientFromConfig(config)
|
||||
}
|
||||
|
||||
// WatchAll starts namespace-specific controllers for all relevant kinds.
|
||||
func (c *clientWrapper) WatchAll(namespaces k8s.Namespaces, stopCh <-chan struct{}) (<-chan interface{}, error) {
|
||||
eventCh := make(chan interface{}, 1)
|
||||
eventHandler := c.newResourceEventHandler(eventCh)
|
||||
|
||||
if len(namespaces) == 0 {
|
||||
namespaces = k8s.Namespaces{metav1.NamespaceAll}
|
||||
c.isNamespaceAll = true
|
||||
}
|
||||
c.watchedNamespaces = namespaces
|
||||
|
||||
for _, ns := range namespaces {
|
||||
factoryCrd := externalversions.NewSharedInformerFactoryWithOptions(c.csCrd, resyncPeriod, externalversions.WithNamespace(ns))
|
||||
factoryCrd.Traefik().V1alpha1().IngressRoutes().Informer().AddEventHandler(eventHandler)
|
||||
factoryCrd.Traefik().V1alpha1().Middlewares().Informer().AddEventHandler(eventHandler)
|
||||
|
||||
factoryKube := informers.NewFilteredSharedInformerFactory(c.csKube, resyncPeriod, ns, nil)
|
||||
factoryKube.Extensions().V1beta1().Ingresses().Informer().AddEventHandler(eventHandler)
|
||||
factoryKube.Core().V1().Services().Informer().AddEventHandler(eventHandler)
|
||||
factoryKube.Core().V1().Endpoints().Informer().AddEventHandler(eventHandler)
|
||||
|
||||
c.factoriesCrd[ns] = factoryCrd
|
||||
c.factoriesKube[ns] = factoryKube
|
||||
}
|
||||
|
||||
for _, ns := range namespaces {
|
||||
c.factoriesCrd[ns].Start(stopCh)
|
||||
c.factoriesKube[ns].Start(stopCh)
|
||||
}
|
||||
|
||||
for _, ns := range namespaces {
|
||||
for t, ok := range c.factoriesCrd[ns].WaitForCacheSync(stopCh) {
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("timed out waiting for controller caches to sync %s in namespace %q", t.String(), ns)
|
||||
}
|
||||
}
|
||||
|
||||
for t, ok := range c.factoriesKube[ns].WaitForCacheSync(stopCh) {
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("timed out waiting for controller caches to sync %s in namespace %q", t.String(), ns)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do not wait for the Secrets store to get synced since we cannot rely on
|
||||
// users having granted RBAC permissions for this object.
|
||||
// https://github.com/containous/traefik/issues/1784 should improve the
|
||||
// situation here in the future.
|
||||
for _, ns := range namespaces {
|
||||
c.factoriesKube[ns].Core().V1().Secrets().Informer().AddEventHandler(eventHandler)
|
||||
c.factoriesKube[ns].Start(stopCh)
|
||||
}
|
||||
|
||||
return eventCh, nil
|
||||
}
|
||||
|
||||
func (c *clientWrapper) GetIngressRoutes() []*v1alpha1.IngressRoute {
|
||||
var result []*v1alpha1.IngressRoute
|
||||
|
||||
for ns, factory := range c.factoriesCrd {
|
||||
ings, err := factory.Traefik().V1alpha1().IngressRoutes().Lister().List(c.ingressLabelSelector)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to list ingresses in namespace %s: %s", ns, err)
|
||||
}
|
||||
result = append(result, ings...)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (c *clientWrapper) GetMiddlewares() []*v1alpha1.Middleware {
|
||||
var result []*v1alpha1.Middleware
|
||||
|
||||
for ns, factory := range c.factoriesCrd {
|
||||
ings, err := factory.Traefik().V1alpha1().Middlewares().Lister().List(c.ingressLabelSelector)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to list ingresses in namespace %s: %s", ns, err)
|
||||
}
|
||||
result = append(result, ings...)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// GetIngresses returns all Ingresses for observed namespaces in the cluster.
|
||||
func (c *clientWrapper) GetIngresses() []*extensionsv1beta1.Ingress {
|
||||
var result []*extensionsv1beta1.Ingress
|
||||
for ns, factory := range c.factoriesKube {
|
||||
ings, err := factory.Extensions().V1beta1().Ingresses().Lister().List(c.ingressLabelSelector)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to list ingresses in namespace %s: %s", ns, err)
|
||||
}
|
||||
result = append(result, ings...)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// UpdateIngressStatus updates an Ingress with a provided status.
|
||||
func (c *clientWrapper) UpdateIngressStatus(namespace, name, ip, hostname string) error {
|
||||
if !c.isWatchedNamespace(namespace) {
|
||||
return fmt.Errorf("failed to get ingress %s/%s: namespace is not within watched namespaces", namespace, name)
|
||||
}
|
||||
|
||||
ing, err := c.factoriesKube[c.lookupNamespace(namespace)].Extensions().V1beta1().Ingresses().Lister().Ingresses(namespace).Get(name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get ingress %s/%s: %v", namespace, name, err)
|
||||
}
|
||||
|
||||
if len(ing.Status.LoadBalancer.Ingress) > 0 {
|
||||
if ing.Status.LoadBalancer.Ingress[0].Hostname == hostname && ing.Status.LoadBalancer.Ingress[0].IP == ip {
|
||||
// If status is already set, skip update
|
||||
log.Debugf("Skipping status update on ingress %s/%s", ing.Namespace, ing.Name)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
ingCopy := ing.DeepCopy()
|
||||
ingCopy.Status = extensionsv1beta1.IngressStatus{LoadBalancer: corev1.LoadBalancerStatus{Ingress: []corev1.LoadBalancerIngress{{IP: ip, Hostname: hostname}}}}
|
||||
|
||||
_, err = c.csKube.ExtensionsV1beta1().Ingresses(ingCopy.Namespace).UpdateStatus(ingCopy)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update ingress status %s/%s: %v", namespace, name, err)
|
||||
}
|
||||
log.Infof("Updated status on ingress %s/%s", namespace, name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetService returns the named service from the given namespace.
|
||||
func (c *clientWrapper) GetService(namespace, name string) (*corev1.Service, bool, error) {
|
||||
if !c.isWatchedNamespace(namespace) {
|
||||
return nil, false, fmt.Errorf("failed to get service %s/%s: namespace is not within watched namespaces", namespace, name)
|
||||
}
|
||||
|
||||
service, err := c.factoriesKube[c.lookupNamespace(namespace)].Core().V1().Services().Lister().Services(namespace).Get(name)
|
||||
exist, err := translateNotFoundError(err)
|
||||
return service, exist, err
|
||||
}
|
||||
|
||||
// GetEndpoints returns the named endpoints from the given namespace.
|
||||
func (c *clientWrapper) GetEndpoints(namespace, name string) (*corev1.Endpoints, bool, error) {
|
||||
if !c.isWatchedNamespace(namespace) {
|
||||
return nil, false, fmt.Errorf("failed to get endpoints %s/%s: namespace is not within watched namespaces", namespace, name)
|
||||
}
|
||||
|
||||
endpoint, err := c.factoriesKube[c.lookupNamespace(namespace)].Core().V1().Endpoints().Lister().Endpoints(namespace).Get(name)
|
||||
exist, err := translateNotFoundError(err)
|
||||
return endpoint, exist, err
|
||||
}
|
||||
|
||||
// GetSecret returns the named secret from the given namespace.
|
||||
func (c *clientWrapper) GetSecret(namespace, name string) (*corev1.Secret, bool, error) {
|
||||
if !c.isWatchedNamespace(namespace) {
|
||||
return nil, false, fmt.Errorf("failed to get secret %s/%s: namespace is not within watched namespaces", namespace, name)
|
||||
}
|
||||
|
||||
secret, err := c.factoriesKube[c.lookupNamespace(namespace)].Core().V1().Secrets().Lister().Secrets(namespace).Get(name)
|
||||
exist, err := translateNotFoundError(err)
|
||||
return secret, exist, err
|
||||
}
|
||||
|
||||
// lookupNamespace returns the lookup namespace key for the given namespace.
|
||||
// When listening on all namespaces, it returns the client-go identifier ("")
|
||||
// for all-namespaces. Otherwise, it returns the given namespace.
|
||||
// The distinction is necessary because we index all informers on the special
|
||||
// identifier iff all-namespaces are requested but receive specific namespace
|
||||
// identifiers from the Kubernetes API, so we have to bridge this gap.
|
||||
func (c *clientWrapper) lookupNamespace(ns string) string {
|
||||
if c.isNamespaceAll {
|
||||
return metav1.NamespaceAll
|
||||
}
|
||||
return ns
|
||||
}
|
||||
|
||||
func (c *clientWrapper) newResourceEventHandler(events chan<- interface{}) cache.ResourceEventHandler {
|
||||
return &cache.FilteringResourceEventHandler{
|
||||
FilterFunc: func(obj interface{}) bool {
|
||||
// Ignore Ingresses that do not match our custom label selector.
|
||||
if ing, ok := obj.(*extensionsv1beta1.Ingress); ok {
|
||||
lbls := labels.Set(ing.GetLabels())
|
||||
return c.ingressLabelSelector.Matches(lbls)
|
||||
}
|
||||
return true
|
||||
},
|
||||
Handler: &resourceEventHandler{ev: events},
|
||||
}
|
||||
}
|
||||
|
||||
// eventHandlerFunc will pass the obj on to the events channel or drop it.
|
||||
// This is so passing the events along won't block in the case of high volume.
|
||||
// The events are only used for signaling anyway so dropping a few is ok.
|
||||
func eventHandlerFunc(events chan<- interface{}, obj interface{}) {
|
||||
select {
|
||||
case events <- obj:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
// translateNotFoundError will translate a "not found" error to a boolean return
|
||||
// value which indicates if the resource exists and a nil error.
|
||||
func translateNotFoundError(err error) (bool, error) {
|
||||
if kubeerror.IsNotFound(err) {
|
||||
return false, nil
|
||||
}
|
||||
return err == nil, err
|
||||
}
|
||||
|
||||
// isWatchedNamespace checks to ensure that the namespace is being watched before we request
|
||||
// it to ensure we don't panic by requesting an out-of-watch object.
|
||||
func (c *clientWrapper) isWatchedNamespace(ns string) bool {
|
||||
if c.isNamespaceAll {
|
||||
return true
|
||||
}
|
||||
for _, watchedNamespace := range c.watchedNamespaces {
|
||||
if watchedNamespace == ns {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
133
provider/kubernetes/crd/client_mock_test.go
Normal file
133
provider/kubernetes/crd/client_mock_test.go
Normal file
|
@ -0,0 +1,133 @@
|
|||
package crd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/containous/traefik/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
"github.com/containous/traefik/provider/kubernetes/k8s"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
|
||||
v1beta12 "k8s.io/api/extensions/v1beta1"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
)
|
||||
|
||||
var _ Client = (*clientMock)(nil)
|
||||
|
||||
func init() {
|
||||
// required by k8s.MustParseYaml
|
||||
err := v1alpha1.AddToScheme(scheme.Scheme)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
type clientMock struct {
|
||||
ingresses []*extensionsv1beta1.Ingress
|
||||
services []*corev1.Service
|
||||
secrets []*corev1.Secret
|
||||
endpoints []*corev1.Endpoints
|
||||
|
||||
apiServiceError error
|
||||
apiSecretError error
|
||||
apiEndpointsError error
|
||||
apiIngressStatusError error
|
||||
|
||||
ingressRoutes []*v1alpha1.IngressRoute
|
||||
middlewares []*v1alpha1.Middleware
|
||||
|
||||
watchChan chan interface{}
|
||||
}
|
||||
|
||||
func newClientMock(paths ...string) clientMock {
|
||||
var c clientMock
|
||||
|
||||
for _, path := range paths {
|
||||
yamlContent, err := ioutil.ReadFile("./fixtures/" + path)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
k8sObjects := k8s.MustParseYaml(yamlContent)
|
||||
for _, obj := range k8sObjects {
|
||||
switch o := obj.(type) {
|
||||
case *corev1.Service:
|
||||
c.services = append(c.services, o)
|
||||
case *corev1.Endpoints:
|
||||
c.endpoints = append(c.endpoints, o)
|
||||
case *v1alpha1.IngressRoute:
|
||||
c.ingressRoutes = append(c.ingressRoutes, o)
|
||||
case *v1alpha1.Middleware:
|
||||
c.middlewares = append(c.middlewares, o)
|
||||
case *v1beta12.Ingress:
|
||||
c.ingresses = append(c.ingresses, o)
|
||||
case *corev1.Secret:
|
||||
c.secrets = append(c.secrets, o)
|
||||
default:
|
||||
panic(fmt.Sprintf("Unknown runtime object %+v %T", o, o))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func (c clientMock) GetIngressRoutes() []*v1alpha1.IngressRoute {
|
||||
return c.ingressRoutes
|
||||
}
|
||||
|
||||
func (c clientMock) GetMiddlewares() []*v1alpha1.Middleware {
|
||||
return c.middlewares
|
||||
}
|
||||
|
||||
func (c clientMock) GetIngresses() []*extensionsv1beta1.Ingress {
|
||||
return c.ingresses
|
||||
}
|
||||
|
||||
func (c clientMock) GetService(namespace, name string) (*corev1.Service, bool, error) {
|
||||
if c.apiServiceError != nil {
|
||||
return nil, false, c.apiServiceError
|
||||
}
|
||||
|
||||
for _, service := range c.services {
|
||||
if service.Namespace == namespace && service.Name == name {
|
||||
return service, true, nil
|
||||
}
|
||||
}
|
||||
return nil, false, c.apiServiceError
|
||||
}
|
||||
|
||||
func (c clientMock) GetEndpoints(namespace, name string) (*corev1.Endpoints, bool, error) {
|
||||
if c.apiEndpointsError != nil {
|
||||
return nil, false, c.apiEndpointsError
|
||||
}
|
||||
|
||||
for _, endpoints := range c.endpoints {
|
||||
if endpoints.Namespace == namespace && endpoints.Name == name {
|
||||
return endpoints, true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return &corev1.Endpoints{}, false, nil
|
||||
}
|
||||
|
||||
func (c clientMock) GetSecret(namespace, name string) (*corev1.Secret, bool, error) {
|
||||
if c.apiSecretError != nil {
|
||||
return nil, false, c.apiSecretError
|
||||
}
|
||||
|
||||
for _, secret := range c.secrets {
|
||||
if secret.Namespace == namespace && secret.Name == name {
|
||||
return secret, true, nil
|
||||
}
|
||||
}
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
func (c clientMock) WatchAll(namespaces k8s.Namespaces, stopCh <-chan struct{}) (<-chan interface{}, error) {
|
||||
return c.watchChan, nil
|
||||
}
|
||||
|
||||
func (c clientMock) UpdateIngressStatus(namespace, name, ip, hostname string) error {
|
||||
return c.apiIngressStatusError
|
||||
}
|
88
provider/kubernetes/crd/fixtures/services.yml
Normal file
88
provider/kubernetes/crd/fixtures/services.yml
Normal file
|
@ -0,0 +1,88 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: whoami
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- name: web
|
||||
port: 80
|
||||
selector:
|
||||
app: containous
|
||||
task: whoami
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: whoami
|
||||
namespace: default
|
||||
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
- ip: 10.10.0.2
|
||||
ports:
|
||||
- name: web
|
||||
port: 80
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: whoami2
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
selector:
|
||||
app: containous
|
||||
task: whoami2
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: whoami2
|
||||
namespace: default
|
||||
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.10.0.3
|
||||
- ip: 10.10.0.4
|
||||
ports:
|
||||
- name: web
|
||||
port: 8080
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: whoamitls
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- name: web-secure
|
||||
port: 443
|
||||
selector:
|
||||
app: containous
|
||||
task: whoami2
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: whoamitls
|
||||
namespace: default
|
||||
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.10.0.5
|
||||
- ip: 10.10.0.6
|
||||
ports:
|
||||
- name: web-secure
|
||||
port: 443
|
17
provider/kubernetes/crd/fixtures/simple.yml
Normal file
17
provider/kubernetes/crd/fixtures/simple.yml
Normal file
|
@ -0,0 +1,17 @@
|
|||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.crd
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- foo
|
||||
|
||||
routes:
|
||||
- match: Host(`foo.com`) && PathPrefix(`/bar`)
|
||||
kind: Rule
|
||||
priority: 12
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
17
provider/kubernetes/crd/fixtures/with_bad_host_rule.yml
Normal file
17
provider/kubernetes/crd/fixtures/with_bad_host_rule.yml
Normal file
|
@ -0,0 +1,17 @@
|
|||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.crd
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
|
||||
routes:
|
||||
- match: Host(`foo.com"0"`) && PathPrefix(`/bar`)
|
||||
kind: Rule
|
||||
priority: 12
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
17
provider/kubernetes/crd/fixtures/with_https_default.yml
Normal file
17
provider/kubernetes/crd/fixtures/with_https_default.yml
Normal file
|
@ -0,0 +1,17 @@
|
|||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.crd
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- foo
|
||||
|
||||
routes:
|
||||
- match: Host(`foo.com`) && PathPrefix(`/bar`)
|
||||
kind: Rule
|
||||
priority: 12
|
||||
services:
|
||||
- name: whoamitls
|
||||
port: 443
|
44
provider/kubernetes/crd/fixtures/with_middleware.yml
Normal file
44
provider/kubernetes/crd/fixtures/with_middleware.yml
Normal file
|
@ -0,0 +1,44 @@
|
|||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: stripprefix
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
stripPrefix:
|
||||
prefixes:
|
||||
- /tobestripped
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: addprefix
|
||||
namespace: foo
|
||||
|
||||
spec:
|
||||
addPrefix:
|
||||
prefix: /tobeadded
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test2.crd
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
|
||||
routes:
|
||||
- match: Host(`foo.com`) && PathPrefix(`/tobestripped`)
|
||||
priority: 12
|
||||
kind: Rule
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
middlewares:
|
||||
- name: stripprefix
|
||||
- name: addprefix
|
||||
namespace: foo
|
17
provider/kubernetes/crd/fixtures/with_no_rule_value.yml
Normal file
17
provider/kubernetes/crd/fixtures/with_no_rule_value.yml
Normal file
|
@ -0,0 +1,17 @@
|
|||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.crd
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
|
||||
routes:
|
||||
- match: ""
|
||||
kind: Rule
|
||||
priority: 12
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
31
provider/kubernetes/crd/fixtures/with_tls.yml
Normal file
31
provider/kubernetes/crd/fixtures/with_tls.yml
Normal file
|
@ -0,0 +1,31 @@
|
|||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: supersecret
|
||||
namespace: default
|
||||
|
||||
data:
|
||||
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
|
||||
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0=
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.crd
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
|
||||
routes:
|
||||
- match: Host(`foo.com`) && PathPrefix(`/bar`)
|
||||
kind: Rule
|
||||
priority: 12
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
|
||||
tls:
|
||||
secretName: supersecret
|
23
provider/kubernetes/crd/fixtures/with_two_rules.yml
Normal file
23
provider/kubernetes/crd/fixtures/with_two_rules.yml
Normal file
|
@ -0,0 +1,23 @@
|
|||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.crd
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
|
||||
routes:
|
||||
- match: Host(`foo.com`) && PathPrefix(`/foo`)
|
||||
kind: Rule
|
||||
priority: 12
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
- match: Host(`foo.com`) && PathPrefix(`/bar`)
|
||||
kind: Rule
|
||||
priority: 14
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
20
provider/kubernetes/crd/fixtures/with_two_services.yml
Normal file
20
provider/kubernetes/crd/fixtures/with_two_services.yml
Normal file
|
@ -0,0 +1,20 @@
|
|||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.crd
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
|
||||
routes:
|
||||
- match: Host(`foo.com`) && PathPrefix(`/foo`)
|
||||
kind: Rule
|
||||
priority: 12
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
- name: whoami2
|
||||
port: 8080
|
||||
|
16
provider/kubernetes/crd/fixtures/with_wrong_rule_kind.yml
Normal file
16
provider/kubernetes/crd/fixtures/with_wrong_rule_kind.yml
Normal file
|
@ -0,0 +1,16 @@
|
|||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test.crd
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
|
||||
routes:
|
||||
- match: /prefix
|
||||
priority: 12
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package versioned
|
||||
|
||||
import (
|
||||
traefikv1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/generated/clientset/versioned/typed/traefik/v1alpha1"
|
||||
discovery "k8s.io/client-go/discovery"
|
||||
rest "k8s.io/client-go/rest"
|
||||
flowcontrol "k8s.io/client-go/util/flowcontrol"
|
||||
)
|
||||
|
||||
type Interface interface {
|
||||
Discovery() discovery.DiscoveryInterface
|
||||
TraefikV1alpha1() traefikv1alpha1.TraefikV1alpha1Interface
|
||||
// Deprecated: please explicitly pick a version if possible.
|
||||
Traefik() traefikv1alpha1.TraefikV1alpha1Interface
|
||||
}
|
||||
|
||||
// Clientset contains the clients for groups. Each group has exactly one
|
||||
// version included in a Clientset.
|
||||
type Clientset struct {
|
||||
*discovery.DiscoveryClient
|
||||
traefikV1alpha1 *traefikv1alpha1.TraefikV1alpha1Client
|
||||
}
|
||||
|
||||
// TraefikV1alpha1 retrieves the TraefikV1alpha1Client
|
||||
func (c *Clientset) TraefikV1alpha1() traefikv1alpha1.TraefikV1alpha1Interface {
|
||||
return c.traefikV1alpha1
|
||||
}
|
||||
|
||||
// Deprecated: Traefik retrieves the default version of TraefikClient.
|
||||
// Please explicitly pick a version.
|
||||
func (c *Clientset) Traefik() traefikv1alpha1.TraefikV1alpha1Interface {
|
||||
return c.traefikV1alpha1
|
||||
}
|
||||
|
||||
// Discovery retrieves the DiscoveryClient
|
||||
func (c *Clientset) Discovery() discovery.DiscoveryInterface {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
return c.DiscoveryClient
|
||||
}
|
||||
|
||||
// NewForConfig creates a new Clientset for the given config.
|
||||
func NewForConfig(c *rest.Config) (*Clientset, error) {
|
||||
configShallowCopy := *c
|
||||
if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 {
|
||||
configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst)
|
||||
}
|
||||
var cs Clientset
|
||||
var err error
|
||||
cs.traefikV1alpha1, err = traefikv1alpha1.NewForConfig(&configShallowCopy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &cs, nil
|
||||
}
|
||||
|
||||
// NewForConfigOrDie creates a new Clientset for the given config and
|
||||
// panics if there is an error in the config.
|
||||
func NewForConfigOrDie(c *rest.Config) *Clientset {
|
||||
var cs Clientset
|
||||
cs.traefikV1alpha1 = traefikv1alpha1.NewForConfigOrDie(c)
|
||||
|
||||
cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c)
|
||||
return &cs
|
||||
}
|
||||
|
||||
// New creates a new Clientset for the given RESTClient.
|
||||
func New(c rest.Interface) *Clientset {
|
||||
var cs Clientset
|
||||
cs.traefikV1alpha1 = traefikv1alpha1.New(c)
|
||||
|
||||
cs.DiscoveryClient = discovery.NewDiscoveryClient(c)
|
||||
return &cs
|
||||
}
|
28
provider/kubernetes/crd/generated/clientset/versioned/doc.go
Normal file
28
provider/kubernetes/crd/generated/clientset/versioned/doc.go
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
// This package has the automatically generated clientset.
|
||||
package versioned
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
clientset "github.com/containous/traefik/provider/kubernetes/crd/generated/clientset/versioned"
|
||||
traefikv1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/generated/clientset/versioned/typed/traefik/v1alpha1"
|
||||
faketraefikv1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/generated/clientset/versioned/typed/traefik/v1alpha1/fake"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/discovery"
|
||||
fakediscovery "k8s.io/client-go/discovery/fake"
|
||||
"k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
// NewSimpleClientset returns a clientset that will respond with the provided objects.
|
||||
// It's backed by a very simple object tracker that processes creates, updates and deletions as-is,
|
||||
// without applying any validations and/or defaults. It shouldn't be considered a replacement
|
||||
// for a real clientset and is mostly useful in simple unit tests.
|
||||
func NewSimpleClientset(objects ...runtime.Object) *Clientset {
|
||||
o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder())
|
||||
for _, obj := range objects {
|
||||
if err := o.Add(obj); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
cs := &Clientset{}
|
||||
cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake}
|
||||
cs.AddReactor("*", "*", testing.ObjectReaction(o))
|
||||
cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) {
|
||||
gvr := action.GetResource()
|
||||
ns := action.GetNamespace()
|
||||
watch, err := o.Watch(gvr, ns)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
return true, watch, nil
|
||||
})
|
||||
|
||||
return cs
|
||||
}
|
||||
|
||||
// Clientset implements clientset.Interface. Meant to be embedded into a
|
||||
// struct to get a default implementation. This makes faking out just the method
|
||||
// you want to test easier.
|
||||
type Clientset struct {
|
||||
testing.Fake
|
||||
discovery *fakediscovery.FakeDiscovery
|
||||
}
|
||||
|
||||
func (c *Clientset) Discovery() discovery.DiscoveryInterface {
|
||||
return c.discovery
|
||||
}
|
||||
|
||||
var _ clientset.Interface = &Clientset{}
|
||||
|
||||
// TraefikV1alpha1 retrieves the TraefikV1alpha1Client
|
||||
func (c *Clientset) TraefikV1alpha1() traefikv1alpha1.TraefikV1alpha1Interface {
|
||||
return &faketraefikv1alpha1.FakeTraefikV1alpha1{Fake: &c.Fake}
|
||||
}
|
||||
|
||||
// Traefik retrieves the TraefikV1alpha1Client
|
||||
func (c *Clientset) Traefik() traefikv1alpha1.TraefikV1alpha1Interface {
|
||||
return &faketraefikv1alpha1.FakeTraefikV1alpha1{Fake: &c.Fake}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
// This package has the automatically generated fake clientset.
|
||||
package fake
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
traefikv1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
serializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
)
|
||||
|
||||
var scheme = runtime.NewScheme()
|
||||
var codecs = serializer.NewCodecFactory(scheme)
|
||||
var parameterCodec = runtime.NewParameterCodec(scheme)
|
||||
|
||||
func init() {
|
||||
v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"})
|
||||
AddToScheme(scheme)
|
||||
}
|
||||
|
||||
// AddToScheme adds all types of this clientset into the given scheme. This allows composition
|
||||
// of clientsets, like in:
|
||||
//
|
||||
// import (
|
||||
// "k8s.io/client-go/kubernetes"
|
||||
// clientsetscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
|
||||
// )
|
||||
//
|
||||
// kclientset, _ := kubernetes.NewForConfig(c)
|
||||
// aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
|
||||
//
|
||||
// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
|
||||
// correctly.
|
||||
func AddToScheme(scheme *runtime.Scheme) {
|
||||
traefikv1alpha1.AddToScheme(scheme)
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
// This package contains the scheme of the automatically generated clientset.
|
||||
package scheme
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package scheme
|
||||
|
||||
import (
|
||||
traefikv1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
serializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
)
|
||||
|
||||
var Scheme = runtime.NewScheme()
|
||||
var Codecs = serializer.NewCodecFactory(Scheme)
|
||||
var ParameterCodec = runtime.NewParameterCodec(Scheme)
|
||||
|
||||
func init() {
|
||||
v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"})
|
||||
AddToScheme(Scheme)
|
||||
}
|
||||
|
||||
// AddToScheme adds all types of this clientset into the given scheme. This allows composition
|
||||
// of clientsets, like in:
|
||||
//
|
||||
// import (
|
||||
// "k8s.io/client-go/kubernetes"
|
||||
// clientsetscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
|
||||
// )
|
||||
//
|
||||
// kclientset, _ := kubernetes.NewForConfig(c)
|
||||
// aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
|
||||
//
|
||||
// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
|
||||
// correctly.
|
||||
func AddToScheme(scheme *runtime.Scheme) {
|
||||
traefikv1alpha1.AddToScheme(scheme)
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
// This package has the automatically generated typed clients.
|
||||
package v1alpha1
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
// Package fake has the automatically generated clients.
|
||||
package fake
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
v1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
labels "k8s.io/apimachinery/pkg/labels"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
testing "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
// FakeIngressRoutes implements IngressRouteInterface
|
||||
type FakeIngressRoutes struct {
|
||||
Fake *FakeTraefikV1alpha1
|
||||
ns string
|
||||
}
|
||||
|
||||
var ingressroutesResource = schema.GroupVersionResource{Group: "traefik.containo.us", Version: "v1alpha1", Resource: "ingressroutes"}
|
||||
|
||||
var ingressroutesKind = schema.GroupVersionKind{Group: "traefik.containo.us", Version: "v1alpha1", Kind: "IngressRoute"}
|
||||
|
||||
// Get takes name of the ingressRoute, and returns the corresponding ingressRoute object, and an error if there is any.
|
||||
func (c *FakeIngressRoutes) Get(name string, options v1.GetOptions) (result *v1alpha1.IngressRoute, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewGetAction(ingressroutesResource, c.ns, name), &v1alpha1.IngressRoute{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.IngressRoute), err
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of IngressRoutes that match those selectors.
|
||||
func (c *FakeIngressRoutes) List(opts v1.ListOptions) (result *v1alpha1.IngressRouteList, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewListAction(ingressroutesResource, ingressroutesKind, c.ns, opts), &v1alpha1.IngressRouteList{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
label, _, _ := testing.ExtractFromListOptions(opts)
|
||||
if label == nil {
|
||||
label = labels.Everything()
|
||||
}
|
||||
list := &v1alpha1.IngressRouteList{ListMeta: obj.(*v1alpha1.IngressRouteList).ListMeta}
|
||||
for _, item := range obj.(*v1alpha1.IngressRouteList).Items {
|
||||
if label.Matches(labels.Set(item.Labels)) {
|
||||
list.Items = append(list.Items, item)
|
||||
}
|
||||
}
|
||||
return list, err
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested ingressRoutes.
|
||||
func (c *FakeIngressRoutes) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
return c.Fake.
|
||||
InvokesWatch(testing.NewWatchAction(ingressroutesResource, c.ns, opts))
|
||||
|
||||
}
|
||||
|
||||
// Create takes the representation of a ingressRoute and creates it. Returns the server's representation of the ingressRoute, and an error, if there is any.
|
||||
func (c *FakeIngressRoutes) Create(ingressRoute *v1alpha1.IngressRoute) (result *v1alpha1.IngressRoute, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewCreateAction(ingressroutesResource, c.ns, ingressRoute), &v1alpha1.IngressRoute{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.IngressRoute), err
|
||||
}
|
||||
|
||||
// Update takes the representation of a ingressRoute and updates it. Returns the server's representation of the ingressRoute, and an error, if there is any.
|
||||
func (c *FakeIngressRoutes) Update(ingressRoute *v1alpha1.IngressRoute) (result *v1alpha1.IngressRoute, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewUpdateAction(ingressroutesResource, c.ns, ingressRoute), &v1alpha1.IngressRoute{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.IngressRoute), err
|
||||
}
|
||||
|
||||
// Delete takes name of the ingressRoute and deletes it. Returns an error if one occurs.
|
||||
func (c *FakeIngressRoutes) Delete(name string, options *v1.DeleteOptions) error {
|
||||
_, err := c.Fake.
|
||||
Invokes(testing.NewDeleteAction(ingressroutesResource, c.ns, name), &v1alpha1.IngressRoute{})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *FakeIngressRoutes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
action := testing.NewDeleteCollectionAction(ingressroutesResource, c.ns, listOptions)
|
||||
|
||||
_, err := c.Fake.Invokes(action, &v1alpha1.IngressRouteList{})
|
||||
return err
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched ingressRoute.
|
||||
func (c *FakeIngressRoutes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.IngressRoute, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewPatchSubresourceAction(ingressroutesResource, c.ns, name, data, subresources...), &v1alpha1.IngressRoute{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.IngressRoute), err
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
v1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
labels "k8s.io/apimachinery/pkg/labels"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
testing "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
// FakeMiddlewares implements MiddlewareInterface
|
||||
type FakeMiddlewares struct {
|
||||
Fake *FakeTraefikV1alpha1
|
||||
ns string
|
||||
}
|
||||
|
||||
var middlewaresResource = schema.GroupVersionResource{Group: "traefik.containo.us", Version: "v1alpha1", Resource: "middlewares"}
|
||||
|
||||
var middlewaresKind = schema.GroupVersionKind{Group: "traefik.containo.us", Version: "v1alpha1", Kind: "Middleware"}
|
||||
|
||||
// Get takes name of the middleware, and returns the corresponding middleware object, and an error if there is any.
|
||||
func (c *FakeMiddlewares) Get(name string, options v1.GetOptions) (result *v1alpha1.Middleware, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewGetAction(middlewaresResource, c.ns, name), &v1alpha1.Middleware{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.Middleware), err
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of Middlewares that match those selectors.
|
||||
func (c *FakeMiddlewares) List(opts v1.ListOptions) (result *v1alpha1.MiddlewareList, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewListAction(middlewaresResource, middlewaresKind, c.ns, opts), &v1alpha1.MiddlewareList{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
label, _, _ := testing.ExtractFromListOptions(opts)
|
||||
if label == nil {
|
||||
label = labels.Everything()
|
||||
}
|
||||
list := &v1alpha1.MiddlewareList{ListMeta: obj.(*v1alpha1.MiddlewareList).ListMeta}
|
||||
for _, item := range obj.(*v1alpha1.MiddlewareList).Items {
|
||||
if label.Matches(labels.Set(item.Labels)) {
|
||||
list.Items = append(list.Items, item)
|
||||
}
|
||||
}
|
||||
return list, err
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested middlewares.
|
||||
func (c *FakeMiddlewares) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
return c.Fake.
|
||||
InvokesWatch(testing.NewWatchAction(middlewaresResource, c.ns, opts))
|
||||
|
||||
}
|
||||
|
||||
// Create takes the representation of a middleware and creates it. Returns the server's representation of the middleware, and an error, if there is any.
|
||||
func (c *FakeMiddlewares) Create(middleware *v1alpha1.Middleware) (result *v1alpha1.Middleware, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewCreateAction(middlewaresResource, c.ns, middleware), &v1alpha1.Middleware{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.Middleware), err
|
||||
}
|
||||
|
||||
// Update takes the representation of a middleware and updates it. Returns the server's representation of the middleware, and an error, if there is any.
|
||||
func (c *FakeMiddlewares) Update(middleware *v1alpha1.Middleware) (result *v1alpha1.Middleware, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewUpdateAction(middlewaresResource, c.ns, middleware), &v1alpha1.Middleware{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.Middleware), err
|
||||
}
|
||||
|
||||
// Delete takes name of the middleware and deletes it. Returns an error if one occurs.
|
||||
func (c *FakeMiddlewares) Delete(name string, options *v1.DeleteOptions) error {
|
||||
_, err := c.Fake.
|
||||
Invokes(testing.NewDeleteAction(middlewaresResource, c.ns, name), &v1alpha1.Middleware{})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *FakeMiddlewares) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
action := testing.NewDeleteCollectionAction(middlewaresResource, c.ns, listOptions)
|
||||
|
||||
_, err := c.Fake.Invokes(action, &v1alpha1.MiddlewareList{})
|
||||
return err
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched middleware.
|
||||
func (c *FakeMiddlewares) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Middleware, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewPatchSubresourceAction(middlewaresResource, c.ns, name, data, subresources...), &v1alpha1.Middleware{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.Middleware), err
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
v1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/generated/clientset/versioned/typed/traefik/v1alpha1"
|
||||
rest "k8s.io/client-go/rest"
|
||||
testing "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
type FakeTraefikV1alpha1 struct {
|
||||
*testing.Fake
|
||||
}
|
||||
|
||||
func (c *FakeTraefikV1alpha1) IngressRoutes(namespace string) v1alpha1.IngressRouteInterface {
|
||||
return &FakeIngressRoutes{c, namespace}
|
||||
}
|
||||
|
||||
func (c *FakeTraefikV1alpha1) Middlewares(namespace string) v1alpha1.MiddlewareInterface {
|
||||
return &FakeMiddlewares{c, namespace}
|
||||
}
|
||||
|
||||
// RESTClient returns a RESTClient that is used to communicate
|
||||
// with API server by this client implementation.
|
||||
func (c *FakeTraefikV1alpha1) RESTClient() rest.Interface {
|
||||
var ret *rest.RESTClient
|
||||
return ret
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
type IngressRouteExpansion interface{}
|
||||
|
||||
type MiddlewareExpansion interface{}
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
scheme "github.com/containous/traefik/provider/kubernetes/crd/generated/clientset/versioned/scheme"
|
||||
v1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
rest "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// IngressRoutesGetter has a method to return a IngressRouteInterface.
|
||||
// A group's client should implement this interface.
|
||||
type IngressRoutesGetter interface {
|
||||
IngressRoutes(namespace string) IngressRouteInterface
|
||||
}
|
||||
|
||||
// IngressRouteInterface has methods to work with IngressRoute resources.
|
||||
type IngressRouteInterface interface {
|
||||
Create(*v1alpha1.IngressRoute) (*v1alpha1.IngressRoute, error)
|
||||
Update(*v1alpha1.IngressRoute) (*v1alpha1.IngressRoute, error)
|
||||
Delete(name string, options *v1.DeleteOptions) error
|
||||
DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error
|
||||
Get(name string, options v1.GetOptions) (*v1alpha1.IngressRoute, error)
|
||||
List(opts v1.ListOptions) (*v1alpha1.IngressRouteList, error)
|
||||
Watch(opts v1.ListOptions) (watch.Interface, error)
|
||||
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.IngressRoute, err error)
|
||||
IngressRouteExpansion
|
||||
}
|
||||
|
||||
// ingressRoutes implements IngressRouteInterface
|
||||
type ingressRoutes struct {
|
||||
client rest.Interface
|
||||
ns string
|
||||
}
|
||||
|
||||
// newIngressRoutes returns a IngressRoutes
|
||||
func newIngressRoutes(c *TraefikV1alpha1Client, namespace string) *ingressRoutes {
|
||||
return &ingressRoutes{
|
||||
client: c.RESTClient(),
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// Get takes name of the ingressRoute, and returns the corresponding ingressRoute object, and an error if there is any.
|
||||
func (c *ingressRoutes) Get(name string, options v1.GetOptions) (result *v1alpha1.IngressRoute, err error) {
|
||||
result = &v1alpha1.IngressRoute{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("ingressroutes").
|
||||
Name(name).
|
||||
VersionedParams(&options, scheme.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of IngressRoutes that match those selectors.
|
||||
func (c *ingressRoutes) List(opts v1.ListOptions) (result *v1alpha1.IngressRouteList, err error) {
|
||||
result = &v1alpha1.IngressRouteList{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("ingressroutes").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested ingressRoutes.
|
||||
func (c *ingressRoutes) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
opts.Watch = true
|
||||
return c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("ingressroutes").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Watch()
|
||||
}
|
||||
|
||||
// Create takes the representation of a ingressRoute and creates it. Returns the server's representation of the ingressRoute, and an error, if there is any.
|
||||
func (c *ingressRoutes) Create(ingressRoute *v1alpha1.IngressRoute) (result *v1alpha1.IngressRoute, err error) {
|
||||
result = &v1alpha1.IngressRoute{}
|
||||
err = c.client.Post().
|
||||
Namespace(c.ns).
|
||||
Resource("ingressroutes").
|
||||
Body(ingressRoute).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update takes the representation of a ingressRoute and updates it. Returns the server's representation of the ingressRoute, and an error, if there is any.
|
||||
func (c *ingressRoutes) Update(ingressRoute *v1alpha1.IngressRoute) (result *v1alpha1.IngressRoute, err error) {
|
||||
result = &v1alpha1.IngressRoute{}
|
||||
err = c.client.Put().
|
||||
Namespace(c.ns).
|
||||
Resource("ingressroutes").
|
||||
Name(ingressRoute.Name).
|
||||
Body(ingressRoute).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes name of the ingressRoute and deletes it. Returns an error if one occurs.
|
||||
func (c *ingressRoutes) Delete(name string, options *v1.DeleteOptions) error {
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("ingressroutes").
|
||||
Name(name).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *ingressRoutes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("ingressroutes").
|
||||
VersionedParams(&listOptions, scheme.ParameterCodec).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched ingressRoute.
|
||||
func (c *ingressRoutes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.IngressRoute, err error) {
|
||||
result = &v1alpha1.IngressRoute{}
|
||||
err = c.client.Patch(pt).
|
||||
Namespace(c.ns).
|
||||
Resource("ingressroutes").
|
||||
SubResource(subresources...).
|
||||
Name(name).
|
||||
Body(data).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
scheme "github.com/containous/traefik/provider/kubernetes/crd/generated/clientset/versioned/scheme"
|
||||
v1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
rest "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// MiddlewaresGetter has a method to return a MiddlewareInterface.
|
||||
// A group's client should implement this interface.
|
||||
type MiddlewaresGetter interface {
|
||||
Middlewares(namespace string) MiddlewareInterface
|
||||
}
|
||||
|
||||
// MiddlewareInterface has methods to work with Middleware resources.
|
||||
type MiddlewareInterface interface {
|
||||
Create(*v1alpha1.Middleware) (*v1alpha1.Middleware, error)
|
||||
Update(*v1alpha1.Middleware) (*v1alpha1.Middleware, error)
|
||||
Delete(name string, options *v1.DeleteOptions) error
|
||||
DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error
|
||||
Get(name string, options v1.GetOptions) (*v1alpha1.Middleware, error)
|
||||
List(opts v1.ListOptions) (*v1alpha1.MiddlewareList, error)
|
||||
Watch(opts v1.ListOptions) (watch.Interface, error)
|
||||
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Middleware, err error)
|
||||
MiddlewareExpansion
|
||||
}
|
||||
|
||||
// middlewares implements MiddlewareInterface
|
||||
type middlewares struct {
|
||||
client rest.Interface
|
||||
ns string
|
||||
}
|
||||
|
||||
// newMiddlewares returns a Middlewares
|
||||
func newMiddlewares(c *TraefikV1alpha1Client, namespace string) *middlewares {
|
||||
return &middlewares{
|
||||
client: c.RESTClient(),
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// Get takes name of the middleware, and returns the corresponding middleware object, and an error if there is any.
|
||||
func (c *middlewares) Get(name string, options v1.GetOptions) (result *v1alpha1.Middleware, err error) {
|
||||
result = &v1alpha1.Middleware{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("middlewares").
|
||||
Name(name).
|
||||
VersionedParams(&options, scheme.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of Middlewares that match those selectors.
|
||||
func (c *middlewares) List(opts v1.ListOptions) (result *v1alpha1.MiddlewareList, err error) {
|
||||
result = &v1alpha1.MiddlewareList{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("middlewares").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested middlewares.
|
||||
func (c *middlewares) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
opts.Watch = true
|
||||
return c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("middlewares").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Watch()
|
||||
}
|
||||
|
||||
// Create takes the representation of a middleware and creates it. Returns the server's representation of the middleware, and an error, if there is any.
|
||||
func (c *middlewares) Create(middleware *v1alpha1.Middleware) (result *v1alpha1.Middleware, err error) {
|
||||
result = &v1alpha1.Middleware{}
|
||||
err = c.client.Post().
|
||||
Namespace(c.ns).
|
||||
Resource("middlewares").
|
||||
Body(middleware).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update takes the representation of a middleware and updates it. Returns the server's representation of the middleware, and an error, if there is any.
|
||||
func (c *middlewares) Update(middleware *v1alpha1.Middleware) (result *v1alpha1.Middleware, err error) {
|
||||
result = &v1alpha1.Middleware{}
|
||||
err = c.client.Put().
|
||||
Namespace(c.ns).
|
||||
Resource("middlewares").
|
||||
Name(middleware.Name).
|
||||
Body(middleware).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes name of the middleware and deletes it. Returns an error if one occurs.
|
||||
func (c *middlewares) Delete(name string, options *v1.DeleteOptions) error {
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("middlewares").
|
||||
Name(name).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *middlewares) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("middlewares").
|
||||
VersionedParams(&listOptions, scheme.ParameterCodec).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched middleware.
|
||||
func (c *middlewares) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Middleware, err error) {
|
||||
result = &v1alpha1.Middleware{}
|
||||
err = c.client.Patch(pt).
|
||||
Namespace(c.ns).
|
||||
Resource("middlewares").
|
||||
SubResource(subresources...).
|
||||
Name(name).
|
||||
Body(data).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"github.com/containous/traefik/provider/kubernetes/crd/generated/clientset/versioned/scheme"
|
||||
v1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
serializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
rest "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
type TraefikV1alpha1Interface interface {
|
||||
RESTClient() rest.Interface
|
||||
IngressRoutesGetter
|
||||
MiddlewaresGetter
|
||||
}
|
||||
|
||||
// TraefikV1alpha1Client is used to interact with features provided by the traefik.containo.us group.
|
||||
type TraefikV1alpha1Client struct {
|
||||
restClient rest.Interface
|
||||
}
|
||||
|
||||
func (c *TraefikV1alpha1Client) IngressRoutes(namespace string) IngressRouteInterface {
|
||||
return newIngressRoutes(c, namespace)
|
||||
}
|
||||
|
||||
func (c *TraefikV1alpha1Client) Middlewares(namespace string) MiddlewareInterface {
|
||||
return newMiddlewares(c, namespace)
|
||||
}
|
||||
|
||||
// NewForConfig creates a new TraefikV1alpha1Client for the given config.
|
||||
func NewForConfig(c *rest.Config) (*TraefikV1alpha1Client, error) {
|
||||
config := *c
|
||||
if err := setConfigDefaults(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client, err := rest.RESTClientFor(&config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &TraefikV1alpha1Client{client}, nil
|
||||
}
|
||||
|
||||
// NewForConfigOrDie creates a new TraefikV1alpha1Client for the given config and
|
||||
// panics if there is an error in the config.
|
||||
func NewForConfigOrDie(c *rest.Config) *TraefikV1alpha1Client {
|
||||
client, err := NewForConfig(c)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return client
|
||||
}
|
||||
|
||||
// New creates a new TraefikV1alpha1Client for the given RESTClient.
|
||||
func New(c rest.Interface) *TraefikV1alpha1Client {
|
||||
return &TraefikV1alpha1Client{c}
|
||||
}
|
||||
|
||||
func setConfigDefaults(config *rest.Config) error {
|
||||
gv := v1alpha1.SchemeGroupVersion
|
||||
config.GroupVersion = &gv
|
||||
config.APIPath = "/apis"
|
||||
config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs}
|
||||
|
||||
if config.UserAgent == "" {
|
||||
config.UserAgent = rest.DefaultKubernetesUserAgent()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RESTClient returns a RESTClient that is used to communicate
|
||||
// with API server by this client implementation.
|
||||
func (c *TraefikV1alpha1Client) RESTClient() rest.Interface {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
return c.restClient
|
||||
}
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package externalversions
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
time "time"
|
||||
|
||||
versioned "github.com/containous/traefik/provider/kubernetes/crd/generated/clientset/versioned"
|
||||
internalinterfaces "github.com/containous/traefik/provider/kubernetes/crd/generated/informers/externalversions/internalinterfaces"
|
||||
traefik "github.com/containous/traefik/provider/kubernetes/crd/generated/informers/externalversions/traefik"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// SharedInformerOption defines the functional option type for SharedInformerFactory.
|
||||
type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory
|
||||
|
||||
type sharedInformerFactory struct {
|
||||
client versioned.Interface
|
||||
namespace string
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
lock sync.Mutex
|
||||
defaultResync time.Duration
|
||||
customResync map[reflect.Type]time.Duration
|
||||
|
||||
informers map[reflect.Type]cache.SharedIndexInformer
|
||||
// startedInformers is used for tracking which informers have been started.
|
||||
// This allows Start() to be called multiple times safely.
|
||||
startedInformers map[reflect.Type]bool
|
||||
}
|
||||
|
||||
// WithCustomResyncConfig sets a custom resync period for the specified informer types.
|
||||
func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption {
|
||||
return func(factory *sharedInformerFactory) *sharedInformerFactory {
|
||||
for k, v := range resyncConfig {
|
||||
factory.customResync[reflect.TypeOf(k)] = v
|
||||
}
|
||||
return factory
|
||||
}
|
||||
}
|
||||
|
||||
// WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory.
|
||||
func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption {
|
||||
return func(factory *sharedInformerFactory) *sharedInformerFactory {
|
||||
factory.tweakListOptions = tweakListOptions
|
||||
return factory
|
||||
}
|
||||
}
|
||||
|
||||
// WithNamespace limits the SharedInformerFactory to the specified namespace.
|
||||
func WithNamespace(namespace string) SharedInformerOption {
|
||||
return func(factory *sharedInformerFactory) *sharedInformerFactory {
|
||||
factory.namespace = namespace
|
||||
return factory
|
||||
}
|
||||
}
|
||||
|
||||
// NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces.
|
||||
func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory {
|
||||
return NewSharedInformerFactoryWithOptions(client, defaultResync)
|
||||
}
|
||||
|
||||
// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory.
|
||||
// Listers obtained via this SharedInformerFactory will be subject to the same filters
|
||||
// as specified here.
|
||||
// Deprecated: Please use NewSharedInformerFactoryWithOptions instead
|
||||
func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory {
|
||||
return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions))
|
||||
}
|
||||
|
||||
// NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options.
|
||||
func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory {
|
||||
factory := &sharedInformerFactory{
|
||||
client: client,
|
||||
namespace: v1.NamespaceAll,
|
||||
defaultResync: defaultResync,
|
||||
informers: make(map[reflect.Type]cache.SharedIndexInformer),
|
||||
startedInformers: make(map[reflect.Type]bool),
|
||||
customResync: make(map[reflect.Type]time.Duration),
|
||||
}
|
||||
|
||||
// Apply all options
|
||||
for _, opt := range options {
|
||||
factory = opt(factory)
|
||||
}
|
||||
|
||||
return factory
|
||||
}
|
||||
|
||||
// Start initializes all requested informers.
|
||||
func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
for informerType, informer := range f.informers {
|
||||
if !f.startedInformers[informerType] {
|
||||
go informer.Run(stopCh)
|
||||
f.startedInformers[informerType] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WaitForCacheSync waits for all started informers' cache were synced.
|
||||
func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool {
|
||||
informers := func() map[reflect.Type]cache.SharedIndexInformer {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
informers := map[reflect.Type]cache.SharedIndexInformer{}
|
||||
for informerType, informer := range f.informers {
|
||||
if f.startedInformers[informerType] {
|
||||
informers[informerType] = informer
|
||||
}
|
||||
}
|
||||
return informers
|
||||
}()
|
||||
|
||||
res := map[reflect.Type]bool{}
|
||||
for informType, informer := range informers {
|
||||
res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// InternalInformerFor returns the SharedIndexInformer for obj using an internal
|
||||
// client.
|
||||
func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
informerType := reflect.TypeOf(obj)
|
||||
informer, exists := f.informers[informerType]
|
||||
if exists {
|
||||
return informer
|
||||
}
|
||||
|
||||
resyncPeriod, exists := f.customResync[informerType]
|
||||
if !exists {
|
||||
resyncPeriod = f.defaultResync
|
||||
}
|
||||
|
||||
informer = newFunc(f.client, resyncPeriod)
|
||||
f.informers[informerType] = informer
|
||||
|
||||
return informer
|
||||
}
|
||||
|
||||
// SharedInformerFactory provides shared informers for resources in all known
|
||||
// API group versions.
|
||||
type SharedInformerFactory interface {
|
||||
internalinterfaces.SharedInformerFactory
|
||||
ForResource(resource schema.GroupVersionResource) (GenericInformer, error)
|
||||
WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool
|
||||
|
||||
Traefik() traefik.Interface
|
||||
}
|
||||
|
||||
func (f *sharedInformerFactory) Traefik() traefik.Interface {
|
||||
return traefik.New(f, f.namespace, f.tweakListOptions)
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package externalversions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
v1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// GenericInformer is type of SharedIndexInformer which will locate and delegate to other
|
||||
// sharedInformers based on type
|
||||
type GenericInformer interface {
|
||||
Informer() cache.SharedIndexInformer
|
||||
Lister() cache.GenericLister
|
||||
}
|
||||
|
||||
type genericInformer struct {
|
||||
informer cache.SharedIndexInformer
|
||||
resource schema.GroupResource
|
||||
}
|
||||
|
||||
// Informer returns the SharedIndexInformer.
|
||||
func (f *genericInformer) Informer() cache.SharedIndexInformer {
|
||||
return f.informer
|
||||
}
|
||||
|
||||
// Lister returns the GenericLister.
|
||||
func (f *genericInformer) Lister() cache.GenericLister {
|
||||
return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource)
|
||||
}
|
||||
|
||||
// ForResource gives generic access to a shared informer of the matching type
|
||||
// TODO extend this to unknown resources with a client pool
|
||||
func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) {
|
||||
switch resource {
|
||||
case v1alpha1.SchemeGroupVersion.WithResource("ingressroutes"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Traefik().V1alpha1().IngressRoutes().Informer()}, nil
|
||||
case v1alpha1.SchemeGroupVersion.WithResource("middlewares"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Traefik().V1alpha1().Middlewares().Informer()}, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("no informer found for %v", resource)
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package internalinterfaces
|
||||
|
||||
import (
|
||||
time "time"
|
||||
|
||||
versioned "github.com/containous/traefik/provider/kubernetes/crd/generated/clientset/versioned"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer
|
||||
|
||||
// SharedInformerFactory a small interface to allow for adding an informer without an import cycle
|
||||
type SharedInformerFactory interface {
|
||||
Start(stopCh <-chan struct{})
|
||||
InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer
|
||||
}
|
||||
|
||||
type TweakListOptionsFunc func(*v1.ListOptions)
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package traefik
|
||||
|
||||
import (
|
||||
internalinterfaces "github.com/containous/traefik/provider/kubernetes/crd/generated/informers/externalversions/internalinterfaces"
|
||||
v1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/generated/informers/externalversions/traefik/v1alpha1"
|
||||
)
|
||||
|
||||
// Interface provides access to each of this group's versions.
|
||||
type Interface interface {
|
||||
// V1alpha1 provides access to shared informers for resources in V1alpha1.
|
||||
V1alpha1() v1alpha1.Interface
|
||||
}
|
||||
|
||||
type group struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
namespace string
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
}
|
||||
|
||||
// New returns a new Interface.
|
||||
func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
|
||||
return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
|
||||
}
|
||||
|
||||
// V1alpha1 returns a new v1alpha1.Interface.
|
||||
func (g *group) V1alpha1() v1alpha1.Interface {
|
||||
return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions)
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
time "time"
|
||||
|
||||
versioned "github.com/containous/traefik/provider/kubernetes/crd/generated/clientset/versioned"
|
||||
internalinterfaces "github.com/containous/traefik/provider/kubernetes/crd/generated/informers/externalversions/internalinterfaces"
|
||||
v1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/generated/listers/traefik/v1alpha1"
|
||||
traefikv1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// IngressRouteInformer provides access to a shared informer and lister for
|
||||
// IngressRoutes.
|
||||
type IngressRouteInformer interface {
|
||||
Informer() cache.SharedIndexInformer
|
||||
Lister() v1alpha1.IngressRouteLister
|
||||
}
|
||||
|
||||
type ingressRouteInformer struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
namespace string
|
||||
}
|
||||
|
||||
// NewIngressRouteInformer constructs a new informer for IngressRoute type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewIngressRouteInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
|
||||
return NewFilteredIngressRouteInformer(client, namespace, resyncPeriod, indexers, nil)
|
||||
}
|
||||
|
||||
// NewFilteredIngressRouteInformer constructs a new informer for IngressRoute type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewFilteredIngressRouteInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
|
||||
return cache.NewSharedIndexInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.TraefikV1alpha1().IngressRoutes(namespace).List(options)
|
||||
},
|
||||
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.TraefikV1alpha1().IngressRoutes(namespace).Watch(options)
|
||||
},
|
||||
},
|
||||
&traefikv1alpha1.IngressRoute{},
|
||||
resyncPeriod,
|
||||
indexers,
|
||||
)
|
||||
}
|
||||
|
||||
func (f *ingressRouteInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
|
||||
return NewFilteredIngressRouteInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
|
||||
}
|
||||
|
||||
func (f *ingressRouteInformer) Informer() cache.SharedIndexInformer {
|
||||
return f.factory.InformerFor(&traefikv1alpha1.IngressRoute{}, f.defaultInformer)
|
||||
}
|
||||
|
||||
func (f *ingressRouteInformer) Lister() v1alpha1.IngressRouteLister {
|
||||
return v1alpha1.NewIngressRouteLister(f.Informer().GetIndexer())
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
internalinterfaces "github.com/containous/traefik/provider/kubernetes/crd/generated/informers/externalversions/internalinterfaces"
|
||||
)
|
||||
|
||||
// Interface provides access to all the informers in this group version.
|
||||
type Interface interface {
|
||||
// IngressRoutes returns a IngressRouteInformer.
|
||||
IngressRoutes() IngressRouteInformer
|
||||
// Middlewares returns a MiddlewareInformer.
|
||||
Middlewares() MiddlewareInformer
|
||||
}
|
||||
|
||||
type version struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
namespace string
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
}
|
||||
|
||||
// New returns a new Interface.
|
||||
func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
|
||||
return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
|
||||
}
|
||||
|
||||
// IngressRoutes returns a IngressRouteInformer.
|
||||
func (v *version) IngressRoutes() IngressRouteInformer {
|
||||
return &ingressRouteInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
|
||||
}
|
||||
|
||||
// Middlewares returns a MiddlewareInformer.
|
||||
func (v *version) Middlewares() MiddlewareInformer {
|
||||
return &middlewareInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
time "time"
|
||||
|
||||
versioned "github.com/containous/traefik/provider/kubernetes/crd/generated/clientset/versioned"
|
||||
internalinterfaces "github.com/containous/traefik/provider/kubernetes/crd/generated/informers/externalversions/internalinterfaces"
|
||||
v1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/generated/listers/traefik/v1alpha1"
|
||||
traefikv1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// MiddlewareInformer provides access to a shared informer and lister for
|
||||
// Middlewares.
|
||||
type MiddlewareInformer interface {
|
||||
Informer() cache.SharedIndexInformer
|
||||
Lister() v1alpha1.MiddlewareLister
|
||||
}
|
||||
|
||||
type middlewareInformer struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
namespace string
|
||||
}
|
||||
|
||||
// NewMiddlewareInformer constructs a new informer for Middleware type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewMiddlewareInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
|
||||
return NewFilteredMiddlewareInformer(client, namespace, resyncPeriod, indexers, nil)
|
||||
}
|
||||
|
||||
// NewFilteredMiddlewareInformer constructs a new informer for Middleware type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewFilteredMiddlewareInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
|
||||
return cache.NewSharedIndexInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.TraefikV1alpha1().Middlewares(namespace).List(options)
|
||||
},
|
||||
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.TraefikV1alpha1().Middlewares(namespace).Watch(options)
|
||||
},
|
||||
},
|
||||
&traefikv1alpha1.Middleware{},
|
||||
resyncPeriod,
|
||||
indexers,
|
||||
)
|
||||
}
|
||||
|
||||
func (f *middlewareInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
|
||||
return NewFilteredMiddlewareInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
|
||||
}
|
||||
|
||||
func (f *middlewareInformer) Informer() cache.SharedIndexInformer {
|
||||
return f.factory.InformerFor(&traefikv1alpha1.Middleware{}, f.defaultInformer)
|
||||
}
|
||||
|
||||
func (f *middlewareInformer) Lister() v1alpha1.MiddlewareLister {
|
||||
return v1alpha1.NewMiddlewareLister(f.Informer().GetIndexer())
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by lister-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
// IngressRouteListerExpansion allows custom methods to be added to
|
||||
// IngressRouteLister.
|
||||
type IngressRouteListerExpansion interface{}
|
||||
|
||||
// IngressRouteNamespaceListerExpansion allows custom methods to be added to
|
||||
// IngressRouteNamespaceLister.
|
||||
type IngressRouteNamespaceListerExpansion interface{}
|
||||
|
||||
// MiddlewareListerExpansion allows custom methods to be added to
|
||||
// MiddlewareLister.
|
||||
type MiddlewareListerExpansion interface{}
|
||||
|
||||
// MiddlewareNamespaceListerExpansion allows custom methods to be added to
|
||||
// MiddlewareNamespaceLister.
|
||||
type MiddlewareNamespaceListerExpansion interface{}
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by lister-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
v1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// IngressRouteLister helps list IngressRoutes.
|
||||
type IngressRouteLister interface {
|
||||
// List lists all IngressRoutes in the indexer.
|
||||
List(selector labels.Selector) (ret []*v1alpha1.IngressRoute, err error)
|
||||
// IngressRoutes returns an object that can list and get IngressRoutes.
|
||||
IngressRoutes(namespace string) IngressRouteNamespaceLister
|
||||
IngressRouteListerExpansion
|
||||
}
|
||||
|
||||
// ingressRouteLister implements the IngressRouteLister interface.
|
||||
type ingressRouteLister struct {
|
||||
indexer cache.Indexer
|
||||
}
|
||||
|
||||
// NewIngressRouteLister returns a new IngressRouteLister.
|
||||
func NewIngressRouteLister(indexer cache.Indexer) IngressRouteLister {
|
||||
return &ingressRouteLister{indexer: indexer}
|
||||
}
|
||||
|
||||
// List lists all IngressRoutes in the indexer.
|
||||
func (s *ingressRouteLister) List(selector labels.Selector) (ret []*v1alpha1.IngressRoute, err error) {
|
||||
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1alpha1.IngressRoute))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// IngressRoutes returns an object that can list and get IngressRoutes.
|
||||
func (s *ingressRouteLister) IngressRoutes(namespace string) IngressRouteNamespaceLister {
|
||||
return ingressRouteNamespaceLister{indexer: s.indexer, namespace: namespace}
|
||||
}
|
||||
|
||||
// IngressRouteNamespaceLister helps list and get IngressRoutes.
|
||||
type IngressRouteNamespaceLister interface {
|
||||
// List lists all IngressRoutes in the indexer for a given namespace.
|
||||
List(selector labels.Selector) (ret []*v1alpha1.IngressRoute, err error)
|
||||
// Get retrieves the IngressRoute from the indexer for a given namespace and name.
|
||||
Get(name string) (*v1alpha1.IngressRoute, error)
|
||||
IngressRouteNamespaceListerExpansion
|
||||
}
|
||||
|
||||
// ingressRouteNamespaceLister implements the IngressRouteNamespaceLister
|
||||
// interface.
|
||||
type ingressRouteNamespaceLister struct {
|
||||
indexer cache.Indexer
|
||||
namespace string
|
||||
}
|
||||
|
||||
// List lists all IngressRoutes in the indexer for a given namespace.
|
||||
func (s ingressRouteNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.IngressRoute, err error) {
|
||||
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1alpha1.IngressRoute))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get retrieves the IngressRoute from the indexer for a given namespace and name.
|
||||
func (s ingressRouteNamespaceLister) Get(name string) (*v1alpha1.IngressRoute, error) {
|
||||
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exists {
|
||||
return nil, errors.NewNotFound(v1alpha1.Resource("ingressroute"), name)
|
||||
}
|
||||
return obj.(*v1alpha1.IngressRoute), nil
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by lister-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
v1alpha1 "github.com/containous/traefik/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// MiddlewareLister helps list Middlewares.
|
||||
type MiddlewareLister interface {
|
||||
// List lists all Middlewares in the indexer.
|
||||
List(selector labels.Selector) (ret []*v1alpha1.Middleware, err error)
|
||||
// Middlewares returns an object that can list and get Middlewares.
|
||||
Middlewares(namespace string) MiddlewareNamespaceLister
|
||||
MiddlewareListerExpansion
|
||||
}
|
||||
|
||||
// middlewareLister implements the MiddlewareLister interface.
|
||||
type middlewareLister struct {
|
||||
indexer cache.Indexer
|
||||
}
|
||||
|
||||
// NewMiddlewareLister returns a new MiddlewareLister.
|
||||
func NewMiddlewareLister(indexer cache.Indexer) MiddlewareLister {
|
||||
return &middlewareLister{indexer: indexer}
|
||||
}
|
||||
|
||||
// List lists all Middlewares in the indexer.
|
||||
func (s *middlewareLister) List(selector labels.Selector) (ret []*v1alpha1.Middleware, err error) {
|
||||
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1alpha1.Middleware))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Middlewares returns an object that can list and get Middlewares.
|
||||
func (s *middlewareLister) Middlewares(namespace string) MiddlewareNamespaceLister {
|
||||
return middlewareNamespaceLister{indexer: s.indexer, namespace: namespace}
|
||||
}
|
||||
|
||||
// MiddlewareNamespaceLister helps list and get Middlewares.
|
||||
type MiddlewareNamespaceLister interface {
|
||||
// List lists all Middlewares in the indexer for a given namespace.
|
||||
List(selector labels.Selector) (ret []*v1alpha1.Middleware, err error)
|
||||
// Get retrieves the Middleware from the indexer for a given namespace and name.
|
||||
Get(name string) (*v1alpha1.Middleware, error)
|
||||
MiddlewareNamespaceListerExpansion
|
||||
}
|
||||
|
||||
// middlewareNamespaceLister implements the MiddlewareNamespaceLister
|
||||
// interface.
|
||||
type middlewareNamespaceLister struct {
|
||||
indexer cache.Indexer
|
||||
namespace string
|
||||
}
|
||||
|
||||
// List lists all Middlewares in the indexer for a given namespace.
|
||||
func (s middlewareNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.Middleware, err error) {
|
||||
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1alpha1.Middleware))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get retrieves the Middleware from the indexer for a given namespace and name.
|
||||
func (s middlewareNamespaceLister) Get(name string) (*v1alpha1.Middleware, error) {
|
||||
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exists {
|
||||
return nil, errors.NewNotFound(v1alpha1.Resource("middleware"), name)
|
||||
}
|
||||
return obj.(*v1alpha1.Middleware), nil
|
||||
}
|
458
provider/kubernetes/crd/kubernetes.go
Normal file
458
provider/kubernetes/crd/kubernetes.go
Normal file
|
@ -0,0 +1,458 @@
|
|||
package crd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff"
|
||||
"github.com/containous/traefik/config"
|
||||
"github.com/containous/traefik/job"
|
||||
"github.com/containous/traefik/log"
|
||||
"github.com/containous/traefik/provider"
|
||||
"github.com/containous/traefik/provider/kubernetes/crd/traefik/v1alpha1"
|
||||
"github.com/containous/traefik/provider/kubernetes/k8s"
|
||||
"github.com/containous/traefik/safe"
|
||||
"github.com/containous/traefik/tls"
|
||||
"github.com/pkg/errors"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
const (
|
||||
annotationKubernetesIngressClass = "kubernetes.io/ingress.class"
|
||||
traefikDefaultIngressClass = "traefik"
|
||||
)
|
||||
|
||||
// IngressEndpoint holds the endpoint information for the Kubernetes provider.
|
||||
type IngressEndpoint struct {
|
||||
IP string `description:"IP used for Kubernetes Ingress endpoints"`
|
||||
Hostname string `description:"Hostname used for Kubernetes Ingress endpoints"`
|
||||
PublishedService string `description:"Published Kubernetes Service to copy status from"`
|
||||
}
|
||||
|
||||
// Provider holds configurations of the provider.
|
||||
type Provider struct {
|
||||
provider.BaseProvider `mapstructure:",squash" export:"true"`
|
||||
Endpoint string `description:"Kubernetes server endpoint (required for external cluster client)"`
|
||||
Token string `description:"Kubernetes bearer token (not needed for in-cluster client)"`
|
||||
CertAuthFilePath string `description:"Kubernetes certificate authority file path (not needed for in-cluster client)"`
|
||||
DisablePassHostHeaders bool `description:"Kubernetes disable PassHost Headers" export:"true"`
|
||||
EnablePassTLSCert bool `description:"Kubernetes enable Pass TLS Client Certs" export:"true"` // Deprecated
|
||||
Namespaces k8s.Namespaces `description:"Kubernetes namespaces" export:"true"`
|
||||
LabelSelector string `description:"Kubernetes Ingress label selector to use" export:"true"`
|
||||
IngressClass string `description:"Value of kubernetes.io/ingress.class annotation to watch for" export:"true"`
|
||||
IngressEndpoint *IngressEndpoint `description:"Kubernetes Ingress Endpoint"`
|
||||
lastConfiguration safe.Safe
|
||||
}
|
||||
|
||||
func (p *Provider) newK8sClient(ctx context.Context, ingressLabelSelector string) (*clientWrapper, error) {
|
||||
ingLabelSel, err := labels.Parse(ingressLabelSelector)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid ingress label selector: %q", ingressLabelSelector)
|
||||
}
|
||||
log.FromContext(ctx).Infof("ingress label selector is: %q", ingLabelSel)
|
||||
|
||||
withEndpoint := ""
|
||||
if p.Endpoint != "" {
|
||||
withEndpoint = fmt.Sprintf(" with endpoint %v", p.Endpoint)
|
||||
}
|
||||
|
||||
var client *clientWrapper
|
||||
switch {
|
||||
case os.Getenv("KUBERNETES_SERVICE_HOST") != "" && os.Getenv("KUBERNETES_SERVICE_PORT") != "":
|
||||
log.FromContext(ctx).Infof("Creating in-cluster Provider client%s", withEndpoint)
|
||||
client, err = newInClusterClient(p.Endpoint)
|
||||
case os.Getenv("KUBECONFIG") != "":
|
||||
log.FromContext(ctx).Infof("Creating cluster-external Provider client from KUBECONFIG %s", os.Getenv("KUBECONFIG"))
|
||||
client, err = newExternalClusterClientFromFile(os.Getenv("KUBECONFIG"))
|
||||
default:
|
||||
log.FromContext(ctx).Infof("Creating cluster-external Provider client%s", withEndpoint)
|
||||
client, err = newExternalClusterClient(p.Endpoint, p.Token, p.CertAuthFilePath)
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
client.ingressLabelSelector = ingLabelSel
|
||||
}
|
||||
|
||||
return client, err
|
||||
}
|
||||
|
||||
// Init the provider.
|
||||
func (p *Provider) Init() error {
|
||||
return p.BaseProvider.Init()
|
||||
}
|
||||
|
||||
// Provide allows the k8s provider to provide configurations to traefik
|
||||
// using the given configuration channel.
|
||||
func (p *Provider) Provide(configurationChan chan<- config.Message, pool *safe.Pool) error {
|
||||
ctxLog := log.With(context.Background(), log.Str(log.ProviderName, "kubernetescrd"))
|
||||
logger := log.FromContext(ctxLog)
|
||||
// Tell glog (used by client-go) to log into STDERR. Otherwise, we risk
|
||||
// certain kinds of API errors getting logged into a directory not
|
||||
// available in a `FROM scratch` Docker container, causing glog to abort
|
||||
// hard with an exit code > 0.
|
||||
err := flag.Set("logtostderr", "true")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Debugf("Using Ingress label selector: %q", p.LabelSelector)
|
||||
k8sClient, err := p.newK8sClient(ctxLog, p.LabelSelector)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pool.Go(func(stop chan bool) {
|
||||
operation := func() error {
|
||||
stopWatch := make(chan struct{}, 1)
|
||||
defer close(stopWatch)
|
||||
eventsChan, err := k8sClient.WatchAll(p.Namespaces, stopWatch)
|
||||
if err != nil {
|
||||
logger.Errorf("Error watching kubernetes events: %v", err)
|
||||
timer := time.NewTimer(1 * time.Second)
|
||||
select {
|
||||
case <-timer.C:
|
||||
return err
|
||||
case <-stop:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
for {
|
||||
select {
|
||||
case <-stop:
|
||||
return nil
|
||||
case event := <-eventsChan:
|
||||
conf := p.loadConfigurationFromIngresses(ctxLog, k8sClient)
|
||||
|
||||
if reflect.DeepEqual(p.lastConfiguration.Get(), conf) {
|
||||
logger.Debugf("Skipping Kubernetes event kind %T", event)
|
||||
} else {
|
||||
p.lastConfiguration.Set(conf)
|
||||
configurationChan <- config.Message{
|
||||
ProviderName: "kubernetescrd",
|
||||
Configuration: conf,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
notify := func(err error, time time.Duration) {
|
||||
logger.Errorf("Provider connection error: %s; retrying in %s", err, time)
|
||||
}
|
||||
err := backoff.RetryNotify(safe.OperationWithRecover(operation), job.NewBackOff(backoff.NewExponentialBackOff()), notify)
|
||||
if err != nil {
|
||||
logger.Errorf("Cannot connect to Provider: %s", err)
|
||||
}
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkStringQuoteValidity(value string) error {
|
||||
_, err := strconv.Unquote(`"` + value + `"`)
|
||||
return err
|
||||
}
|
||||
|
||||
func loadServers(client Client, namespace string, svc v1alpha1.Service) ([]config.Server, error) {
|
||||
strategy := svc.Strategy
|
||||
if strategy == "" {
|
||||
strategy = "RoundRobin"
|
||||
}
|
||||
if strategy != "RoundRobin" {
|
||||
return nil, fmt.Errorf("load balancing strategy %v is not supported", strategy)
|
||||
}
|
||||
|
||||
service, exists, err := client.GetService(namespace, svc.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !exists {
|
||||
return nil, errors.New("service not found")
|
||||
}
|
||||
|
||||
var portSpec corev1.ServicePort
|
||||
var match bool
|
||||
// TODO: support name ports? do we actually care?
|
||||
for _, p := range service.Spec.Ports {
|
||||
if svc.Port == p.Port {
|
||||
portSpec = p
|
||||
match = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !match {
|
||||
return nil, errors.New("service port not found")
|
||||
}
|
||||
|
||||
var servers []config.Server
|
||||
if service.Spec.Type == corev1.ServiceTypeExternalName {
|
||||
servers = append(servers, config.Server{
|
||||
URL: fmt.Sprintf("http://%s:%d", service.Spec.ExternalName, portSpec.Port),
|
||||
Weight: 1,
|
||||
})
|
||||
} else {
|
||||
endpoints, endpointsExists, endpointsErr := client.GetEndpoints(namespace, svc.Name)
|
||||
if endpointsErr != nil {
|
||||
return nil, endpointsErr
|
||||
}
|
||||
|
||||
if !endpointsExists {
|
||||
return nil, errors.New("endpoints not found")
|
||||
}
|
||||
|
||||
if len(endpoints.Subsets) == 0 {
|
||||
return nil, errors.New("subset not found")
|
||||
}
|
||||
|
||||
var port int32
|
||||
for _, subset := range endpoints.Subsets {
|
||||
for _, p := range subset.Ports {
|
||||
if portSpec.Name == p.Name {
|
||||
port = p.Port
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if port == 0 {
|
||||
return nil, errors.New("cannot define a port")
|
||||
}
|
||||
|
||||
protocol := "http"
|
||||
if port == 443 || strings.HasPrefix(portSpec.Name, "https") {
|
||||
protocol = "https"
|
||||
}
|
||||
|
||||
for _, addr := range subset.Addresses {
|
||||
servers = append(servers, config.Server{
|
||||
URL: fmt.Sprintf("%s://%s:%d", protocol, addr.IP, port),
|
||||
Weight: 1,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return servers, nil
|
||||
}
|
||||
|
||||
func (p *Provider) loadConfigurationFromIngresses(ctx context.Context, client Client) *config.Configuration {
|
||||
|
||||
conf := &config.Configuration{
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{},
|
||||
},
|
||||
TCP: &config.TCPConfiguration{},
|
||||
}
|
||||
tlsConfigs := make(map[string]*tls.Configuration)
|
||||
|
||||
for _, ingressRoute := range client.GetIngressRoutes() {
|
||||
logger := log.FromContext(log.With(ctx, log.Str("ingress", ingressRoute.Name), log.Str("namespace", ingressRoute.Namespace)))
|
||||
|
||||
// TODO keep the name ingressClass?
|
||||
if !shouldProcessIngress(p.IngressClass, ingressRoute.Annotations[annotationKubernetesIngressClass]) {
|
||||
continue
|
||||
}
|
||||
|
||||
err := getTLS(ctx, ingressRoute, client, tlsConfigs)
|
||||
if err != nil {
|
||||
logger.Errorf("Error configuring TLS: %v", err)
|
||||
}
|
||||
|
||||
ingressName := ingressRoute.Name
|
||||
if len(ingressName) == 0 {
|
||||
ingressName = ingressRoute.GenerateName
|
||||
}
|
||||
|
||||
for _, route := range ingressRoute.Spec.Routes {
|
||||
if route.Kind != "Rule" {
|
||||
logger.Errorf("Unsupported match kind: %s. Only \"Rule\" is supported for now.", route.Kind)
|
||||
continue
|
||||
}
|
||||
|
||||
if len(route.Match) == 0 {
|
||||
logger.Errorf("Empty match rule")
|
||||
continue
|
||||
}
|
||||
|
||||
if err := checkStringQuoteValidity(route.Match); err != nil {
|
||||
logger.Errorf("Invalid syntax for match rule: %s", route.Match)
|
||||
continue
|
||||
}
|
||||
|
||||
var allServers []config.Server
|
||||
for _, service := range route.Services {
|
||||
servers, err := loadServers(client, ingressRoute.Namespace, service)
|
||||
if err != nil {
|
||||
logger.
|
||||
WithField("serviceName", service.Name).
|
||||
WithField("servicePort", service.Port).
|
||||
Errorf("Cannot create service: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
allServers = append(allServers, servers...)
|
||||
}
|
||||
|
||||
// TODO: support middlewares from other providers.
|
||||
// Mechanism: in the spec, prefix the name with the provider name,
|
||||
// with dot as the separator. In which case. we ignore the
|
||||
// namespace.
|
||||
|
||||
var mds []string
|
||||
for _, mi := range route.Middlewares {
|
||||
ns := mi.Namespace
|
||||
if len(ns) == 0 {
|
||||
ns = ingressRoute.Namespace
|
||||
}
|
||||
mds = append(mds, makeID(ns, mi.Name))
|
||||
}
|
||||
|
||||
h := sha256.New()
|
||||
_, err = h.Write([]byte(route.Match))
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
continue
|
||||
}
|
||||
key := fmt.Sprintf("%s-%.10x", ingressName, h.Sum(nil))
|
||||
|
||||
serviceName := makeID(ingressRoute.Namespace, key)
|
||||
|
||||
conf.HTTP.Routers[serviceName] = &config.Router{
|
||||
Middlewares: mds,
|
||||
Priority: route.Priority,
|
||||
EntryPoints: ingressRoute.Spec.EntryPoints,
|
||||
Rule: route.Match,
|
||||
Service: serviceName,
|
||||
}
|
||||
if ingressRoute.Spec.TLS != nil {
|
||||
conf.HTTP.Routers[serviceName].TLS = &config.RouterTLSConfig{}
|
||||
}
|
||||
conf.HTTP.Services[serviceName] = &config.Service{
|
||||
LoadBalancer: &config.LoadBalancerService{
|
||||
Servers: allServers,
|
||||
// TODO: support other strategies.
|
||||
Method: "wrr",
|
||||
PassHostHeader: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
conf.TLS = getTLSConfig(tlsConfigs)
|
||||
|
||||
for _, middleware := range client.GetMiddlewares() {
|
||||
conf.HTTP.Middlewares[makeID(middleware.Namespace, middleware.Name)] = &middleware.Spec
|
||||
}
|
||||
|
||||
return conf
|
||||
}
|
||||
|
||||
func makeID(namespace, name string) string {
|
||||
if namespace == "" {
|
||||
return name
|
||||
}
|
||||
return namespace + "/" + name
|
||||
}
|
||||
|
||||
func shouldProcessIngress(ingressClass string, ingressClassAnnotation string) bool {
|
||||
return ingressClass == ingressClassAnnotation ||
|
||||
(len(ingressClass) == 0 && ingressClassAnnotation == traefikDefaultIngressClass)
|
||||
}
|
||||
|
||||
func getTLS(ctx context.Context, ingressRoute *v1alpha1.IngressRoute, k8sClient Client, tlsConfigs map[string]*tls.Configuration) error {
|
||||
if ingressRoute.Spec.TLS == nil {
|
||||
return nil
|
||||
}
|
||||
if ingressRoute.Spec.TLS.SecretName == "" {
|
||||
log.FromContext(ctx).Debugf("Skipping TLS sub-section: No secret name provided")
|
||||
return nil
|
||||
}
|
||||
|
||||
configKey := ingressRoute.Namespace + "/" + ingressRoute.Spec.TLS.SecretName
|
||||
if _, tlsExists := tlsConfigs[configKey]; !tlsExists {
|
||||
secret, exists, err := k8sClient.GetSecret(ingressRoute.Namespace, ingressRoute.Spec.TLS.SecretName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to fetch secret %s/%s: %v", ingressRoute.Namespace, ingressRoute.Spec.TLS.SecretName, err)
|
||||
}
|
||||
if !exists {
|
||||
return fmt.Errorf("secret %s/%s does not exist", ingressRoute.Namespace, ingressRoute.Spec.TLS.SecretName)
|
||||
}
|
||||
|
||||
cert, key, err := getCertificateBlocks(secret, ingressRoute.Namespace, ingressRoute.Spec.TLS.SecretName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tlsConfigs[configKey] = &tls.Configuration{
|
||||
Certificate: &tls.Certificate{
|
||||
CertFile: tls.FileOrContent(cert),
|
||||
KeyFile: tls.FileOrContent(key),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getTLSConfig(tlsConfigs map[string]*tls.Configuration) []*tls.Configuration {
|
||||
var secretNames []string
|
||||
for secretName := range tlsConfigs {
|
||||
secretNames = append(secretNames, secretName)
|
||||
}
|
||||
sort.Strings(secretNames)
|
||||
|
||||
var configs []*tls.Configuration
|
||||
for _, secretName := range secretNames {
|
||||
configs = append(configs, tlsConfigs[secretName])
|
||||
}
|
||||
|
||||
return configs
|
||||
}
|
||||
|
||||
func getCertificateBlocks(secret *corev1.Secret, namespace, secretName string) (string, string, error) {
|
||||
var missingEntries []string
|
||||
|
||||
tlsCrtData, tlsCrtExists := secret.Data["tls.crt"]
|
||||
if !tlsCrtExists {
|
||||
missingEntries = append(missingEntries, "tls.crt")
|
||||
}
|
||||
|
||||
tlsKeyData, tlsKeyExists := secret.Data["tls.key"]
|
||||
if !tlsKeyExists {
|
||||
missingEntries = append(missingEntries, "tls.key")
|
||||
}
|
||||
|
||||
if len(missingEntries) > 0 {
|
||||
return "", "", fmt.Errorf("secret %s/%s is missing the following TLS data entries: %s",
|
||||
namespace, secretName, strings.Join(missingEntries, ", "))
|
||||
}
|
||||
|
||||
cert := string(tlsCrtData)
|
||||
if cert == "" {
|
||||
missingEntries = append(missingEntries, "tls.crt")
|
||||
}
|
||||
|
||||
key := string(tlsKeyData)
|
||||
if key == "" {
|
||||
missingEntries = append(missingEntries, "tls.key")
|
||||
}
|
||||
|
||||
if len(missingEntries) > 0 {
|
||||
return "", "", fmt.Errorf("secret %s/%s contains the following empty TLS data entries: %s",
|
||||
namespace, secretName, strings.Join(missingEntries, ", "))
|
||||
}
|
||||
|
||||
return cert, key, nil
|
||||
}
|
368
provider/kubernetes/crd/kubernetes_test.go
Normal file
368
provider/kubernetes/crd/kubernetes_test.go
Normal file
|
@ -0,0 +1,368 @@
|
|||
package crd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/containous/traefik/config"
|
||||
"github.com/containous/traefik/provider"
|
||||
"github.com/containous/traefik/tls"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var _ provider.Provider = (*Provider)(nil)
|
||||
|
||||
func TestLoadIngressRoutes(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
ingressClass string
|
||||
paths []string
|
||||
expected *config.Configuration
|
||||
}{
|
||||
{
|
||||
desc: "Empty",
|
||||
expected: &config.Configuration{
|
||||
TCP: &config.TCPConfiguration{},
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Simple Ingress Route, with foo entrypoint",
|
||||
paths: []string{"services.yml", "simple.yml"},
|
||||
expected: &config.Configuration{
|
||||
TCP: &config.TCPConfiguration{},
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{
|
||||
"default/test.crd-6b204d94623b3df4370c": {
|
||||
EntryPoints: []string{"foo"},
|
||||
Service: "default/test.crd-6b204d94623b3df4370c",
|
||||
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
|
||||
Priority: 12,
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{
|
||||
"default/test.crd-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &config.LoadBalancerService{
|
||||
Servers: []config.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
Weight: 1,
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
Weight: 1,
|
||||
},
|
||||
},
|
||||
Method: "wrr",
|
||||
PassHostHeader: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Simple Ingress Route with middleware",
|
||||
paths: []string{"services.yml", "with_middleware.yml"},
|
||||
expected: &config.Configuration{
|
||||
TCP: &config.TCPConfiguration{},
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{
|
||||
"default/test2.crd-23c7f4c450289ee29016": {
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "default/test2.crd-23c7f4c450289ee29016",
|
||||
Rule: "Host(`foo.com`) && PathPrefix(`/tobestripped`)",
|
||||
Priority: 12,
|
||||
Middlewares: []string{"default/stripprefix", "foo/addprefix"},
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*config.Middleware{
|
||||
"default/stripprefix": {
|
||||
StripPrefix: &config.StripPrefix{
|
||||
Prefixes: []string{"/tobestripped"},
|
||||
},
|
||||
},
|
||||
"foo/addprefix": {
|
||||
AddPrefix: &config.AddPrefix{
|
||||
Prefix: "/tobeadded",
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*config.Service{
|
||||
"default/test2.crd-23c7f4c450289ee29016": {
|
||||
LoadBalancer: &config.LoadBalancerService{
|
||||
Servers: []config.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
Weight: 1,
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
Weight: 1,
|
||||
},
|
||||
},
|
||||
Method: "wrr",
|
||||
PassHostHeader: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "One ingress Route with two different rules",
|
||||
paths: []string{"services.yml", "with_two_rules.yml"},
|
||||
expected: &config.Configuration{
|
||||
TCP: &config.TCPConfiguration{},
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{
|
||||
"default/test.crd-6b204d94623b3df4370c": {
|
||||
EntryPoints: []string{"web"},
|
||||
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
|
||||
Service: "default/test.crd-6b204d94623b3df4370c",
|
||||
Priority: 14,
|
||||
},
|
||||
"default/test.crd-77c62dfe9517144aeeaa": {
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "default/test.crd-77c62dfe9517144aeeaa",
|
||||
Rule: "Host(`foo.com`) && PathPrefix(`/foo`)",
|
||||
Priority: 12,
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{
|
||||
"default/test.crd-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &config.LoadBalancerService{
|
||||
Servers: []config.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
Weight: 1,
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
Weight: 1,
|
||||
},
|
||||
},
|
||||
Method: "wrr",
|
||||
PassHostHeader: true,
|
||||
},
|
||||
},
|
||||
"default/test.crd-77c62dfe9517144aeeaa": {
|
||||
LoadBalancer: &config.LoadBalancerService{
|
||||
Servers: []config.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
Weight: 1,
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
Weight: 1,
|
||||
},
|
||||
},
|
||||
Method: "wrr",
|
||||
PassHostHeader: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "One ingress Route with two different services, their servers will merge",
|
||||
paths: []string{"services.yml", "with_two_services.yml"},
|
||||
expected: &config.Configuration{
|
||||
TCP: &config.TCPConfiguration{},
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{
|
||||
"default/test.crd-77c62dfe9517144aeeaa": {
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "default/test.crd-77c62dfe9517144aeeaa",
|
||||
Rule: "Host(`foo.com`) && PathPrefix(`/foo`)",
|
||||
Priority: 12,
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{
|
||||
"default/test.crd-77c62dfe9517144aeeaa": {
|
||||
LoadBalancer: &config.LoadBalancerService{
|
||||
Servers: []config.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
Weight: 1,
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
Weight: 1,
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.3:8080",
|
||||
Weight: 1,
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.4:8080",
|
||||
Weight: 1,
|
||||
},
|
||||
},
|
||||
Method: "wrr",
|
||||
PassHostHeader: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Ingress class",
|
||||
paths: []string{"services.yml", "simple.yml"},
|
||||
ingressClass: "tchouk",
|
||||
expected: &config.Configuration{
|
||||
TCP: &config.TCPConfiguration{},
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Route with empty rule value is ignored",
|
||||
paths: []string{"services.yml", "with_no_rule_value.yml"},
|
||||
expected: &config.Configuration{
|
||||
TCP: &config.TCPConfiguration{},
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Route with kind not of a rule type (empty kind) is ignored",
|
||||
paths: []string{"services.yml", "with_wrong_rule_kind.yml"},
|
||||
expected: &config.Configuration{
|
||||
TCP: &config.TCPConfiguration{},
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "check rule quoting validity",
|
||||
paths: []string{"services.yml", "with_bad_host_rule.yml"},
|
||||
expected: &config.Configuration{
|
||||
TCP: &config.TCPConfiguration{},
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "TLS",
|
||||
paths: []string{"services.yml", "with_tls.yml"},
|
||||
expected: &config.Configuration{
|
||||
TLS: []*tls.Configuration{
|
||||
{
|
||||
Certificate: &tls.Certificate{
|
||||
CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||
KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
||||
},
|
||||
},
|
||||
},
|
||||
TCP: &config.TCPConfiguration{},
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{
|
||||
"default/test.crd-6b204d94623b3df4370c": {
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "default/test.crd-6b204d94623b3df4370c",
|
||||
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
|
||||
Priority: 12,
|
||||
TLS: &config.RouterTLSConfig{},
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{
|
||||
"default/test.crd-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &config.LoadBalancerService{
|
||||
Servers: []config.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
Weight: 1,
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
Weight: 1,
|
||||
},
|
||||
},
|
||||
Method: "wrr",
|
||||
PassHostHeader: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Simple Ingress Route, defaulting to https for servers",
|
||||
paths: []string{"services.yml", "with_https_default.yml"},
|
||||
expected: &config.Configuration{
|
||||
TCP: &config.TCPConfiguration{},
|
||||
HTTP: &config.HTTPConfiguration{
|
||||
Routers: map[string]*config.Router{
|
||||
"default/test.crd-6b204d94623b3df4370c": {
|
||||
EntryPoints: []string{"foo"},
|
||||
Service: "default/test.crd-6b204d94623b3df4370c",
|
||||
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
|
||||
Priority: 12,
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*config.Middleware{},
|
||||
Services: map[string]*config.Service{
|
||||
"default/test.crd-6b204d94623b3df4370c": {
|
||||
LoadBalancer: &config.LoadBalancerService{
|
||||
Servers: []config.Server{
|
||||
{
|
||||
URL: "https://10.10.0.5:443",
|
||||
Weight: 1,
|
||||
},
|
||||
{
|
||||
URL: "https://10.10.0.6:443",
|
||||
Weight: 1,
|
||||
},
|
||||
},
|
||||
Method: "wrr",
|
||||
PassHostHeader: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "port selected by name (TODO)",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if test.expected == nil {
|
||||
return
|
||||
}
|
||||
|
||||
p := Provider{IngressClass: test.ingressClass}
|
||||
conf := p.loadConfigurationFromIngresses(context.Background(), newClientMock(test.paths...))
|
||||
assert.Equal(t, test.expected, conf)
|
||||
})
|
||||
}
|
||||
}
|
5
provider/kubernetes/crd/traefik/v1alpha1/doc.go
Normal file
5
provider/kubernetes/crd/traefik/v1alpha1/doc.go
Normal file
|
@ -0,0 +1,5 @@
|
|||
// +k8s:deepcopy-gen=package
|
||||
|
||||
// Package v1alpha1 is the v1alpha1 version of the API.
|
||||
// +groupName=traefik.containo.us
|
||||
package v1alpha1
|
72
provider/kubernetes/crd/traefik/v1alpha1/ingressroute.go
Normal file
72
provider/kubernetes/crd/traefik/v1alpha1/ingressroute.go
Normal file
|
@ -0,0 +1,72 @@
|
|||
package v1alpha1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// IngressRouteSpec is a specification for a IngressRouteSpec resource.
|
||||
type IngressRouteSpec struct {
|
||||
Routes []Route `json:"routes"`
|
||||
EntryPoints []string `json:"entryPoints"`
|
||||
TLS *TLS `json:"tls,omitempty"`
|
||||
}
|
||||
|
||||
// Route contains the set of routes.
|
||||
type Route struct {
|
||||
Match string `json:"match"`
|
||||
Kind string `json:"kind"`
|
||||
Priority int `json:"priority"`
|
||||
Services []Service `json:"services,omitempty"`
|
||||
Middlewares []MiddlewareRef `json:"middlewares"`
|
||||
}
|
||||
|
||||
// TLS contains the TLS certificates configuration of the routes.
|
||||
type TLS struct {
|
||||
SecretName string `json:"secretName"`
|
||||
// TODO MinimumProtocolVersion string `json:"minimumProtocolVersion,omitempty"`
|
||||
}
|
||||
|
||||
// Service defines an upstream to proxy traffic.
|
||||
type Service struct {
|
||||
Name string `json:"name"`
|
||||
Port int32 `json:"port"`
|
||||
// TODO Weight int `json:"weight,omitempty"`
|
||||
HealthCheck *HealthCheck `json:"healthCheck,omitempty"`
|
||||
Strategy string `json:"strategy,omitempty"`
|
||||
}
|
||||
|
||||
// MiddlewareRef is a ref to the Middleware resources.
|
||||
type MiddlewareRef struct {
|
||||
Name string `json:"name"`
|
||||
Namespace string `json:"namespace"`
|
||||
}
|
||||
|
||||
// HealthCheck is the HealthCheck definition.
|
||||
type HealthCheck struct {
|
||||
Path string `json:"path"`
|
||||
Host string `json:"host,omitempty"`
|
||||
Scheme string `json:"scheme"`
|
||||
IntervalSeconds int64 `json:"intervalSeconds"`
|
||||
TimeoutSeconds int64 `json:"timeoutSeconds"`
|
||||
Headers map[string]string `json:"headers"`
|
||||
}
|
||||
|
||||
// +genclient
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// IngressRoute is an Ingress CRD specification.
|
||||
type IngressRoute struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata"`
|
||||
|
||||
Spec IngressRouteSpec `json:"spec"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// IngressRouteList is a list of IngressRoutes.
|
||||
type IngressRouteList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata"`
|
||||
Items []IngressRoute `json:"items"`
|
||||
}
|
27
provider/kubernetes/crd/traefik/v1alpha1/middleware.go
Normal file
27
provider/kubernetes/crd/traefik/v1alpha1/middleware.go
Normal file
|
@ -0,0 +1,27 @@
|
|||
package v1alpha1
|
||||
|
||||
import (
|
||||
"github.com/containous/traefik/config"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// +genclient
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// Middleware is a specification for a Middleware resource.
|
||||
type Middleware struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata"`
|
||||
|
||||
Spec config.Middleware `json:"spec"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// MiddlewareList is a list of Middleware resources.
|
||||
type MiddlewareList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata"`
|
||||
|
||||
Items []Middleware `json:"items"`
|
||||
}
|
43
provider/kubernetes/crd/traefik/v1alpha1/register.go
Normal file
43
provider/kubernetes/crd/traefik/v1alpha1/register.go
Normal file
|
@ -0,0 +1,43 @@
|
|||
package v1alpha1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// GroupName is the group name for Traefik.
|
||||
const GroupName = "traefik.containo.us"
|
||||
|
||||
var (
|
||||
// SchemeBuilder collects the scheme builder functions.
|
||||
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
|
||||
|
||||
// AddToScheme applies the SchemeBuilder functions to a specified scheme.
|
||||
AddToScheme = SchemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
// SchemeGroupVersion is group version used to register these objects.
|
||||
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"}
|
||||
|
||||
// Kind takes an unqualified kind and returns back a Group qualified GroupKind.
|
||||
func Kind(kind string) schema.GroupKind {
|
||||
return SchemeGroupVersion.WithKind(kind).GroupKind()
|
||||
}
|
||||
|
||||
// Resource takes an unqualified resource and returns a Group qualified GroupResource.
|
||||
func Resource(resource string) schema.GroupResource {
|
||||
return SchemeGroupVersion.WithResource(resource).GroupResource()
|
||||
}
|
||||
|
||||
// Adds the list of known types to Scheme.
|
||||
func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||
&IngressRoute{},
|
||||
&IngressRouteList{},
|
||||
&Middleware{},
|
||||
&MiddlewareList{},
|
||||
)
|
||||
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,290 @@
|
|||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Containous SAS
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Code generated by deepcopy-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HealthCheck) DeepCopyInto(out *HealthCheck) {
|
||||
*out = *in
|
||||
if in.Headers != nil {
|
||||
in, out := &in.Headers, &out.Headers
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HealthCheck.
|
||||
func (in *HealthCheck) DeepCopy() *HealthCheck {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(HealthCheck)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *IngressRoute) DeepCopyInto(out *IngressRoute) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IngressRoute.
|
||||
func (in *IngressRoute) DeepCopy() *IngressRoute {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(IngressRoute)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *IngressRoute) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *IngressRouteList) DeepCopyInto(out *IngressRouteList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]IngressRoute, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IngressRouteList.
|
||||
func (in *IngressRouteList) DeepCopy() *IngressRouteList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(IngressRouteList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *IngressRouteList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *IngressRouteSpec) DeepCopyInto(out *IngressRouteSpec) {
|
||||
*out = *in
|
||||
if in.Routes != nil {
|
||||
in, out := &in.Routes, &out.Routes
|
||||
*out = make([]Route, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.EntryPoints != nil {
|
||||
in, out := &in.EntryPoints, &out.EntryPoints
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.TLS != nil {
|
||||
in, out := &in.TLS, &out.TLS
|
||||
*out = new(TLS)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IngressRouteSpec.
|
||||
func (in *IngressRouteSpec) DeepCopy() *IngressRouteSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(IngressRouteSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Middleware) DeepCopyInto(out *Middleware) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Middleware.
|
||||
func (in *Middleware) DeepCopy() *Middleware {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Middleware)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *Middleware) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *MiddlewareList) DeepCopyInto(out *MiddlewareList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]Middleware, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MiddlewareList.
|
||||
func (in *MiddlewareList) DeepCopy() *MiddlewareList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(MiddlewareList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *MiddlewareList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *MiddlewareRef) DeepCopyInto(out *MiddlewareRef) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MiddlewareRef.
|
||||
func (in *MiddlewareRef) DeepCopy() *MiddlewareRef {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(MiddlewareRef)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Route) DeepCopyInto(out *Route) {
|
||||
*out = *in
|
||||
if in.Services != nil {
|
||||
in, out := &in.Services, &out.Services
|
||||
*out = make([]Service, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.Middlewares != nil {
|
||||
in, out := &in.Middlewares, &out.Middlewares
|
||||
*out = make([]MiddlewareRef, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Route.
|
||||
func (in *Route) DeepCopy() *Route {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Route)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Service) DeepCopyInto(out *Service) {
|
||||
*out = *in
|
||||
if in.HealthCheck != nil {
|
||||
in, out := &in.HealthCheck, &out.HealthCheck
|
||||
*out = new(HealthCheck)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Service.
|
||||
func (in *Service) DeepCopy() *Service {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Service)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TLS) DeepCopyInto(out *TLS) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLS.
|
||||
func (in *TLS) DeepCopy() *TLS {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(TLS)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
63
provider/kubernetes/ingress/builder_ingress_test.go
Normal file
63
provider/kubernetes/ingress/builder_ingress_test.go
Normal file
|
@ -0,0 +1,63 @@
|
|||
package ingress
|
||||
|
||||
import (
|
||||
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
|
||||
)
|
||||
|
||||
func buildIngress(opts ...func(*extensionsv1beta1.Ingress)) *extensionsv1beta1.Ingress {
|
||||
i := &extensionsv1beta1.Ingress{}
|
||||
i.Kind = "Ingress"
|
||||
for _, opt := range opts {
|
||||
opt(i)
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
func iNamespace(value string) func(*extensionsv1beta1.Ingress) {
|
||||
return func(i *extensionsv1beta1.Ingress) {
|
||||
i.Namespace = value
|
||||
}
|
||||
}
|
||||
|
||||
func iRules(opts ...func(*extensionsv1beta1.IngressSpec)) func(*extensionsv1beta1.Ingress) {
|
||||
return func(i *extensionsv1beta1.Ingress) {
|
||||
s := &extensionsv1beta1.IngressSpec{}
|
||||
for _, opt := range opts {
|
||||
opt(s)
|
||||
}
|
||||
i.Spec = *s
|
||||
}
|
||||
}
|
||||
|
||||
func iRule(opts ...func(*extensionsv1beta1.IngressRule)) func(*extensionsv1beta1.IngressSpec) {
|
||||
return func(spec *extensionsv1beta1.IngressSpec) {
|
||||
r := &extensionsv1beta1.IngressRule{}
|
||||
for _, opt := range opts {
|
||||
opt(r)
|
||||
}
|
||||
spec.Rules = append(spec.Rules, *r)
|
||||
}
|
||||
}
|
||||
|
||||
func iHost(name string) func(*extensionsv1beta1.IngressRule) {
|
||||
return func(rule *extensionsv1beta1.IngressRule) {
|
||||
rule.Host = name
|
||||
}
|
||||
}
|
||||
|
||||
func iTLSes(opts ...func(*extensionsv1beta1.IngressTLS)) func(*extensionsv1beta1.Ingress) {
|
||||
return func(i *extensionsv1beta1.Ingress) {
|
||||
for _, opt := range opts {
|
||||
iTLS := extensionsv1beta1.IngressTLS{}
|
||||
opt(&iTLS)
|
||||
i.Spec.TLS = append(i.Spec.TLS, iTLS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func iTLS(secret string, hosts ...string) func(*extensionsv1beta1.IngressTLS) {
|
||||
return func(i *extensionsv1beta1.IngressTLS) {
|
||||
i.SecretName = secret
|
||||
i.Hosts = hosts
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package kubernetes
|
||||
package ingress
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
@ -7,6 +7,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/containous/traefik/old/log"
|
||||
"github.com/containous/traefik/provider/kubernetes/k8s"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
|
||||
kubeerror "k8s.io/apimachinery/pkg/api/errors"
|
||||
|
@ -41,7 +42,7 @@ func (reh *resourceEventHandler) OnDelete(obj interface{}) {
|
|||
// WatchAll starts the watch of the Provider resources and updates the stores.
|
||||
// The stores can then be accessed via the Get* functions.
|
||||
type Client interface {
|
||||
WatchAll(namespaces Namespaces, stopCh <-chan struct{}) (<-chan interface{}, error)
|
||||
WatchAll(namespaces k8s.Namespaces, stopCh <-chan struct{}) (<-chan interface{}, error)
|
||||
GetIngresses() []*extensionsv1beta1.Ingress
|
||||
GetService(namespace, name string) (*corev1.Service, bool, error)
|
||||
GetSecret(namespace, name string) (*corev1.Secret, bool, error)
|
||||
|
@ -49,24 +50,17 @@ type Client interface {
|
|||
UpdateIngressStatus(namespace, name, ip, hostname string) error
|
||||
}
|
||||
|
||||
type clientImpl struct {
|
||||
type clientWrapper struct {
|
||||
clientset *kubernetes.Clientset
|
||||
factories map[string]informers.SharedInformerFactory
|
||||
ingressLabelSelector labels.Selector
|
||||
isNamespaceAll bool
|
||||
watchedNamespaces Namespaces
|
||||
}
|
||||
|
||||
func newClientImpl(clientset *kubernetes.Clientset) *clientImpl {
|
||||
return &clientImpl{
|
||||
clientset: clientset,
|
||||
factories: make(map[string]informers.SharedInformerFactory),
|
||||
}
|
||||
watchedNamespaces k8s.Namespaces
|
||||
}
|
||||
|
||||
// newInClusterClient returns a new Provider client that is expected to run
|
||||
// inside the cluster.
|
||||
func newInClusterClient(endpoint string) (*clientImpl, error) {
|
||||
func newInClusterClient(endpoint string) (*clientWrapper, error) {
|
||||
config, err := rest.InClusterConfig()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create in-cluster configuration: %s", err)
|
||||
|
@ -79,7 +73,7 @@ func newInClusterClient(endpoint string) (*clientImpl, error) {
|
|||
return createClientFromConfig(config)
|
||||
}
|
||||
|
||||
func newExternalClusterClientFromFile(file string) (*clientImpl, error) {
|
||||
func newExternalClusterClientFromFile(file string) (*clientWrapper, error) {
|
||||
configFromFlags, err := clientcmd.BuildConfigFromFlags("", file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -90,7 +84,7 @@ func newExternalClusterClientFromFile(file string) (*clientImpl, error) {
|
|||
// newExternalClusterClient returns a new Provider client that may run outside
|
||||
// of the cluster.
|
||||
// The endpoint parameter must not be empty.
|
||||
func newExternalClusterClient(endpoint, token, caFilePath string) (*clientImpl, error) {
|
||||
func newExternalClusterClient(endpoint, token, caFilePath string) (*clientWrapper, error) {
|
||||
if endpoint == "" {
|
||||
return nil, errors.New("endpoint missing for external cluster client")
|
||||
}
|
||||
|
@ -111,7 +105,7 @@ func newExternalClusterClient(endpoint, token, caFilePath string) (*clientImpl,
|
|||
return createClientFromConfig(config)
|
||||
}
|
||||
|
||||
func createClientFromConfig(c *rest.Config) (*clientImpl, error) {
|
||||
func createClientFromConfig(c *rest.Config) (*clientWrapper, error) {
|
||||
clientset, err := kubernetes.NewForConfig(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -120,18 +114,25 @@ func createClientFromConfig(c *rest.Config) (*clientImpl, error) {
|
|||
return newClientImpl(clientset), nil
|
||||
}
|
||||
|
||||
func newClientImpl(clientset *kubernetes.Clientset) *clientWrapper {
|
||||
return &clientWrapper{
|
||||
clientset: clientset,
|
||||
factories: make(map[string]informers.SharedInformerFactory),
|
||||
}
|
||||
}
|
||||
|
||||
// WatchAll starts namespace-specific controllers for all relevant kinds.
|
||||
func (c *clientImpl) WatchAll(namespaces Namespaces, stopCh <-chan struct{}) (<-chan interface{}, error) {
|
||||
func (c *clientWrapper) WatchAll(namespaces k8s.Namespaces, stopCh <-chan struct{}) (<-chan interface{}, error) {
|
||||
eventCh := make(chan interface{}, 1)
|
||||
eventHandler := c.newResourceEventHandler(eventCh)
|
||||
|
||||
if len(namespaces) == 0 {
|
||||
namespaces = Namespaces{metav1.NamespaceAll}
|
||||
namespaces = k8s.Namespaces{metav1.NamespaceAll}
|
||||
c.isNamespaceAll = true
|
||||
}
|
||||
|
||||
c.watchedNamespaces = namespaces
|
||||
|
||||
eventHandler := c.newResourceEventHandler(eventCh)
|
||||
for _, ns := range namespaces {
|
||||
factory := informers.NewFilteredSharedInformerFactory(c.clientset, resyncPeriod, ns, nil)
|
||||
factory.Extensions().V1beta1().Ingresses().Informer().AddEventHandler(eventHandler)
|
||||
|
@ -165,7 +166,7 @@ func (c *clientImpl) WatchAll(namespaces Namespaces, stopCh <-chan struct{}) (<-
|
|||
}
|
||||
|
||||
// GetIngresses returns all Ingresses for observed namespaces in the cluster.
|
||||
func (c *clientImpl) GetIngresses() []*extensionsv1beta1.Ingress {
|
||||
func (c *clientWrapper) GetIngresses() []*extensionsv1beta1.Ingress {
|
||||
var result []*extensionsv1beta1.Ingress
|
||||
for ns, factory := range c.factories {
|
||||
ings, err := factory.Extensions().V1beta1().Ingresses().Lister().List(c.ingressLabelSelector)
|
||||
|
@ -178,7 +179,7 @@ func (c *clientImpl) GetIngresses() []*extensionsv1beta1.Ingress {
|
|||
}
|
||||
|
||||
// UpdateIngressStatus updates an Ingress with a provided status.
|
||||
func (c *clientImpl) UpdateIngressStatus(namespace, name, ip, hostname string) error {
|
||||
func (c *clientWrapper) UpdateIngressStatus(namespace, name, ip, hostname string) error {
|
||||
if !c.isWatchedNamespace(namespace) {
|
||||
return fmt.Errorf("failed to get ingress %s/%s: namespace is not within watched namespaces", namespace, name)
|
||||
}
|
||||
|
@ -207,7 +208,7 @@ func (c *clientImpl) UpdateIngressStatus(namespace, name, ip, hostname string) e
|
|||
}
|
||||
|
||||
// GetService returns the named service from the given namespace.
|
||||
func (c *clientImpl) GetService(namespace, name string) (*corev1.Service, bool, error) {
|
||||
func (c *clientWrapper) GetService(namespace, name string) (*corev1.Service, bool, error) {
|
||||
if !c.isWatchedNamespace(namespace) {
|
||||
return nil, false, fmt.Errorf("failed to get service %s/%s: namespace is not within watched namespaces", namespace, name)
|
||||
}
|
||||
|
@ -218,7 +219,7 @@ func (c *clientImpl) GetService(namespace, name string) (*corev1.Service, bool,
|
|||
}
|
||||
|
||||
// GetEndpoints returns the named endpoints from the given namespace.
|
||||
func (c *clientImpl) GetEndpoints(namespace, name string) (*corev1.Endpoints, bool, error) {
|
||||
func (c *clientWrapper) GetEndpoints(namespace, name string) (*corev1.Endpoints, bool, error) {
|
||||
if !c.isWatchedNamespace(namespace) {
|
||||
return nil, false, fmt.Errorf("failed to get endpoints %s/%s: namespace is not within watched namespaces", namespace, name)
|
||||
}
|
||||
|
@ -229,7 +230,7 @@ func (c *clientImpl) GetEndpoints(namespace, name string) (*corev1.Endpoints, bo
|
|||
}
|
||||
|
||||
// GetSecret returns the named secret from the given namespace.
|
||||
func (c *clientImpl) GetSecret(namespace, name string) (*corev1.Secret, bool, error) {
|
||||
func (c *clientWrapper) GetSecret(namespace, name string) (*corev1.Secret, bool, error) {
|
||||
if !c.isWatchedNamespace(namespace) {
|
||||
return nil, false, fmt.Errorf("failed to get secret %s/%s: namespace is not within watched namespaces", namespace, name)
|
||||
}
|
||||
|
@ -245,14 +246,14 @@ func (c *clientImpl) GetSecret(namespace, name string) (*corev1.Secret, bool, er
|
|||
// The distinction is necessary because we index all informers on the special
|
||||
// identifier iff all-namespaces are requested but receive specific namespace
|
||||
// identifiers from the Kubernetes API, so we have to bridge this gap.
|
||||
func (c *clientImpl) lookupNamespace(ns string) string {
|
||||
func (c *clientWrapper) lookupNamespace(ns string) string {
|
||||
if c.isNamespaceAll {
|
||||
return metav1.NamespaceAll
|
||||
}
|
||||
return ns
|
||||
}
|
||||
|
||||
func (c *clientImpl) newResourceEventHandler(events chan<- interface{}) cache.ResourceEventHandler {
|
||||
func (c *clientWrapper) newResourceEventHandler(events chan<- interface{}) cache.ResourceEventHandler {
|
||||
return &cache.FilteringResourceEventHandler{
|
||||
FilterFunc: func(obj interface{}) bool {
|
||||
// Ignore Ingresses that do not match our custom label selector.
|
||||
|
@ -287,7 +288,7 @@ func translateNotFoundError(err error) (bool, error) {
|
|||
|
||||
// isWatchedNamespace checks to ensure that the namespace is being watched before we request
|
||||
// it to ensure we don't panic by requesting an out-of-watch object.
|
||||
func (c *clientImpl) isWatchedNamespace(ns string) bool {
|
||||
func (c *clientWrapper) isWatchedNamespace(ns string) bool {
|
||||
if c.isNamespaceAll {
|
||||
return true
|
||||
}
|
|
@ -1,21 +1,58 @@
|
|||
package kubernetes
|
||||
package ingress
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/containous/traefik/provider/kubernetes/k8s"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
|
||||
v1beta12 "k8s.io/api/extensions/v1beta1"
|
||||
)
|
||||
|
||||
var _ Client = (*clientMock)(nil)
|
||||
|
||||
type clientMock struct {
|
||||
ingresses []*extensionsv1beta1.Ingress
|
||||
services []*corev1.Service
|
||||
secrets []*corev1.Secret
|
||||
endpoints []*corev1.Endpoints
|
||||
watchChan chan interface{}
|
||||
|
||||
apiServiceError error
|
||||
apiSecretError error
|
||||
apiEndpointsError error
|
||||
apiIngressStatusError error
|
||||
|
||||
watchChan chan interface{}
|
||||
}
|
||||
|
||||
func newClientMock(paths ...string) clientMock {
|
||||
var c clientMock
|
||||
|
||||
for _, path := range paths {
|
||||
yamlContent, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
k8sObjects := k8s.MustParseYaml(yamlContent)
|
||||
for _, obj := range k8sObjects {
|
||||
switch o := obj.(type) {
|
||||
case *corev1.Service:
|
||||
c.services = append(c.services, o)
|
||||
case *corev1.Secret:
|
||||
c.secrets = append(c.secrets, o)
|
||||
case *corev1.Endpoints:
|
||||
c.endpoints = append(c.endpoints, o)
|
||||
case *v1beta12.Ingress:
|
||||
c.ingresses = append(c.ingresses, o)
|
||||
default:
|
||||
panic(fmt.Sprintf("Unknown runtime object %+v %T", o, o))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func (c clientMock) GetIngresses() []*extensionsv1beta1.Ingress {
|
||||
|
@ -62,7 +99,7 @@ func (c clientMock) GetSecret(namespace, name string) (*corev1.Secret, bool, err
|
|||
return nil, false, nil
|
||||
}
|
||||
|
||||
func (c clientMock) WatchAll(namespaces Namespaces, stopCh <-chan struct{}) (<-chan interface{}, error) {
|
||||
func (c clientMock) WatchAll(namespaces k8s.Namespaces, stopCh <-chan struct{}) (<-chan interface{}, error) {
|
||||
return c.watchChan, nil
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package kubernetes
|
||||
package ingress
|
||||
|
||||
import (
|
||||
"fmt"
|
|
@ -0,0 +1,29 @@
|
|||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
- ip: 10.10.0.2
|
||||
ports:
|
||||
- name: tchouk
|
||||
port: 8089
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: toto
|
||||
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.11.0.1
|
||||
- ip: 10.11.0.2
|
||||
ports:
|
||||
- name: tchouk
|
||||
port: 8089
|
|
@ -0,0 +1,37 @@
|
|||
---
|
||||
kind: Ingress
|
||||
apiVersion: extensions/v1beta1
|
||||
metadata:
|
||||
name: ""
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
rules:
|
||||
- host: traefik.tchouk
|
||||
http:
|
||||
paths:
|
||||
- path: /bar
|
||||
backend:
|
||||
serviceName: service1
|
||||
servicePort: tchouk
|
||||
- path: /foo
|
||||
backend:
|
||||
serviceName: service1
|
||||
servicePort: carotte
|
||||
|
||||
---
|
||||
kind: Ingress
|
||||
apiVersion: extensions/v1beta1
|
||||
metadata:
|
||||
name: ""
|
||||
namespace: toto
|
||||
|
||||
spec:
|
||||
rules:
|
||||
- host: toto.traefik.tchouk
|
||||
http:
|
||||
paths:
|
||||
- path: /bar
|
||||
backend:
|
||||
serviceName: service1
|
||||
servicePort: tchouk
|
|
@ -0,0 +1,24 @@
|
|||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- name: tchouk
|
||||
port: 80
|
||||
clusterIp: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: toto
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- name: tchouk
|
||||
port: 80
|
||||
clusterIp: 10.0.0.1
|
|
@ -0,0 +1,32 @@
|
|||
kind: Endpoints
|
||||
apiversion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.30.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- addresses:
|
||||
- ip: 10.41.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
|
||||
---
|
||||
kind: Endpoints
|
||||
apiversion: v1
|
||||
metadata:
|
||||
name: service2
|
||||
namespace: testing
|
||||
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- addresses:
|
||||
- ip: 10.21.0.1
|
||||
ports:
|
||||
- port: 8080
|
|
@ -0,0 +1,22 @@
|
|||
kind: Ingress
|
||||
apiVersion: extensions/v1beta1
|
||||
metadata:
|
||||
name: ""
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
backend:
|
||||
serviceName: service1
|
||||
servicePort: 80
|
||||
|
||||
---
|
||||
kind: Ingress
|
||||
apiVersion: extensions/v1beta1
|
||||
metadata:
|
||||
name: ""
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
backend:
|
||||
serviceName: service2
|
||||
servicePort: 80
|
|
@ -0,0 +1,22 @@
|
|||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
clusterIp: 10.0.0.1
|
||||
|
||||
---
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service2
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
clusterIp: 10.0.0.1
|
|
@ -0,0 +1,15 @@
|
|||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- addresses:
|
||||
- ip: 10.21.0.1
|
||||
ports:
|
||||
- port: 8080
|
|
@ -0,0 +1,22 @@
|
|||
kind: Ingress
|
||||
apiVersion: extensions/v1beta1
|
||||
metadata:
|
||||
name: ""
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
rules:
|
||||
- host: traefik.tchouk
|
||||
http:
|
||||
paths:
|
||||
- path: /bar
|
||||
backend:
|
||||
serviceName: service1
|
||||
servicePort: 80
|
||||
- host: traefik.courgette
|
||||
http:
|
||||
paths:
|
||||
- path: /carotte
|
||||
backend:
|
||||
serviceName: service1
|
||||
servicePort: 80
|
|
@ -0,0 +1,10 @@
|
|||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
clusterIp: 10.0.0.1
|
|
@ -0,0 +1,15 @@
|
|||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- addresses:
|
||||
- ip: 10.21.0.1
|
||||
ports:
|
||||
- port: 8080
|
|
@ -0,0 +1,19 @@
|
|||
kind: Ingress
|
||||
apiVersion: extensions/v1beta1
|
||||
metadata:
|
||||
name: ""
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
rules:
|
||||
- host: traefik.tchouk
|
||||
http:
|
||||
paths:
|
||||
- path: /bar
|
||||
backend:
|
||||
serviceName: service1
|
||||
servicePort: 80
|
||||
- path: /foo
|
||||
backend:
|
||||
serviceName: service1
|
||||
servicePort: 80
|
|
@ -0,0 +1,10 @@
|
|||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
clusterIp: 10.0.0.1
|
|
@ -0,0 +1,15 @@
|
|||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- addresses:
|
||||
- ip: 10.21.0.1
|
||||
ports:
|
||||
- port: 8080
|
|
@ -0,0 +1,15 @@
|
|||
kind: Ingress
|
||||
apiVersion: extensions/v1beta1
|
||||
metadata:
|
||||
name: ""
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
rules:
|
||||
- host: traefik.tchouk
|
||||
http:
|
||||
paths:
|
||||
- path: /bar
|
||||
backend:
|
||||
serviceName: service1
|
||||
servicePort: 80
|
|
@ -0,0 +1,10 @@
|
|||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
clusterIp: 10.0.0.1
|
|
@ -0,0 +1,15 @@
|
|||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- addresses:
|
||||
- ip: 10.21.0.1
|
||||
ports:
|
||||
- port: 8080
|
|
@ -0,0 +1,18 @@
|
|||
kind: Ingress
|
||||
apiVersion: extensions/v1beta1
|
||||
metadata:
|
||||
name: ""
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
rules:
|
||||
- http:
|
||||
paths:
|
||||
- path: /bar
|
||||
backend:
|
||||
serviceName: service1
|
||||
servicePort: 80
|
||||
- path: /foo
|
||||
backend:
|
||||
serviceName: service1
|
||||
servicePort: 80
|
|
@ -0,0 +1,10 @@
|
|||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
clusterIp: 10.0.0.1
|
|
@ -0,0 +1,15 @@
|
|||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- addresses:
|
||||
- ip: 10.21.0.1
|
||||
ports:
|
||||
- port: 8080
|
|
@ -0,0 +1,22 @@
|
|||
kind: Ingress
|
||||
apiVersion: extensions/v1beta1
|
||||
metadata:
|
||||
name: ""
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
rules:
|
||||
- host: traefik.tchouk"0"
|
||||
http:
|
||||
paths:
|
||||
- path: /foo
|
||||
backend:
|
||||
serviceName: service1
|
||||
servicePort: 80
|
||||
- host: traefik.courgette
|
||||
http:
|
||||
paths:
|
||||
- path: /carotte
|
||||
backend:
|
||||
serviceName: service1
|
||||
servicePort: 80
|
|
@ -0,0 +1,10 @@
|
|||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
clusterIp: 10.0.0.1
|
|
@ -0,0 +1,15 @@
|
|||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- addresses:
|
||||
- ip: 10.21.0.1
|
||||
ports:
|
||||
- port: 8080
|
|
@ -0,0 +1,23 @@
|
|||
kind: Ingress
|
||||
apiVersion: extensions/v1beta1
|
||||
metadata:
|
||||
name: ""
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
rules:
|
||||
- host: ""
|
||||
http:
|
||||
paths:
|
||||
- path: /foo
|
||||
backend:
|
||||
serviceName: service1
|
||||
servicePort: 80
|
||||
- path: /bar-"0"
|
||||
backend:
|
||||
serviceName: service1
|
||||
servicePort: 80
|
||||
- path: /bar
|
||||
backend:
|
||||
serviceName: service1
|
||||
servicePort: 80
|
|
@ -0,0 +1,10 @@
|
|||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
clusterIp: 10.0.0.1
|
|
@ -0,0 +1,15 @@
|
|||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 443
|
||||
- addresses:
|
||||
- ip: 10.21.0.1
|
||||
ports:
|
||||
- port: 443
|
|
@ -0,0 +1,14 @@
|
|||
kind: Ingress
|
||||
apiVersion: extensions/v1beta1
|
||||
metadata:
|
||||
name: ""
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
rules:
|
||||
- http:
|
||||
paths:
|
||||
- path: /bar
|
||||
backend:
|
||||
serviceName: service1
|
||||
servicePort: 443
|
|
@ -0,0 +1,10 @@
|
|||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- port: 443
|
||||
clusterIp: 10.0.0.1
|
|
@ -0,0 +1,17 @@
|
|||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- name: https
|
||||
port: 8443
|
||||
- addresses:
|
||||
- ip: 10.21.0.1
|
||||
ports:
|
||||
- name: https
|
||||
port: 8443
|
|
@ -0,0 +1,14 @@
|
|||
kind: Ingress
|
||||
apiVersion: extensions/v1beta1
|
||||
metadata:
|
||||
name: ""
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
rules:
|
||||
- http:
|
||||
paths:
|
||||
- path: /bar
|
||||
backend:
|
||||
serviceName: service1
|
||||
servicePort: 8443
|
|
@ -0,0 +1,12 @@
|
|||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- name: https
|
||||
protocol: ""
|
||||
port: 8443
|
||||
clusterIp: 10.0.0.1
|
|
@ -0,0 +1,17 @@
|
|||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- name: https-foo
|
||||
port: 8443
|
||||
- addresses:
|
||||
- ip: 10.21.0.1
|
||||
ports:
|
||||
- name: https-foo
|
||||
port: 8443
|
|
@ -0,0 +1,14 @@
|
|||
kind: Ingress
|
||||
apiVersion: extensions/v1beta1
|
||||
metadata:
|
||||
name: ""
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
rules:
|
||||
- http:
|
||||
paths:
|
||||
- path: /bar
|
||||
backend:
|
||||
serviceName: service1
|
||||
servicePort: 8443
|
|
@ -0,0 +1,12 @@
|
|||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- name: https-foo
|
||||
protocol: ""
|
||||
port: 8443
|
||||
clusterIp: 10.0.0.1
|
|
@ -0,0 +1,15 @@
|
|||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
||||
- addresses:
|
||||
- ip: 10.21.0.1
|
||||
ports:
|
||||
- port: 8080
|
|
@ -0,0 +1,14 @@
|
|||
kind: Ingress
|
||||
apiVersion: extensions/v1beta1
|
||||
metadata:
|
||||
name: ""
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
rules:
|
||||
- http:
|
||||
paths:
|
||||
- path: /bar
|
||||
backend:
|
||||
serviceName: service1
|
||||
servicePort: 80
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
clusterIp: 10.0.0.1
|
|
@ -0,0 +1,11 @@
|
|||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
|
@ -0,0 +1,16 @@
|
|||
kind: Ingress
|
||||
apiVersion: extensions/v1beta1
|
||||
metadata:
|
||||
name: ""
|
||||
namespace: testing
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: traefik
|
||||
|
||||
spec:
|
||||
rules:
|
||||
- http:
|
||||
paths:
|
||||
- path: /bar
|
||||
backend:
|
||||
serviceName: service1
|
||||
servicePort: 80
|
|
@ -0,0 +1,10 @@
|
|||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
clusterIp: 10.0.0.1
|
|
@ -0,0 +1,11 @@
|
|||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
|
@ -0,0 +1,16 @@
|
|||
kind: Ingress
|
||||
apiVersion: extensions/v1beta1
|
||||
metadata:
|
||||
name: ""
|
||||
namespace: testing
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: traefik
|
||||
|
||||
spec:
|
||||
rules:
|
||||
- http:
|
||||
paths:
|
||||
- path: /bar
|
||||
backend:
|
||||
serviceName: service1
|
||||
servicePort: 80
|
|
@ -0,0 +1,10 @@
|
|||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
clusterIp: 10.0.0.1
|
|
@ -0,0 +1,11 @@
|
|||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.10.0.1
|
||||
ports:
|
||||
- port: 8080
|
|
@ -0,0 +1,16 @@
|
|||
kind: Ingress
|
||||
apiVersion: extensions/v1beta1
|
||||
metadata:
|
||||
name: ""
|
||||
namespace: testing
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: toto
|
||||
|
||||
spec:
|
||||
rules:
|
||||
- http:
|
||||
paths:
|
||||
- path: /bar
|
||||
backend:
|
||||
serviceName: service1
|
||||
servicePort: 80
|
|
@ -0,0 +1,10 @@
|
|||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: service1
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
clusterIp: 10.0.0.1
|
|
@ -0,0 +1,12 @@
|
|||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: example-com
|
||||
namespace: testing
|
||||
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.11.0.1
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
|
@ -0,0 +1,14 @@
|
|||
kind: Ingress
|
||||
apiVersion: extensions/v1beta1
|
||||
metadata:
|
||||
name: ""
|
||||
namespace: testing
|
||||
|
||||
spec:
|
||||
rules:
|
||||
- host: example.com
|
||||
http:
|
||||
paths:
|
||||
- backend:
|
||||
serviceName: example-com
|
||||
servicePort: 80
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue