Merge fc86119061
into 908807a76d
This commit is contained in:
commit
90e6eda976
77 changed files with 2159 additions and 4679 deletions
11
artifacts/examples/crd.yaml
Normal file
11
artifacts/examples/crd.yaml
Normal file
|
@ -0,0 +1,11 @@
|
|||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: foos.samplecontroller.k8s.io
|
||||
spec:
|
||||
group: samplecontroller.k8s.io
|
||||
version: v1alpha1
|
||||
names:
|
||||
kind: Foo
|
||||
plural: foos
|
||||
scope: Namespaced
|
7
artifacts/examples/example-foo.yaml
Normal file
7
artifacts/examples/example-foo.yaml
Normal file
|
@ -0,0 +1,7 @@
|
|||
apiVersion: samplecontroller.k8s.io/v1alpha1
|
||||
kind: Foo
|
||||
metadata:
|
||||
name: example-foo
|
||||
spec:
|
||||
deploymentName: example-foo
|
||||
replicas: 1
|
16
hack/custom-boilerplate.go.txt
Normal file
16
hack/custom-boilerplate.go.txt
Normal file
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
Copyright YEAR The Kubernetes sample-controller Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
34
hack/update-codegen.sh
Executable file
34
hack/update-codegen.sh
Executable file
|
@ -0,0 +1,34 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Copyright 2017 The Kubernetes Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
|
||||
SCRIPT_ROOT=$(dirname ${BASH_SOURCE})/..
|
||||
CODEGEN_PKG=${CODEGEN_PKG:-$(cd ${SCRIPT_ROOT}; ls -d -1 ./vendor/k8s.io/code-generator 2>/dev/null || echo ../code-generator)}
|
||||
|
||||
# generate the code with:
|
||||
# --output-base because this script should also be able to run inside the vendor dir of
|
||||
# k8s.io/kubernetes. The output-base is needed for the generators to output into the vendor dir
|
||||
# instead of the $GOPATH directly. For normal projects this can be dropped.
|
||||
${CODEGEN_PKG}/generate-groups.sh "deepcopy,client,informer,lister" \
|
||||
k8s.io/ingress-nginx/pkg/client k8s.io/ingress-nginx/pkg/apis \
|
||||
nginxingress:v1alpha1 \
|
||||
--output-base "$(dirname ${BASH_SOURCE})/../../.."
|
||||
|
||||
# To use your own boilerplate text append:
|
||||
# --go-header-file ${SCRIPT_ROOT}/hack/custom-boilerplate.go.txt
|
49
hack/verify-codegen.sh
Executable file
49
hack/verify-codegen.sh
Executable file
|
@ -0,0 +1,49 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Copyright 2017 The Kubernetes Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
|
||||
SCRIPT_ROOT=$(dirname "${BASH_SOURCE}")/..
|
||||
SCRIPT_BASE=${SCRIPT_ROOT}/../..
|
||||
|
||||
DIFFROOT="${SCRIPT_ROOT}/pkg"
|
||||
TMP_DIFFROOT="${SCRIPT_ROOT}/_tmp/pkg"
|
||||
_tmp="${SCRIPT_ROOT}/_tmp"
|
||||
|
||||
cleanup() {
|
||||
rm -rf "${_tmp}"
|
||||
}
|
||||
trap "cleanup" EXIT SIGINT
|
||||
|
||||
cleanup
|
||||
|
||||
mkdir -p "${TMP_DIFFROOT}"
|
||||
cp -a "${DIFFROOT}"/* "${TMP_DIFFROOT}"
|
||||
|
||||
"${SCRIPT_ROOT}/hack/update-codegen.sh"
|
||||
echo "diffing ${DIFFROOT} against freshly generated codegen"
|
||||
ret=0
|
||||
diff -Naupr "${DIFFROOT}" "${TMP_DIFFROOT}" || ret=$?
|
||||
cp -a "${TMP_DIFFROOT}"/* "${DIFFROOT}"
|
||||
if [[ $ret -eq 0 ]]
|
||||
then
|
||||
echo "${DIFFROOT} up to date."
|
||||
else
|
||||
echo "${DIFFROOT} is out of date. Please run hack/update-codegen.sh"
|
||||
exit 1
|
||||
fi
|
|
@ -14,25 +14,8 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package serviceupstream
|
||||
|
||||
import (
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
|
||||
)
|
||||
package nginxingress
|
||||
|
||||
const (
|
||||
annotationServiceUpstream = "ingress.kubernetes.io/service-upstream"
|
||||
GroupName = "nginx.ingress.k8s.io"
|
||||
)
|
||||
|
||||
type serviceUpstream struct {
|
||||
}
|
||||
|
||||
// NewParser creates a new serviceUpstream annotation parser
|
||||
func NewParser() parser.IngressAnnotation {
|
||||
return serviceUpstream{}
|
||||
}
|
||||
|
||||
func (s serviceUpstream) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||
return parser.GetBoolAnnotation(annotationServiceUpstream, ing)
|
||||
}
|
21
pkg/apis/nginxingress/v1alpha1/doc.go
Normal file
21
pkg/apis/nginxingress/v1alpha1/doc.go
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// +k8s:deepcopy-gen=package,register
|
||||
|
||||
// Package v1alpha1 is the v1alpha1 version of the API.
|
||||
// +groupName=nginx.ingress.k8s.io
|
||||
package v1alpha1
|
57
pkg/apis/nginxingress/v1alpha1/register.go
Normal file
57
pkg/apis/nginxingress/v1alpha1/register.go
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/apis/nginxingress"
|
||||
)
|
||||
|
||||
// SchemeGroupVersion is group version used to register these objects
|
||||
var SchemeGroupVersion = schema.GroupVersion{Group: nginxingress.GroupName, Version: "v1alpha1"}
|
||||
|
||||
// Resource takes an unqualified resource and returns a Group qualified GroupResource
|
||||
func Resource(resource string) schema.GroupResource {
|
||||
return SchemeGroupVersion.WithResource(resource).GroupResource()
|
||||
}
|
||||
|
||||
var (
|
||||
// localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes.
|
||||
SchemeBuilder runtime.SchemeBuilder
|
||||
localSchemeBuilder = &SchemeBuilder
|
||||
AddToScheme = localSchemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
func init() {
|
||||
// We only register manually written functions here. The registration of the
|
||||
// generated functions takes place in the generated files. The separation
|
||||
// makes the code compile even when the generated files are missing.
|
||||
localSchemeBuilder.Register(addKnownTypes)
|
||||
}
|
||||
|
||||
// Adds the list of known types to api.Scheme.
|
||||
func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||
&Configuration{},
|
||||
&ConfigurationList{},
|
||||
)
|
||||
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
|
||||
return nil
|
||||
}
|
240
pkg/apis/nginxingress/v1alpha1/types.go
Normal file
240
pkg/apis/nginxingress/v1alpha1/types.go
Normal file
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/resolver"
|
||||
)
|
||||
|
||||
// +genclient
|
||||
// +k8s:openapi-gen=true
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
// +resource:path=nginxconfiguration
|
||||
|
||||
// Configuration is a specification for a NGINXConfiguration resource
|
||||
type Configuration struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec ConfigurationSpec `json:"spec"`
|
||||
}
|
||||
|
||||
// ConfigurationSpec is the spec for a NGINXConfiguration resource
|
||||
type ConfigurationSpec struct {
|
||||
Auth *Auth `json:"auth,omitempty"`
|
||||
// ConfigurationSnippet contains additional configuration for the backend
|
||||
// to be considered in the configuration of the location
|
||||
ConfigurationSnippet string `json:"configurationSnippet,omitempty"`
|
||||
DefaultBackend string `json:"defaultBackend,omitempty"`
|
||||
// EnableCORS indicates if path must support CORS
|
||||
// +optional
|
||||
EnableCORS bool `json:"enableCors,omitempty"`
|
||||
// Proxy contains information about timeouts and buffer sizes
|
||||
// to be used in connections against endpoints
|
||||
// +optional
|
||||
Proxy *ProxyConfiguration `json:"proxy,omitempty"`
|
||||
// RateLimit describes a limit in the number of connections per IP
|
||||
// address or connections per second.
|
||||
// The Redirect annotation precedes RateLimit
|
||||
// +optional
|
||||
RateLimit *RateLimit `json:"rateLimit,omitempty"`
|
||||
// Redirect describes a temporal o permanent redirection this location.
|
||||
// +optional
|
||||
Redirect *Redirect `json:"redirect,omitempty"`
|
||||
// Rewrite describes the redirection this location.
|
||||
// +optional
|
||||
Rewrite *Rewrite `json:"rewrite,omitempty"`
|
||||
// ServerAlias return the alias of the server name
|
||||
// +optional
|
||||
ServerAlias string `json:"serverAlias,omitempty"`
|
||||
ServerSnippet string `json:"serverSnippet,omitempty"`
|
||||
SSLPassthrough bool `json:"sslPassthrough,omitempty"`
|
||||
// UsePortInRedirects indicates if redirects must specify the port
|
||||
// +optional
|
||||
UsePortInRedirects bool `json:"usePortInRedirects,omitempty"`
|
||||
// VTSFilterKey contains the vts filter key on the location level
|
||||
// https://github.com/vozlt/nginx-module-vts#vhost_traffic_status_filter_by_set_key
|
||||
// +optional
|
||||
VTSFilterKey string `json:"vtsFilterKey,omitempty"`
|
||||
// Whitelist indicates only connections from certain client
|
||||
// addresses or networks are allowed.
|
||||
// +optional
|
||||
Whitelist *Whitelist `json:"whitelist,omitempty"`
|
||||
|
||||
Upstream *Upstream `json:"upstream,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
// +resource:path=foos
|
||||
|
||||
// ConfigurationList is a list of Configuration resources
|
||||
type ConfigurationList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata"`
|
||||
|
||||
Items []Configuration `json:"items"`
|
||||
}
|
||||
|
||||
type Auth struct {
|
||||
Basic BasicDigestAuth `json:"basic"`
|
||||
Digest BasicDigestAuth `json:"digest"`
|
||||
Cert CertAuth `json:"cert"`
|
||||
External ExternalAuth `json:"external"`
|
||||
}
|
||||
|
||||
type CertAuth struct {
|
||||
resolver.AuthSSLCert
|
||||
VerifyClient string `json:"verify_client"`
|
||||
ValidationDepth int `json:"validationDepth"`
|
||||
ErrorPage string `json:"errorPage"`
|
||||
}
|
||||
|
||||
type BasicDigestAuth struct {
|
||||
Realm string `json:"realm"`
|
||||
File string `json:"file"`
|
||||
}
|
||||
|
||||
type ExternalAuth struct {
|
||||
URL string `json:"url"`
|
||||
// Host contains the hostname defined in the URL
|
||||
Host string `json:"host"`
|
||||
SigninURL string `json:"signinUrl"`
|
||||
Method string `json:"method"`
|
||||
SendBody bool `json:"sendBody"`
|
||||
ResponseHeaders []string `json:"responseHeaders,omitEmpty"`
|
||||
}
|
||||
|
||||
// ProxyConfiguration returns the proxy timeout to use in the upstream server/s
|
||||
type ProxyConfiguration struct {
|
||||
BodySize string `json:"bodySize"`
|
||||
// ClientBodyBufferSize allows for the configuration of the client body
|
||||
// buffer size for a specific location.
|
||||
ClientBodyBufferSize string `json:"clientBodyBufferSize"`
|
||||
ConnectTimeout int `json:"connectTimeout"`
|
||||
SendTimeout int `json:"sendTimeout"`
|
||||
ReadTimeout int `json:"readTimeout"`
|
||||
BufferSize string `json:"bufferSize"`
|
||||
CookieDomain string `json:"cookieDomain"`
|
||||
CookiePath string `json:"cookiePath"`
|
||||
NextUpstream string `json:"nextUpstream"`
|
||||
PassParams string `json:"passParams"`
|
||||
RequestBuffering string `json:"requestBuffering"`
|
||||
// UpstreamVirtualHost overwrites the Host header passed into the backend.
|
||||
// Defaults to virtual host of the incoming request.
|
||||
HostHeader string `json:"upstreamVirtualHost"`
|
||||
}
|
||||
|
||||
// Upstream returns the URL and method to use check the status of
|
||||
// the upstream server/s
|
||||
type Upstream struct {
|
||||
UseServiceInUpstream bool
|
||||
// SecureUpstream describes SSL backend configuration
|
||||
SecureUpstream bool `json:"secure"`
|
||||
UpstreamCACertificate AuthSSLCert `json:"caCert"`
|
||||
HashBy string `json:"hashBy"`
|
||||
MaxFails int `json:"maxFails"`
|
||||
FailTimeout int `json:"failTimeout"`
|
||||
// SessionAffinity configures the nginx session affinity
|
||||
SessionAffinity *AffinityConfig `json:"sessionAfinity,omitempty"`
|
||||
}
|
||||
|
||||
// AuthSSLCert contains the necessary information to do certificate based
|
||||
// authentication of an ingress location
|
||||
type AuthSSLCert struct {
|
||||
// Secret contains the name of the secret this was fetched from
|
||||
Secret string `json:"secret"`
|
||||
// CAFileName contains the path to the secrets 'ca.crt'
|
||||
CAFileName string `json:"caFilename"`
|
||||
// PemSHA contains the SHA1 hash of the 'ca.crt' or combinations of (tls.crt, tls.key, tls.crt) depending on certs in secret
|
||||
PemSHA string `json:"pemSha"`
|
||||
}
|
||||
|
||||
type Whitelist struct {
|
||||
CIDR []string `json:"cidr,omitEmpty"`
|
||||
}
|
||||
|
||||
type Redirect struct {
|
||||
URL string `json:"url"`
|
||||
Code int `json:"code"`
|
||||
FromToWWW bool `json:"fromToWWW"`
|
||||
}
|
||||
|
||||
type Rewrite struct {
|
||||
// AddBaseURL indicates if is required to add a base tag in the head
|
||||
// of the responses from the upstream servers
|
||||
AddBaseURL bool `json:"addBaseUrl"`
|
||||
// AppRoot defines the Application Root that the Controller must redirect if it's not in '/' context
|
||||
AppRoot string `json:"appRoot"`
|
||||
// BaseURLScheme override for the scheme passed to the base tag
|
||||
BaseURLScheme string `json:"baseUrlScheme"`
|
||||
// ForceSSLRedirect indicates if the location section is accessible SSL only
|
||||
ForceSSLRedirect bool `json:"forceSSLRedirect"`
|
||||
// SSLRedirect indicates if the location section is accessible SSL only
|
||||
SSLRedirect bool `json:"sslRedirect"`
|
||||
// Target URI where the traffic must be redirected
|
||||
Target string `json:"target"`
|
||||
}
|
||||
|
||||
// RateLimit returns rate limit configuration for an Ingress rule limiting the
|
||||
// number of connections per IP address and/or connections per second.
|
||||
// If you both annotations are specified in a single Ingress rule, RPS limits
|
||||
// takes precedence
|
||||
type RateLimit struct {
|
||||
// Connections indicates a limit with the number of connections per IP address
|
||||
Connections Zone `json:"connections"`
|
||||
// RPS indicates a limit with the number of connections per second
|
||||
RPS Zone `json:"rps"`
|
||||
// RPM indicates a limit with the number of connections per minute
|
||||
RPM Zone `json:"rpm"`
|
||||
|
||||
LimitRate int `json:"limit-rate"`
|
||||
|
||||
LimitRateAfter int `json:"limit-rate-after"`
|
||||
|
||||
Name string `json:"name"`
|
||||
|
||||
ID string `json:"id"`
|
||||
|
||||
Whitelist Whitelist `json:"whitelist"`
|
||||
}
|
||||
|
||||
// AffinityConfig describes the per ingress session affinity configuration
|
||||
type AffinityConfig struct {
|
||||
// The type of affinity that will be used
|
||||
AffinityType string `json:"type"`
|
||||
CookieConfig
|
||||
}
|
||||
|
||||
// CookieConfig describes the Config of cookie type affinity
|
||||
type CookieConfig struct {
|
||||
// The name of the cookie that will be used in case of cookie affinity type.
|
||||
Name string `json:"name"`
|
||||
// The hash that will be used to encode the cookie in case of cookie affinity type
|
||||
Hash string `json:"hash"`
|
||||
Locations map[string][]string `json:"locations,omitempty"`
|
||||
}
|
||||
|
||||
// Zone returns information about the NGINX rate limit (limit_req_zone)
|
||||
// http://nginx.org/en/docs/http/ngx_http_limit_req_module.html#limit_req_zone
|
||||
type Zone struct {
|
||||
Name string `json:"name"`
|
||||
Limit int `json:"limit"`
|
||||
Burst int `json:"burst"`
|
||||
// SharedSize amount of shared memory for the zone
|
||||
SharedSize int `json:"sharedSize"`
|
||||
}
|
449
pkg/apis/nginxingress/v1alpha1/zz_generated.deepcopy.go
Normal file
449
pkg/apis/nginxingress/v1alpha1/zz_generated.deepcopy.go
Normal file
|
@ -0,0 +1,449 @@
|
|||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
conversion "k8s.io/apimachinery/pkg/conversion"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(RegisterDeepCopies)
|
||||
}
|
||||
|
||||
// RegisterDeepCopies adds deep-copy functions to the given scheme. Public
|
||||
// to allow building arbitrary schemes.
|
||||
//
|
||||
// Deprecated: deepcopy registration will go away when static deepcopy is fully implemented.
|
||||
func RegisterDeepCopies(scheme *runtime.Scheme) error {
|
||||
return scheme.AddGeneratedDeepCopyFuncs(
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*AffinityConfig).DeepCopyInto(out.(*AffinityConfig))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&AffinityConfig{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*Auth).DeepCopyInto(out.(*Auth))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&Auth{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*BasicDigestAuth).DeepCopyInto(out.(*BasicDigestAuth))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&BasicDigestAuth{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*CertAuth).DeepCopyInto(out.(*CertAuth))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&CertAuth{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*Configuration).DeepCopyInto(out.(*Configuration))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&Configuration{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*ConfigurationList).DeepCopyInto(out.(*ConfigurationList))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&ConfigurationList{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*ConfigurationSpec).DeepCopyInto(out.(*ConfigurationSpec))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&ConfigurationSpec{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*CookieConfig).DeepCopyInto(out.(*CookieConfig))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&CookieConfig{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*ExternalAuth).DeepCopyInto(out.(*ExternalAuth))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&ExternalAuth{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*ProxyConfiguration).DeepCopyInto(out.(*ProxyConfiguration))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&ProxyConfiguration{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*RateLimit).DeepCopyInto(out.(*RateLimit))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&RateLimit{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*Redirect).DeepCopyInto(out.(*Redirect))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&Redirect{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*Rewrite).DeepCopyInto(out.(*Rewrite))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&Rewrite{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*Whitelist).DeepCopyInto(out.(*Whitelist))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&Whitelist{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*Zone).DeepCopyInto(out.(*Zone))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&Zone{})},
|
||||
)
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AffinityConfig) DeepCopyInto(out *AffinityConfig) {
|
||||
*out = *in
|
||||
out.CookieConfig = in.CookieConfig
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AffinityConfig.
|
||||
func (in *AffinityConfig) DeepCopy() *AffinityConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(AffinityConfig)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Auth) DeepCopyInto(out *Auth) {
|
||||
*out = *in
|
||||
out.Basic = in.Basic
|
||||
out.Digest = in.Digest
|
||||
out.Cert = in.Cert
|
||||
in.External.DeepCopyInto(&out.External)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Auth.
|
||||
func (in *Auth) DeepCopy() *Auth {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Auth)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *BasicDigestAuth) DeepCopyInto(out *BasicDigestAuth) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BasicDigestAuth.
|
||||
func (in *BasicDigestAuth) DeepCopy() *BasicDigestAuth {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(BasicDigestAuth)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CertAuth) DeepCopyInto(out *CertAuth) {
|
||||
*out = *in
|
||||
out.AuthSSLCert = in.AuthSSLCert
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CertAuth.
|
||||
func (in *CertAuth) DeepCopy() *CertAuth {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CertAuth)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Configuration) DeepCopyInto(out *Configuration) {
|
||||
*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 Configuration.
|
||||
func (in *Configuration) DeepCopy() *Configuration {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Configuration)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *Configuration) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ConfigurationList) DeepCopyInto(out *ConfigurationList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]Configuration, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigurationList.
|
||||
func (in *ConfigurationList) DeepCopy() *ConfigurationList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ConfigurationList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *ConfigurationList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ConfigurationSpec) DeepCopyInto(out *ConfigurationSpec) {
|
||||
*out = *in
|
||||
if in.Auth != nil {
|
||||
in, out := &in.Auth, &out.Auth
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(Auth)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
if in.Proxy != nil {
|
||||
in, out := &in.Proxy, &out.Proxy
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(ProxyConfiguration)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.RateLimit != nil {
|
||||
in, out := &in.RateLimit, &out.RateLimit
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(RateLimit)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
if in.Redirect != nil {
|
||||
in, out := &in.Redirect, &out.Redirect
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(Redirect)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
out.Rewrite = in.Rewrite
|
||||
if in.SessionAffinity != nil {
|
||||
in, out := &in.SessionAffinity, &out.SessionAffinity
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(AffinityConfig)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.Whitelist != nil {
|
||||
in, out := &in.Whitelist, &out.Whitelist
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(Whitelist)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigurationSpec.
|
||||
func (in *ConfigurationSpec) DeepCopy() *ConfigurationSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ConfigurationSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CookieConfig) DeepCopyInto(out *CookieConfig) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CookieConfig.
|
||||
func (in *CookieConfig) DeepCopy() *CookieConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CookieConfig)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ExternalAuth) DeepCopyInto(out *ExternalAuth) {
|
||||
*out = *in
|
||||
if in.ResponseHeaders != nil {
|
||||
in, out := &in.ResponseHeaders, &out.ResponseHeaders
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalAuth.
|
||||
func (in *ExternalAuth) DeepCopy() *ExternalAuth {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ExternalAuth)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ProxyConfiguration) DeepCopyInto(out *ProxyConfiguration) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProxyConfiguration.
|
||||
func (in *ProxyConfiguration) DeepCopy() *ProxyConfiguration {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ProxyConfiguration)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *RateLimit) DeepCopyInto(out *RateLimit) {
|
||||
*out = *in
|
||||
out.Connections = in.Connections
|
||||
out.RPS = in.RPS
|
||||
out.RPM = in.RPM
|
||||
if in.Whitelist != nil {
|
||||
in, out := &in.Whitelist, &out.Whitelist
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RateLimit.
|
||||
func (in *RateLimit) DeepCopy() *RateLimit {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(RateLimit)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Redirect) DeepCopyInto(out *Redirect) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Redirect.
|
||||
func (in *Redirect) DeepCopy() *Redirect {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Redirect)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Rewrite) DeepCopyInto(out *Rewrite) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Rewrite.
|
||||
func (in *Rewrite) DeepCopy() *Rewrite {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Rewrite)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Whitelist) DeepCopyInto(out *Whitelist) {
|
||||
*out = *in
|
||||
if in.CIDR != nil {
|
||||
in, out := &in.CIDR, &out.CIDR
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Whitelist.
|
||||
func (in *Whitelist) DeepCopy() *Whitelist {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Whitelist)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Zone) DeepCopyInto(out *Zone) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Zone.
|
||||
func (in *Zone) DeepCopy() *Zone {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Zone)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
98
pkg/client/clientset/versioned/clientset.go
Normal file
98
pkg/client/clientset/versioned/clientset.go
Normal file
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package versioned
|
||||
|
||||
import (
|
||||
glog "github.com/golang/glog"
|
||||
discovery "k8s.io/client-go/discovery"
|
||||
rest "k8s.io/client-go/rest"
|
||||
flowcontrol "k8s.io/client-go/util/flowcontrol"
|
||||
nginxv1alpha1 "k8s.io/ingress-nginx/pkg/client/clientset/versioned/typed/nginx/v1alpha1"
|
||||
)
|
||||
|
||||
type Interface interface {
|
||||
Discovery() discovery.DiscoveryInterface
|
||||
NginxV1alpha1() nginxv1alpha1.NginxV1alpha1Interface
|
||||
// Deprecated: please explicitly pick a version if possible.
|
||||
Nginx() nginxv1alpha1.NginxV1alpha1Interface
|
||||
}
|
||||
|
||||
// Clientset contains the clients for groups. Each group has exactly one
|
||||
// version included in a Clientset.
|
||||
type Clientset struct {
|
||||
*discovery.DiscoveryClient
|
||||
nginxV1alpha1 *nginxv1alpha1.NginxV1alpha1Client
|
||||
}
|
||||
|
||||
// NginxV1alpha1 retrieves the NginxV1alpha1Client
|
||||
func (c *Clientset) NginxV1alpha1() nginxv1alpha1.NginxV1alpha1Interface {
|
||||
return c.nginxV1alpha1
|
||||
}
|
||||
|
||||
// Deprecated: Nginx retrieves the default version of NginxClient.
|
||||
// Please explicitly pick a version.
|
||||
func (c *Clientset) Nginx() nginxv1alpha1.NginxV1alpha1Interface {
|
||||
return c.nginxV1alpha1
|
||||
}
|
||||
|
||||
// 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.nginxV1alpha1, err = nginxv1alpha1.NewForConfig(&configShallowCopy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy)
|
||||
if err != nil {
|
||||
glog.Errorf("failed to create the DiscoveryClient: %v", err)
|
||||
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.nginxV1alpha1 = nginxv1alpha1.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.nginxV1alpha1 = nginxv1alpha1.New(c)
|
||||
|
||||
cs.DiscoveryClient = discovery.NewDiscoveryClient(c)
|
||||
return &cs
|
||||
}
|
20
pkg/client/clientset/versioned/doc.go
Normal file
20
pkg/client/clientset/versioned/doc.go
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// This package is generated by client-gen with custom arguments.
|
||||
|
||||
// This package has the automatically generated clientset.
|
||||
package versioned
|
71
pkg/client/clientset/versioned/fake/clientset_generated.go
Normal file
71
pkg/client/clientset/versioned/fake/clientset_generated.go
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
"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"
|
||||
clientset "k8s.io/ingress-nginx/pkg/client/clientset/versioned"
|
||||
nginxv1alpha1 "k8s.io/ingress-nginx/pkg/client/clientset/versioned/typed/nginx/v1alpha1"
|
||||
fakenginxv1alpha1 "k8s.io/ingress-nginx/pkg/client/clientset/versioned/typed/nginx/v1alpha1/fake"
|
||||
)
|
||||
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
||||
fakePtr := testing.Fake{}
|
||||
fakePtr.AddReactor("*", "*", testing.ObjectReaction(o))
|
||||
fakePtr.AddWatchReactor("*", testing.DefaultWatchReactor(watch.NewFake(), nil))
|
||||
|
||||
return &Clientset{fakePtr, &fakediscovery.FakeDiscovery{Fake: &fakePtr}}
|
||||
}
|
||||
|
||||
// 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{}
|
||||
|
||||
// NginxV1alpha1 retrieves the NginxV1alpha1Client
|
||||
func (c *Clientset) NginxV1alpha1() nginxv1alpha1.NginxV1alpha1Interface {
|
||||
return &fakenginxv1alpha1.FakeNginxV1alpha1{Fake: &c.Fake}
|
||||
}
|
||||
|
||||
// Nginx retrieves the NginxV1alpha1Client
|
||||
func (c *Clientset) Nginx() nginxv1alpha1.NginxV1alpha1Interface {
|
||||
return &fakenginxv1alpha1.FakeNginxV1alpha1{Fake: &c.Fake}
|
||||
}
|
20
pkg/client/clientset/versioned/fake/doc.go
Normal file
20
pkg/client/clientset/versioned/fake/doc.go
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// This package is generated by client-gen with custom arguments.
|
||||
|
||||
// This package has the automatically generated fake clientset.
|
||||
package fake
|
53
pkg/client/clientset/versioned/fake/register.go
Normal file
53
pkg/client/clientset/versioned/fake/register.go
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
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"
|
||||
nginxv1alpha1 "k8s.io/ingress-nginx/pkg/apis/nginxingress/v1alpha1"
|
||||
)
|
||||
|
||||
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/kuberentes/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) {
|
||||
nginxv1alpha1.AddToScheme(scheme)
|
||||
|
||||
}
|
20
pkg/client/clientset/versioned/scheme/doc.go
Normal file
20
pkg/client/clientset/versioned/scheme/doc.go
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// This package is generated by client-gen with custom arguments.
|
||||
|
||||
// This package contains the scheme of the automatically generated clientset.
|
||||
package scheme
|
53
pkg/client/clientset/versioned/scheme/register.go
Normal file
53
pkg/client/clientset/versioned/scheme/register.go
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package scheme
|
||||
|
||||
import (
|
||||
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"
|
||||
nginxv1alpha1 "k8s.io/ingress-nginx/pkg/apis/nginxingress/v1alpha1"
|
||||
)
|
||||
|
||||
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/kuberentes/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) {
|
||||
nginxv1alpha1.AddToScheme(scheme)
|
||||
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
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"
|
||||
v1alpha1 "k8s.io/ingress-nginx/pkg/apis/nginxingress/v1alpha1"
|
||||
scheme "k8s.io/ingress-nginx/pkg/client/clientset/versioned/scheme"
|
||||
)
|
||||
|
||||
// ConfigurationsGetter has a method to return a ConfigurationInterface.
|
||||
// A group's client should implement this interface.
|
||||
type ConfigurationsGetter interface {
|
||||
Configurations(namespace string) ConfigurationInterface
|
||||
}
|
||||
|
||||
// ConfigurationInterface has methods to work with Configuration resources.
|
||||
type ConfigurationInterface interface {
|
||||
Create(*v1alpha1.Configuration) (*v1alpha1.Configuration, error)
|
||||
Update(*v1alpha1.Configuration) (*v1alpha1.Configuration, error)
|
||||
Delete(name string, options *v1.DeleteOptions) error
|
||||
DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error
|
||||
Get(name string, options v1.GetOptions) (*v1alpha1.Configuration, error)
|
||||
List(opts v1.ListOptions) (*v1alpha1.ConfigurationList, error)
|
||||
Watch(opts v1.ListOptions) (watch.Interface, error)
|
||||
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Configuration, err error)
|
||||
ConfigurationExpansion
|
||||
}
|
||||
|
||||
// configurations implements ConfigurationInterface
|
||||
type configurations struct {
|
||||
client rest.Interface
|
||||
ns string
|
||||
}
|
||||
|
||||
// newConfigurations returns a Configurations
|
||||
func newConfigurations(c *NginxV1alpha1Client, namespace string) *configurations {
|
||||
return &configurations{
|
||||
client: c.RESTClient(),
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// Get takes name of the configuration, and returns the corresponding configuration object, and an error if there is any.
|
||||
func (c *configurations) Get(name string, options v1.GetOptions) (result *v1alpha1.Configuration, err error) {
|
||||
result = &v1alpha1.Configuration{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("configurations").
|
||||
Name(name).
|
||||
VersionedParams(&options, scheme.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of Configurations that match those selectors.
|
||||
func (c *configurations) List(opts v1.ListOptions) (result *v1alpha1.ConfigurationList, err error) {
|
||||
result = &v1alpha1.ConfigurationList{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("configurations").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested configurations.
|
||||
func (c *configurations) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
opts.Watch = true
|
||||
return c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("configurations").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Watch()
|
||||
}
|
||||
|
||||
// Create takes the representation of a configuration and creates it. Returns the server's representation of the configuration, and an error, if there is any.
|
||||
func (c *configurations) Create(configuration *v1alpha1.Configuration) (result *v1alpha1.Configuration, err error) {
|
||||
result = &v1alpha1.Configuration{}
|
||||
err = c.client.Post().
|
||||
Namespace(c.ns).
|
||||
Resource("configurations").
|
||||
Body(configuration).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update takes the representation of a configuration and updates it. Returns the server's representation of the configuration, and an error, if there is any.
|
||||
func (c *configurations) Update(configuration *v1alpha1.Configuration) (result *v1alpha1.Configuration, err error) {
|
||||
result = &v1alpha1.Configuration{}
|
||||
err = c.client.Put().
|
||||
Namespace(c.ns).
|
||||
Resource("configurations").
|
||||
Name(configuration.Name).
|
||||
Body(configuration).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes name of the configuration and deletes it. Returns an error if one occurs.
|
||||
func (c *configurations) Delete(name string, options *v1.DeleteOptions) error {
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("configurations").
|
||||
Name(name).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *configurations) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("configurations").
|
||||
VersionedParams(&listOptions, scheme.ParameterCodec).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched configuration.
|
||||
func (c *configurations) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Configuration, err error) {
|
||||
result = &v1alpha1.Configuration{}
|
||||
err = c.client.Patch(pt).
|
||||
Namespace(c.ns).
|
||||
Resource("configurations").
|
||||
SubResource(subresources...).
|
||||
Name(name).
|
||||
Body(data).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
20
pkg/client/clientset/versioned/typed/nginx/v1alpha1/doc.go
Normal file
20
pkg/client/clientset/versioned/typed/nginx/v1alpha1/doc.go
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// This package is generated by client-gen with custom arguments.
|
||||
|
||||
// This package has the automatically generated typed clients.
|
||||
package v1alpha1
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// This package is generated by client-gen with custom arguments.
|
||||
|
||||
// Package fake has the automatically generated clients.
|
||||
package fake
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
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"
|
||||
v1alpha1 "k8s.io/ingress-nginx/pkg/apis/nginxingress/v1alpha1"
|
||||
)
|
||||
|
||||
// FakeConfigurations implements ConfigurationInterface
|
||||
type FakeConfigurations struct {
|
||||
Fake *FakeNginxV1alpha1
|
||||
ns string
|
||||
}
|
||||
|
||||
var configurationsResource = schema.GroupVersionResource{Group: "nginx.ingress.k8s.io", Version: "v1alpha1", Resource: "configurations"}
|
||||
|
||||
var configurationsKind = schema.GroupVersionKind{Group: "nginx.ingress.k8s.io", Version: "v1alpha1", Kind: "Configuration"}
|
||||
|
||||
// Get takes name of the configuration, and returns the corresponding configuration object, and an error if there is any.
|
||||
func (c *FakeConfigurations) Get(name string, options v1.GetOptions) (result *v1alpha1.Configuration, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewGetAction(configurationsResource, c.ns, name), &v1alpha1.Configuration{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.Configuration), err
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of Configurations that match those selectors.
|
||||
func (c *FakeConfigurations) List(opts v1.ListOptions) (result *v1alpha1.ConfigurationList, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewListAction(configurationsResource, configurationsKind, c.ns, opts), &v1alpha1.ConfigurationList{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
label, _, _ := testing.ExtractFromListOptions(opts)
|
||||
if label == nil {
|
||||
label = labels.Everything()
|
||||
}
|
||||
list := &v1alpha1.ConfigurationList{}
|
||||
for _, item := range obj.(*v1alpha1.ConfigurationList).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 configurations.
|
||||
func (c *FakeConfigurations) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
return c.Fake.
|
||||
InvokesWatch(testing.NewWatchAction(configurationsResource, c.ns, opts))
|
||||
|
||||
}
|
||||
|
||||
// Create takes the representation of a configuration and creates it. Returns the server's representation of the configuration, and an error, if there is any.
|
||||
func (c *FakeConfigurations) Create(configuration *v1alpha1.Configuration) (result *v1alpha1.Configuration, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewCreateAction(configurationsResource, c.ns, configuration), &v1alpha1.Configuration{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.Configuration), err
|
||||
}
|
||||
|
||||
// Update takes the representation of a configuration and updates it. Returns the server's representation of the configuration, and an error, if there is any.
|
||||
func (c *FakeConfigurations) Update(configuration *v1alpha1.Configuration) (result *v1alpha1.Configuration, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewUpdateAction(configurationsResource, c.ns, configuration), &v1alpha1.Configuration{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.Configuration), err
|
||||
}
|
||||
|
||||
// Delete takes name of the configuration and deletes it. Returns an error if one occurs.
|
||||
func (c *FakeConfigurations) Delete(name string, options *v1.DeleteOptions) error {
|
||||
_, err := c.Fake.
|
||||
Invokes(testing.NewDeleteAction(configurationsResource, c.ns, name), &v1alpha1.Configuration{})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *FakeConfigurations) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
action := testing.NewDeleteCollectionAction(configurationsResource, c.ns, listOptions)
|
||||
|
||||
_, err := c.Fake.Invokes(action, &v1alpha1.ConfigurationList{})
|
||||
return err
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched configuration.
|
||||
func (c *FakeConfigurations) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Configuration, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewPatchSubresourceAction(configurationsResource, c.ns, name, data, subresources...), &v1alpha1.Configuration{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.Configuration), err
|
||||
}
|
|
@ -14,28 +14,25 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package alias
|
||||
package fake
|
||||
|
||||
import (
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
|
||||
rest "k8s.io/client-go/rest"
|
||||
testing "k8s.io/client-go/testing"
|
||||
v1alpha1 "k8s.io/ingress-nginx/pkg/client/clientset/versioned/typed/nginx/v1alpha1"
|
||||
)
|
||||
|
||||
const (
|
||||
annotation = "ingress.kubernetes.io/server-alias"
|
||||
)
|
||||
|
||||
type alias struct {
|
||||
type FakeNginxV1alpha1 struct {
|
||||
*testing.Fake
|
||||
}
|
||||
|
||||
// NewParser creates a new Alias annotation parser
|
||||
func NewParser() parser.IngressAnnotation {
|
||||
return alias{}
|
||||
func (c *FakeNginxV1alpha1) Configurations(namespace string) v1alpha1.ConfigurationInterface {
|
||||
return &FakeConfigurations{c, namespace}
|
||||
}
|
||||
|
||||
// Parse parses the annotations contained in the ingress rule
|
||||
// used to add an alias to the provided hosts
|
||||
func (a alias) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||
return parser.GetStringAnnotation(annotation, ing)
|
||||
// RESTClient returns a RESTClient that is used to communicate
|
||||
// with API server by this client implementation.
|
||||
func (c *FakeNginxV1alpha1) RESTClient() rest.Interface {
|
||||
var ret *rest.RESTClient
|
||||
return ret
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1alpha1
|
||||
|
||||
type ConfigurationExpansion interface{}
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
serializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
rest "k8s.io/client-go/rest"
|
||||
v1alpha1 "k8s.io/ingress-nginx/pkg/apis/nginxingress/v1alpha1"
|
||||
"k8s.io/ingress-nginx/pkg/client/clientset/versioned/scheme"
|
||||
)
|
||||
|
||||
type NginxV1alpha1Interface interface {
|
||||
RESTClient() rest.Interface
|
||||
ConfigurationsGetter
|
||||
}
|
||||
|
||||
// NginxV1alpha1Client is used to interact with features provided by the nginx.ingress.k8s.io group.
|
||||
type NginxV1alpha1Client struct {
|
||||
restClient rest.Interface
|
||||
}
|
||||
|
||||
func (c *NginxV1alpha1Client) Configurations(namespace string) ConfigurationInterface {
|
||||
return newConfigurations(c, namespace)
|
||||
}
|
||||
|
||||
// NewForConfig creates a new NginxV1alpha1Client for the given config.
|
||||
func NewForConfig(c *rest.Config) (*NginxV1alpha1Client, error) {
|
||||
config := *c
|
||||
if err := setConfigDefaults(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client, err := rest.RESTClientFor(&config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &NginxV1alpha1Client{client}, nil
|
||||
}
|
||||
|
||||
// NewForConfigOrDie creates a new NginxV1alpha1Client for the given config and
|
||||
// panics if there is an error in the config.
|
||||
func NewForConfigOrDie(c *rest.Config) *NginxV1alpha1Client {
|
||||
client, err := NewForConfig(c)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return client
|
||||
}
|
||||
|
||||
// New creates a new NginxV1alpha1Client for the given RESTClient.
|
||||
func New(c rest.Interface) *NginxV1alpha1Client {
|
||||
return &NginxV1alpha1Client{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 *NginxV1alpha1Client) RESTClient() rest.Interface {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
return c.restClient
|
||||
}
|
118
pkg/client/informers/externalversions/factory.go
Normal file
118
pkg/client/informers/externalversions/factory.go
Normal file
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// This file was automatically generated by informer-gen
|
||||
|
||||
package externalversions
|
||||
|
||||
import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
versioned "k8s.io/ingress-nginx/pkg/client/clientset/versioned"
|
||||
internalinterfaces "k8s.io/ingress-nginx/pkg/client/informers/externalversions/internalinterfaces"
|
||||
nginx "k8s.io/ingress-nginx/pkg/client/informers/externalversions/nginx"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
time "time"
|
||||
)
|
||||
|
||||
type sharedInformerFactory struct {
|
||||
client versioned.Interface
|
||||
lock sync.Mutex
|
||||
defaultResync 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
|
||||
}
|
||||
|
||||
// NewSharedInformerFactory constructs a new instance of sharedInformerFactory
|
||||
func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory {
|
||||
return &sharedInformerFactory{
|
||||
client: client,
|
||||
defaultResync: defaultResync,
|
||||
informers: make(map[reflect.Type]cache.SharedIndexInformer),
|
||||
startedInformers: make(map[reflect.Type]bool),
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
informer = newFunc(f.client, f.defaultResync)
|
||||
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
|
||||
|
||||
Nginx() nginx.Interface
|
||||
}
|
||||
|
||||
func (f *sharedInformerFactory) Nginx() nginx.Interface {
|
||||
return nginx.New(f)
|
||||
}
|
61
pkg/client/informers/externalversions/generic.go
Normal file
61
pkg/client/informers/externalversions/generic.go
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// This file was automatically generated by informer-gen
|
||||
|
||||
package externalversions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
v1alpha1 "k8s.io/ingress-nginx/pkg/apis/nginxingress/v1alpha1"
|
||||
)
|
||||
|
||||
// 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 {
|
||||
// Group=Nginx, Version=V1alpha1
|
||||
case v1alpha1.SchemeGroupVersion.WithResource("configurations"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Nginx().V1alpha1().Configurations().Informer()}, nil
|
||||
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("no informer found for %v", resource)
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// This file was automatically generated by informer-gen
|
||||
|
||||
package internalinterfaces
|
||||
|
||||
import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
versioned "k8s.io/ingress-nginx/pkg/client/clientset/versioned"
|
||||
time "time"
|
||||
)
|
||||
|
||||
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
|
||||
}
|
44
pkg/client/informers/externalversions/nginx/interface.go
Normal file
44
pkg/client/informers/externalversions/nginx/interface.go
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// This file was automatically generated by informer-gen
|
||||
|
||||
package nginx
|
||||
|
||||
import (
|
||||
internalinterfaces "k8s.io/ingress-nginx/pkg/client/informers/externalversions/internalinterfaces"
|
||||
v1alpha1 "k8s.io/ingress-nginx/pkg/client/informers/externalversions/nginx/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 {
|
||||
internalinterfaces.SharedInformerFactory
|
||||
}
|
||||
|
||||
// New returns a new Interface.
|
||||
func New(f internalinterfaces.SharedInformerFactory) Interface {
|
||||
return &group{f}
|
||||
}
|
||||
|
||||
// V1alpha1 returns a new v1alpha1.Interface.
|
||||
func (g *group) V1alpha1() v1alpha1.Interface {
|
||||
return v1alpha1.New(g.SharedInformerFactory)
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// This file was automatically generated by informer-gen
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
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"
|
||||
nginxingress_v1alpha1 "k8s.io/ingress-nginx/pkg/apis/nginxingress/v1alpha1"
|
||||
versioned "k8s.io/ingress-nginx/pkg/client/clientset/versioned"
|
||||
internalinterfaces "k8s.io/ingress-nginx/pkg/client/informers/externalversions/internalinterfaces"
|
||||
v1alpha1 "k8s.io/ingress-nginx/pkg/client/listers/nginx/v1alpha1"
|
||||
time "time"
|
||||
)
|
||||
|
||||
// ConfigurationInformer provides access to a shared informer and lister for
|
||||
// Configurations.
|
||||
type ConfigurationInformer interface {
|
||||
Informer() cache.SharedIndexInformer
|
||||
Lister() v1alpha1.ConfigurationLister
|
||||
}
|
||||
|
||||
type configurationInformer struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
}
|
||||
|
||||
// NewConfigurationInformer constructs a new informer for Configuration 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 NewConfigurationInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
|
||||
return cache.NewSharedIndexInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
|
||||
return client.NginxV1alpha1().Configurations(namespace).List(options)
|
||||
},
|
||||
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
|
||||
return client.NginxV1alpha1().Configurations(namespace).Watch(options)
|
||||
},
|
||||
},
|
||||
&nginxingress_v1alpha1.Configuration{},
|
||||
resyncPeriod,
|
||||
indexers,
|
||||
)
|
||||
}
|
||||
|
||||
func defaultConfigurationInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
|
||||
return NewConfigurationInformer(client, v1.NamespaceAll, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})
|
||||
}
|
||||
|
||||
func (f *configurationInformer) Informer() cache.SharedIndexInformer {
|
||||
return f.factory.InformerFor(&nginxingress_v1alpha1.Configuration{}, defaultConfigurationInformer)
|
||||
}
|
||||
|
||||
func (f *configurationInformer) Lister() v1alpha1.ConfigurationLister {
|
||||
return v1alpha1.NewConfigurationLister(f.Informer().GetIndexer())
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// This file was automatically generated by informer-gen
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
internalinterfaces "k8s.io/ingress-nginx/pkg/client/informers/externalversions/internalinterfaces"
|
||||
)
|
||||
|
||||
// Interface provides access to all the informers in this group version.
|
||||
type Interface interface {
|
||||
// Configurations returns a ConfigurationInformer.
|
||||
Configurations() ConfigurationInformer
|
||||
}
|
||||
|
||||
type version struct {
|
||||
internalinterfaces.SharedInformerFactory
|
||||
}
|
||||
|
||||
// New returns a new Interface.
|
||||
func New(f internalinterfaces.SharedInformerFactory) Interface {
|
||||
return &version{f}
|
||||
}
|
||||
|
||||
// Configurations returns a ConfigurationInformer.
|
||||
func (v *version) Configurations() ConfigurationInformer {
|
||||
return &configurationInformer{factory: v.SharedInformerFactory}
|
||||
}
|
94
pkg/client/listers/nginx/v1alpha1/configuration.go
Normal file
94
pkg/client/listers/nginx/v1alpha1/configuration.go
Normal file
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// This file was automatically generated by lister-gen
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
v1alpha1 "k8s.io/ingress-nginx/pkg/apis/nginxingress/v1alpha1"
|
||||
)
|
||||
|
||||
// ConfigurationLister helps list Configurations.
|
||||
type ConfigurationLister interface {
|
||||
// List lists all Configurations in the indexer.
|
||||
List(selector labels.Selector) (ret []*v1alpha1.Configuration, err error)
|
||||
// Configurations returns an object that can list and get Configurations.
|
||||
Configurations(namespace string) ConfigurationNamespaceLister
|
||||
ConfigurationListerExpansion
|
||||
}
|
||||
|
||||
// configurationLister implements the ConfigurationLister interface.
|
||||
type configurationLister struct {
|
||||
indexer cache.Indexer
|
||||
}
|
||||
|
||||
// NewConfigurationLister returns a new ConfigurationLister.
|
||||
func NewConfigurationLister(indexer cache.Indexer) ConfigurationLister {
|
||||
return &configurationLister{indexer: indexer}
|
||||
}
|
||||
|
||||
// List lists all Configurations in the indexer.
|
||||
func (s *configurationLister) List(selector labels.Selector) (ret []*v1alpha1.Configuration, err error) {
|
||||
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1alpha1.Configuration))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Configurations returns an object that can list and get Configurations.
|
||||
func (s *configurationLister) Configurations(namespace string) ConfigurationNamespaceLister {
|
||||
return configurationNamespaceLister{indexer: s.indexer, namespace: namespace}
|
||||
}
|
||||
|
||||
// ConfigurationNamespaceLister helps list and get Configurations.
|
||||
type ConfigurationNamespaceLister interface {
|
||||
// List lists all Configurations in the indexer for a given namespace.
|
||||
List(selector labels.Selector) (ret []*v1alpha1.Configuration, err error)
|
||||
// Get retrieves the Configuration from the indexer for a given namespace and name.
|
||||
Get(name string) (*v1alpha1.Configuration, error)
|
||||
ConfigurationNamespaceListerExpansion
|
||||
}
|
||||
|
||||
// configurationNamespaceLister implements the ConfigurationNamespaceLister
|
||||
// interface.
|
||||
type configurationNamespaceLister struct {
|
||||
indexer cache.Indexer
|
||||
namespace string
|
||||
}
|
||||
|
||||
// List lists all Configurations in the indexer for a given namespace.
|
||||
func (s configurationNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.Configuration, err error) {
|
||||
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1alpha1.Configuration))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get retrieves the Configuration from the indexer for a given namespace and name.
|
||||
func (s configurationNamespaceLister) Get(name string) (*v1alpha1.Configuration, error) {
|
||||
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exists {
|
||||
return nil, errors.NewNotFound(v1alpha1.Resource("configuration"), name)
|
||||
}
|
||||
return obj.(*v1alpha1.Configuration), nil
|
||||
}
|
27
pkg/client/listers/nginx/v1alpha1/expansion_generated.go
Normal file
27
pkg/client/listers/nginx/v1alpha1/expansion_generated.go
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// This file was automatically generated by lister-gen
|
||||
|
||||
package v1alpha1
|
||||
|
||||
// ConfigurationListerExpansion allows custom methods to be added to
|
||||
// ConfigurationLister.
|
||||
type ConfigurationListerExpansion interface{}
|
||||
|
||||
// ConfigurationNamespaceListerExpansion allows custom methods to be added to
|
||||
// ConfigurationNamespaceLister.
|
||||
type ConfigurationNamespaceListerExpansion interface{}
|
|
@ -1,60 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package alias
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
api "k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
ap := NewParser()
|
||||
if ap == nil {
|
||||
t.Fatalf("expected a parser.IngressAnnotation but returned nil")
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
annotations map[string]string
|
||||
expected string
|
||||
}{
|
||||
{map[string]string{annotation: "www.example.com"}, "www.example.com"},
|
||||
{map[string]string{annotation: "*.example.com www.example.*"}, "*.example.com www.example.*"},
|
||||
{map[string]string{annotation: `~^www\d+\.example\.com$`}, `~^www\d+\.example\.com$`},
|
||||
{map[string]string{annotation: ""}, ""},
|
||||
{map[string]string{}, ""},
|
||||
{nil, ""},
|
||||
}
|
||||
|
||||
ing := &extensions.Ingress{
|
||||
ObjectMeta: meta_v1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Namespace: api.NamespaceDefault,
|
||||
},
|
||||
Spec: extensions.IngressSpec{},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
ing.SetAnnotations(testCase.annotations)
|
||||
result, _ := ap.Parse(ing)
|
||||
if result != testCase.expected {
|
||||
t.Errorf("expected %v but returned %v, annotations: %s", testCase.expected, result, testCase.annotations)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,171 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
api "k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/file"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
|
||||
ing_errors "k8s.io/ingress-nginx/pkg/ingress/errors"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/resolver"
|
||||
)
|
||||
|
||||
const (
|
||||
authType = "ingress.kubernetes.io/auth-type"
|
||||
authSecret = "ingress.kubernetes.io/auth-secret"
|
||||
authRealm = "ingress.kubernetes.io/auth-realm"
|
||||
)
|
||||
|
||||
var (
|
||||
authTypeRegex = regexp.MustCompile(`basic|digest`)
|
||||
// AuthDirectory default directory used to store files
|
||||
// to authenticate request
|
||||
AuthDirectory = "/etc/ingress-controller/auth"
|
||||
)
|
||||
|
||||
// BasicDigest returns authentication configuration for an Ingress rule
|
||||
type BasicDigest struct {
|
||||
Type string `json:"type"`
|
||||
Realm string `json:"realm"`
|
||||
File string `json:"file"`
|
||||
Secured bool `json:"secured"`
|
||||
FileSHA string `json:"fileSha"`
|
||||
}
|
||||
|
||||
// Equal tests for equality between two BasicDigest types
|
||||
func (bd1 *BasicDigest) Equal(bd2 *BasicDigest) bool {
|
||||
if bd1 == bd2 {
|
||||
return true
|
||||
}
|
||||
if bd1 == nil || bd2 == nil {
|
||||
return false
|
||||
}
|
||||
if bd1.Type != bd2.Type {
|
||||
return false
|
||||
}
|
||||
if bd1.Realm != bd2.Realm {
|
||||
return false
|
||||
}
|
||||
if bd1.File != bd2.File {
|
||||
return false
|
||||
}
|
||||
if bd1.Secured != bd2.Secured {
|
||||
return false
|
||||
}
|
||||
if bd1.FileSHA != bd2.FileSHA {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
type auth struct {
|
||||
secretResolver resolver.Secret
|
||||
authDirectory string
|
||||
}
|
||||
|
||||
// NewParser creates a new authentication annotation parser
|
||||
func NewParser(authDirectory string, sr resolver.Secret) parser.IngressAnnotation {
|
||||
os.MkdirAll(authDirectory, 0755)
|
||||
|
||||
currPath := authDirectory
|
||||
for currPath != "/" {
|
||||
currPath = path.Dir(currPath)
|
||||
err := os.Chmod(currPath, 0755)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return auth{sr, authDirectory}
|
||||
}
|
||||
|
||||
// Parse parses the annotations contained in the ingress
|
||||
// rule used to add authentication in the paths defined in the rule
|
||||
// and generated an htpasswd compatible file to be used as source
|
||||
// during the authentication process
|
||||
func (a auth) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||
at, err := parser.GetStringAnnotation(authType, ing)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !authTypeRegex.MatchString(at) {
|
||||
return nil, ing_errors.NewLocationDenied("invalid authentication type")
|
||||
}
|
||||
|
||||
s, err := parser.GetStringAnnotation(authSecret, ing)
|
||||
if err != nil {
|
||||
return nil, ing_errors.LocationDenied{
|
||||
Reason: errors.Wrap(err, "error reading secret name from annotation"),
|
||||
}
|
||||
}
|
||||
|
||||
name := fmt.Sprintf("%v/%v", ing.Namespace, s)
|
||||
secret, err := a.secretResolver.GetSecret(name)
|
||||
if err != nil {
|
||||
return nil, ing_errors.LocationDenied{
|
||||
Reason: errors.Wrapf(err, "unexpected error reading secret %v", name),
|
||||
}
|
||||
}
|
||||
|
||||
realm, _ := parser.GetStringAnnotation(authRealm, ing)
|
||||
|
||||
passFile := fmt.Sprintf("%v/%v-%v.passwd", a.authDirectory, ing.GetNamespace(), ing.GetName())
|
||||
err = dumpSecret(passFile, secret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &BasicDigest{
|
||||
Type: at,
|
||||
Realm: realm,
|
||||
File: passFile,
|
||||
Secured: true,
|
||||
FileSHA: file.SHA1(passFile),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// dumpSecret dumps the content of a secret into a file
|
||||
// in the expected format for the specified authorization
|
||||
func dumpSecret(filename string, secret *api.Secret) error {
|
||||
val, ok := secret.Data["auth"]
|
||||
if !ok {
|
||||
return ing_errors.LocationDenied{
|
||||
Reason: errors.Errorf("the secret %v does not contain a key with value auth", secret.Name),
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: check permissions required
|
||||
err := ioutil.WriteFile(filename, val, 0777)
|
||||
if err != nil {
|
||||
return ing_errors.LocationDenied{
|
||||
Reason: errors.Wrap(err, "unexpected error creating password file"),
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,177 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
api "k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
)
|
||||
|
||||
func buildIngress() *extensions.Ingress {
|
||||
defaultBackend := extensions.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
}
|
||||
|
||||
return &extensions.Ingress{
|
||||
ObjectMeta: meta_v1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Namespace: api.NamespaceDefault,
|
||||
},
|
||||
Spec: extensions.IngressSpec{
|
||||
Backend: &extensions.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
},
|
||||
Rules: []extensions.IngressRule{
|
||||
{
|
||||
Host: "foo.bar.com",
|
||||
IngressRuleValue: extensions.IngressRuleValue{
|
||||
HTTP: &extensions.HTTPIngressRuleValue{
|
||||
Paths: []extensions.HTTPIngressPath{
|
||||
{
|
||||
Path: "/foo",
|
||||
Backend: defaultBackend,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type mockSecret struct {
|
||||
}
|
||||
|
||||
func (m mockSecret) GetSecret(name string) (*api.Secret, error) {
|
||||
if name != "default/demo-secret" {
|
||||
return nil, errors.Errorf("there is no secret with name %v", name)
|
||||
}
|
||||
|
||||
return &api.Secret{
|
||||
ObjectMeta: meta_v1.ObjectMeta{
|
||||
Namespace: api.NamespaceDefault,
|
||||
Name: "demo-secret",
|
||||
},
|
||||
Data: map[string][]byte{"auth": []byte("foo:$apr1$OFG3Xybp$ckL0FHDAkoXYIlH9.cysT0")},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func TestIngressWithoutAuth(t *testing.T) {
|
||||
ing := buildIngress()
|
||||
_, dir, _ := dummySecretContent(t)
|
||||
defer os.RemoveAll(dir)
|
||||
_, err := NewParser(dir, mockSecret{}).Parse(ing)
|
||||
if err == nil {
|
||||
t.Error("Expected error with ingress without annotations")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIngressAuth(t *testing.T) {
|
||||
ing := buildIngress()
|
||||
|
||||
data := map[string]string{}
|
||||
data[authType] = "basic"
|
||||
data[authSecret] = "demo-secret"
|
||||
data[authRealm] = "-realm-"
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
_, dir, _ := dummySecretContent(t)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
i, err := NewParser(dir, mockSecret{}).Parse(ing)
|
||||
if err != nil {
|
||||
t.Errorf("Uxpected error with ingress: %v", err)
|
||||
}
|
||||
auth, ok := i.(*BasicDigest)
|
||||
if !ok {
|
||||
t.Errorf("expected a BasicDigest type")
|
||||
}
|
||||
if auth.Type != "basic" {
|
||||
t.Errorf("Expected basic as auth type but returned %s", auth.Type)
|
||||
}
|
||||
if auth.Realm != "-realm-" {
|
||||
t.Errorf("Expected -realm- as realm but returned %s", auth.Realm)
|
||||
}
|
||||
if !auth.Secured {
|
||||
t.Errorf("Expected true as secured but returned %v", auth.Secured)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIngressAuthWithoutSecret(t *testing.T) {
|
||||
ing := buildIngress()
|
||||
|
||||
data := map[string]string{}
|
||||
data[authType] = "basic"
|
||||
data[authSecret] = "invalid-secret"
|
||||
data[authRealm] = "-realm-"
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
_, dir, _ := dummySecretContent(t)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
_, err := NewParser(dir, mockSecret{}).Parse(ing)
|
||||
if err == nil {
|
||||
t.Errorf("expected an error with invalid secret name")
|
||||
}
|
||||
}
|
||||
|
||||
func dummySecretContent(t *testing.T) (string, string, *api.Secret) {
|
||||
dir, err := ioutil.TempDir("", fmt.Sprintf("%v", time.Now().Unix()))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
tmpfile, err := ioutil.TempFile("", "example-")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
defer tmpfile.Close()
|
||||
s, _ := mockSecret{}.GetSecret("default/demo-secret")
|
||||
return tmpfile.Name(), dir, s
|
||||
}
|
||||
|
||||
func TestDumpSecret(t *testing.T) {
|
||||
tmpfile, dir, s := dummySecretContent(t)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
sd := s.Data
|
||||
s.Data = nil
|
||||
|
||||
err := dumpSecret(tmpfile, s)
|
||||
if err == nil {
|
||||
t.Errorf("Expected error with secret without auth")
|
||||
}
|
||||
|
||||
s.Data = sd
|
||||
err = dumpSecret(tmpfile, s)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error creating htpasswd file %v: %v", tmpfile, err)
|
||||
}
|
||||
}
|
|
@ -1,183 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package authreq
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
|
||||
ing_errors "k8s.io/ingress-nginx/pkg/ingress/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
// external URL that provides the authentication
|
||||
authURL = "ingress.kubernetes.io/auth-url"
|
||||
authSigninURL = "ingress.kubernetes.io/auth-signin"
|
||||
authMethod = "ingress.kubernetes.io/auth-method"
|
||||
authBody = "ingress.kubernetes.io/auth-send-body"
|
||||
authHeaders = "ingress.kubernetes.io/auth-response-headers"
|
||||
)
|
||||
|
||||
// External returns external authentication configuration for an Ingress rule
|
||||
type External struct {
|
||||
URL string `json:"url"`
|
||||
// Host contains the hostname defined in the URL
|
||||
Host string `json:"host"`
|
||||
SigninURL string `json:"signinUrl"`
|
||||
Method string `json:"method"`
|
||||
SendBody bool `json:"sendBody"`
|
||||
ResponseHeaders []string `json:"responseHeaders,omitEmpty"`
|
||||
}
|
||||
|
||||
// Equal tests for equality between two External types
|
||||
func (e1 *External) Equal(e2 *External) bool {
|
||||
if e1 == e2 {
|
||||
return true
|
||||
}
|
||||
if e1 == nil || e2 == nil {
|
||||
return false
|
||||
}
|
||||
if e1.URL != e2.URL {
|
||||
return false
|
||||
}
|
||||
if e1.Host != e2.Host {
|
||||
return false
|
||||
}
|
||||
if e1.SigninURL != e2.SigninURL {
|
||||
return false
|
||||
}
|
||||
if e1.Method != e2.Method {
|
||||
return false
|
||||
}
|
||||
if e1.SendBody != e2.SendBody {
|
||||
return false
|
||||
}
|
||||
if e1.Method != e2.Method {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, ep1 := range e1.ResponseHeaders {
|
||||
found := false
|
||||
for _, ep2 := range e2.ResponseHeaders {
|
||||
if ep1 == ep2 {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
var (
|
||||
methods = []string{"GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "CONNECT", "OPTIONS", "TRACE"}
|
||||
headerRegexp = regexp.MustCompile(`^[a-zA-Z\d\-_]+$`)
|
||||
)
|
||||
|
||||
func validMethod(method string) bool {
|
||||
if len(method) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, m := range methods {
|
||||
if method == m {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func validHeader(header string) bool {
|
||||
return headerRegexp.Match([]byte(header))
|
||||
}
|
||||
|
||||
type authReq struct {
|
||||
}
|
||||
|
||||
// NewParser creates a new authentication request annotation parser
|
||||
func NewParser() parser.IngressAnnotation {
|
||||
return authReq{}
|
||||
}
|
||||
|
||||
// ParseAnnotations parses the annotations contained in the ingress
|
||||
// rule used to use an external URL as source for authentication
|
||||
func (a authReq) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||
str, err := parser.GetStringAnnotation(authURL, ing)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if str == "" {
|
||||
return nil, ing_errors.NewLocationDenied("an empty string is not a valid URL")
|
||||
}
|
||||
|
||||
signin, _ := parser.GetStringAnnotation(authSigninURL, ing)
|
||||
|
||||
ur, err := url.Parse(str)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ur.Scheme == "" {
|
||||
return nil, ing_errors.NewLocationDenied("url scheme is empty")
|
||||
}
|
||||
if ur.Host == "" {
|
||||
return nil, ing_errors.NewLocationDenied("url host is empty")
|
||||
}
|
||||
|
||||
if strings.Contains(ur.Host, "..") {
|
||||
return nil, ing_errors.NewLocationDenied("invalid url host")
|
||||
}
|
||||
|
||||
m, _ := parser.GetStringAnnotation(authMethod, ing)
|
||||
if len(m) != 0 && !validMethod(m) {
|
||||
return nil, ing_errors.NewLocationDenied("invalid HTTP method")
|
||||
}
|
||||
|
||||
h := []string{}
|
||||
hstr, _ := parser.GetStringAnnotation(authHeaders, ing)
|
||||
if len(hstr) != 0 {
|
||||
|
||||
harr := strings.Split(hstr, ",")
|
||||
for _, header := range harr {
|
||||
header = strings.TrimSpace(header)
|
||||
if len(header) > 0 {
|
||||
if !validHeader(header) {
|
||||
return nil, ing_errors.NewLocationDenied("invalid headers list")
|
||||
}
|
||||
h = append(h, header)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sb, _ := parser.GetBoolAnnotation(authBody, ing)
|
||||
|
||||
return &External{
|
||||
URL: str,
|
||||
Host: ur.Hostname(),
|
||||
SigninURL: signin,
|
||||
Method: m,
|
||||
SendBody: sb,
|
||||
ResponseHeaders: h,
|
||||
}, nil
|
||||
}
|
|
@ -1,167 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package authreq
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
api "k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
)
|
||||
|
||||
func buildIngress() *extensions.Ingress {
|
||||
defaultBackend := extensions.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
}
|
||||
|
||||
return &extensions.Ingress{
|
||||
ObjectMeta: meta_v1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Namespace: api.NamespaceDefault,
|
||||
},
|
||||
Spec: extensions.IngressSpec{
|
||||
Backend: &extensions.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
},
|
||||
Rules: []extensions.IngressRule{
|
||||
{
|
||||
Host: "foo.bar.com",
|
||||
IngressRuleValue: extensions.IngressRuleValue{
|
||||
HTTP: &extensions.HTTPIngressRuleValue{
|
||||
Paths: []extensions.HTTPIngressPath{
|
||||
{
|
||||
Path: "/foo",
|
||||
Backend: defaultBackend,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnnotations(t *testing.T) {
|
||||
ing := buildIngress()
|
||||
|
||||
data := map[string]string{}
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
tests := []struct {
|
||||
title string
|
||||
url string
|
||||
signinURL string
|
||||
method string
|
||||
sendBody bool
|
||||
expErr bool
|
||||
}{
|
||||
{"empty", "", "", "", false, true},
|
||||
{"no scheme", "bar", "bar", "", false, true},
|
||||
{"invalid host", "http://", "http://", "", false, true},
|
||||
{"invalid host (multiple dots)", "http://foo..bar.com", "http://foo..bar.com", "", false, true},
|
||||
{"valid URL", "http://bar.foo.com/external-auth", "http://bar.foo.com/external-auth", "", false, false},
|
||||
{"valid URL - send body", "http://foo.com/external-auth", "http://foo.com/external-auth", "POST", true, false},
|
||||
{"valid URL - send body", "http://foo.com/external-auth", "http://foo.com/external-auth", "GET", true, false},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
data[authURL] = test.url
|
||||
data[authSigninURL] = test.signinURL
|
||||
data[authBody] = fmt.Sprintf("%v", test.sendBody)
|
||||
data[authMethod] = fmt.Sprintf("%v", test.method)
|
||||
|
||||
i, err := NewParser().Parse(ing)
|
||||
if test.expErr {
|
||||
if err == nil {
|
||||
t.Errorf("%v: expected error but retuned nil", test.title)
|
||||
}
|
||||
continue
|
||||
}
|
||||
u, ok := i.(*External)
|
||||
if !ok {
|
||||
t.Errorf("%v: expected an External type", test.title)
|
||||
}
|
||||
if u.URL != test.url {
|
||||
t.Errorf("%v: expected \"%v\" but \"%v\" was returned", test.title, test.url, u.URL)
|
||||
}
|
||||
if u.SigninURL != test.signinURL {
|
||||
t.Errorf("%v: expected \"%v\" but \"%v\" was returned", test.title, test.signinURL, u.SigninURL)
|
||||
}
|
||||
if u.Method != test.method {
|
||||
t.Errorf("%v: expected \"%v\" but \"%v\" was returned", test.title, test.method, u.Method)
|
||||
}
|
||||
if u.SendBody != test.sendBody {
|
||||
t.Errorf("%v: expected \"%v\" but \"%v\" was returned", test.title, test.sendBody, u.SendBody)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHeaderAnnotations(t *testing.T) {
|
||||
ing := buildIngress()
|
||||
|
||||
data := map[string]string{}
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
tests := []struct {
|
||||
title string
|
||||
url string
|
||||
headers string
|
||||
parsedHeaders []string
|
||||
expErr bool
|
||||
}{
|
||||
{"single header", "http://goog.url", "h1", []string{"h1"}, false},
|
||||
{"nothing", "http://goog.url", "", []string{}, false},
|
||||
{"spaces", "http://goog.url", " ", []string{}, false},
|
||||
{"two headers", "http://goog.url", "1,2", []string{"1", "2"}, false},
|
||||
{"two headers and empty entries", "http://goog.url", ",1,,2,", []string{"1", "2"}, false},
|
||||
{"header with spaces", "http://goog.url", "1 2", []string{}, true},
|
||||
{"header with other bad symbols", "http://goog.url", "1+2", []string{}, true},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
data[authURL] = test.url
|
||||
data[authHeaders] = test.headers
|
||||
data[authMethod] = "GET"
|
||||
|
||||
i, err := NewParser().Parse(ing)
|
||||
if test.expErr {
|
||||
if err == nil {
|
||||
t.Errorf("%v: expected error but retuned nil", err.Error())
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
t.Log(i)
|
||||
u, ok := i.(*External)
|
||||
if !ok {
|
||||
t.Errorf("%v: expected an External type", test.title)
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(u.ResponseHeaders, test.parsedHeaders) {
|
||||
t.Errorf("%v: expected \"%v\" but \"%v\" was returned", test.title, test.headers, u.ResponseHeaders)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,131 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package authtls
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
|
||||
ing_errors "k8s.io/ingress-nginx/pkg/ingress/errors"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/resolver"
|
||||
"k8s.io/ingress-nginx/pkg/k8s"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
const (
|
||||
// name of the secret
|
||||
annotationAuthTLSSecret = "ingress.kubernetes.io/auth-tls-secret"
|
||||
annotationAuthVerifyClient = "ingress.kubernetes.io/auth-tls-verify-client"
|
||||
annotationAuthTLSDepth = "ingress.kubernetes.io/auth-tls-verify-depth"
|
||||
annotationAuthTLSErrorPage = "ingress.kubernetes.io/auth-tls-error-page"
|
||||
defaultAuthTLSDepth = 1
|
||||
defaultAuthVerifyClient = "on"
|
||||
)
|
||||
|
||||
var (
|
||||
authVerifyClientRegex = regexp.MustCompile(`on|off|optional|optional_no_ca`)
|
||||
)
|
||||
|
||||
// AuthSSLConfig contains the AuthSSLCert used for muthual autentication
|
||||
// and the configured ValidationDepth
|
||||
type AuthSSLConfig struct {
|
||||
resolver.AuthSSLCert
|
||||
VerifyClient string `json:"verify_client"`
|
||||
ValidationDepth int `json:"validationDepth"`
|
||||
ErrorPage string `json:"errorPage"`
|
||||
}
|
||||
|
||||
// Equal tests for equality between two AuthSSLConfig types
|
||||
func (assl1 *AuthSSLConfig) Equal(assl2 *AuthSSLConfig) bool {
|
||||
if assl1 == assl2 {
|
||||
return true
|
||||
}
|
||||
if assl1 == nil || assl2 == nil {
|
||||
return false
|
||||
}
|
||||
if !(&assl1.AuthSSLCert).Equal(&assl2.AuthSSLCert) {
|
||||
return false
|
||||
}
|
||||
if assl1.VerifyClient != assl2.VerifyClient {
|
||||
return false
|
||||
}
|
||||
if assl1.ValidationDepth != assl2.ValidationDepth {
|
||||
return false
|
||||
}
|
||||
if assl1.ErrorPage != assl2.ErrorPage {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// NewParser creates a new TLS authentication annotation parser
|
||||
func NewParser(resolver resolver.AuthCertificate) parser.IngressAnnotation {
|
||||
return authTLS{resolver}
|
||||
}
|
||||
|
||||
type authTLS struct {
|
||||
certResolver resolver.AuthCertificate
|
||||
}
|
||||
|
||||
// Parse parses the annotations contained in the ingress
|
||||
// rule used to use a Certificate as authentication method
|
||||
func (a authTLS) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||
|
||||
tlsauthsecret, err := parser.GetStringAnnotation(annotationAuthTLSSecret, ing)
|
||||
if err != nil {
|
||||
return &AuthSSLConfig{}, err
|
||||
}
|
||||
|
||||
if tlsauthsecret == "" {
|
||||
return &AuthSSLConfig{}, ing_errors.NewLocationDenied("an empty string is not a valid secret name")
|
||||
}
|
||||
|
||||
_, _, err = k8s.ParseNameNS(tlsauthsecret)
|
||||
if err != nil {
|
||||
return &AuthSSLConfig{}, ing_errors.NewLocationDenied(err.Error())
|
||||
}
|
||||
|
||||
tlsVerifyClient, err := parser.GetStringAnnotation(annotationAuthVerifyClient, ing)
|
||||
if err != nil || !authVerifyClientRegex.MatchString(tlsVerifyClient) {
|
||||
tlsVerifyClient = defaultAuthVerifyClient
|
||||
}
|
||||
|
||||
tlsdepth, err := parser.GetIntAnnotation(annotationAuthTLSDepth, ing)
|
||||
if err != nil || tlsdepth == 0 {
|
||||
tlsdepth = defaultAuthTLSDepth
|
||||
}
|
||||
|
||||
authCert, err := a.certResolver.GetAuthCertificate(tlsauthsecret)
|
||||
if err != nil {
|
||||
return &AuthSSLConfig{}, ing_errors.LocationDenied{
|
||||
Reason: errors.Wrap(err, "error obtaining certificate"),
|
||||
}
|
||||
}
|
||||
|
||||
errorpage, err := parser.GetStringAnnotation(annotationAuthTLSErrorPage, ing)
|
||||
if err != nil || errorpage == "" {
|
||||
errorpage = ""
|
||||
}
|
||||
|
||||
return &AuthSSLConfig{
|
||||
AuthSSLCert: *authCert,
|
||||
VerifyClient: tlsVerifyClient,
|
||||
ValidationDepth: tlsdepth,
|
||||
ErrorPage: errorpage,
|
||||
}, nil
|
||||
}
|
|
@ -1,108 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package authtls
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
api "k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
)
|
||||
|
||||
func buildIngress() *extensions.Ingress {
|
||||
defaultBackend := extensions.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
}
|
||||
|
||||
return &extensions.Ingress{
|
||||
ObjectMeta: meta_v1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Namespace: api.NamespaceDefault,
|
||||
},
|
||||
Spec: extensions.IngressSpec{
|
||||
Backend: &extensions.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
},
|
||||
Rules: []extensions.IngressRule{
|
||||
{
|
||||
Host: "foo.bar.com",
|
||||
IngressRuleValue: extensions.IngressRuleValue{
|
||||
HTTP: &extensions.HTTPIngressRuleValue{
|
||||
Paths: []extensions.HTTPIngressPath{
|
||||
{
|
||||
Path: "/foo",
|
||||
Backend: defaultBackend,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnnotations(t *testing.T) {
|
||||
ing := buildIngress()
|
||||
|
||||
data := map[string]string{}
|
||||
ing.SetAnnotations(data)
|
||||
/*
|
||||
tests := []struct {
|
||||
title string
|
||||
url string
|
||||
method string
|
||||
sendBody bool
|
||||
expErr bool
|
||||
}{
|
||||
{"empty", "", "", false, true},
|
||||
{"no scheme", "bar", "", false, true},
|
||||
{"invalid host", "http://", "", false, true},
|
||||
{"invalid host (multiple dots)", "http://foo..bar.com", "", false, true},
|
||||
{"valid URL", "http://bar.foo.com/external-auth", "", false, false},
|
||||
{"valid URL - send body", "http://foo.com/external-auth", "POST", true, false},
|
||||
{"valid URL - send body", "http://foo.com/external-auth", "GET", true, false},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
data[authTLSSecret] = ""
|
||||
test.title
|
||||
|
||||
u, err := ParseAnnotations(ing)
|
||||
|
||||
if test.expErr {
|
||||
if err == nil {
|
||||
t.Errorf("%v: expected error but retuned nil", test.title)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if u.URL != test.url {
|
||||
t.Errorf("%v: expected \"%v\" but \"%v\" was returned", test.title, test.url, u.URL)
|
||||
}
|
||||
if u.Method != test.method {
|
||||
t.Errorf("%v: expected \"%v\" but \"%v\" was returned", test.title, test.method, u.Method)
|
||||
}
|
||||
if u.SendBody != test.sendBody {
|
||||
t.Errorf("%v: expected \"%v\" but \"%v\" was returned", test.title, test.sendBody, u.SendBody)
|
||||
}
|
||||
}*/
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package clientbodybuffersize
|
||||
|
||||
import (
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
|
||||
)
|
||||
|
||||
const (
|
||||
annotation = "ingress.kubernetes.io/client-body-buffer-size"
|
||||
)
|
||||
|
||||
type clientBodyBufferSize struct {
|
||||
}
|
||||
|
||||
// NewParser creates a new clientBodyBufferSize annotation parser
|
||||
func NewParser() parser.IngressAnnotation {
|
||||
return clientBodyBufferSize{}
|
||||
}
|
||||
|
||||
// Parse parses the annotations contained in the ingress rule
|
||||
// used to add an client-body-buffer-size to the provided locations
|
||||
func (a clientBodyBufferSize) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||
return parser.GetStringAnnotation(annotation, ing)
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package clientbodybuffersize
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
api "k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
ap := NewParser()
|
||||
if ap == nil {
|
||||
t.Fatalf("expected a parser.IngressAnnotation but returned nil")
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
annotations map[string]string
|
||||
expected string
|
||||
}{
|
||||
{map[string]string{annotation: "8k"}, "8k"},
|
||||
{map[string]string{annotation: "16k"}, "16k"},
|
||||
{map[string]string{annotation: ""}, ""},
|
||||
{map[string]string{}, ""},
|
||||
{nil, ""},
|
||||
}
|
||||
|
||||
ing := &extensions.Ingress{
|
||||
ObjectMeta: meta_v1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Namespace: api.NamespaceDefault,
|
||||
},
|
||||
Spec: extensions.IngressSpec{},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
ing.SetAnnotations(testCase.annotations)
|
||||
result, _ := ap.Parse(ing)
|
||||
if result != testCase.expected {
|
||||
t.Errorf("expected %v but returned %v, annotations: %s", testCase.expected, result, testCase.annotations)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cors
|
||||
|
||||
import (
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
|
||||
)
|
||||
|
||||
const (
|
||||
annotation = "ingress.kubernetes.io/enable-cors"
|
||||
)
|
||||
|
||||
type cors struct {
|
||||
}
|
||||
|
||||
// NewParser creates a new CORS annotation parser
|
||||
func NewParser() parser.IngressAnnotation {
|
||||
return cors{}
|
||||
}
|
||||
|
||||
// Parse parses the annotations contained in the ingress
|
||||
// rule used to indicate if the location/s should allows CORS
|
||||
func (a cors) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||
return parser.GetBoolAnnotation(annotation, ing)
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cors
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
api "k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
notCorsAnnotation = "ingress.kubernetes.io/enable-not-cors"
|
||||
)
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
ap := NewParser()
|
||||
if ap == nil {
|
||||
t.Fatalf("expected a parser.IngressAnnotation but returned nil")
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
annotations map[string]string
|
||||
expected bool
|
||||
}{
|
||||
{map[string]string{annotation: "true"}, true},
|
||||
{map[string]string{annotation: "false"}, false},
|
||||
{map[string]string{notCorsAnnotation: "true"}, false},
|
||||
{map[string]string{}, false},
|
||||
{nil, false},
|
||||
}
|
||||
|
||||
ing := &extensions.Ingress{
|
||||
ObjectMeta: meta_v1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Namespace: api.NamespaceDefault,
|
||||
},
|
||||
Spec: extensions.IngressSpec{},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
ing.SetAnnotations(testCase.annotations)
|
||||
result, _ := ap.Parse(ing)
|
||||
if result != testCase.expected {
|
||||
t.Errorf("expected %t but returned %t, annotations: %s", testCase.expected, result, testCase.annotations)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package defaultbackend
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/resolver"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultBackend = "ingress.kubernetes.io/default-backend"
|
||||
)
|
||||
|
||||
type backend struct {
|
||||
serviceResolver resolver.Service
|
||||
}
|
||||
|
||||
// NewParser creates a new default backend annotation parser
|
||||
func NewParser(sr resolver.Service) parser.IngressAnnotation {
|
||||
return backend{sr}
|
||||
}
|
||||
|
||||
// Parse parses the annotations contained in the ingress to use
|
||||
// a custom default backend
|
||||
func (db backend) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||
s, err := parser.GetStringAnnotation(defaultBackend, ing)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
name := fmt.Sprintf("%v/%v", ing.Namespace, s)
|
||||
svc, err := db.serviceResolver.GetService(name)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "unexpected error reading service %v", name)
|
||||
}
|
||||
|
||||
return svc, nil
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package healthcheck
|
||||
|
||||
import (
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/resolver"
|
||||
)
|
||||
|
||||
const (
|
||||
upsMaxFails = "ingress.kubernetes.io/upstream-max-fails"
|
||||
upsFailTimeout = "ingress.kubernetes.io/upstream-fail-timeout"
|
||||
)
|
||||
|
||||
// Upstream returns the URL and method to use check the status of
|
||||
// the upstream server/s
|
||||
type Upstream struct {
|
||||
MaxFails int `json:"maxFails"`
|
||||
FailTimeout int `json:"failTimeout"`
|
||||
}
|
||||
|
||||
type healthCheck struct {
|
||||
backendResolver resolver.DefaultBackend
|
||||
}
|
||||
|
||||
// NewParser creates a new health check annotation parser
|
||||
func NewParser(br resolver.DefaultBackend) parser.IngressAnnotation {
|
||||
return healthCheck{br}
|
||||
}
|
||||
|
||||
// ParseAnnotations parses the annotations contained in the ingress
|
||||
// rule used to configure upstream check parameters
|
||||
func (a healthCheck) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||
defBackend := a.backendResolver.GetDefaultBackend()
|
||||
if ing.GetAnnotations() == nil {
|
||||
return &Upstream{defBackend.UpstreamMaxFails, defBackend.UpstreamFailTimeout}, nil
|
||||
}
|
||||
|
||||
mf, err := parser.GetIntAnnotation(upsMaxFails, ing)
|
||||
if err != nil {
|
||||
mf = defBackend.UpstreamMaxFails
|
||||
}
|
||||
|
||||
ft, err := parser.GetIntAnnotation(upsFailTimeout, ing)
|
||||
if err != nil {
|
||||
ft = defBackend.UpstreamFailTimeout
|
||||
}
|
||||
|
||||
return &Upstream{mf, ft}, nil
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package healthcheck
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
api "k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress/defaults"
|
||||
)
|
||||
|
||||
func buildIngress() *extensions.Ingress {
|
||||
defaultBackend := extensions.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
}
|
||||
|
||||
return &extensions.Ingress{
|
||||
ObjectMeta: meta_v1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Namespace: api.NamespaceDefault,
|
||||
},
|
||||
Spec: extensions.IngressSpec{
|
||||
Backend: &extensions.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
},
|
||||
Rules: []extensions.IngressRule{
|
||||
{
|
||||
Host: "foo.bar.com",
|
||||
IngressRuleValue: extensions.IngressRuleValue{
|
||||
HTTP: &extensions.HTTPIngressRuleValue{
|
||||
Paths: []extensions.HTTPIngressPath{
|
||||
{
|
||||
Path: "/foo",
|
||||
Backend: defaultBackend,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type mockBackend struct {
|
||||
}
|
||||
|
||||
func (m mockBackend) GetDefaultBackend() defaults.Backend {
|
||||
return defaults.Backend{UpstreamFailTimeout: 1}
|
||||
}
|
||||
|
||||
func TestIngressHealthCheck(t *testing.T) {
|
||||
ing := buildIngress()
|
||||
|
||||
data := map[string]string{}
|
||||
data[upsMaxFails] = "2"
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
hzi, _ := NewParser(mockBackend{}).Parse(ing)
|
||||
nginxHz, ok := hzi.(*Upstream)
|
||||
if !ok {
|
||||
t.Errorf("expected a Upstream type")
|
||||
}
|
||||
|
||||
if nginxHz.MaxFails != 2 {
|
||||
t.Errorf("expected 2 as max-fails but returned %v", nginxHz.MaxFails)
|
||||
}
|
||||
|
||||
if nginxHz.FailTimeout != 1 {
|
||||
t.Errorf("expected 0 as fail-timeout but returned %v", nginxHz.FailTimeout)
|
||||
}
|
||||
}
|
|
@ -1,113 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package ipwhitelist
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
"k8s.io/ingress-nginx/pkg/net"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
|
||||
ing_errors "k8s.io/ingress-nginx/pkg/ingress/errors"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/resolver"
|
||||
)
|
||||
|
||||
const (
|
||||
whitelist = "ingress.kubernetes.io/whitelist-source-range"
|
||||
)
|
||||
|
||||
// SourceRange returns the CIDR
|
||||
type SourceRange struct {
|
||||
CIDR []string `json:"cidr,omitEmpty"`
|
||||
}
|
||||
|
||||
// Equal tests for equality between two SourceRange types
|
||||
func (sr1 *SourceRange) Equal(sr2 *SourceRange) bool {
|
||||
if sr1 == sr2 {
|
||||
return true
|
||||
}
|
||||
if sr1 == nil || sr2 == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(sr1.CIDR) != len(sr2.CIDR) {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, s1l := range sr1.CIDR {
|
||||
found := false
|
||||
for _, sl2 := range sr2.CIDR {
|
||||
if s1l == sl2 {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
type ipwhitelist struct {
|
||||
backendResolver resolver.DefaultBackend
|
||||
}
|
||||
|
||||
// NewParser creates a new whitelist annotation parser
|
||||
func NewParser(br resolver.DefaultBackend) parser.IngressAnnotation {
|
||||
return ipwhitelist{br}
|
||||
}
|
||||
|
||||
// ParseAnnotations parses the annotations contained in the ingress
|
||||
// rule used to limit access to certain client addresses or networks.
|
||||
// Multiple ranges can specified using commas as separator
|
||||
// e.g. `18.0.0.0/8,56.0.0.0/8`
|
||||
func (a ipwhitelist) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||
defBackend := a.backendResolver.GetDefaultBackend()
|
||||
sort.Strings(defBackend.WhitelistSourceRange)
|
||||
|
||||
val, err := parser.GetStringAnnotation(whitelist, ing)
|
||||
// A missing annotation is not a problem, just use the default
|
||||
if err == ing_errors.ErrMissingAnnotations {
|
||||
return &SourceRange{CIDR: defBackend.WhitelistSourceRange}, nil
|
||||
}
|
||||
|
||||
values := strings.Split(val, ",")
|
||||
ipnets, ips, err := net.ParseIPNets(values...)
|
||||
if err != nil && len(ips) == 0 {
|
||||
return &SourceRange{CIDR: defBackend.WhitelistSourceRange}, ing_errors.LocationDenied{
|
||||
Reason: errors.Wrap(err, "the annotation does not contain a valid IP address or network"),
|
||||
}
|
||||
}
|
||||
|
||||
cidrs := []string{}
|
||||
for k := range ipnets {
|
||||
cidrs = append(cidrs, k)
|
||||
}
|
||||
for k := range ips {
|
||||
cidrs = append(cidrs, k)
|
||||
}
|
||||
|
||||
sort.Strings(cidrs)
|
||||
|
||||
return &SourceRange{cidrs}, nil
|
||||
}
|
|
@ -1,199 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package ipwhitelist
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
api "k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress/defaults"
|
||||
)
|
||||
|
||||
func buildIngress() *extensions.Ingress {
|
||||
defaultBackend := extensions.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
}
|
||||
|
||||
return &extensions.Ingress{
|
||||
ObjectMeta: meta_v1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Namespace: api.NamespaceDefault,
|
||||
},
|
||||
Spec: extensions.IngressSpec{
|
||||
Backend: &extensions.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
},
|
||||
Rules: []extensions.IngressRule{
|
||||
{
|
||||
Host: "foo.bar.com",
|
||||
IngressRuleValue: extensions.IngressRuleValue{
|
||||
HTTP: &extensions.HTTPIngressRuleValue{
|
||||
Paths: []extensions.HTTPIngressPath{
|
||||
{
|
||||
Path: "/foo",
|
||||
Backend: defaultBackend,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type mockBackend struct {
|
||||
defaults.Backend
|
||||
}
|
||||
|
||||
func (m mockBackend) GetDefaultBackend() defaults.Backend {
|
||||
return m.Backend
|
||||
}
|
||||
|
||||
func TestParseAnnotations(t *testing.T) {
|
||||
ing := buildIngress()
|
||||
tests := map[string]struct {
|
||||
net string
|
||||
expectCidr []string
|
||||
expectErr bool
|
||||
errOut string
|
||||
}{
|
||||
"test parse a valid net": {
|
||||
net: "10.0.0.0/24",
|
||||
expectCidr: []string{"10.0.0.0/24"},
|
||||
expectErr: false,
|
||||
},
|
||||
"test parse a invalid net": {
|
||||
net: "ww",
|
||||
expectErr: true,
|
||||
errOut: "the annotation does not contain a valid IP address or network: invalid CIDR address: ww",
|
||||
},
|
||||
"test parse a empty net": {
|
||||
net: "",
|
||||
expectErr: true,
|
||||
errOut: "the annotation does not contain a valid IP address or network: invalid CIDR address: ",
|
||||
},
|
||||
"test parse multiple valid cidr": {
|
||||
net: "2.2.2.2/32,1.1.1.1/32,3.3.3.0/24",
|
||||
expectCidr: []string{"1.1.1.1/32", "2.2.2.2/32", "3.3.3.0/24"},
|
||||
expectErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
for testName, test := range tests {
|
||||
data := map[string]string{}
|
||||
data[whitelist] = test.net
|
||||
ing.SetAnnotations(data)
|
||||
p := NewParser(mockBackend{})
|
||||
i, err := p.Parse(ing)
|
||||
if err != nil && !test.expectErr {
|
||||
t.Errorf("%v:unexpected error: %v", testName, err)
|
||||
}
|
||||
if test.expectErr {
|
||||
if err.Error() != test.errOut {
|
||||
t.Errorf("%v:expected error: %v but %v return", testName, test.errOut, err.Error())
|
||||
}
|
||||
}
|
||||
if !test.expectErr {
|
||||
sr, ok := i.(*SourceRange)
|
||||
if !ok {
|
||||
t.Errorf("%v:expected a SourceRange type", testName)
|
||||
}
|
||||
if !strsEquals(sr.CIDR, test.expectCidr) {
|
||||
t.Errorf("%v:expected %v CIDR but %v returned", testName, test.expectCidr, sr.CIDR)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test that when we have a whitelist set on the Backend that is used when we
|
||||
// don't have the annotation
|
||||
func TestParseAnnotationsWithDefaultConfig(t *testing.T) {
|
||||
ing := buildIngress()
|
||||
mockBackend := mockBackend{}
|
||||
mockBackend.Backend.WhitelistSourceRange = []string{"4.4.4.0/24", "1.2.3.4/32"}
|
||||
tests := map[string]struct {
|
||||
net string
|
||||
expectCidr []string
|
||||
expectErr bool
|
||||
errOut string
|
||||
}{
|
||||
"test parse a valid net": {
|
||||
net: "10.0.0.0/24",
|
||||
expectCidr: []string{"10.0.0.0/24"},
|
||||
expectErr: false,
|
||||
},
|
||||
"test parse a invalid net": {
|
||||
net: "ww",
|
||||
expectErr: true,
|
||||
errOut: "the annotation does not contain a valid IP address or network: invalid CIDR address: ww",
|
||||
},
|
||||
"test parse a empty net": {
|
||||
net: "",
|
||||
expectErr: true,
|
||||
errOut: "the annotation does not contain a valid IP address or network: invalid CIDR address: ",
|
||||
},
|
||||
"test parse multiple valid cidr": {
|
||||
net: "2.2.2.2/32,1.1.1.1/32,3.3.3.0/24",
|
||||
expectCidr: []string{"1.1.1.1/32", "2.2.2.2/32", "3.3.3.0/24"},
|
||||
expectErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
for testName, test := range tests {
|
||||
data := map[string]string{}
|
||||
data[whitelist] = test.net
|
||||
ing.SetAnnotations(data)
|
||||
p := NewParser(mockBackend)
|
||||
i, err := p.Parse(ing)
|
||||
if err != nil && !test.expectErr {
|
||||
t.Errorf("%v:unexpected error: %v", testName, err)
|
||||
}
|
||||
if test.expectErr {
|
||||
if err.Error() != test.errOut {
|
||||
t.Errorf("%v:expected error: %v but %v return", testName, test.errOut, err.Error())
|
||||
}
|
||||
}
|
||||
if !test.expectErr {
|
||||
sr, ok := i.(*SourceRange)
|
||||
if !ok {
|
||||
t.Errorf("%v:expected a SourceRange type", testName)
|
||||
}
|
||||
if !strsEquals(sr.CIDR, test.expectCidr) {
|
||||
t.Errorf("%v:expected %v CIDR but %v returned", testName, test.expectCidr, sr.CIDR)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func strsEquals(a, b []string) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i, v := range a {
|
||||
if v != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package portinredirect
|
||||
|
||||
import (
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/resolver"
|
||||
)
|
||||
|
||||
const (
|
||||
annotation = "ingress.kubernetes.io/use-port-in-redirects"
|
||||
)
|
||||
|
||||
type portInRedirect struct {
|
||||
backendResolver resolver.DefaultBackend
|
||||
}
|
||||
|
||||
// NewParser creates a new port in redirect annotation parser
|
||||
func NewParser(db resolver.DefaultBackend) parser.IngressAnnotation {
|
||||
return portInRedirect{db}
|
||||
}
|
||||
|
||||
// Parse parses the annotations contained in the ingress
|
||||
// rule used to indicate if the redirects must
|
||||
func (a portInRedirect) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||
up, err := parser.GetBoolAnnotation(annotation, ing)
|
||||
if err != nil {
|
||||
return a.backendResolver.GetDefaultBackend().UsePortInRedirects, nil
|
||||
}
|
||||
|
||||
return up, nil
|
||||
}
|
|
@ -1,121 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package portinredirect
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
api "k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
|
||||
"fmt"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress/defaults"
|
||||
)
|
||||
|
||||
func buildIngress() *extensions.Ingress {
|
||||
defaultBackend := extensions.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
}
|
||||
|
||||
return &extensions.Ingress{
|
||||
ObjectMeta: meta_v1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Namespace: api.NamespaceDefault,
|
||||
},
|
||||
Spec: extensions.IngressSpec{
|
||||
Backend: &extensions.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
},
|
||||
Rules: []extensions.IngressRule{
|
||||
{
|
||||
Host: "foo.bar.com",
|
||||
IngressRuleValue: extensions.IngressRuleValue{
|
||||
HTTP: &extensions.HTTPIngressRuleValue{
|
||||
Paths: []extensions.HTTPIngressPath{
|
||||
{
|
||||
Path: "/foo",
|
||||
Backend: defaultBackend,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type mockBackend struct {
|
||||
usePortInRedirects bool
|
||||
}
|
||||
|
||||
func (m mockBackend) GetDefaultBackend() defaults.Backend {
|
||||
return defaults.Backend{UsePortInRedirects: m.usePortInRedirects}
|
||||
}
|
||||
|
||||
func TestPortInRedirect(t *testing.T) {
|
||||
tests := []struct {
|
||||
title string
|
||||
usePort *bool
|
||||
def bool
|
||||
exp bool
|
||||
}{
|
||||
{"false - default false", newFalse(), false, false},
|
||||
{"false - default true", newFalse(), true, false},
|
||||
{"no annotation - default false", nil, false, false},
|
||||
{"no annotation - default true", nil, true, true},
|
||||
{"true - default true", newTrue(), true, true},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
ing := buildIngress()
|
||||
|
||||
data := map[string]string{}
|
||||
if test.usePort != nil {
|
||||
data[annotation] = fmt.Sprintf("%v", *test.usePort)
|
||||
}
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
i, err := NewParser(mockBackend{test.def}).Parse(ing)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error parsing a valid")
|
||||
}
|
||||
p, ok := i.(bool)
|
||||
if !ok {
|
||||
t.Errorf("expected a bool type")
|
||||
}
|
||||
|
||||
if p != test.exp {
|
||||
t.Errorf("%v: expected \"%v\" but \"%v\" was returned", test.title, test.exp, p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func newTrue() *bool {
|
||||
b := true
|
||||
return &b
|
||||
}
|
||||
|
||||
func newFalse() *bool {
|
||||
b := false
|
||||
return &b
|
||||
}
|
|
@ -1,160 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package proxy
|
||||
|
||||
import (
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/resolver"
|
||||
)
|
||||
|
||||
const (
|
||||
bodySize = "ingress.kubernetes.io/proxy-body-size"
|
||||
connect = "ingress.kubernetes.io/proxy-connect-timeout"
|
||||
send = "ingress.kubernetes.io/proxy-send-timeout"
|
||||
read = "ingress.kubernetes.io/proxy-read-timeout"
|
||||
bufferSize = "ingress.kubernetes.io/proxy-buffer-size"
|
||||
cookiePath = "ingress.kubernetes.io/proxy-cookie-path"
|
||||
cookieDomain = "ingress.kubernetes.io/proxy-cookie-domain"
|
||||
nextUpstream = "ingress.kubernetes.io/proxy-next-upstream"
|
||||
passParams = "ingress.kubernetes.io/proxy-pass-params"
|
||||
requestBuffering = "ingress.kubernetes.io/proxy-request-buffering"
|
||||
)
|
||||
|
||||
// Configuration returns the proxy timeout to use in the upstream server/s
|
||||
type Configuration struct {
|
||||
BodySize string `json:"bodySize"`
|
||||
ConnectTimeout int `json:"connectTimeout"`
|
||||
SendTimeout int `json:"sendTimeout"`
|
||||
ReadTimeout int `json:"readTimeout"`
|
||||
BufferSize string `json:"bufferSize"`
|
||||
CookieDomain string `json:"cookieDomain"`
|
||||
CookiePath string `json:"cookiePath"`
|
||||
NextUpstream string `json:"nextUpstream"`
|
||||
PassParams string `json:"passParams"`
|
||||
RequestBuffering string `json:"requestBuffering"`
|
||||
}
|
||||
|
||||
// Equal tests for equality between two Configuration types
|
||||
func (l1 *Configuration) Equal(l2 *Configuration) bool {
|
||||
if l1 == l2 {
|
||||
return true
|
||||
}
|
||||
if l1 == nil || l2 == nil {
|
||||
return false
|
||||
}
|
||||
if l1.BodySize != l2.BodySize {
|
||||
return false
|
||||
}
|
||||
if l1.ConnectTimeout != l2.ConnectTimeout {
|
||||
return false
|
||||
}
|
||||
if l1.SendTimeout != l2.SendTimeout {
|
||||
return false
|
||||
}
|
||||
if l1.ReadTimeout != l2.ReadTimeout {
|
||||
return false
|
||||
}
|
||||
if l1.BufferSize != l2.BufferSize {
|
||||
return false
|
||||
}
|
||||
if l1.CookieDomain != l2.CookieDomain {
|
||||
return false
|
||||
}
|
||||
if l1.CookiePath != l2.CookiePath {
|
||||
return false
|
||||
}
|
||||
if l1.NextUpstream != l2.NextUpstream {
|
||||
return false
|
||||
}
|
||||
if l1.PassParams != l2.PassParams {
|
||||
return false
|
||||
}
|
||||
|
||||
if l1.RequestBuffering != l2.RequestBuffering {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
type proxy struct {
|
||||
backendResolver resolver.DefaultBackend
|
||||
}
|
||||
|
||||
// NewParser creates a new reverse proxy configuration annotation parser
|
||||
func NewParser(br resolver.DefaultBackend) parser.IngressAnnotation {
|
||||
return proxy{br}
|
||||
}
|
||||
|
||||
// ParseAnnotations parses the annotations contained in the ingress
|
||||
// rule used to configure upstream check parameters
|
||||
func (a proxy) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||
defBackend := a.backendResolver.GetDefaultBackend()
|
||||
ct, err := parser.GetIntAnnotation(connect, ing)
|
||||
if err != nil {
|
||||
ct = defBackend.ProxyConnectTimeout
|
||||
}
|
||||
|
||||
st, err := parser.GetIntAnnotation(send, ing)
|
||||
if err != nil {
|
||||
st = defBackend.ProxySendTimeout
|
||||
}
|
||||
|
||||
rt, err := parser.GetIntAnnotation(read, ing)
|
||||
if err != nil {
|
||||
rt = defBackend.ProxyReadTimeout
|
||||
}
|
||||
|
||||
bufs, err := parser.GetStringAnnotation(bufferSize, ing)
|
||||
if err != nil || bufs == "" {
|
||||
bufs = defBackend.ProxyBufferSize
|
||||
}
|
||||
|
||||
cp, err := parser.GetStringAnnotation(cookiePath, ing)
|
||||
if err != nil || cp == "" {
|
||||
cp = defBackend.ProxyCookiePath
|
||||
}
|
||||
|
||||
cd, err := parser.GetStringAnnotation(cookieDomain, ing)
|
||||
if err != nil || cd == "" {
|
||||
cd = defBackend.ProxyCookieDomain
|
||||
}
|
||||
|
||||
bs, err := parser.GetStringAnnotation(bodySize, ing)
|
||||
if err != nil || bs == "" {
|
||||
bs = defBackend.ProxyBodySize
|
||||
}
|
||||
|
||||
nu, err := parser.GetStringAnnotation(nextUpstream, ing)
|
||||
if err != nil || nu == "" {
|
||||
nu = defBackend.ProxyNextUpstream
|
||||
}
|
||||
|
||||
pp, err := parser.GetStringAnnotation(passParams, ing)
|
||||
if err != nil || pp == "" {
|
||||
pp = defBackend.ProxyPassParams
|
||||
}
|
||||
|
||||
rb, err := parser.GetStringAnnotation(requestBuffering, ing)
|
||||
if err != nil || rb == "" {
|
||||
rb = defBackend.ProxyRequestBuffering
|
||||
}
|
||||
|
||||
return &Configuration{bs, ct, st, rt, bufs, cd, cp, nu, pp, rb}, nil
|
||||
}
|
|
@ -1,168 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
api "k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress/defaults"
|
||||
)
|
||||
|
||||
func buildIngress() *extensions.Ingress {
|
||||
defaultBackend := extensions.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
}
|
||||
|
||||
return &extensions.Ingress{
|
||||
ObjectMeta: meta_v1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Namespace: api.NamespaceDefault,
|
||||
},
|
||||
Spec: extensions.IngressSpec{
|
||||
Backend: &extensions.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
},
|
||||
Rules: []extensions.IngressRule{
|
||||
{
|
||||
Host: "foo.bar.com",
|
||||
IngressRuleValue: extensions.IngressRuleValue{
|
||||
HTTP: &extensions.HTTPIngressRuleValue{
|
||||
Paths: []extensions.HTTPIngressPath{
|
||||
{
|
||||
Path: "/foo",
|
||||
Backend: defaultBackend,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type mockBackend struct {
|
||||
}
|
||||
|
||||
func (m mockBackend) GetDefaultBackend() defaults.Backend {
|
||||
return defaults.Backend{
|
||||
UpstreamFailTimeout: 1,
|
||||
ProxyConnectTimeout: 10,
|
||||
ProxySendTimeout: 15,
|
||||
ProxyReadTimeout: 20,
|
||||
ProxyBufferSize: "10k",
|
||||
ProxyBodySize: "3k",
|
||||
ProxyNextUpstream: "error",
|
||||
ProxyPassParams: "nocanon keepalive=On",
|
||||
ProxyRequestBuffering: "on",
|
||||
}
|
||||
}
|
||||
|
||||
func TestProxy(t *testing.T) {
|
||||
ing := buildIngress()
|
||||
|
||||
data := map[string]string{}
|
||||
data[connect] = "1"
|
||||
data[send] = "2"
|
||||
data[read] = "3"
|
||||
data[bufferSize] = "1k"
|
||||
data[bodySize] = "2k"
|
||||
data[nextUpstream] = "off"
|
||||
data[passParams] = "smax=5 max=10"
|
||||
data[requestBuffering] = "off"
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
i, err := NewParser(mockBackend{}).Parse(ing)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error parsing a valid")
|
||||
}
|
||||
p, ok := i.(*Configuration)
|
||||
if !ok {
|
||||
t.Fatalf("expected a Configuration type")
|
||||
}
|
||||
if p.ConnectTimeout != 1 {
|
||||
t.Errorf("expected 1 as connect-timeout but returned %v", p.ConnectTimeout)
|
||||
}
|
||||
if p.SendTimeout != 2 {
|
||||
t.Errorf("expected 2 as send-timeout but returned %v", p.SendTimeout)
|
||||
}
|
||||
if p.ReadTimeout != 3 {
|
||||
t.Errorf("expected 3 as read-timeout but returned %v", p.ReadTimeout)
|
||||
}
|
||||
if p.BufferSize != "1k" {
|
||||
t.Errorf("expected 1k as buffer-size but returned %v", p.BufferSize)
|
||||
}
|
||||
if p.BodySize != "2k" {
|
||||
t.Errorf("expected 2k as body-size but returned %v", p.BodySize)
|
||||
}
|
||||
if p.NextUpstream != "off" {
|
||||
t.Errorf("expected off as next-upstream but returned %v", p.NextUpstream)
|
||||
}
|
||||
if p.PassParams != "smax=5 max=10" {
|
||||
t.Errorf("expected \"smax=5 max=10\" as pass-params but returned \"%v\"", p.PassParams)
|
||||
}
|
||||
if p.RequestBuffering != "off" {
|
||||
t.Errorf("expected off as request-buffering but returned %v", p.RequestBuffering)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProxyWithNoAnnotation(t *testing.T) {
|
||||
ing := buildIngress()
|
||||
|
||||
data := map[string]string{}
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
i, err := NewParser(mockBackend{}).Parse(ing)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error parsing a valid")
|
||||
}
|
||||
p, ok := i.(*Configuration)
|
||||
if !ok {
|
||||
t.Fatalf("expected a Configuration type")
|
||||
}
|
||||
if p.ConnectTimeout != 10 {
|
||||
t.Errorf("expected 10 as connect-timeout but returned %v", p.ConnectTimeout)
|
||||
}
|
||||
if p.SendTimeout != 15 {
|
||||
t.Errorf("expected 15 as send-timeout but returned %v", p.SendTimeout)
|
||||
}
|
||||
if p.ReadTimeout != 20 {
|
||||
t.Errorf("expected 20 as read-timeout but returned %v", p.ReadTimeout)
|
||||
}
|
||||
if p.BufferSize != "10k" {
|
||||
t.Errorf("expected 10k as buffer-size but returned %v", p.BufferSize)
|
||||
}
|
||||
if p.BodySize != "3k" {
|
||||
t.Errorf("expected 3k as body-size but returned %v", p.BodySize)
|
||||
}
|
||||
if p.NextUpstream != "error" {
|
||||
t.Errorf("expected error as next-upstream but returned %v", p.NextUpstream)
|
||||
}
|
||||
if p.PassParams != "nocanon keepalive=On" {
|
||||
t.Errorf("expected \"nocanon keepalive=On\" as pass-params but returned \"%v\"", p.PassParams)
|
||||
}
|
||||
if p.RequestBuffering != "on" {
|
||||
t.Errorf("expected on as request-buffering but returned %v", p.RequestBuffering)
|
||||
}
|
||||
}
|
|
@ -1,255 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package ratelimit
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/resolver"
|
||||
"k8s.io/ingress-nginx/pkg/net"
|
||||
)
|
||||
|
||||
const (
|
||||
limitIP = "ingress.kubernetes.io/limit-connections"
|
||||
limitRPS = "ingress.kubernetes.io/limit-rps"
|
||||
limitRPM = "ingress.kubernetes.io/limit-rpm"
|
||||
limitRATE = "ingress.kubernetes.io/limit-rate"
|
||||
limitRATEAFTER = "ingress.kubernetes.io/limit-rate-after"
|
||||
limitWhitelist = "ingress.kubernetes.io/limit-whitelist"
|
||||
|
||||
// allow 5 times the specified limit as burst
|
||||
defBurst = 5
|
||||
|
||||
// 1MB -> 16 thousand 64-byte states or about 8 thousand 128-byte states
|
||||
// default is 5MB
|
||||
defSharedSize = 5
|
||||
)
|
||||
|
||||
// RateLimit returns rate limit configuration for an Ingress rule limiting the
|
||||
// number of connections per IP address and/or connections per second.
|
||||
// If you both annotations are specified in a single Ingress rule, RPS limits
|
||||
// takes precedence
|
||||
type RateLimit struct {
|
||||
// Connections indicates a limit with the number of connections per IP address
|
||||
Connections Zone `json:"connections"`
|
||||
// RPS indicates a limit with the number of connections per second
|
||||
RPS Zone `json:"rps"`
|
||||
|
||||
RPM Zone `json:"rpm"`
|
||||
|
||||
LimitRate int `json:"limit-rate"`
|
||||
|
||||
LimitRateAfter int `json:"limit-rate-after"`
|
||||
|
||||
Name string `json:"name"`
|
||||
|
||||
ID string `json:"id"`
|
||||
|
||||
Whitelist []string `json:"whitelist"`
|
||||
}
|
||||
|
||||
// Equal tests for equality between two RateLimit types
|
||||
func (rt1 *RateLimit) Equal(rt2 *RateLimit) bool {
|
||||
if rt1 == rt2 {
|
||||
return true
|
||||
}
|
||||
if rt1 == nil || rt2 == nil {
|
||||
return false
|
||||
}
|
||||
if !(&rt1.Connections).Equal(&rt2.Connections) {
|
||||
return false
|
||||
}
|
||||
if !(&rt1.RPM).Equal(&rt2.RPM) {
|
||||
return false
|
||||
}
|
||||
if !(&rt1.RPS).Equal(&rt2.RPS) {
|
||||
return false
|
||||
}
|
||||
if rt1.LimitRate != rt2.LimitRate {
|
||||
return false
|
||||
}
|
||||
if rt1.LimitRateAfter != rt2.LimitRateAfter {
|
||||
return false
|
||||
}
|
||||
if rt1.ID != rt2.ID {
|
||||
return false
|
||||
}
|
||||
if rt1.Name != rt2.Name {
|
||||
return false
|
||||
}
|
||||
if len(rt1.Whitelist) != len(rt2.Whitelist) {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, r1l := range rt1.Whitelist {
|
||||
found := false
|
||||
for _, rl2 := range rt2.Whitelist {
|
||||
if r1l == rl2 {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Zone returns information about the NGINX rate limit (limit_req_zone)
|
||||
// http://nginx.org/en/docs/http/ngx_http_limit_req_module.html#limit_req_zone
|
||||
type Zone struct {
|
||||
Name string `json:"name"`
|
||||
Limit int `json:"limit"`
|
||||
Burst int `json:"burst"`
|
||||
// SharedSize amount of shared memory for the zone
|
||||
SharedSize int `json:"sharedSize"`
|
||||
}
|
||||
|
||||
// Equal tests for equality between two Zone types
|
||||
func (z1 *Zone) Equal(z2 *Zone) bool {
|
||||
if z1 == z2 {
|
||||
return true
|
||||
}
|
||||
if z1 == nil || z2 == nil {
|
||||
return false
|
||||
}
|
||||
if z1.Name != z2.Name {
|
||||
return false
|
||||
}
|
||||
if z1.Limit != z2.Limit {
|
||||
return false
|
||||
}
|
||||
if z1.Burst != z2.Burst {
|
||||
return false
|
||||
}
|
||||
if z1.SharedSize != z2.SharedSize {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
type ratelimit struct {
|
||||
backendResolver resolver.DefaultBackend
|
||||
}
|
||||
|
||||
// NewParser creates a new ratelimit annotation parser
|
||||
func NewParser(br resolver.DefaultBackend) parser.IngressAnnotation {
|
||||
return ratelimit{br}
|
||||
}
|
||||
|
||||
// ParseAnnotations parses the annotations contained in the ingress
|
||||
// rule used to rewrite the defined paths
|
||||
func (a ratelimit) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||
defBackend := a.backendResolver.GetDefaultBackend()
|
||||
lr, err := parser.GetIntAnnotation(limitRATE, ing)
|
||||
if err != nil {
|
||||
lr = defBackend.LimitRate
|
||||
}
|
||||
lra, err := parser.GetIntAnnotation(limitRATEAFTER, ing)
|
||||
if err != nil {
|
||||
lra = defBackend.LimitRateAfter
|
||||
}
|
||||
|
||||
rpm, _ := parser.GetIntAnnotation(limitRPM, ing)
|
||||
rps, _ := parser.GetIntAnnotation(limitRPS, ing)
|
||||
conn, _ := parser.GetIntAnnotation(limitIP, ing)
|
||||
|
||||
val, _ := parser.GetStringAnnotation(limitWhitelist, ing)
|
||||
|
||||
cidrs, err := parseCIDRs(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if rpm == 0 && rps == 0 && conn == 0 {
|
||||
return &RateLimit{
|
||||
Connections: Zone{},
|
||||
RPS: Zone{},
|
||||
RPM: Zone{},
|
||||
LimitRate: lr,
|
||||
LimitRateAfter: lra,
|
||||
}, nil
|
||||
}
|
||||
|
||||
zoneName := fmt.Sprintf("%v_%v", ing.GetNamespace(), ing.GetName())
|
||||
|
||||
return &RateLimit{
|
||||
Connections: Zone{
|
||||
Name: fmt.Sprintf("%v_conn", zoneName),
|
||||
Limit: conn,
|
||||
Burst: conn * defBurst,
|
||||
SharedSize: defSharedSize,
|
||||
},
|
||||
RPS: Zone{
|
||||
Name: fmt.Sprintf("%v_rps", zoneName),
|
||||
Limit: rps,
|
||||
Burst: rps * defBurst,
|
||||
SharedSize: defSharedSize,
|
||||
},
|
||||
RPM: Zone{
|
||||
Name: fmt.Sprintf("%v_rpm", zoneName),
|
||||
Limit: rpm,
|
||||
Burst: rpm * defBurst,
|
||||
SharedSize: defSharedSize,
|
||||
},
|
||||
LimitRate: lr,
|
||||
LimitRateAfter: lra,
|
||||
Name: zoneName,
|
||||
ID: encode(zoneName),
|
||||
Whitelist: cidrs,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func parseCIDRs(s string) ([]string, error) {
|
||||
if s == "" {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
values := strings.Split(s, ",")
|
||||
|
||||
ipnets, ips, err := net.ParseIPNets(values...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cidrs := []string{}
|
||||
for k := range ipnets {
|
||||
cidrs = append(cidrs, k)
|
||||
}
|
||||
|
||||
for k := range ips {
|
||||
cidrs = append(cidrs, k)
|
||||
}
|
||||
|
||||
sort.Strings(cidrs)
|
||||
|
||||
return cidrs, nil
|
||||
}
|
||||
|
||||
func encode(s string) string {
|
||||
str := base64.URLEncoding.EncodeToString([]byte(s))
|
||||
return strings.Replace(str, "=", "", -1)
|
||||
}
|
|
@ -1,129 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package ratelimit
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
api "k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/defaults"
|
||||
)
|
||||
|
||||
func buildIngress() *extensions.Ingress {
|
||||
defaultBackend := extensions.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
}
|
||||
|
||||
return &extensions.Ingress{
|
||||
ObjectMeta: meta_v1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Namespace: api.NamespaceDefault,
|
||||
},
|
||||
Spec: extensions.IngressSpec{
|
||||
Backend: &extensions.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
},
|
||||
Rules: []extensions.IngressRule{
|
||||
{
|
||||
Host: "foo.bar.com",
|
||||
IngressRuleValue: extensions.IngressRuleValue{
|
||||
HTTP: &extensions.HTTPIngressRuleValue{
|
||||
Paths: []extensions.HTTPIngressPath{
|
||||
{
|
||||
Path: "/foo",
|
||||
Backend: defaultBackend,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type mockBackend struct {
|
||||
}
|
||||
|
||||
func (m mockBackend) GetDefaultBackend() defaults.Backend {
|
||||
return defaults.Backend{
|
||||
LimitRateAfter: 0,
|
||||
LimitRate: 0,
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithoutAnnotations(t *testing.T) {
|
||||
ing := buildIngress()
|
||||
_, err := NewParser(mockBackend{}).Parse(ing)
|
||||
if err != nil {
|
||||
t.Error("unexpected error with ingress without annotations")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBadRateLimiting(t *testing.T) {
|
||||
ing := buildIngress()
|
||||
|
||||
data := map[string]string{}
|
||||
data[limitIP] = "0"
|
||||
data[limitRPS] = "0"
|
||||
data[limitRPM] = "0"
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
_, err := NewParser(mockBackend{}).Parse(ing)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error with invalid limits (0)")
|
||||
}
|
||||
|
||||
data = map[string]string{}
|
||||
data[limitIP] = "5"
|
||||
data[limitRPS] = "100"
|
||||
data[limitRPM] = "10"
|
||||
data[limitRATEAFTER] = "100"
|
||||
data[limitRATE] = "10"
|
||||
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
i, err := NewParser(mockBackend{}).Parse(ing)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
rateLimit, ok := i.(*RateLimit)
|
||||
if !ok {
|
||||
t.Errorf("expected a RateLimit type")
|
||||
}
|
||||
if rateLimit.Connections.Limit != 5 {
|
||||
t.Errorf("expected 5 in limit by ip but %v was returend", rateLimit.Connections)
|
||||
}
|
||||
if rateLimit.RPS.Limit != 100 {
|
||||
t.Errorf("expected 100 in limit by rps but %v was returend", rateLimit.RPS)
|
||||
}
|
||||
if rateLimit.RPM.Limit != 10 {
|
||||
t.Errorf("expected 10 in limit by rpm but %v was returend", rateLimit.RPM)
|
||||
}
|
||||
if rateLimit.LimitRateAfter != 100 {
|
||||
t.Errorf("expected 100 in limit by limitrateafter but %v was returend", rateLimit.LimitRateAfter)
|
||||
}
|
||||
if rateLimit.LimitRate != 10 {
|
||||
t.Errorf("expected 10 in limit by limitrate but %v was returend", rateLimit.LimitRate)
|
||||
}
|
||||
}
|
|
@ -1,131 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package redirect
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
permanent = "ingress.kubernetes.io/permanent-redirect"
|
||||
temporal = "ingress.kubernetes.io/temporal-redirect"
|
||||
www = "ingress.kubernetes.io/from-to-www-redirect"
|
||||
)
|
||||
|
||||
// Redirect returns the redirect configuration for an Ingress rule
|
||||
type Redirect struct {
|
||||
URL string `json:"url"`
|
||||
Code int `json:"code"`
|
||||
FromToWWW bool `json:"fromToWWW"`
|
||||
}
|
||||
|
||||
type redirect struct{}
|
||||
|
||||
// NewParser creates a new redirect annotation parser
|
||||
func NewParser() parser.IngressAnnotation {
|
||||
return redirect{}
|
||||
}
|
||||
|
||||
// Parse parses the annotations contained in the ingress
|
||||
// rule used to create a redirect in the paths defined in the rule.
|
||||
// If the Ingress containes both annotations the execution order is
|
||||
// temporal and then permanent
|
||||
func (a redirect) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||
r3w, _ := parser.GetBoolAnnotation(www, ing)
|
||||
|
||||
tr, err := parser.GetStringAnnotation(temporal, ing)
|
||||
if err != nil && !errors.IsMissingAnnotations(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if tr != "" {
|
||||
if err := isValidURL(tr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Redirect{
|
||||
URL: tr,
|
||||
Code: http.StatusFound,
|
||||
FromToWWW: r3w,
|
||||
}, nil
|
||||
}
|
||||
|
||||
pr, err := parser.GetStringAnnotation(permanent, ing)
|
||||
if err != nil && !errors.IsMissingAnnotations(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if pr != "" {
|
||||
if err := isValidURL(pr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Redirect{
|
||||
URL: pr,
|
||||
Code: http.StatusMovedPermanently,
|
||||
FromToWWW: r3w,
|
||||
}, nil
|
||||
}
|
||||
|
||||
if r3w {
|
||||
return &Redirect{
|
||||
FromToWWW: r3w,
|
||||
}, nil
|
||||
}
|
||||
|
||||
return nil, errors.ErrMissingAnnotations
|
||||
}
|
||||
|
||||
// Equal tests for equality between two Redirect types
|
||||
func (r1 *Redirect) Equal(r2 *Redirect) bool {
|
||||
if r1 == r2 {
|
||||
return true
|
||||
}
|
||||
if r1 == nil || r2 == nil {
|
||||
return false
|
||||
}
|
||||
if r1.URL != r2.URL {
|
||||
return false
|
||||
}
|
||||
if r1.Code != r2.Code {
|
||||
return false
|
||||
}
|
||||
if r1.FromToWWW != r2.FromToWWW {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func isValidURL(s string) error {
|
||||
u, err := url.Parse(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(u.Scheme, "http") {
|
||||
return errors.Errorf("only http and https are valid protocols (%v)", u.Scheme)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package rewrite
|
||||
|
||||
import (
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/resolver"
|
||||
)
|
||||
|
||||
const (
|
||||
rewriteTo = "ingress.kubernetes.io/rewrite-target"
|
||||
addBaseURL = "ingress.kubernetes.io/add-base-url"
|
||||
baseURLScheme = "ingress.kubernetes.io/base-url-scheme"
|
||||
sslRedirect = "ingress.kubernetes.io/ssl-redirect"
|
||||
forceSSLRedirect = "ingress.kubernetes.io/force-ssl-redirect"
|
||||
appRoot = "ingress.kubernetes.io/app-root"
|
||||
)
|
||||
|
||||
// Redirect describes the per location redirect config
|
||||
type Redirect struct {
|
||||
// Target URI where the traffic must be redirected
|
||||
Target string `json:"target"`
|
||||
// AddBaseURL indicates if is required to add a base tag in the head
|
||||
// of the responses from the upstream servers
|
||||
AddBaseURL bool `json:"addBaseUrl"`
|
||||
// BaseURLScheme override for the scheme passed to the base tag
|
||||
BaseURLScheme string `json:"baseUrlScheme"`
|
||||
// SSLRedirect indicates if the location section is accessible SSL only
|
||||
SSLRedirect bool `json:"sslRedirect"`
|
||||
// ForceSSLRedirect indicates if the location section is accessible SSL only
|
||||
ForceSSLRedirect bool `json:"forceSSLRedirect"`
|
||||
// AppRoot defines the Application Root that the Controller must redirect if it's not in '/' context
|
||||
AppRoot string `json:"appRoot"`
|
||||
}
|
||||
|
||||
// Equal tests for equality between two Redirect types
|
||||
func (r1 *Redirect) Equal(r2 *Redirect) bool {
|
||||
if r1 == r2 {
|
||||
return true
|
||||
}
|
||||
if r1 == nil || r2 == nil {
|
||||
return false
|
||||
}
|
||||
if r1.Target != r2.Target {
|
||||
return false
|
||||
}
|
||||
if r1.AddBaseURL != r2.AddBaseURL {
|
||||
return false
|
||||
}
|
||||
if r1.BaseURLScheme != r2.BaseURLScheme {
|
||||
return false
|
||||
}
|
||||
if r1.SSLRedirect != r2.SSLRedirect {
|
||||
return false
|
||||
}
|
||||
if r1.ForceSSLRedirect != r2.ForceSSLRedirect {
|
||||
return false
|
||||
}
|
||||
if r1.AppRoot != r2.AppRoot {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
type rewrite struct {
|
||||
backendResolver resolver.DefaultBackend
|
||||
}
|
||||
|
||||
// NewParser creates a new reqrite annotation parser
|
||||
func NewParser(br resolver.DefaultBackend) parser.IngressAnnotation {
|
||||
return rewrite{br}
|
||||
}
|
||||
|
||||
// ParseAnnotations parses the annotations contained in the ingress
|
||||
// rule used to rewrite the defined paths
|
||||
func (a rewrite) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||
rt, _ := parser.GetStringAnnotation(rewriteTo, ing)
|
||||
sslRe, err := parser.GetBoolAnnotation(sslRedirect, ing)
|
||||
if err != nil {
|
||||
sslRe = a.backendResolver.GetDefaultBackend().SSLRedirect
|
||||
}
|
||||
fSslRe, err := parser.GetBoolAnnotation(forceSSLRedirect, ing)
|
||||
if err != nil {
|
||||
fSslRe = a.backendResolver.GetDefaultBackend().ForceSSLRedirect
|
||||
}
|
||||
abu, _ := parser.GetBoolAnnotation(addBaseURL, ing)
|
||||
bus, _ := parser.GetStringAnnotation(baseURLScheme, ing)
|
||||
ar, _ := parser.GetStringAnnotation(appRoot, ing)
|
||||
return &Redirect{
|
||||
Target: rt,
|
||||
AddBaseURL: abu,
|
||||
BaseURLScheme: bus,
|
||||
SSLRedirect: sslRe,
|
||||
ForceSSLRedirect: fSslRe,
|
||||
AppRoot: ar,
|
||||
}, nil
|
||||
}
|
|
@ -1,178 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package rewrite
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
api "k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress/defaults"
|
||||
)
|
||||
|
||||
const (
|
||||
defRoute = "/demo"
|
||||
)
|
||||
|
||||
func buildIngress() *extensions.Ingress {
|
||||
defaultBackend := extensions.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
}
|
||||
|
||||
return &extensions.Ingress{
|
||||
ObjectMeta: meta_v1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Namespace: api.NamespaceDefault,
|
||||
},
|
||||
Spec: extensions.IngressSpec{
|
||||
Backend: &extensions.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
},
|
||||
Rules: []extensions.IngressRule{
|
||||
{
|
||||
Host: "foo.bar.com",
|
||||
IngressRuleValue: extensions.IngressRuleValue{
|
||||
HTTP: &extensions.HTTPIngressRuleValue{
|
||||
Paths: []extensions.HTTPIngressPath{
|
||||
{
|
||||
Path: "/foo",
|
||||
Backend: defaultBackend,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type mockBackend struct {
|
||||
redirect bool
|
||||
}
|
||||
|
||||
func (m mockBackend) GetDefaultBackend() defaults.Backend {
|
||||
return defaults.Backend{SSLRedirect: m.redirect}
|
||||
}
|
||||
|
||||
func TestWithoutAnnotations(t *testing.T) {
|
||||
ing := buildIngress()
|
||||
_, err := NewParser(mockBackend{}).Parse(ing)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error with ingress without annotations: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRedirect(t *testing.T) {
|
||||
ing := buildIngress()
|
||||
|
||||
data := map[string]string{}
|
||||
data[rewriteTo] = defRoute
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
i, err := NewParser(mockBackend{}).Parse(ing)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error with ingress: %v", err)
|
||||
}
|
||||
redirect, ok := i.(*Redirect)
|
||||
if !ok {
|
||||
t.Errorf("expected a Redirect type")
|
||||
}
|
||||
if redirect.Target != defRoute {
|
||||
t.Errorf("Expected %v as redirect but returned %s", defRoute, redirect.Target)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSSLRedirect(t *testing.T) {
|
||||
ing := buildIngress()
|
||||
|
||||
data := map[string]string{}
|
||||
data[rewriteTo] = defRoute
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
i, _ := NewParser(mockBackend{true}).Parse(ing)
|
||||
redirect, ok := i.(*Redirect)
|
||||
if !ok {
|
||||
t.Errorf("expected a Redirect type")
|
||||
}
|
||||
if !redirect.SSLRedirect {
|
||||
t.Errorf("Expected true but returned false")
|
||||
}
|
||||
|
||||
data[sslRedirect] = "false"
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
i, _ = NewParser(mockBackend{false}).Parse(ing)
|
||||
redirect, ok = i.(*Redirect)
|
||||
if !ok {
|
||||
t.Errorf("expected a Redirect type")
|
||||
}
|
||||
if redirect.SSLRedirect {
|
||||
t.Errorf("Expected false but returned true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestForceSSLRedirect(t *testing.T) {
|
||||
ing := buildIngress()
|
||||
|
||||
data := map[string]string{}
|
||||
data[rewriteTo] = defRoute
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
i, _ := NewParser(mockBackend{true}).Parse(ing)
|
||||
redirect, ok := i.(*Redirect)
|
||||
if !ok {
|
||||
t.Errorf("expected a Redirect type")
|
||||
}
|
||||
if redirect.ForceSSLRedirect {
|
||||
t.Errorf("Expected false but returned true")
|
||||
}
|
||||
|
||||
data[forceSSLRedirect] = "true"
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
i, _ = NewParser(mockBackend{false}).Parse(ing)
|
||||
redirect, ok = i.(*Redirect)
|
||||
if !ok {
|
||||
t.Errorf("expected a Redirect type")
|
||||
}
|
||||
if !redirect.ForceSSLRedirect {
|
||||
t.Errorf("Expected true but returned false")
|
||||
}
|
||||
}
|
||||
func TestAppRoot(t *testing.T) {
|
||||
ing := buildIngress()
|
||||
|
||||
data := map[string]string{}
|
||||
data[appRoot] = "/app1"
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
i, _ := NewParser(mockBackend{true}).Parse(ing)
|
||||
redirect, ok := i.(*Redirect)
|
||||
if !ok {
|
||||
t.Errorf("expected a App Context")
|
||||
}
|
||||
if redirect.AppRoot != "/app1" {
|
||||
t.Errorf("Unexpected value got in AppRoot")
|
||||
}
|
||||
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package secureupstream
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/resolver"
|
||||
)
|
||||
|
||||
const (
|
||||
secureUpstream = "ingress.kubernetes.io/secure-backends"
|
||||
secureVerifyCASecret = "ingress.kubernetes.io/secure-verify-ca-secret"
|
||||
)
|
||||
|
||||
// Secure describes SSL backend configuration
|
||||
type Secure struct {
|
||||
Secure bool `json:"secure"`
|
||||
CACert resolver.AuthSSLCert `json:"caCert"`
|
||||
}
|
||||
|
||||
type su struct {
|
||||
certResolver resolver.AuthCertificate
|
||||
}
|
||||
|
||||
// NewParser creates a new secure upstream annotation parser
|
||||
func NewParser(resolver resolver.AuthCertificate) parser.IngressAnnotation {
|
||||
return su{
|
||||
certResolver: resolver,
|
||||
}
|
||||
}
|
||||
|
||||
// Parse parses the annotations contained in the ingress
|
||||
// rule used to indicate if the upstream servers should use SSL
|
||||
func (a su) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||
s, _ := parser.GetBoolAnnotation(secureUpstream, ing)
|
||||
ca, _ := parser.GetStringAnnotation(secureVerifyCASecret, ing)
|
||||
secure := &Secure{
|
||||
Secure: s,
|
||||
CACert: resolver.AuthSSLCert{},
|
||||
}
|
||||
if !s && ca != "" {
|
||||
return secure,
|
||||
errors.Errorf("trying to use CA from secret %v/%v on a non secure backend", ing.Namespace, ca)
|
||||
}
|
||||
if ca == "" {
|
||||
return secure, nil
|
||||
}
|
||||
caCert, err := a.certResolver.GetAuthCertificate(fmt.Sprintf("%v/%v", ing.Namespace, ca))
|
||||
if err != nil {
|
||||
return secure, errors.Wrap(err, "error obtaining certificate")
|
||||
}
|
||||
if caCert == nil {
|
||||
return secure, nil
|
||||
}
|
||||
return &Secure{
|
||||
Secure: s,
|
||||
CACert: *caCert,
|
||||
}, nil
|
||||
}
|
|
@ -1,121 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package secureupstream
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
api "k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/resolver"
|
||||
)
|
||||
|
||||
func buildIngress() *extensions.Ingress {
|
||||
defaultBackend := extensions.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
}
|
||||
|
||||
return &extensions.Ingress{
|
||||
ObjectMeta: meta_v1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Namespace: api.NamespaceDefault,
|
||||
},
|
||||
Spec: extensions.IngressSpec{
|
||||
Backend: &extensions.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
},
|
||||
Rules: []extensions.IngressRule{
|
||||
{
|
||||
Host: "foo.bar.com",
|
||||
IngressRuleValue: extensions.IngressRuleValue{
|
||||
HTTP: &extensions.HTTPIngressRuleValue{
|
||||
Paths: []extensions.HTTPIngressPath{
|
||||
{
|
||||
Path: "/foo",
|
||||
Backend: defaultBackend,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type mockCfg struct {
|
||||
certs map[string]resolver.AuthSSLCert
|
||||
}
|
||||
|
||||
func (cfg mockCfg) GetAuthCertificate(secret string) (*resolver.AuthSSLCert, error) {
|
||||
if cert, ok := cfg.certs[secret]; ok {
|
||||
return &cert, nil
|
||||
}
|
||||
return nil, fmt.Errorf("secret not found: %v", secret)
|
||||
}
|
||||
|
||||
func TestAnnotations(t *testing.T) {
|
||||
ing := buildIngress()
|
||||
data := map[string]string{}
|
||||
data[secureUpstream] = "true"
|
||||
data[secureVerifyCASecret] = "secure-verify-ca"
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
_, err := NewParser(mockCfg{
|
||||
certs: map[string]resolver.AuthSSLCert{
|
||||
"default/secure-verify-ca": {},
|
||||
},
|
||||
}).Parse(ing)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error on ingress: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSecretNotFound(t *testing.T) {
|
||||
ing := buildIngress()
|
||||
data := map[string]string{}
|
||||
data[secureUpstream] = "true"
|
||||
data[secureVerifyCASecret] = "secure-verify-ca"
|
||||
ing.SetAnnotations(data)
|
||||
_, err := NewParser(mockCfg{}).Parse(ing)
|
||||
if err == nil {
|
||||
t.Error("Expected secret not found error on ingress")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSecretOnNonSecure(t *testing.T) {
|
||||
ing := buildIngress()
|
||||
data := map[string]string{}
|
||||
data[secureUpstream] = "false"
|
||||
data[secureVerifyCASecret] = "secure-verify-ca"
|
||||
ing.SetAnnotations(data)
|
||||
_, err := NewParser(mockCfg{
|
||||
certs: map[string]resolver.AuthSSLCert{
|
||||
"default/secure-verify-ca": {},
|
||||
},
|
||||
}).Parse(ing)
|
||||
if err == nil {
|
||||
t.Error("Expected CA secret on non secure backend error on ingress")
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package serversnippet
|
||||
|
||||
import (
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
|
||||
)
|
||||
|
||||
const (
|
||||
annotation = "ingress.kubernetes.io/server-snippet"
|
||||
)
|
||||
|
||||
type serverSnippet struct {
|
||||
}
|
||||
|
||||
// NewParser creates a new server snippet annotation parser
|
||||
func NewParser() parser.IngressAnnotation {
|
||||
return serverSnippet{}
|
||||
}
|
||||
|
||||
// Parse parses the annotations contained in the ingress rule
|
||||
// used to indicate if the location/s contains a fragment of
|
||||
// configuration to be included inside the paths of the rules
|
||||
func (a serverSnippet) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||
return parser.GetStringAnnotation(annotation, ing)
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package serversnippet
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
api "k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
ap := NewParser()
|
||||
if ap == nil {
|
||||
t.Fatalf("expected a parser.IngressAnnotation but returned nil")
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
annotations map[string]string
|
||||
expected string
|
||||
}{
|
||||
{map[string]string{annotation: "more_headers"}, "more_headers"},
|
||||
{map[string]string{annotation: "false"}, "false"},
|
||||
{map[string]string{}, ""},
|
||||
{nil, ""},
|
||||
}
|
||||
|
||||
ing := &extensions.Ingress{
|
||||
ObjectMeta: meta_v1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Namespace: api.NamespaceDefault,
|
||||
},
|
||||
Spec: extensions.IngressSpec{},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
ing.SetAnnotations(testCase.annotations)
|
||||
result, _ := ap.Parse(ing)
|
||||
if result != testCase.expected {
|
||||
t.Errorf("expected %v but returned %v, annotations: %s", testCase.expected, result, testCase.annotations)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,112 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package serviceupstream
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
api "k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
)
|
||||
|
||||
func buildIngress() *extensions.Ingress {
|
||||
defaultBackend := extensions.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
}
|
||||
|
||||
return &extensions.Ingress{
|
||||
ObjectMeta: meta_v1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Namespace: api.NamespaceDefault,
|
||||
},
|
||||
Spec: extensions.IngressSpec{
|
||||
Backend: &extensions.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
},
|
||||
Rules: []extensions.IngressRule{
|
||||
{
|
||||
Host: "foo.bar.com",
|
||||
IngressRuleValue: extensions.IngressRuleValue{
|
||||
HTTP: &extensions.HTTPIngressRuleValue{
|
||||
Paths: []extensions.HTTPIngressPath{
|
||||
{
|
||||
Path: "/foo",
|
||||
Backend: defaultBackend,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestIngressAnnotationServiceUpstreamEnabled(t *testing.T) {
|
||||
ing := buildIngress()
|
||||
|
||||
data := map[string]string{}
|
||||
data[annotationServiceUpstream] = "true"
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
val, _ := NewParser().Parse(ing)
|
||||
enabled, ok := val.(bool)
|
||||
if !ok {
|
||||
t.Errorf("expected a bool type")
|
||||
}
|
||||
|
||||
if !enabled {
|
||||
t.Errorf("expected annotation value to be true, got false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIngressAnnotationServiceUpstreamSetFalse(t *testing.T) {
|
||||
ing := buildIngress()
|
||||
|
||||
// Test with explicitly set to false
|
||||
data := map[string]string{}
|
||||
data[annotationServiceUpstream] = "false"
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
val, _ := NewParser().Parse(ing)
|
||||
enabled, ok := val.(bool)
|
||||
if !ok {
|
||||
t.Errorf("expected a bool type")
|
||||
}
|
||||
|
||||
if enabled {
|
||||
t.Errorf("expected annotation value to be false, got true")
|
||||
}
|
||||
|
||||
// Test with no annotation specified, should default to false
|
||||
data = map[string]string{}
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
val, _ = NewParser().Parse(ing)
|
||||
enabled, ok = val.(bool)
|
||||
if !ok {
|
||||
t.Errorf("expected a bool type")
|
||||
}
|
||||
|
||||
if enabled {
|
||||
t.Errorf("expected annotation value to be false, got true")
|
||||
}
|
||||
}
|
|
@ -1,115 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package sessionaffinity
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
|
||||
)
|
||||
|
||||
const (
|
||||
annotationAffinityType = "ingress.kubernetes.io/affinity"
|
||||
// If a cookie with this name exists,
|
||||
// its value is used as an index into the list of available backends.
|
||||
annotationAffinityCookieName = "ingress.kubernetes.io/session-cookie-name"
|
||||
defaultAffinityCookieName = "INGRESSCOOKIE"
|
||||
// This is the algorithm used by nginx to generate a value for the session cookie, if
|
||||
// one isn't supplied and affinity is set to "cookie".
|
||||
annotationAffinityCookieHash = "ingress.kubernetes.io/session-cookie-hash"
|
||||
defaultAffinityCookieHash = "md5"
|
||||
)
|
||||
|
||||
var (
|
||||
affinityCookieHashRegex = regexp.MustCompile(`^(index|md5|sha1)$`)
|
||||
)
|
||||
|
||||
// AffinityConfig describes the per ingress session affinity config
|
||||
type AffinityConfig struct {
|
||||
// The type of affinity that will be used
|
||||
AffinityType string `json:"type"`
|
||||
CookieConfig
|
||||
}
|
||||
|
||||
// CookieConfig describes the Config of cookie type affinity
|
||||
type CookieConfig struct {
|
||||
// The name of the cookie that will be used in case of cookie affinity type.
|
||||
Name string `json:"name"`
|
||||
// The hash that will be used to encode the cookie in case of cookie affinity type
|
||||
Hash string `json:"hash"`
|
||||
}
|
||||
|
||||
// CookieAffinityParse gets the annotation values related to Cookie Affinity
|
||||
// It also sets default values when no value or incorrect value is found
|
||||
func CookieAffinityParse(ing *extensions.Ingress) *CookieConfig {
|
||||
|
||||
sn, err := parser.GetStringAnnotation(annotationAffinityCookieName, ing)
|
||||
|
||||
if err != nil || sn == "" {
|
||||
glog.V(3).Infof("Ingress %v: No value found in annotation %v. Using the default %v", ing.Name, annotationAffinityCookieName, defaultAffinityCookieName)
|
||||
sn = defaultAffinityCookieName
|
||||
}
|
||||
|
||||
sh, err := parser.GetStringAnnotation(annotationAffinityCookieHash, ing)
|
||||
|
||||
if err != nil || !affinityCookieHashRegex.MatchString(sh) {
|
||||
glog.V(3).Infof("Invalid or no annotation value found in Ingress %v: %v. Setting it to default %v", ing.Name, annotationAffinityCookieHash, defaultAffinityCookieHash)
|
||||
sh = defaultAffinityCookieHash
|
||||
}
|
||||
|
||||
return &CookieConfig{
|
||||
Name: sn,
|
||||
Hash: sh,
|
||||
}
|
||||
}
|
||||
|
||||
// NewParser creates a new Affinity annotation parser
|
||||
func NewParser() parser.IngressAnnotation {
|
||||
return affinity{}
|
||||
}
|
||||
|
||||
type affinity struct {
|
||||
}
|
||||
|
||||
// ParseAnnotations parses the annotations contained in the ingress
|
||||
// rule used to configure the affinity directives
|
||||
func (a affinity) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||
cookieAffinityConfig := &CookieConfig{}
|
||||
// Check the type of affinity that will be used
|
||||
at, err := parser.GetStringAnnotation(annotationAffinityType, ing)
|
||||
if err != nil {
|
||||
at = ""
|
||||
}
|
||||
|
||||
switch at {
|
||||
case "cookie":
|
||||
cookieAffinityConfig = CookieAffinityParse(ing)
|
||||
|
||||
default:
|
||||
glog.V(3).Infof("No default affinity was found for Ingress %v", ing.Name)
|
||||
|
||||
}
|
||||
return &AffinityConfig{
|
||||
AffinityType: at,
|
||||
CookieConfig: *cookieAffinityConfig,
|
||||
}, nil
|
||||
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package sessionaffinity
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
api "k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
)
|
||||
|
||||
func buildIngress() *extensions.Ingress {
|
||||
defaultBackend := extensions.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
}
|
||||
|
||||
return &extensions.Ingress{
|
||||
ObjectMeta: meta_v1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Namespace: api.NamespaceDefault,
|
||||
},
|
||||
Spec: extensions.IngressSpec{
|
||||
Backend: &extensions.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
},
|
||||
Rules: []extensions.IngressRule{
|
||||
{
|
||||
Host: "foo.bar.com",
|
||||
IngressRuleValue: extensions.IngressRuleValue{
|
||||
HTTP: &extensions.HTTPIngressRuleValue{
|
||||
Paths: []extensions.HTTPIngressPath{
|
||||
{
|
||||
Path: "/foo",
|
||||
Backend: defaultBackend,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestIngressAffinityCookieConfig(t *testing.T) {
|
||||
ing := buildIngress()
|
||||
|
||||
data := map[string]string{}
|
||||
data[annotationAffinityType] = "cookie"
|
||||
data[annotationAffinityCookieHash] = "sha123"
|
||||
data[annotationAffinityCookieName] = "INGRESSCOOKIE"
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
affin, _ := NewParser().Parse(ing)
|
||||
nginxAffinity, ok := affin.(*AffinityConfig)
|
||||
if !ok {
|
||||
t.Errorf("expected a Config type")
|
||||
}
|
||||
|
||||
if nginxAffinity.AffinityType != "cookie" {
|
||||
t.Errorf("expected cookie as sticky-type but returned %v", nginxAffinity.AffinityType)
|
||||
}
|
||||
|
||||
if nginxAffinity.CookieConfig.Hash != "md5" {
|
||||
t.Errorf("expected md5 as sticky-hash but returned %v", nginxAffinity.CookieConfig.Hash)
|
||||
}
|
||||
|
||||
if nginxAffinity.CookieConfig.Name != "INGRESSCOOKIE" {
|
||||
t.Errorf("expected route as sticky-name but returned %v", nginxAffinity.CookieConfig.Name)
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package snippet
|
||||
|
||||
import (
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
|
||||
)
|
||||
|
||||
const (
|
||||
annotation = "ingress.kubernetes.io/configuration-snippet"
|
||||
)
|
||||
|
||||
type snippet struct {
|
||||
}
|
||||
|
||||
// NewParser creates a new CORS annotation parser
|
||||
func NewParser() parser.IngressAnnotation {
|
||||
return snippet{}
|
||||
}
|
||||
|
||||
// Parse parses the annotations contained in the ingress rule
|
||||
// used to indicate if the location/s contains a fragment of
|
||||
// configuration to be included inside the paths of the rules
|
||||
func (a snippet) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||
return parser.GetStringAnnotation(annotation, ing)
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package snippet
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
api "k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
ap := NewParser()
|
||||
if ap == nil {
|
||||
t.Fatalf("expected a parser.IngressAnnotation but returned nil")
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
annotations map[string]string
|
||||
expected string
|
||||
}{
|
||||
{map[string]string{annotation: "more_headers"}, "more_headers"},
|
||||
{map[string]string{annotation: "false"}, "false"},
|
||||
{map[string]string{}, ""},
|
||||
{nil, ""},
|
||||
}
|
||||
|
||||
ing := &extensions.Ingress{
|
||||
ObjectMeta: meta_v1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Namespace: api.NamespaceDefault,
|
||||
},
|
||||
Spec: extensions.IngressSpec{},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
ing.SetAnnotations(testCase.annotations)
|
||||
result, _ := ap.Parse(ing)
|
||||
if result != testCase.expected {
|
||||
t.Errorf("expected %v but returned %v, annotations: %s", testCase.expected, result, testCase.annotations)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package sslpassthrough
|
||||
|
||||
import (
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
|
||||
ing_errors "k8s.io/ingress-nginx/pkg/ingress/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
passthrough = "ingress.kubernetes.io/ssl-passthrough"
|
||||
)
|
||||
|
||||
type sslpt struct {
|
||||
}
|
||||
|
||||
// NewParser creates a new SSL passthrough annotation parser
|
||||
func NewParser() parser.IngressAnnotation {
|
||||
return sslpt{}
|
||||
}
|
||||
|
||||
// ParseAnnotations parses the annotations contained in the ingress
|
||||
// rule used to indicate if is required to configure
|
||||
func (a sslpt) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||
if ing.GetAnnotations() == nil {
|
||||
return false, ing_errors.ErrMissingAnnotations
|
||||
}
|
||||
|
||||
return parser.GetBoolAnnotation(passthrough, ing)
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package sslpassthrough
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
api "k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
)
|
||||
|
||||
func buildIngress() *extensions.Ingress {
|
||||
return &extensions.Ingress{
|
||||
ObjectMeta: meta_v1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Namespace: api.NamespaceDefault,
|
||||
},
|
||||
Spec: extensions.IngressSpec{
|
||||
Backend: &extensions.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseAnnotations(t *testing.T) {
|
||||
ing := buildIngress()
|
||||
|
||||
_, err := NewParser().Parse(ing)
|
||||
if err == nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
data := map[string]string{}
|
||||
data[passthrough] = "true"
|
||||
ing.SetAnnotations(data)
|
||||
// test ingress using the annotation without a TLS section
|
||||
_, err = NewParser().Parse(ing)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error parsing ingress with sslpassthrough")
|
||||
}
|
||||
|
||||
// test with a valid host
|
||||
ing.Spec.TLS = []extensions.IngressTLS{
|
||||
{
|
||||
Hosts: []string{"foo.bar.com"},
|
||||
},
|
||||
}
|
||||
i, err := NewParser().Parse(ing)
|
||||
if err != nil {
|
||||
t.Errorf("expected error parsing ingress with sslpassthrough")
|
||||
}
|
||||
val, ok := i.(bool)
|
||||
if !ok {
|
||||
t.Errorf("expected a bool type")
|
||||
}
|
||||
if !val {
|
||||
t.Errorf("expected true but false returned")
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package upstreamhashby
|
||||
|
||||
import (
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
|
||||
)
|
||||
|
||||
const (
|
||||
annotation = "ingress.kubernetes.io/upstream-hash-by"
|
||||
)
|
||||
|
||||
type upstreamhashby struct {
|
||||
}
|
||||
|
||||
// NewParser creates a new CORS annotation parser
|
||||
func NewParser() parser.IngressAnnotation {
|
||||
return upstreamhashby{}
|
||||
}
|
||||
|
||||
// Parse parses the annotations contained in the ingress rule
|
||||
// used to indicate if the location/s contains a fragment of
|
||||
// configuration to be included inside the paths of the rules
|
||||
func (a upstreamhashby) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||
return parser.GetStringAnnotation(annotation, ing)
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package upstreamhashby
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
api "k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
ap := NewParser()
|
||||
if ap == nil {
|
||||
t.Fatalf("expected a parser.IngressAnnotation but returned nil")
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
annotations map[string]string
|
||||
expected string
|
||||
}{
|
||||
{map[string]string{annotation: "$request_uri"}, "$request_uri"},
|
||||
{map[string]string{annotation: "false"}, "false"},
|
||||
{map[string]string{}, ""},
|
||||
{nil, ""},
|
||||
}
|
||||
|
||||
ing := &extensions.Ingress{
|
||||
ObjectMeta: meta_v1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Namespace: api.NamespaceDefault,
|
||||
},
|
||||
Spec: extensions.IngressSpec{},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
ing.SetAnnotations(testCase.annotations)
|
||||
result, _ := ap.Parse(ing)
|
||||
if result != testCase.expected {
|
||||
t.Errorf("expected %v but returned %v, annotations: %s", testCase.expected, result, testCase.annotations)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package upstreamvhost
|
||||
|
||||
import (
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
|
||||
)
|
||||
|
||||
const (
|
||||
annotation = "ingress.kubernetes.io/upstream-vhost"
|
||||
)
|
||||
|
||||
type upstreamVhost struct {
|
||||
}
|
||||
|
||||
// NewParser creates a new upstream VHost annotation parser
|
||||
func NewParser() parser.IngressAnnotation {
|
||||
return upstreamVhost{}
|
||||
}
|
||||
|
||||
// Parse parses the annotations contained in the ingress rule
|
||||
// used to indicate if the location/s contains a fragment of
|
||||
// configuration to be included inside the paths of the rules
|
||||
func (a upstreamVhost) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||
return parser.GetStringAnnotation(annotation, ing)
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package vtsfilterkey
|
||||
|
||||
import (
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
|
||||
)
|
||||
|
||||
const (
|
||||
annotation = "ingress.kubernetes.io/vts-filter-key"
|
||||
)
|
||||
|
||||
type vtsFilterKey struct {
|
||||
}
|
||||
|
||||
// NewParser creates a new vts filter key annotation parser
|
||||
func NewParser() parser.IngressAnnotation {
|
||||
return vtsFilterKey{}
|
||||
}
|
||||
|
||||
// Parse parses the annotations contained in the ingress rule
|
||||
// used to indicate if the location/s contains a fragment of
|
||||
// configuration to be included inside the paths of the rules
|
||||
func (a vtsFilterKey) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||
return parser.GetStringAnnotation(annotation, ing)
|
||||
}
|
|
@ -1,199 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controller
|
||||
|
||||
import (
|
||||
"github.com/golang/glog"
|
||||
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/alias"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/auth"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/authreq"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/authtls"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/clientbodybuffersize"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/cors"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/defaultbackend"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/healthcheck"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/ipwhitelist"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/portinredirect"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/proxy"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/ratelimit"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/redirect"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/rewrite"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/secureupstream"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/serversnippet"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/serviceupstream"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/sessionaffinity"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/snippet"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/sslpassthrough"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/upstreamhashby"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/upstreamvhost"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/vtsfilterkey"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/errors"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/resolver"
|
||||
)
|
||||
|
||||
type extractorConfig interface {
|
||||
resolver.AuthCertificate
|
||||
resolver.DefaultBackend
|
||||
resolver.Secret
|
||||
resolver.Service
|
||||
}
|
||||
|
||||
type annotationExtractor struct {
|
||||
secretResolver resolver.Secret
|
||||
annotations map[string]parser.IngressAnnotation
|
||||
}
|
||||
|
||||
func newAnnotationExtractor(cfg extractorConfig) annotationExtractor {
|
||||
return annotationExtractor{
|
||||
cfg,
|
||||
map[string]parser.IngressAnnotation{
|
||||
"BasicDigestAuth": auth.NewParser(auth.AuthDirectory, cfg),
|
||||
"ExternalAuth": authreq.NewParser(),
|
||||
"CertificateAuth": authtls.NewParser(cfg),
|
||||
"EnableCORS": cors.NewParser(),
|
||||
"HealthCheck": healthcheck.NewParser(cfg),
|
||||
"Whitelist": ipwhitelist.NewParser(cfg),
|
||||
"UsePortInRedirects": portinredirect.NewParser(cfg),
|
||||
"Proxy": proxy.NewParser(cfg),
|
||||
"RateLimit": ratelimit.NewParser(cfg),
|
||||
"Redirect": redirect.NewParser(),
|
||||
"Rewrite": rewrite.NewParser(cfg),
|
||||
"SecureUpstream": secureupstream.NewParser(cfg),
|
||||
"ServiceUpstream": serviceupstream.NewParser(),
|
||||
"SessionAffinity": sessionaffinity.NewParser(),
|
||||
"SSLPassthrough": sslpassthrough.NewParser(),
|
||||
"ConfigurationSnippet": snippet.NewParser(),
|
||||
"Alias": alias.NewParser(),
|
||||
"ClientBodyBufferSize": clientbodybuffersize.NewParser(),
|
||||
"DefaultBackend": defaultbackend.NewParser(cfg),
|
||||
"UpstreamHashBy": upstreamhashby.NewParser(),
|
||||
"UpstreamVhost": upstreamvhost.NewParser(),
|
||||
"VtsFilterKey": vtsfilterkey.NewParser(),
|
||||
"ServerSnippet": serversnippet.NewParser(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (e *annotationExtractor) Extract(ing *extensions.Ingress) map[string]interface{} {
|
||||
anns := make(map[string]interface{})
|
||||
for name, annotationParser := range e.annotations {
|
||||
val, err := annotationParser.Parse(ing)
|
||||
glog.V(5).Infof("annotation %v in Ingress %v/%v: %v", name, ing.GetNamespace(), ing.GetName(), val)
|
||||
if err != nil {
|
||||
if errors.IsMissingAnnotations(err) {
|
||||
continue
|
||||
}
|
||||
|
||||
if !errors.IsLocationDenied(err) {
|
||||
continue
|
||||
}
|
||||
|
||||
_, alreadyDenied := anns[DeniedKeyName]
|
||||
if !alreadyDenied {
|
||||
anns[DeniedKeyName] = err
|
||||
glog.Errorf("error reading %v annotation in Ingress %v/%v: %v", name, ing.GetNamespace(), ing.GetName(), err)
|
||||
continue
|
||||
}
|
||||
|
||||
glog.V(5).Infof("error reading %v annotation in Ingress %v/%v: %v", name, ing.GetNamespace(), ing.GetName(), err)
|
||||
}
|
||||
|
||||
if val != nil {
|
||||
anns[name] = val
|
||||
}
|
||||
}
|
||||
|
||||
return anns
|
||||
}
|
||||
|
||||
const (
|
||||
secureUpstream = "SecureUpstream"
|
||||
healthCheck = "HealthCheck"
|
||||
sslPassthrough = "SSLPassthrough"
|
||||
sessionAffinity = "SessionAffinity"
|
||||
serviceUpstream = "ServiceUpstream"
|
||||
serverAlias = "Alias"
|
||||
clientBodyBufferSize = "ClientBodyBufferSize"
|
||||
certificateAuth = "CertificateAuth"
|
||||
serverSnippet = "ServerSnippet"
|
||||
upstreamHashBy = "UpstreamHashBy"
|
||||
)
|
||||
|
||||
func (e *annotationExtractor) ServiceUpstream(ing *extensions.Ingress) bool {
|
||||
val, _ := e.annotations[serviceUpstream].Parse(ing)
|
||||
return val.(bool)
|
||||
}
|
||||
|
||||
func (e *annotationExtractor) SecureUpstream(ing *extensions.Ingress) *secureupstream.Secure {
|
||||
val, err := e.annotations[secureUpstream].Parse(ing)
|
||||
if err != nil {
|
||||
glog.Errorf("error parsing secure upstream: %v", err)
|
||||
}
|
||||
secure := val.(*secureupstream.Secure)
|
||||
return secure
|
||||
}
|
||||
|
||||
func (e *annotationExtractor) HealthCheck(ing *extensions.Ingress) *healthcheck.Upstream {
|
||||
val, _ := e.annotations[healthCheck].Parse(ing)
|
||||
return val.(*healthcheck.Upstream)
|
||||
}
|
||||
|
||||
func (e *annotationExtractor) SSLPassthrough(ing *extensions.Ingress) bool {
|
||||
val, _ := e.annotations[sslPassthrough].Parse(ing)
|
||||
return val.(bool)
|
||||
}
|
||||
|
||||
func (e *annotationExtractor) Alias(ing *extensions.Ingress) string {
|
||||
val, _ := e.annotations[serverAlias].Parse(ing)
|
||||
return val.(string)
|
||||
}
|
||||
|
||||
func (e *annotationExtractor) ClientBodyBufferSize(ing *extensions.Ingress) string {
|
||||
val, _ := e.annotations[clientBodyBufferSize].Parse(ing)
|
||||
return val.(string)
|
||||
}
|
||||
|
||||
func (e *annotationExtractor) SessionAffinity(ing *extensions.Ingress) *sessionaffinity.AffinityConfig {
|
||||
val, _ := e.annotations[sessionAffinity].Parse(ing)
|
||||
return val.(*sessionaffinity.AffinityConfig)
|
||||
}
|
||||
|
||||
func (e *annotationExtractor) CertificateAuth(ing *extensions.Ingress) *authtls.AuthSSLConfig {
|
||||
val, err := e.annotations[certificateAuth].Parse(ing)
|
||||
if errors.IsMissingAnnotations(err) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
glog.Errorf("error parsing certificate auth: %v", err)
|
||||
}
|
||||
secure := val.(*authtls.AuthSSLConfig)
|
||||
return secure
|
||||
}
|
||||
|
||||
func (e *annotationExtractor) ServerSnippet(ing *extensions.Ingress) string {
|
||||
val, _ := e.annotations[serverSnippet].Parse(ing)
|
||||
return val.(string)
|
||||
}
|
||||
|
||||
func (e *annotationExtractor) UpstreamHashBy(ing *extensions.Ingress) string {
|
||||
val, _ := e.annotations[upstreamHashBy].Parse(ing)
|
||||
return val.(string)
|
||||
}
|
|
@ -1,295 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controller
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress/defaults"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/resolver"
|
||||
)
|
||||
|
||||
const (
|
||||
annotationSecureUpstream = "ingress.kubernetes.io/secure-backends"
|
||||
annotationSecureVerifyCACert = "ingress.kubernetes.io/secure-verify-ca-secret"
|
||||
annotationUpsMaxFails = "ingress.kubernetes.io/upstream-max-fails"
|
||||
annotationUpsFailTimeout = "ingress.kubernetes.io/upstream-fail-timeout"
|
||||
annotationPassthrough = "ingress.kubernetes.io/ssl-passthrough"
|
||||
annotationAffinityType = "ingress.kubernetes.io/affinity"
|
||||
annotationAffinityCookieName = "ingress.kubernetes.io/session-cookie-name"
|
||||
annotationAffinityCookieHash = "ingress.kubernetes.io/session-cookie-hash"
|
||||
annotationUpstreamHashBy = "ingress.kubernetes.io/upstream-hash-by"
|
||||
)
|
||||
|
||||
type mockCfg struct {
|
||||
MockSecrets map[string]*apiv1.Secret
|
||||
MockServices map[string]*apiv1.Service
|
||||
}
|
||||
|
||||
func (m mockCfg) GetDefaultBackend() defaults.Backend {
|
||||
return defaults.Backend{}
|
||||
}
|
||||
|
||||
func (m mockCfg) GetSecret(name string) (*apiv1.Secret, error) {
|
||||
return m.MockSecrets[name], nil
|
||||
}
|
||||
|
||||
func (m mockCfg) GetService(name string) (*apiv1.Service, error) {
|
||||
return m.MockServices[name], nil
|
||||
}
|
||||
|
||||
func (m mockCfg) GetAuthCertificate(name string) (*resolver.AuthSSLCert, error) {
|
||||
if secret, _ := m.GetSecret(name); secret != nil {
|
||||
return &resolver.AuthSSLCert{
|
||||
Secret: name,
|
||||
CAFileName: "/opt/ca.pem",
|
||||
PemSHA: "123",
|
||||
}, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func TestAnnotationExtractor(t *testing.T) {
|
||||
ec := newAnnotationExtractor(mockCfg{})
|
||||
ing := buildIngress()
|
||||
|
||||
m := ec.Extract(ing)
|
||||
// the map at least should contains HealthCheck and Proxy information (defaults)
|
||||
if _, ok := m["HealthCheck"]; !ok {
|
||||
t.Error("expected HealthCheck annotation")
|
||||
}
|
||||
if _, ok := m["Proxy"]; !ok {
|
||||
t.Error("expected Proxy annotation")
|
||||
}
|
||||
}
|
||||
|
||||
func buildIngress() *extensions.Ingress {
|
||||
defaultBackend := extensions.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
}
|
||||
|
||||
return &extensions.Ingress{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Namespace: apiv1.NamespaceDefault,
|
||||
},
|
||||
Spec: extensions.IngressSpec{
|
||||
Backend: &extensions.IngressBackend{
|
||||
ServiceName: "default-backend",
|
||||
ServicePort: intstr.FromInt(80),
|
||||
},
|
||||
Rules: []extensions.IngressRule{
|
||||
{
|
||||
Host: "foo.bar.com",
|
||||
IngressRuleValue: extensions.IngressRuleValue{
|
||||
HTTP: &extensions.HTTPIngressRuleValue{
|
||||
Paths: []extensions.HTTPIngressPath{
|
||||
{
|
||||
Path: "/foo",
|
||||
Backend: defaultBackend,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestSecureUpstream(t *testing.T) {
|
||||
ec := newAnnotationExtractor(mockCfg{})
|
||||
ing := buildIngress()
|
||||
|
||||
fooAnns := []struct {
|
||||
annotations map[string]string
|
||||
er bool
|
||||
}{
|
||||
{map[string]string{annotationSecureUpstream: "true"}, true},
|
||||
{map[string]string{annotationSecureUpstream: "false"}, false},
|
||||
{map[string]string{annotationSecureUpstream + "_no": "true"}, false},
|
||||
{map[string]string{}, false},
|
||||
{nil, false},
|
||||
}
|
||||
|
||||
for _, foo := range fooAnns {
|
||||
ing.SetAnnotations(foo.annotations)
|
||||
r := ec.SecureUpstream(ing)
|
||||
if r.Secure != foo.er {
|
||||
t.Errorf("Returned %v but expected %v", r, foo.er)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSecureVerifyCACert(t *testing.T) {
|
||||
ec := newAnnotationExtractor(mockCfg{
|
||||
MockSecrets: map[string]*apiv1.Secret{
|
||||
"default/secure-verify-ca": {
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "secure-verify-ca",
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
anns := []struct {
|
||||
it int
|
||||
annotations map[string]string
|
||||
exists bool
|
||||
}{
|
||||
{1, map[string]string{annotationSecureUpstream: "true", annotationSecureVerifyCACert: "not"}, false},
|
||||
{2, map[string]string{annotationSecureUpstream: "false", annotationSecureVerifyCACert: "secure-verify-ca"}, false},
|
||||
{3, map[string]string{annotationSecureUpstream: "true", annotationSecureVerifyCACert: "secure-verify-ca"}, true},
|
||||
{4, map[string]string{annotationSecureUpstream: "true", annotationSecureVerifyCACert + "_not": "secure-verify-ca"}, false},
|
||||
{5, map[string]string{annotationSecureUpstream: "true"}, false},
|
||||
{6, map[string]string{}, false},
|
||||
{7, nil, false},
|
||||
}
|
||||
|
||||
for _, ann := range anns {
|
||||
ing := buildIngress()
|
||||
ing.SetAnnotations(ann.annotations)
|
||||
res := ec.SecureUpstream(ing)
|
||||
if (res.CACert.CAFileName != "") != ann.exists {
|
||||
t.Errorf("Expected exists was %v on iteration %v", ann.exists, ann.it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHealthCheck(t *testing.T) {
|
||||
ec := newAnnotationExtractor(mockCfg{})
|
||||
ing := buildIngress()
|
||||
|
||||
fooAnns := []struct {
|
||||
annotations map[string]string
|
||||
eumf int
|
||||
euft int
|
||||
}{
|
||||
{map[string]string{annotationUpsMaxFails: "3", annotationUpsFailTimeout: "10"}, 3, 10},
|
||||
{map[string]string{annotationUpsMaxFails: "3"}, 3, 0},
|
||||
{map[string]string{annotationUpsFailTimeout: "10"}, 0, 10},
|
||||
{map[string]string{}, 0, 0},
|
||||
{nil, 0, 0},
|
||||
}
|
||||
|
||||
for _, foo := range fooAnns {
|
||||
ing.SetAnnotations(foo.annotations)
|
||||
r := ec.HealthCheck(ing)
|
||||
if r == nil {
|
||||
t.Errorf("Returned nil but expected a healthcheck.Upstream")
|
||||
continue
|
||||
}
|
||||
|
||||
if r.FailTimeout != foo.euft {
|
||||
t.Errorf("Returned %d but expected %d for FailTimeout", r.FailTimeout, foo.euft)
|
||||
}
|
||||
|
||||
if r.MaxFails != foo.eumf {
|
||||
t.Errorf("Returned %d but expected %d for MaxFails", r.MaxFails, foo.eumf)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSSLPassthrough(t *testing.T) {
|
||||
ec := newAnnotationExtractor(mockCfg{})
|
||||
ing := buildIngress()
|
||||
|
||||
fooAnns := []struct {
|
||||
annotations map[string]string
|
||||
er bool
|
||||
}{
|
||||
{map[string]string{annotationPassthrough: "true"}, true},
|
||||
{map[string]string{annotationPassthrough: "false"}, false},
|
||||
{map[string]string{annotationPassthrough + "_no": "true"}, false},
|
||||
{map[string]string{}, false},
|
||||
{nil, false},
|
||||
}
|
||||
|
||||
for _, foo := range fooAnns {
|
||||
ing.SetAnnotations(foo.annotations)
|
||||
r := ec.SSLPassthrough(ing)
|
||||
if r != foo.er {
|
||||
t.Errorf("Returned %v but expected %v", r, foo.er)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpstreamHashBy(t *testing.T) {
|
||||
ec := newAnnotationExtractor(mockCfg{})
|
||||
ing := buildIngress()
|
||||
|
||||
fooAnns := []struct {
|
||||
annotations map[string]string
|
||||
er string
|
||||
}{
|
||||
{map[string]string{annotationUpstreamHashBy: "$request_uri"}, "$request_uri"},
|
||||
{map[string]string{annotationUpstreamHashBy: "false"}, "false"},
|
||||
{map[string]string{annotationUpstreamHashBy + "_no": "true"}, ""},
|
||||
{map[string]string{}, ""},
|
||||
{nil, ""},
|
||||
}
|
||||
|
||||
for _, foo := range fooAnns {
|
||||
ing.SetAnnotations(foo.annotations)
|
||||
r := ec.UpstreamHashBy(ing)
|
||||
if r != foo.er {
|
||||
t.Errorf("Returned %v but expected %v", r, foo.er)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAffinitySession(t *testing.T) {
|
||||
ec := newAnnotationExtractor(mockCfg{})
|
||||
ing := buildIngress()
|
||||
|
||||
fooAnns := []struct {
|
||||
annotations map[string]string
|
||||
affinitytype string
|
||||
hash string
|
||||
name string
|
||||
}{
|
||||
{map[string]string{annotationAffinityType: "cookie", annotationAffinityCookieHash: "md5", annotationAffinityCookieName: "route"}, "cookie", "md5", "route"},
|
||||
{map[string]string{annotationAffinityType: "cookie", annotationAffinityCookieHash: "xpto", annotationAffinityCookieName: "route1"}, "cookie", "md5", "route1"},
|
||||
{map[string]string{annotationAffinityType: "cookie", annotationAffinityCookieHash: "", annotationAffinityCookieName: ""}, "cookie", "md5", "INGRESSCOOKIE"},
|
||||
{map[string]string{}, "", "", ""},
|
||||
{nil, "", "", ""},
|
||||
}
|
||||
|
||||
for _, foo := range fooAnns {
|
||||
ing.SetAnnotations(foo.annotations)
|
||||
r := ec.SessionAffinity(ing)
|
||||
t.Logf("Testing pass %v %v %v", foo.affinitytype, foo.hash, foo.name)
|
||||
if r == nil {
|
||||
t.Errorf("Returned nil but expected a SessionAffinity.AffinityConfig")
|
||||
continue
|
||||
}
|
||||
|
||||
if r.CookieConfig.Hash != foo.hash {
|
||||
t.Errorf("Returned %v but expected %v for Hash", r.CookieConfig.Hash, foo.hash)
|
||||
}
|
||||
|
||||
if r.CookieConfig.Name != foo.name {
|
||||
t.Errorf("Returned %v but expected %v for Name", r.CookieConfig.Name, foo.name)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,6 +28,7 @@ import (
|
|||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/aledbf/ingress-controller/pkg/ingress/annotations/proxy"
|
||||
"github.com/golang/glog"
|
||||
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
|
@ -41,13 +42,12 @@ import (
|
|||
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
"k8s.io/client-go/tools/record"
|
||||
"k8s.io/client-go/util/flowcontrol"
|
||||
"k8s.io/contrib/ingress/controllers/nginx/nginx/healthcheck"
|
||||
"k8s.io/kubernetes/pkg/kubelet/util/sliceutils"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/class"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/healthcheck"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/proxy"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/defaults"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/resolver"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/status"
|
||||
|
|
|
@ -2,13 +2,8 @@ package defaults
|
|||
|
||||
import "net"
|
||||
|
||||
// Backend defines the mandatory configuration that an Ingress controller must provide
|
||||
// The reason of this requirements is the annotations are generic. If some implementation do not supports
|
||||
// one or more annotations it just can provides defaults
|
||||
// Backend defines the mandatory configuration for NGINX.
|
||||
type Backend struct {
|
||||
// AppRoot contains the AppRoot for apps that doesn't exposes its content in the 'root' context
|
||||
AppRoot string `json:"app-root"`
|
||||
|
||||
// enables which HTTP codes should be passed for processing with the error_page directive
|
||||
// http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_intercept_errors
|
||||
// http://nginx.org/en/docs/http/ngx_http_core_module.html#error_page
|
||||
|
@ -101,15 +96,4 @@ type Backend struct {
|
|||
// WhitelistSourceRange allows limiting access to certain client addresses
|
||||
// http://nginx.org/en/docs/http/ngx_http_access_module.html
|
||||
WhitelistSourceRange []string `json:"whitelist-source-range,-"`
|
||||
|
||||
// Limits the rate of response transmission to a client.
|
||||
// The rate is specified in bytes per second. The zero value disables rate limiting.
|
||||
// The limit is set per a request, and so if a client simultaneously opens two connections,
|
||||
// the overall rate will be twice as much as the specified limit.
|
||||
// http://nginx.org/en/docs/http/ngx_http_core_module.html#limit_rate
|
||||
LimitRate int `json:"limit-rate"`
|
||||
|
||||
// Sets the initial amount after which the further transmission of a response to a client will be rate limited.
|
||||
// http://nginx.org/en/docs/http/ngx_http_core_module.html#limit_rate_after
|
||||
LimitRateAfter int `json:"limit-rate-after"`
|
||||
}
|
||||
|
|
|
@ -26,14 +26,7 @@ import (
|
|||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
"k8s.io/apiserver/pkg/server/healthz"
|
||||
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/auth"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/authreq"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/authtls"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/ipwhitelist"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/proxy"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/ratelimit"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/redirect"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/rewrite"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/defaults"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/resolver"
|
||||
"k8s.io/ingress-nginx/pkg/ingress/store"
|
||||
|
@ -174,26 +167,6 @@ type Backend struct {
|
|||
UpstreamHashBy string `json:"upstream-hash-by,omitempty"`
|
||||
}
|
||||
|
||||
// SessionAffinityConfig describes different affinity configurations for new sessions.
|
||||
// Once a session is mapped to a backend based on some affinity setting, it
|
||||
// retains that mapping till the backend goes down, or the ingress controller
|
||||
// restarts. Exactly one of these values will be set on the upstream, since multiple
|
||||
// affinity values are incompatible. Once set, the backend makes no guarantees
|
||||
// about honoring updates.
|
||||
// +k8s:deepcopy-gen=true
|
||||
type SessionAffinityConfig struct {
|
||||
AffinityType string `json:"name"`
|
||||
CookieSessionAffinity CookieSessionAffinity `json:"cookieSessionAffinity"`
|
||||
}
|
||||
|
||||
// CookieSessionAffinity defines the structure used in Affinity configured by Cookies.
|
||||
// +k8s:deepcopy-gen=true
|
||||
type CookieSessionAffinity struct {
|
||||
Name string `json:"name"`
|
||||
Hash string `json:"hash"`
|
||||
Locations map[string][]string `json:"locations,omitempty"`
|
||||
}
|
||||
|
||||
// Endpoint describes a kubernetes endpoint in a backend
|
||||
// +k8s:deepcopy-gen=true
|
||||
type Endpoint struct {
|
||||
|
@ -241,7 +214,6 @@ type Server struct {
|
|||
// CertificateAuth indicates the this server requires mutual authentication
|
||||
// +optional
|
||||
CertificateAuth authtls.AuthSSLConfig `json:"certificateAuth"`
|
||||
|
||||
// ServerSnippet returns the snippet of server
|
||||
// +optional
|
||||
ServerSnippet string `json:"serverSnippet"`
|
||||
|
@ -282,57 +254,9 @@ type Location struct {
|
|||
Service *apiv1.Service `json:"service,omitempty"`
|
||||
// Port describes to which port from the service
|
||||
Port intstr.IntOrString `json:"port"`
|
||||
// Overwrite the Host header passed into the backend. Defaults to
|
||||
// vhost of the incoming request.
|
||||
// +optional
|
||||
UpstreamVhost string `json:"upstream-vhost"`
|
||||
// BasicDigestAuth returns authentication configuration for
|
||||
// an Ingress rule.
|
||||
// +optional
|
||||
BasicDigestAuth auth.BasicDigest `json:"basicDigestAuth,omitempty"`
|
||||
// Denied returns an error when this location cannot not be allowed
|
||||
// Requesting a denied location should return HTTP code 403.
|
||||
Denied error `json:"denied,omitempty"`
|
||||
// EnableCORS indicates if path must support CORS
|
||||
// +optional
|
||||
EnableCORS bool `json:"enableCors,omitempty"`
|
||||
// ExternalAuth indicates the access to this location requires
|
||||
// authentication using an external provider
|
||||
// +optional
|
||||
ExternalAuth authreq.External `json:"externalAuth,omitempty"`
|
||||
// RateLimit describes a limit in the number of connections per IP
|
||||
// address or connections per second.
|
||||
// The Redirect annotation precedes RateLimit
|
||||
// +optional
|
||||
RateLimit ratelimit.RateLimit `json:"rateLimit,omitempty"`
|
||||
// Redirect describes a temporal o permanent redirection this location.
|
||||
// +optional
|
||||
Redirect redirect.Redirect `json:"redirect,omitempty"`
|
||||
// Rewrite describes the redirection this location.
|
||||
// +optional
|
||||
Rewrite rewrite.Redirect `json:"rewrite,omitempty"`
|
||||
// Whitelist indicates only connections from certain client
|
||||
// addresses or networks are allowed.
|
||||
// +optional
|
||||
Whitelist ipwhitelist.SourceRange `json:"whitelist,omitempty"`
|
||||
// Proxy contains information about timeouts and buffer sizes
|
||||
// to be used in connections against endpoints
|
||||
// +optional
|
||||
Proxy proxy.Configuration `json:"proxy,omitempty"`
|
||||
// UsePortInRedirects indicates if redirects must specify the port
|
||||
// +optional
|
||||
UsePortInRedirects bool `json:"usePortInRedirects"`
|
||||
// VtsFilterKey contains the vts filter key on the location level
|
||||
// https://github.com/vozlt/nginx-module-vts#vhost_traffic_status_filter_by_set_key
|
||||
// +optional
|
||||
VtsFilterKey string `json:"vtsFilterKey,omitempty"`
|
||||
// ConfigurationSnippet contains additional configuration for the backend
|
||||
// to be considered in the configuration of the location
|
||||
ConfigurationSnippet string `json:"configurationSnippet"`
|
||||
// ClientBodyBufferSize allows for the configuration of the client body
|
||||
// buffer size for a specific location.
|
||||
// +optional
|
||||
ClientBodyBufferSize string `json:"clientBodyBufferSize,omitempty"`
|
||||
// DefaultBackend allows the use of a custom default backend for this location.
|
||||
// +optional
|
||||
DefaultBackend *apiv1.Service `json:"defaultBackend,omitempty"`
|
||||
|
|
Loading…
Reference in a new issue