Add named port support to Kubernetes IngressRoute CRDs

This commit is contained in:
Cirrith 2021-01-15 06:54:04 -08:00 committed by GitHub
parent b1ddd0e038
commit bbee63fcf3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 154 additions and 57 deletions

View file

@ -145,7 +145,7 @@ The Kubernetes Ingress Controller, The Custom Resource Way.
spec: spec:
entryPoints: entryPoints:
- fooudp - udpep
routes: routes:
- kind: Rule - kind: Rule
services: services:
@ -331,7 +331,7 @@ Register the `IngressRoute` [kind](../../reference/dynamic-configuration/kuberne
name: foo name: foo
namespace: default namespace: default
passHostHeader: true passHostHeader: true
port: 80 port: 80 # [9]
responseForwarding: responseForwarding:
flushInterval: 1ms flushInterval: 1ms
scheme: https scheme: https
@ -343,21 +343,21 @@ Register the `IngressRoute` [kind](../../reference/dynamic-configuration/kuberne
sameSite: none sameSite: none
strategy: RoundRobin strategy: RoundRobin
weight: 10 weight: 10
tls: # [9] tls: # [10]
secretName: supersecret # [10] secretName: supersecret # [11]
options: # [11] options: # [12]
name: opt # [12] name: opt # [13]
namespace: default # [13] namespace: default # [14]
certResolver: foo # [14] certResolver: foo # [15]
domains: # [15] domains: # [16]
- main: example.net # [16] - main: example.net # [17]
sans: # [17] sans: # [18]
- a.example.net - a.example.net
- b.example.net - b.example.net
``` ```
| Ref | Attribute | Purpose | | Ref | Attribute | Purpose |
|------|----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |------|------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [1] | `entryPoints` | List of [entry points](../routers/index.md#entrypoints) names | | [1] | `entryPoints` | List of [entry points](../routers/index.md#entrypoints) names |
| [2] | `routes` | List of routes | | [2] | `routes` | List of routes |
| [3] | `routes[n].match` | Defines the [rule](../routers/index.md#rule) corresponding to an underlying router. | | [3] | `routes[n].match` | Defines the [rule](../routers/index.md#rule) corresponding to an underlying router. |
@ -366,15 +366,16 @@ Register the `IngressRoute` [kind](../../reference/dynamic-configuration/kuberne
| [6] | `middlewares[n].name` | Defines the [Middleware](#kind-middleware) name | | [6] | `middlewares[n].name` | Defines the [Middleware](#kind-middleware) name |
| [7] | `middlewares[n].namespace` | Defines the [Middleware](#kind-middleware) namespace | | [7] | `middlewares[n].namespace` | Defines the [Middleware](#kind-middleware) namespace |
| [8] | `routes[n].services` | List of any combination of [TraefikService](#kind-traefikservice) and reference to a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) (See below for `ExternalName Service` setup) | | [8] | `routes[n].services` | List of any combination of [TraefikService](#kind-traefikservice) and reference to a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) (See below for `ExternalName Service` setup) |
| [9] | `tls` | Defines [TLS](../routers/index.md#tls) certificate configuration | | [9] | `services[n].port` | Defines the port of a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/). This can be a reference to a named port. |
| [10] | `tls.secretName` | Defines the [secret](https://kubernetes.io/docs/concepts/configuration/secret/) name used to store the certificate (in the `IngressRoute` namespace) | | [10] | `tls` | Defines [TLS](../routers/index.md#tls) certificate configuration |
| [11] | `tls.options` | Defines the reference to a [TLSOption](#kind-tlsoption) | | [11] | `tls.secretName` | Defines the [secret](https://kubernetes.io/docs/concepts/configuration/secret/) name used to store the certificate (in the `IngressRoute` namespace) |
| [12] | `options.name` | Defines the [TLSOption](#kind-tlsoption) name | | [12] | `tls.options` | Defines the reference to a [TLSOption](#kind-tlsoption) |
| [13] | `options.namespace` | Defines the [TLSOption](#kind-tlsoption) namespace | | [13] | `options.name` | Defines the [TLSOption](#kind-tlsoption) name |
| [14] | `tls.certResolver` | Defines the reference to a [CertResolver](../routers/index.md#certresolver) | | [14] | `options.namespace` | Defines the [TLSOption](#kind-tlsoption) namespace |
| [15] | `tls.domains` | List of [domains](../routers/index.md#domains) | | [15] | `tls.certResolver` | Defines the reference to a [CertResolver](../routers/index.md#certresolver) |
| [16] | `domains[n].main` | Defines the main domain name | | [16] | `tls.domains` | List of [domains](../routers/index.md#domains) |
| [17] | `domains[n].sans` | List of SANs (alternative domains) | | [17] | `domains[n].main` | Defines the main domain name |
| [18] | `domains[n].sans` | List of SANs (alternative domains) |
??? example "Declaring an IngressRoute" ??? example "Declaring an IngressRoute"
@ -1113,7 +1114,7 @@ Register the `IngressRouteTCP` [kind](../../reference/dynamic-configuration/kube
| [3] | `routes[n].match` | Defines the [rule](../routers/index.md#rule_1) corresponding to an underlying router | | [3] | `routes[n].match` | Defines the [rule](../routers/index.md#rule_1) corresponding to an underlying router |
| [4] | `routes[n].services` | List of [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) definitions (See below for `ExternalName Service` setup) | | [4] | `routes[n].services` | List of [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) definitions (See below for `ExternalName Service` setup) |
| [5] | `services[n].name` | Defines the name of a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) | | [5] | `services[n].name` | Defines the name of a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) |
| [6] | `services[n].port` | Defines the port of a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) | | [6] | `services[n].port` | Defines the port of a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/). This can be a reference to a named port. |
| [7] | `services[n].weight` | Defines the weight to apply to the server load balancing | | [7] | `services[n].weight` | Defines the weight to apply to the server load balancing |
| [8] | `services[n].terminationDelay` | corresponds to the deadline that the proxy sets, after one of its connected peers indicates it has closed the writing capability of its connection, to close the reading capability as well, hence fully terminating the connection. It is a duration in milliseconds, defaulting to 100. A negative value means an infinite deadline (i.e. the reading capability is never closed). | | [8] | `services[n].terminationDelay` | corresponds to the deadline that the proxy sets, after one of its connected peers indicates it has closed the writing capability of its connection, to close the reading capability as well, hence fully terminating the connection. It is a duration in milliseconds, defaulting to 100. A negative value means an infinite deadline (i.e. the reading capability is never closed). |
| [9] | `proxyProtocol` | Defines the [PROXY protocol](../services/index.md#proxy-protocol) configuration | | [9] | `proxyProtocol` | Defines the [PROXY protocol](../services/index.md#proxy-protocol) configuration |
@ -1323,7 +1324,7 @@ Register the `IngressRouteUDP` [kind](../../reference/dynamic-configuration/kube
| [2] | `routes` | List of routes | | [2] | `routes` | List of routes |
| [3] | `routes[n].services` | List of [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) definitions | | [3] | `routes[n].services` | List of [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) definitions |
| [4] | `services[n].name` | Defines the name of a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) | | [4] | `services[n].name` | Defines the name of a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) |
| [6] | `services[n].port` | Defines the port of a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) | | [6] | `services[n].port` | Defines the port of a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/). This can be a reference to a named port. |
| [7] | `services[n].weight` | Defines the weight to apply to the server load balancing | | [7] | `services[n].weight` | Defines the weight to apply to the server load balancing |
??? example "Declaring an IngressRouteUDP" ??? example "Declaring an IngressRouteUDP"

View file

@ -24,6 +24,7 @@ import (
"github.com/traefik/traefik/v2/pkg/tls" "github.com/traefik/traefik/v2/pkg/tls"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/util/intstr"
) )
const ( const (
@ -323,18 +324,18 @@ func (p *Provider) loadConfigurationFromCRD(ctx context.Context, client Client)
return conf return conf
} }
func getServicePort(svc *corev1.Service, port int32) (*corev1.ServicePort, error) { func getServicePort(svc *corev1.Service, port intstr.IntOrString) (*corev1.ServicePort, error) {
if svc == nil { if svc == nil {
return nil, errors.New("service is not defined") return nil, errors.New("service is not defined")
} }
if port == 0 { if (port.Type == intstr.Int && port.IntVal == 0) || (port.Type == intstr.String && port.StrVal == "") {
return nil, errors.New("ingressRoute service port not defined") return nil, errors.New("ingressRoute service port not defined")
} }
hasValidPort := false hasValidPort := false
for _, p := range svc.Spec.Ports { for _, p := range svc.Spec.Ports {
if p.Port == port { if (port.Type == intstr.Int && port.IntVal == p.Port) || (port.Type == intstr.String && port.StrVal == p.Name) {
return &p, nil return &p, nil
} }
@ -343,8 +344,8 @@ func getServicePort(svc *corev1.Service, port int32) (*corev1.ServicePort, error
} }
} }
if svc.Spec.Type != corev1.ServiceTypeExternalName { if svc.Spec.Type != corev1.ServiceTypeExternalName || port.Type == intstr.String {
return nil, fmt.Errorf("service port not found: %d", port) return nil, fmt.Errorf("service port not found: %s", &port)
} }
if hasValidPort { if hasValidPort {
@ -352,7 +353,7 @@ func getServicePort(svc *corev1.Service, port int32) (*corev1.ServicePort, error
Warning("The port %d from IngressRoute doesn't match with ports defined in the ExternalName service %s/%s.", port, svc.Namespace, svc.Name) Warning("The port %d from IngressRoute doesn't match with ports defined in the ExternalName service %s/%s.", port, svc.Namespace, svc.Name)
} }
return &corev1.ServicePort{Port: port}, nil return &corev1.ServicePort{Port: port.IntVal}, nil
} }
func (p *Provider) createErrorPageMiddleware(client Client, namespace string, errorPage *v1alpha1.ErrorPage) (*dynamic.ErrorPage, *dynamic.Service, error) { func (p *Provider) createErrorPageMiddleware(client Client, namespace string, errorPage *v1alpha1.ErrorPage) (*dynamic.ErrorPage, *dynamic.Service, error) {

View file

@ -14,6 +14,7 @@ import (
"github.com/traefik/traefik/v2/pkg/provider/kubernetes/crd/traefik/v1alpha1" "github.com/traefik/traefik/v2/pkg/provider/kubernetes/crd/traefik/v1alpha1"
"github.com/traefik/traefik/v2/pkg/tls" "github.com/traefik/traefik/v2/pkg/tls"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/intstr"
) )
const ( const (
@ -399,7 +400,7 @@ func (c configBuilder) nameAndService(ctx context.Context, parentNamespace strin
return fullName, serversLB, nil return fullName, serversLB, nil
case service.Kind == "TraefikService": case service.Kind == "TraefikService":
return fullServiceName(svcCtx, namespace, service, 0), nil, nil return fullServiceName(svcCtx, namespace, service, intstr.FromInt(0)), nil, nil
default: default:
return "", nil, fmt.Errorf("unsupported service kind %s", service.Kind) return "", nil, fmt.Errorf("unsupported service kind %s", service.Kind)
} }
@ -414,9 +415,9 @@ func splitSvcNameProvider(name string) (string, string) {
return svc, pvd return svc, pvd
} }
func fullServiceName(ctx context.Context, namespace string, service v1alpha1.LoadBalancerSpec, port int32) string { func fullServiceName(ctx context.Context, namespace string, service v1alpha1.LoadBalancerSpec, port intstr.IntOrString) string {
if port != 0 { if (port.Type == intstr.Int && port.IntVal != 0) || (port.Type == intstr.String && port.StrVal != "") {
return provider.Normalize(fmt.Sprintf("%s-%s-%d", namespace, service.Name, port)) return provider.Normalize(fmt.Sprintf("%s-%s-%s", namespace, service.Name, &port))
} }
if !strings.Contains(service.Name, providerNamespaceSeparator) { if !strings.Contains(service.Name, providerNamespaceSeparator) {

View file

@ -71,7 +71,7 @@ func (p *Provider) loadIngressRouteTCPConfiguration(ctx context.Context, client
break break
} }
serviceKey := fmt.Sprintf("%s-%s-%d", serviceName, service.Name, service.Port) serviceKey := fmt.Sprintf("%s-%s-%s", serviceName, service.Name, &service.Port)
conf.Services[serviceKey] = balancerServerTCP conf.Services[serviceKey] = balancerServerTCP
srv := dynamic.TCPWRRService{Name: serviceKey} srv := dynamic.TCPWRRService{Name: serviceKey}

View file

@ -18,6 +18,7 @@ import (
"github.com/traefik/traefik/v2/pkg/tls" "github.com/traefik/traefik/v2/pkg/tls"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/intstr"
kubefake "k8s.io/client-go/kubernetes/fake" kubefake "k8s.io/client-go/kubernetes/fake"
) )
@ -3738,7 +3739,7 @@ func TestGetServicePort(t *testing.T) {
testCases := []struct { testCases := []struct {
desc string desc string
svc *corev1.Service svc *corev1.Service
port int32 port intstr.IntOrString
expected *corev1.ServicePort expected *corev1.ServicePort
expectError bool expectError bool
}{ }{
@ -3757,7 +3758,7 @@ func TestGetServicePort(t *testing.T) {
}, },
}, },
}, },
port: 80, port: intstr.FromInt(80),
expected: &corev1.ServicePort{ expected: &corev1.ServicePort{
Port: 80, Port: 80,
}, },
@ -3785,12 +3786,57 @@ func TestGetServicePort(t *testing.T) {
}, },
expectError: true, expectError: true,
}, },
{
desc: "Matching named port",
svc: &corev1.Service{
Spec: corev1.ServiceSpec{
Ports: []corev1.ServicePort{
{
Name: "http",
Port: 80,
},
},
},
},
port: intstr.FromString("http"),
expected: &corev1.ServicePort{
Name: "http",
Port: 80,
},
},
{
desc: "Matching named port (with external name)",
svc: &corev1.Service{
Spec: corev1.ServiceSpec{
Type: corev1.ServiceTypeExternalName,
Ports: []corev1.ServicePort{
{
Name: "http",
Port: 80,
},
},
},
},
port: intstr.FromString("http"),
expected: &corev1.ServicePort{
Name: "http",
Port: 80,
},
},
{ {
desc: "Mismatching, only port(Ingress) defined", desc: "Mismatching, only port(Ingress) defined",
svc: &corev1.Service{ svc: &corev1.Service{
Spec: corev1.ServiceSpec{}, Spec: corev1.ServiceSpec{},
}, },
port: 80, port: intstr.FromInt(80),
expectError: true,
},
{
desc: "Mismatching, only named port(Ingress) defined",
svc: &corev1.Service{
Spec: corev1.ServiceSpec{},
},
port: intstr.FromString("http"),
expectError: true, expectError: true,
}, },
{ {
@ -3800,11 +3846,21 @@ func TestGetServicePort(t *testing.T) {
Type: corev1.ServiceTypeExternalName, Type: corev1.ServiceTypeExternalName,
}, },
}, },
port: 80, port: intstr.FromInt(80),
expected: &corev1.ServicePort{ expected: &corev1.ServicePort{
Port: 80, Port: 80,
}, },
}, },
{
desc: "Mismatching, only named port(Ingress) defined with external name",
svc: &corev1.Service{
Spec: corev1.ServiceSpec{
Type: corev1.ServiceTypeExternalName,
},
},
port: intstr.FromString("http"),
expectError: true,
},
{ {
desc: "Mismatching, only Service port defined", desc: "Mismatching, only Service port defined",
svc: &corev1.Service{ svc: &corev1.Service{
@ -3843,7 +3899,22 @@ func TestGetServicePort(t *testing.T) {
}, },
}, },
}, },
port: 443, port: intstr.FromInt(443),
expectError: true,
},
{
desc: "Two different named ports defined",
svc: &corev1.Service{
Spec: corev1.ServiceSpec{
Ports: []corev1.ServicePort{
{
Name: "foo",
Port: 80,
},
},
},
},
port: intstr.FromString("bar"),
expectError: true, expectError: true,
}, },
{ {
@ -3858,11 +3929,27 @@ func TestGetServicePort(t *testing.T) {
}, },
}, },
}, },
port: 443, port: intstr.FromInt(443),
expected: &corev1.ServicePort{ expected: &corev1.ServicePort{
Port: 443, Port: 443,
}, },
}, },
{
desc: "Two different named ports defined (with external name)",
svc: &corev1.Service{
Spec: corev1.ServiceSpec{
Type: corev1.ServiceTypeExternalName,
Ports: []corev1.ServicePort{
{
Name: "foo",
Port: 80,
},
},
},
},
port: intstr.FromString("bar"),
expectError: true,
},
} }
for _, test := range testCases { for _, test := range testCases {
test := test test := test

View file

@ -11,6 +11,7 @@ import (
"github.com/traefik/traefik/v2/pkg/log" "github.com/traefik/traefik/v2/pkg/log"
"github.com/traefik/traefik/v2/pkg/provider/kubernetes/crd/traefik/v1alpha1" "github.com/traefik/traefik/v2/pkg/provider/kubernetes/crd/traefik/v1alpha1"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/intstr"
) )
func (p *Provider) loadIngressRouteUDPConfiguration(ctx context.Context, client Client) *dynamic.UDPConfiguration { func (p *Provider) loadIngressRouteUDPConfiguration(ctx context.Context, client Client) *dynamic.UDPConfiguration {
@ -52,7 +53,7 @@ func (p *Provider) loadIngressRouteUDPConfiguration(ctx context.Context, client
break break
} }
serviceKey := fmt.Sprintf("%s-%s-%d", serviceName, service.Name, service.Port) serviceKey := fmt.Sprintf("%s-%s-%s", serviceName, service.Name, &service.Port)
conf.Services[serviceKey] = balancerServerUDP conf.Services[serviceKey] = balancerServerUDP
srv := dynamic.UDPWRRService{Name: serviceKey} srv := dynamic.UDPWRRService{Name: serviceKey}
@ -114,7 +115,7 @@ func loadUDPServers(client Client, namespace string, svc v1alpha1.ServiceUDP) ([
var portSpec *corev1.ServicePort var portSpec *corev1.ServicePort
for _, p := range service.Spec.Ports { for _, p := range service.Spec.Ports {
p := p p := p
if svc.Port == p.Port { if (svc.Port.Type == intstr.Int && svc.Port.IntVal == p.Port) || (svc.Port.Type == intstr.String && svc.Port.StrVal == p.Name) {
portSpec = &p portSpec = &p
break break
} }

View file

@ -4,6 +4,7 @@ import (
"github.com/traefik/traefik/v2/pkg/config/dynamic" "github.com/traefik/traefik/v2/pkg/config/dynamic"
"github.com/traefik/traefik/v2/pkg/types" "github.com/traefik/traefik/v2/pkg/types"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
) )
// IngressRouteSpec is a specification for a IngressRouteSpec resource. // IngressRouteSpec is a specification for a IngressRouteSpec resource.
@ -67,7 +68,7 @@ type LoadBalancerSpec struct {
// Port and all the fields below are related to a servers load-balancer, // Port and all the fields below are related to a servers load-balancer,
// and therefore should only be specified when Name references a Kubernetes Service. // and therefore should only be specified when Name references a Kubernetes Service.
Port int32 `json:"port"` Port intstr.IntOrString `json:"port"`
Scheme string `json:"scheme,omitempty"` Scheme string `json:"scheme,omitempty"`
Strategy string `json:"strategy,omitempty"` Strategy string `json:"strategy,omitempty"`
PassHostHeader *bool `json:"passHostHeader,omitempty"` PassHostHeader *bool `json:"passHostHeader,omitempty"`

View file

@ -4,6 +4,7 @@ import (
"github.com/traefik/traefik/v2/pkg/config/dynamic" "github.com/traefik/traefik/v2/pkg/config/dynamic"
"github.com/traefik/traefik/v2/pkg/types" "github.com/traefik/traefik/v2/pkg/types"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
) )
// IngressRouteTCPSpec is a specification for a IngressRouteTCPSpec resource. // IngressRouteTCPSpec is a specification for a IngressRouteTCPSpec resource.
@ -56,7 +57,7 @@ type TLSStoreTCPRef struct {
type ServiceTCP struct { type ServiceTCP struct {
Name string `json:"name"` Name string `json:"name"`
Namespace string `json:"namespace"` Namespace string `json:"namespace"`
Port int32 `json:"port"` Port intstr.IntOrString `json:"port"`
Weight *int `json:"weight,omitempty"` Weight *int `json:"weight,omitempty"`
TerminationDelay *int `json:"terminationDelay,omitempty"` TerminationDelay *int `json:"terminationDelay,omitempty"`
ProxyProtocol *dynamic.ProxyProtocol `json:"proxyProtocol,omitempty"` ProxyProtocol *dynamic.ProxyProtocol `json:"proxyProtocol,omitempty"`

View file

@ -2,6 +2,7 @@ package v1alpha1
import ( import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
) )
// IngressRouteUDPSpec is a specification for a IngressRouteUDPSpec resource. // IngressRouteUDPSpec is a specification for a IngressRouteUDPSpec resource.
@ -25,7 +26,7 @@ type TLSOptionUDPRef struct {
type ServiceUDP struct { type ServiceUDP struct {
Name string `json:"name"` Name string `json:"name"`
Namespace string `json:"namespace"` Namespace string `json:"namespace"`
Port int32 `json:"port"` Port intstr.IntOrString `json:"port"`
Weight *int `json:"weight,omitempty"` Weight *int `json:"weight,omitempty"`
} }

View file

@ -507,6 +507,7 @@ func (in *LoadBalancerSpec) DeepCopyInto(out *LoadBalancerSpec) {
*out = new(dynamic.Sticky) *out = new(dynamic.Sticky)
(*in).DeepCopyInto(*out) (*in).DeepCopyInto(*out)
} }
out.Port = in.Port
if in.PassHostHeader != nil { if in.PassHostHeader != nil {
in, out := &in.PassHostHeader, &out.PassHostHeader in, out := &in.PassHostHeader, &out.PassHostHeader
*out = new(bool) *out = new(bool)
@ -1001,6 +1002,7 @@ func (in *ServiceSpec) DeepCopy() *ServiceSpec {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ServiceTCP) DeepCopyInto(out *ServiceTCP) { func (in *ServiceTCP) DeepCopyInto(out *ServiceTCP) {
*out = *in *out = *in
out.Port = in.Port
if in.Weight != nil { if in.Weight != nil {
in, out := &in.Weight, &out.Weight in, out := &in.Weight, &out.Weight
*out = new(int) *out = new(int)
@ -1032,6 +1034,7 @@ func (in *ServiceTCP) DeepCopy() *ServiceTCP {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ServiceUDP) DeepCopyInto(out *ServiceUDP) { func (in *ServiceUDP) DeepCopyInto(out *ServiceUDP) {
*out = *in *out = *in
out.Port = in.Port
if in.Weight != nil { if in.Weight != nil {
in, out := &in.Weight, &out.Weight in, out := &in.Weight, &out.Weight
*out = new(int) *out = new(int)