Replace annotations with CRDs
This commit is contained in:
parent
a18daabc51
commit
fc86119061
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.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package serviceupstream
|
package nginxingress
|
||||||
|
|
||||||
import (
|
|
||||||
extensions "k8s.io/api/extensions/v1beta1"
|
|
||||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
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.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package alias
|
package fake
|
||||||
|
|
||||||
import (
|
import (
|
||||||
extensions "k8s.io/api/extensions/v1beta1"
|
rest "k8s.io/client-go/rest"
|
||||||
|
testing "k8s.io/client-go/testing"
|
||||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/parser"
|
v1alpha1 "k8s.io/ingress-nginx/pkg/client/clientset/versioned/typed/nginx/v1alpha1"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
type FakeNginxV1alpha1 struct {
|
||||||
annotation = "ingress.kubernetes.io/server-alias"
|
*testing.Fake
|
||||||
)
|
|
||||||
|
|
||||||
type alias struct {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewParser creates a new Alias annotation parser
|
func (c *FakeNginxV1alpha1) Configurations(namespace string) v1alpha1.ConfigurationInterface {
|
||||||
func NewParser() parser.IngressAnnotation {
|
return &FakeConfigurations{c, namespace}
|
||||||
return alias{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse parses the annotations contained in the ingress rule
|
// RESTClient returns a RESTClient that is used to communicate
|
||||||
// used to add an alias to the provided hosts
|
// with API server by this client implementation.
|
||||||
func (a alias) Parse(ing *extensions.Ingress) (interface{}, error) {
|
func (c *FakeNginxV1alpha1) RESTClient() rest.Interface {
|
||||||
return parser.GetStringAnnotation(annotation, ing)
|
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"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/aledbf/ingress-controller/pkg/ingress/annotations/proxy"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
|
|
||||||
apiv1 "k8s.io/api/core/v1"
|
apiv1 "k8s.io/api/core/v1"
|
||||||
|
@ -41,13 +42,12 @@ import (
|
||||||
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
|
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||||
"k8s.io/client-go/tools/record"
|
"k8s.io/client-go/tools/record"
|
||||||
"k8s.io/client-go/util/flowcontrol"
|
"k8s.io/client-go/util/flowcontrol"
|
||||||
|
"k8s.io/contrib/ingress/controllers/nginx/nginx/healthcheck"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/util/sliceutils"
|
"k8s.io/kubernetes/pkg/kubelet/util/sliceutils"
|
||||||
|
|
||||||
"k8s.io/ingress-nginx/pkg/ingress"
|
"k8s.io/ingress-nginx/pkg/ingress"
|
||||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/class"
|
"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/parser"
|
||||||
"k8s.io/ingress-nginx/pkg/ingress/annotations/proxy"
|
|
||||||
"k8s.io/ingress-nginx/pkg/ingress/defaults"
|
"k8s.io/ingress-nginx/pkg/ingress/defaults"
|
||||||
"k8s.io/ingress-nginx/pkg/ingress/resolver"
|
"k8s.io/ingress-nginx/pkg/ingress/resolver"
|
||||||
"k8s.io/ingress-nginx/pkg/ingress/status"
|
"k8s.io/ingress-nginx/pkg/ingress/status"
|
||||||
|
|
|
@ -2,13 +2,8 @@ package defaults
|
||||||
|
|
||||||
import "net"
|
import "net"
|
||||||
|
|
||||||
// Backend defines the mandatory configuration that an Ingress controller must provide
|
// Backend defines the mandatory configuration for NGINX.
|
||||||
// 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
|
|
||||||
type Backend struct {
|
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
|
// 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_proxy_module.html#proxy_intercept_errors
|
||||||
// http://nginx.org/en/docs/http/ngx_http_core_module.html#error_page
|
// 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
|
// WhitelistSourceRange allows limiting access to certain client addresses
|
||||||
// http://nginx.org/en/docs/http/ngx_http_access_module.html
|
// http://nginx.org/en/docs/http/ngx_http_access_module.html
|
||||||
WhitelistSourceRange []string `json:"whitelist-source-range,-"`
|
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/apimachinery/pkg/util/intstr"
|
||||||
"k8s.io/apiserver/pkg/server/healthz"
|
"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/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/defaults"
|
||||||
"k8s.io/ingress-nginx/pkg/ingress/resolver"
|
"k8s.io/ingress-nginx/pkg/ingress/resolver"
|
||||||
"k8s.io/ingress-nginx/pkg/ingress/store"
|
"k8s.io/ingress-nginx/pkg/ingress/store"
|
||||||
|
@ -174,26 +167,6 @@ type Backend struct {
|
||||||
UpstreamHashBy string `json:"upstream-hash-by,omitempty"`
|
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
|
// Endpoint describes a kubernetes endpoint in a backend
|
||||||
// +k8s:deepcopy-gen=true
|
// +k8s:deepcopy-gen=true
|
||||||
type Endpoint struct {
|
type Endpoint struct {
|
||||||
|
@ -241,7 +214,6 @@ type Server struct {
|
||||||
// CertificateAuth indicates the this server requires mutual authentication
|
// CertificateAuth indicates the this server requires mutual authentication
|
||||||
// +optional
|
// +optional
|
||||||
CertificateAuth authtls.AuthSSLConfig `json:"certificateAuth"`
|
CertificateAuth authtls.AuthSSLConfig `json:"certificateAuth"`
|
||||||
|
|
||||||
// ServerSnippet returns the snippet of server
|
// ServerSnippet returns the snippet of server
|
||||||
// +optional
|
// +optional
|
||||||
ServerSnippet string `json:"serverSnippet"`
|
ServerSnippet string `json:"serverSnippet"`
|
||||||
|
@ -282,57 +254,9 @@ type Location struct {
|
||||||
Service *apiv1.Service `json:"service,omitempty"`
|
Service *apiv1.Service `json:"service,omitempty"`
|
||||||
// Port describes to which port from the service
|
// Port describes to which port from the service
|
||||||
Port intstr.IntOrString `json:"port"`
|
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
|
// Denied returns an error when this location cannot not be allowed
|
||||||
// Requesting a denied location should return HTTP code 403.
|
// Requesting a denied location should return HTTP code 403.
|
||||||
Denied error `json:"denied,omitempty"`
|
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.
|
// DefaultBackend allows the use of a custom default backend for this location.
|
||||||
// +optional
|
// +optional
|
||||||
DefaultBackend *apiv1.Service `json:"defaultBackend,omitempty"`
|
DefaultBackend *apiv1.Service `json:"defaultBackend,omitempty"`
|
||||||
|
|
Loading…
Reference in a new issue