diff --git a/artifacts/examples/crd.yaml b/artifacts/examples/crd.yaml new file mode 100644 index 000000000..4a457068d --- /dev/null +++ b/artifacts/examples/crd.yaml @@ -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 diff --git a/artifacts/examples/example-foo.yaml b/artifacts/examples/example-foo.yaml new file mode 100644 index 000000000..897059c3d --- /dev/null +++ b/artifacts/examples/example-foo.yaml @@ -0,0 +1,7 @@ +apiVersion: samplecontroller.k8s.io/v1alpha1 +kind: Foo +metadata: + name: example-foo +spec: + deploymentName: example-foo + replicas: 1 diff --git a/hack/custom-boilerplate.go.txt b/hack/custom-boilerplate.go.txt new file mode 100644 index 000000000..e4cd20e38 --- /dev/null +++ b/hack/custom-boilerplate.go.txt @@ -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. +*/ + diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh new file mode 100755 index 000000000..e785b5c8c --- /dev/null +++ b/hack/update-codegen.sh @@ -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 diff --git a/hack/verify-codegen.sh b/hack/verify-codegen.sh new file mode 100755 index 000000000..f5835c425 --- /dev/null +++ b/hack/verify-codegen.sh @@ -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 diff --git a/pkg/ingress/annotations/serviceupstream/main.go b/pkg/apis/nginxingress/register.go similarity index 52% rename from pkg/ingress/annotations/serviceupstream/main.go rename to pkg/apis/nginxingress/register.go index 0a21fde5f..35f0d9738 100644 --- a/pkg/ingress/annotations/serviceupstream/main.go +++ b/pkg/apis/nginxingress/register.go @@ -14,25 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -package serviceupstream - -import ( - extensions "k8s.io/api/extensions/v1beta1" - "k8s.io/ingress-nginx/pkg/ingress/annotations/parser" -) +package nginxingress const ( - annotationServiceUpstream = "ingress.kubernetes.io/service-upstream" + GroupName = "nginx.ingress.k8s.io" ) - -type serviceUpstream struct { -} - -// NewParser creates a new serviceUpstream annotation parser -func NewParser() parser.IngressAnnotation { - return serviceUpstream{} -} - -func (s serviceUpstream) Parse(ing *extensions.Ingress) (interface{}, error) { - return parser.GetBoolAnnotation(annotationServiceUpstream, ing) -} diff --git a/pkg/apis/nginxingress/v1alpha1/doc.go b/pkg/apis/nginxingress/v1alpha1/doc.go new file mode 100644 index 000000000..53a27060d --- /dev/null +++ b/pkg/apis/nginxingress/v1alpha1/doc.go @@ -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 diff --git a/pkg/apis/nginxingress/v1alpha1/register.go b/pkg/apis/nginxingress/v1alpha1/register.go new file mode 100644 index 000000000..1844f93d4 --- /dev/null +++ b/pkg/apis/nginxingress/v1alpha1/register.go @@ -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 +} diff --git a/pkg/apis/nginxingress/v1alpha1/types.go b/pkg/apis/nginxingress/v1alpha1/types.go new file mode 100644 index 000000000..56b8f8cb5 --- /dev/null +++ b/pkg/apis/nginxingress/v1alpha1/types.go @@ -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"` +} diff --git a/pkg/apis/nginxingress/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/nginxingress/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 000000000..1a1844434 --- /dev/null +++ b/pkg/apis/nginxingress/v1alpha1/zz_generated.deepcopy.go @@ -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 +} diff --git a/pkg/client/clientset/versioned/clientset.go b/pkg/client/clientset/versioned/clientset.go new file mode 100644 index 000000000..456e77a19 --- /dev/null +++ b/pkg/client/clientset/versioned/clientset.go @@ -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 +} diff --git a/pkg/client/clientset/versioned/doc.go b/pkg/client/clientset/versioned/doc.go new file mode 100644 index 000000000..8fd89c6d5 --- /dev/null +++ b/pkg/client/clientset/versioned/doc.go @@ -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 diff --git a/pkg/client/clientset/versioned/fake/clientset_generated.go b/pkg/client/clientset/versioned/fake/clientset_generated.go new file mode 100644 index 000000000..4aaa1d76e --- /dev/null +++ b/pkg/client/clientset/versioned/fake/clientset_generated.go @@ -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} +} diff --git a/pkg/client/clientset/versioned/fake/doc.go b/pkg/client/clientset/versioned/fake/doc.go new file mode 100644 index 000000000..5f565b3c8 --- /dev/null +++ b/pkg/client/clientset/versioned/fake/doc.go @@ -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 diff --git a/pkg/client/clientset/versioned/fake/register.go b/pkg/client/clientset/versioned/fake/register.go new file mode 100644 index 000000000..bce1d7e7d --- /dev/null +++ b/pkg/client/clientset/versioned/fake/register.go @@ -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) + +} diff --git a/pkg/client/clientset/versioned/scheme/doc.go b/pkg/client/clientset/versioned/scheme/doc.go new file mode 100644 index 000000000..5d8ec824f --- /dev/null +++ b/pkg/client/clientset/versioned/scheme/doc.go @@ -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 diff --git a/pkg/client/clientset/versioned/scheme/register.go b/pkg/client/clientset/versioned/scheme/register.go new file mode 100644 index 000000000..8d6878bd1 --- /dev/null +++ b/pkg/client/clientset/versioned/scheme/register.go @@ -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) + +} diff --git a/pkg/client/clientset/versioned/typed/nginx/v1alpha1/configuration.go b/pkg/client/clientset/versioned/typed/nginx/v1alpha1/configuration.go new file mode 100644 index 000000000..3eeb6eb25 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/nginx/v1alpha1/configuration.go @@ -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 +} diff --git a/pkg/client/clientset/versioned/typed/nginx/v1alpha1/doc.go b/pkg/client/clientset/versioned/typed/nginx/v1alpha1/doc.go new file mode 100644 index 000000000..ba8d10d3b --- /dev/null +++ b/pkg/client/clientset/versioned/typed/nginx/v1alpha1/doc.go @@ -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 diff --git a/pkg/client/clientset/versioned/typed/nginx/v1alpha1/fake/doc.go b/pkg/client/clientset/versioned/typed/nginx/v1alpha1/fake/doc.go new file mode 100644 index 000000000..c6548330a --- /dev/null +++ b/pkg/client/clientset/versioned/typed/nginx/v1alpha1/fake/doc.go @@ -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 diff --git a/pkg/client/clientset/versioned/typed/nginx/v1alpha1/fake/fake_configuration.go b/pkg/client/clientset/versioned/typed/nginx/v1alpha1/fake/fake_configuration.go new file mode 100644 index 000000000..a9dee1a0b --- /dev/null +++ b/pkg/client/clientset/versioned/typed/nginx/v1alpha1/fake/fake_configuration.go @@ -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 +} diff --git a/pkg/ingress/annotations/alias/main.go b/pkg/client/clientset/versioned/typed/nginx/v1alpha1/fake/fake_nginx_client.go similarity index 51% rename from pkg/ingress/annotations/alias/main.go rename to pkg/client/clientset/versioned/typed/nginx/v1alpha1/fake/fake_nginx_client.go index cde40e2ba..10e669e88 100644 --- a/pkg/ingress/annotations/alias/main.go +++ b/pkg/client/clientset/versioned/typed/nginx/v1alpha1/fake/fake_nginx_client.go @@ -14,28 +14,25 @@ See the License for the specific language governing permissions and limitations under the License. */ -package alias +package fake import ( - extensions "k8s.io/api/extensions/v1beta1" - - "k8s.io/ingress-nginx/pkg/ingress/annotations/parser" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" + v1alpha1 "k8s.io/ingress-nginx/pkg/client/clientset/versioned/typed/nginx/v1alpha1" ) -const ( - annotation = "ingress.kubernetes.io/server-alias" -) - -type alias struct { +type FakeNginxV1alpha1 struct { + *testing.Fake } -// NewParser creates a new Alias annotation parser -func NewParser() parser.IngressAnnotation { - return alias{} +func (c *FakeNginxV1alpha1) Configurations(namespace string) v1alpha1.ConfigurationInterface { + return &FakeConfigurations{c, namespace} } -// Parse parses the annotations contained in the ingress rule -// used to add an alias to the provided hosts -func (a alias) Parse(ing *extensions.Ingress) (interface{}, error) { - return parser.GetStringAnnotation(annotation, ing) +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeNginxV1alpha1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret } diff --git a/pkg/client/clientset/versioned/typed/nginx/v1alpha1/generated_expansion.go b/pkg/client/clientset/versioned/typed/nginx/v1alpha1/generated_expansion.go new file mode 100644 index 000000000..6b6a05ca5 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/nginx/v1alpha1/generated_expansion.go @@ -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{} diff --git a/pkg/client/clientset/versioned/typed/nginx/v1alpha1/nginx_client.go b/pkg/client/clientset/versioned/typed/nginx/v1alpha1/nginx_client.go new file mode 100644 index 000000000..c2c481acb --- /dev/null +++ b/pkg/client/clientset/versioned/typed/nginx/v1alpha1/nginx_client.go @@ -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 +} diff --git a/pkg/client/informers/externalversions/factory.go b/pkg/client/informers/externalversions/factory.go new file mode 100644 index 000000000..c91bc03bf --- /dev/null +++ b/pkg/client/informers/externalversions/factory.go @@ -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) +} diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go new file mode 100644 index 000000000..d267a2431 --- /dev/null +++ b/pkg/client/informers/externalversions/generic.go @@ -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) +} diff --git a/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go b/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go new file mode 100644 index 000000000..2218aadd6 --- /dev/null +++ b/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go @@ -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 +} diff --git a/pkg/client/informers/externalversions/nginx/interface.go b/pkg/client/informers/externalversions/nginx/interface.go new file mode 100644 index 000000000..342fe50da --- /dev/null +++ b/pkg/client/informers/externalversions/nginx/interface.go @@ -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) +} diff --git a/pkg/client/informers/externalversions/nginx/v1alpha1/configuration.go b/pkg/client/informers/externalversions/nginx/v1alpha1/configuration.go new file mode 100644 index 000000000..3d9ecc109 --- /dev/null +++ b/pkg/client/informers/externalversions/nginx/v1alpha1/configuration.go @@ -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()) +} diff --git a/pkg/client/informers/externalversions/nginx/v1alpha1/interface.go b/pkg/client/informers/externalversions/nginx/v1alpha1/interface.go new file mode 100644 index 000000000..f8b9efdb3 --- /dev/null +++ b/pkg/client/informers/externalversions/nginx/v1alpha1/interface.go @@ -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} +} diff --git a/pkg/client/listers/nginx/v1alpha1/configuration.go b/pkg/client/listers/nginx/v1alpha1/configuration.go new file mode 100644 index 000000000..167be1362 --- /dev/null +++ b/pkg/client/listers/nginx/v1alpha1/configuration.go @@ -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 +} diff --git a/pkg/client/listers/nginx/v1alpha1/expansion_generated.go b/pkg/client/listers/nginx/v1alpha1/expansion_generated.go new file mode 100644 index 000000000..c5a0a04c8 --- /dev/null +++ b/pkg/client/listers/nginx/v1alpha1/expansion_generated.go @@ -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{} diff --git a/pkg/ingress/annotations/alias/main_test.go b/pkg/ingress/annotations/alias/main_test.go deleted file mode 100644 index de4fe17f5..000000000 --- a/pkg/ingress/annotations/alias/main_test.go +++ /dev/null @@ -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) - } - } -} diff --git a/pkg/ingress/annotations/auth/main.go b/pkg/ingress/annotations/auth/main.go deleted file mode 100644 index 5830f0f71..000000000 --- a/pkg/ingress/annotations/auth/main.go +++ /dev/null @@ -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 -} diff --git a/pkg/ingress/annotations/auth/main_test.go b/pkg/ingress/annotations/auth/main_test.go deleted file mode 100644 index df042ad4f..000000000 --- a/pkg/ingress/annotations/auth/main_test.go +++ /dev/null @@ -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) - } -} diff --git a/pkg/ingress/annotations/authreq/main.go b/pkg/ingress/annotations/authreq/main.go deleted file mode 100644 index 1ca77c7ac..000000000 --- a/pkg/ingress/annotations/authreq/main.go +++ /dev/null @@ -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 -} diff --git a/pkg/ingress/annotations/authreq/main_test.go b/pkg/ingress/annotations/authreq/main_test.go deleted file mode 100644 index de9249443..000000000 --- a/pkg/ingress/annotations/authreq/main_test.go +++ /dev/null @@ -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) - } - } -} diff --git a/pkg/ingress/annotations/authtls/main.go b/pkg/ingress/annotations/authtls/main.go deleted file mode 100644 index 7b2746435..000000000 --- a/pkg/ingress/annotations/authtls/main.go +++ /dev/null @@ -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 -} diff --git a/pkg/ingress/annotations/authtls/main_test.go b/pkg/ingress/annotations/authtls/main_test.go deleted file mode 100644 index a3613bb15..000000000 --- a/pkg/ingress/annotations/authtls/main_test.go +++ /dev/null @@ -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) - } - }*/ -} diff --git a/pkg/ingress/annotations/clientbodybuffersize/main.go b/pkg/ingress/annotations/clientbodybuffersize/main.go deleted file mode 100644 index 08547d1e8..000000000 --- a/pkg/ingress/annotations/clientbodybuffersize/main.go +++ /dev/null @@ -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) -} diff --git a/pkg/ingress/annotations/clientbodybuffersize/main_test.go b/pkg/ingress/annotations/clientbodybuffersize/main_test.go deleted file mode 100644 index 8ed6e0c38..000000000 --- a/pkg/ingress/annotations/clientbodybuffersize/main_test.go +++ /dev/null @@ -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) - } - } -} diff --git a/pkg/ingress/annotations/cors/main.go b/pkg/ingress/annotations/cors/main.go deleted file mode 100644 index 8ea55bb1f..000000000 --- a/pkg/ingress/annotations/cors/main.go +++ /dev/null @@ -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) -} diff --git a/pkg/ingress/annotations/cors/main_test.go b/pkg/ingress/annotations/cors/main_test.go deleted file mode 100644 index 330b059f4..000000000 --- a/pkg/ingress/annotations/cors/main_test.go +++ /dev/null @@ -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) - } - } -} diff --git a/pkg/ingress/annotations/defaultbackend/main.go b/pkg/ingress/annotations/defaultbackend/main.go deleted file mode 100644 index 8fc6f0d4e..000000000 --- a/pkg/ingress/annotations/defaultbackend/main.go +++ /dev/null @@ -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 -} diff --git a/pkg/ingress/annotations/healthcheck/main.go b/pkg/ingress/annotations/healthcheck/main.go deleted file mode 100644 index 5d3850d90..000000000 --- a/pkg/ingress/annotations/healthcheck/main.go +++ /dev/null @@ -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 -} diff --git a/pkg/ingress/annotations/healthcheck/main_test.go b/pkg/ingress/annotations/healthcheck/main_test.go deleted file mode 100644 index afcc9540d..000000000 --- a/pkg/ingress/annotations/healthcheck/main_test.go +++ /dev/null @@ -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) - } -} diff --git a/pkg/ingress/annotations/ipwhitelist/main.go b/pkg/ingress/annotations/ipwhitelist/main.go deleted file mode 100644 index df2fe522c..000000000 --- a/pkg/ingress/annotations/ipwhitelist/main.go +++ /dev/null @@ -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 -} diff --git a/pkg/ingress/annotations/ipwhitelist/main_test.go b/pkg/ingress/annotations/ipwhitelist/main_test.go deleted file mode 100644 index 66899a517..000000000 --- a/pkg/ingress/annotations/ipwhitelist/main_test.go +++ /dev/null @@ -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 -} diff --git a/pkg/ingress/annotations/portinredirect/main.go b/pkg/ingress/annotations/portinredirect/main.go deleted file mode 100644 index 90386cc8f..000000000 --- a/pkg/ingress/annotations/portinredirect/main.go +++ /dev/null @@ -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 -} diff --git a/pkg/ingress/annotations/portinredirect/main_test.go b/pkg/ingress/annotations/portinredirect/main_test.go deleted file mode 100644 index 44b0444e9..000000000 --- a/pkg/ingress/annotations/portinredirect/main_test.go +++ /dev/null @@ -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 -} diff --git a/pkg/ingress/annotations/proxy/main.go b/pkg/ingress/annotations/proxy/main.go deleted file mode 100644 index b35696b97..000000000 --- a/pkg/ingress/annotations/proxy/main.go +++ /dev/null @@ -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 -} diff --git a/pkg/ingress/annotations/proxy/main_test.go b/pkg/ingress/annotations/proxy/main_test.go deleted file mode 100644 index 04ffbda53..000000000 --- a/pkg/ingress/annotations/proxy/main_test.go +++ /dev/null @@ -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) - } -} diff --git a/pkg/ingress/annotations/ratelimit/main.go b/pkg/ingress/annotations/ratelimit/main.go deleted file mode 100644 index 651b71859..000000000 --- a/pkg/ingress/annotations/ratelimit/main.go +++ /dev/null @@ -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) -} diff --git a/pkg/ingress/annotations/ratelimit/main_test.go b/pkg/ingress/annotations/ratelimit/main_test.go deleted file mode 100644 index 9b079f293..000000000 --- a/pkg/ingress/annotations/ratelimit/main_test.go +++ /dev/null @@ -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) - } -} diff --git a/pkg/ingress/annotations/redirect/redirect.go b/pkg/ingress/annotations/redirect/redirect.go deleted file mode 100644 index 5fd64a2ee..000000000 --- a/pkg/ingress/annotations/redirect/redirect.go +++ /dev/null @@ -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 -} diff --git a/pkg/ingress/annotations/rewrite/main.go b/pkg/ingress/annotations/rewrite/main.go deleted file mode 100644 index ce97f657d..000000000 --- a/pkg/ingress/annotations/rewrite/main.go +++ /dev/null @@ -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 -} diff --git a/pkg/ingress/annotations/rewrite/main_test.go b/pkg/ingress/annotations/rewrite/main_test.go deleted file mode 100644 index 5da0cfeee..000000000 --- a/pkg/ingress/annotations/rewrite/main_test.go +++ /dev/null @@ -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") - } - -} diff --git a/pkg/ingress/annotations/secureupstream/main.go b/pkg/ingress/annotations/secureupstream/main.go deleted file mode 100644 index 119041cac..000000000 --- a/pkg/ingress/annotations/secureupstream/main.go +++ /dev/null @@ -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 -} diff --git a/pkg/ingress/annotations/secureupstream/main_test.go b/pkg/ingress/annotations/secureupstream/main_test.go deleted file mode 100644 index 27e4f22d7..000000000 --- a/pkg/ingress/annotations/secureupstream/main_test.go +++ /dev/null @@ -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") - } -} diff --git a/pkg/ingress/annotations/serversnippet/main.go b/pkg/ingress/annotations/serversnippet/main.go deleted file mode 100644 index a67cae177..000000000 --- a/pkg/ingress/annotations/serversnippet/main.go +++ /dev/null @@ -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) -} diff --git a/pkg/ingress/annotations/serversnippet/main_test.go b/pkg/ingress/annotations/serversnippet/main_test.go deleted file mode 100644 index 1a4d51bed..000000000 --- a/pkg/ingress/annotations/serversnippet/main_test.go +++ /dev/null @@ -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) - } - } -} diff --git a/pkg/ingress/annotations/serviceupstream/main_test.go b/pkg/ingress/annotations/serviceupstream/main_test.go deleted file mode 100644 index 9dcfdece6..000000000 --- a/pkg/ingress/annotations/serviceupstream/main_test.go +++ /dev/null @@ -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") - } -} diff --git a/pkg/ingress/annotations/sessionaffinity/main.go b/pkg/ingress/annotations/sessionaffinity/main.go deleted file mode 100644 index c0b274b09..000000000 --- a/pkg/ingress/annotations/sessionaffinity/main.go +++ /dev/null @@ -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 - -} diff --git a/pkg/ingress/annotations/sessionaffinity/main_test.go b/pkg/ingress/annotations/sessionaffinity/main_test.go deleted file mode 100644 index 5008c6b1e..000000000 --- a/pkg/ingress/annotations/sessionaffinity/main_test.go +++ /dev/null @@ -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) - } -} diff --git a/pkg/ingress/annotations/snippet/main.go b/pkg/ingress/annotations/snippet/main.go deleted file mode 100644 index 3e37fb5a6..000000000 --- a/pkg/ingress/annotations/snippet/main.go +++ /dev/null @@ -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) -} diff --git a/pkg/ingress/annotations/snippet/main_test.go b/pkg/ingress/annotations/snippet/main_test.go deleted file mode 100644 index b92abfc45..000000000 --- a/pkg/ingress/annotations/snippet/main_test.go +++ /dev/null @@ -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) - } - } -} diff --git a/pkg/ingress/annotations/sslpassthrough/main.go b/pkg/ingress/annotations/sslpassthrough/main.go deleted file mode 100644 index a4fcca83e..000000000 --- a/pkg/ingress/annotations/sslpassthrough/main.go +++ /dev/null @@ -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) -} diff --git a/pkg/ingress/annotations/sslpassthrough/main_test.go b/pkg/ingress/annotations/sslpassthrough/main_test.go deleted file mode 100644 index bf3e083d8..000000000 --- a/pkg/ingress/annotations/sslpassthrough/main_test.go +++ /dev/null @@ -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") - } -} diff --git a/pkg/ingress/annotations/upstreamhashby/main.go b/pkg/ingress/annotations/upstreamhashby/main.go deleted file mode 100644 index b4d898000..000000000 --- a/pkg/ingress/annotations/upstreamhashby/main.go +++ /dev/null @@ -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) -} diff --git a/pkg/ingress/annotations/upstreamhashby/main_test.go b/pkg/ingress/annotations/upstreamhashby/main_test.go deleted file mode 100644 index ad5afafc8..000000000 --- a/pkg/ingress/annotations/upstreamhashby/main_test.go +++ /dev/null @@ -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) - } - } -} diff --git a/pkg/ingress/annotations/upstreamvhost/main.go b/pkg/ingress/annotations/upstreamvhost/main.go deleted file mode 100644 index c7af79246..000000000 --- a/pkg/ingress/annotations/upstreamvhost/main.go +++ /dev/null @@ -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) -} diff --git a/pkg/ingress/annotations/vtsfilterkey/main.go b/pkg/ingress/annotations/vtsfilterkey/main.go deleted file mode 100644 index 04965bbf2..000000000 --- a/pkg/ingress/annotations/vtsfilterkey/main.go +++ /dev/null @@ -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) -} diff --git a/pkg/ingress/controller/annotations.go b/pkg/ingress/controller/annotations.go deleted file mode 100644 index 463d1e8ff..000000000 --- a/pkg/ingress/controller/annotations.go +++ /dev/null @@ -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) -} diff --git a/pkg/ingress/controller/annotations_test.go b/pkg/ingress/controller/annotations_test.go deleted file mode 100644 index 04581d99b..000000000 --- a/pkg/ingress/controller/annotations_test.go +++ /dev/null @@ -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) - } - } -} diff --git a/pkg/ingress/controller/controller.go b/pkg/ingress/controller/controller.go index c16f46a01..fa23b2c8c 100644 --- a/pkg/ingress/controller/controller.go +++ b/pkg/ingress/controller/controller.go @@ -28,6 +28,7 @@ import ( "sync/atomic" "time" + "github.com/aledbf/ingress-controller/pkg/ingress/annotations/proxy" "github.com/golang/glog" apiv1 "k8s.io/api/core/v1" @@ -41,13 +42,12 @@ import ( v1core "k8s.io/client-go/kubernetes/typed/core/v1" "k8s.io/client-go/tools/record" "k8s.io/client-go/util/flowcontrol" + "k8s.io/contrib/ingress/controllers/nginx/nginx/healthcheck" "k8s.io/kubernetes/pkg/kubelet/util/sliceutils" "k8s.io/ingress-nginx/pkg/ingress" "k8s.io/ingress-nginx/pkg/ingress/annotations/class" - "k8s.io/ingress-nginx/pkg/ingress/annotations/healthcheck" "k8s.io/ingress-nginx/pkg/ingress/annotations/parser" - "k8s.io/ingress-nginx/pkg/ingress/annotations/proxy" "k8s.io/ingress-nginx/pkg/ingress/defaults" "k8s.io/ingress-nginx/pkg/ingress/resolver" "k8s.io/ingress-nginx/pkg/ingress/status" diff --git a/pkg/ingress/defaults/main.go b/pkg/ingress/defaults/main.go index 40598028c..097bc0b99 100644 --- a/pkg/ingress/defaults/main.go +++ b/pkg/ingress/defaults/main.go @@ -2,13 +2,8 @@ package defaults import "net" -// Backend defines the mandatory configuration that an Ingress controller must provide -// The reason of this requirements is the annotations are generic. If some implementation do not supports -// one or more annotations it just can provides defaults +// Backend defines the mandatory configuration for NGINX. type Backend struct { - // AppRoot contains the AppRoot for apps that doesn't exposes its content in the 'root' context - AppRoot string `json:"app-root"` - // enables which HTTP codes should be passed for processing with the error_page directive // http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_intercept_errors // http://nginx.org/en/docs/http/ngx_http_core_module.html#error_page @@ -101,15 +96,4 @@ type Backend struct { // WhitelistSourceRange allows limiting access to certain client addresses // http://nginx.org/en/docs/http/ngx_http_access_module.html WhitelistSourceRange []string `json:"whitelist-source-range,-"` - - // Limits the rate of response transmission to a client. - // The rate is specified in bytes per second. The zero value disables rate limiting. - // The limit is set per a request, and so if a client simultaneously opens two connections, - // the overall rate will be twice as much as the specified limit. - // http://nginx.org/en/docs/http/ngx_http_core_module.html#limit_rate - LimitRate int `json:"limit-rate"` - - // Sets the initial amount after which the further transmission of a response to a client will be rate limited. - // http://nginx.org/en/docs/http/ngx_http_core_module.html#limit_rate_after - LimitRateAfter int `json:"limit-rate-after"` } diff --git a/pkg/ingress/types.go b/pkg/ingress/types.go index fac9764a1..618074e26 100644 --- a/pkg/ingress/types.go +++ b/pkg/ingress/types.go @@ -26,14 +26,7 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apiserver/pkg/server/healthz" - "k8s.io/ingress-nginx/pkg/ingress/annotations/auth" - "k8s.io/ingress-nginx/pkg/ingress/annotations/authreq" "k8s.io/ingress-nginx/pkg/ingress/annotations/authtls" - "k8s.io/ingress-nginx/pkg/ingress/annotations/ipwhitelist" - "k8s.io/ingress-nginx/pkg/ingress/annotations/proxy" - "k8s.io/ingress-nginx/pkg/ingress/annotations/ratelimit" - "k8s.io/ingress-nginx/pkg/ingress/annotations/redirect" - "k8s.io/ingress-nginx/pkg/ingress/annotations/rewrite" "k8s.io/ingress-nginx/pkg/ingress/defaults" "k8s.io/ingress-nginx/pkg/ingress/resolver" "k8s.io/ingress-nginx/pkg/ingress/store" @@ -174,26 +167,6 @@ type Backend struct { UpstreamHashBy string `json:"upstream-hash-by,omitempty"` } -// SessionAffinityConfig describes different affinity configurations for new sessions. -// Once a session is mapped to a backend based on some affinity setting, it -// retains that mapping till the backend goes down, or the ingress controller -// restarts. Exactly one of these values will be set on the upstream, since multiple -// affinity values are incompatible. Once set, the backend makes no guarantees -// about honoring updates. -// +k8s:deepcopy-gen=true -type SessionAffinityConfig struct { - AffinityType string `json:"name"` - CookieSessionAffinity CookieSessionAffinity `json:"cookieSessionAffinity"` -} - -// CookieSessionAffinity defines the structure used in Affinity configured by Cookies. -// +k8s:deepcopy-gen=true -type CookieSessionAffinity struct { - Name string `json:"name"` - Hash string `json:"hash"` - Locations map[string][]string `json:"locations,omitempty"` -} - // Endpoint describes a kubernetes endpoint in a backend // +k8s:deepcopy-gen=true type Endpoint struct { @@ -241,7 +214,6 @@ type Server struct { // CertificateAuth indicates the this server requires mutual authentication // +optional CertificateAuth authtls.AuthSSLConfig `json:"certificateAuth"` - // ServerSnippet returns the snippet of server // +optional ServerSnippet string `json:"serverSnippet"` @@ -282,57 +254,9 @@ type Location struct { Service *apiv1.Service `json:"service,omitempty"` // Port describes to which port from the service Port intstr.IntOrString `json:"port"` - // Overwrite the Host header passed into the backend. Defaults to - // vhost of the incoming request. - // +optional - UpstreamVhost string `json:"upstream-vhost"` - // BasicDigestAuth returns authentication configuration for - // an Ingress rule. - // +optional - BasicDigestAuth auth.BasicDigest `json:"basicDigestAuth,omitempty"` // Denied returns an error when this location cannot not be allowed // Requesting a denied location should return HTTP code 403. Denied error `json:"denied,omitempty"` - // EnableCORS indicates if path must support CORS - // +optional - EnableCORS bool `json:"enableCors,omitempty"` - // ExternalAuth indicates the access to this location requires - // authentication using an external provider - // +optional - ExternalAuth authreq.External `json:"externalAuth,omitempty"` - // RateLimit describes a limit in the number of connections per IP - // address or connections per second. - // The Redirect annotation precedes RateLimit - // +optional - RateLimit ratelimit.RateLimit `json:"rateLimit,omitempty"` - // Redirect describes a temporal o permanent redirection this location. - // +optional - Redirect redirect.Redirect `json:"redirect,omitempty"` - // Rewrite describes the redirection this location. - // +optional - Rewrite rewrite.Redirect `json:"rewrite,omitempty"` - // Whitelist indicates only connections from certain client - // addresses or networks are allowed. - // +optional - Whitelist ipwhitelist.SourceRange `json:"whitelist,omitempty"` - // Proxy contains information about timeouts and buffer sizes - // to be used in connections against endpoints - // +optional - Proxy proxy.Configuration `json:"proxy,omitempty"` - // UsePortInRedirects indicates if redirects must specify the port - // +optional - UsePortInRedirects bool `json:"usePortInRedirects"` - // VtsFilterKey contains the vts filter key on the location level - // https://github.com/vozlt/nginx-module-vts#vhost_traffic_status_filter_by_set_key - // +optional - VtsFilterKey string `json:"vtsFilterKey,omitempty"` - // ConfigurationSnippet contains additional configuration for the backend - // to be considered in the configuration of the location - ConfigurationSnippet string `json:"configurationSnippet"` - // ClientBodyBufferSize allows for the configuration of the client body - // buffer size for a specific location. - // +optional - ClientBodyBufferSize string `json:"clientBodyBufferSize,omitempty"` // DefaultBackend allows the use of a custom default backend for this location. // +optional DefaultBackend *apiv1.Service `json:"defaultBackend,omitempty"`