Cleanup
This commit is contained in:
parent
e68cf185cc
commit
3fe8524318
8 changed files with 100 additions and 783 deletions
|
@ -189,7 +189,7 @@ func setupSSLProxy(sslPort, proxyPort int, n *controller.NGINXController) {
|
||||||
var conn net.Conn
|
var conn net.Conn
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if n.IsProxyProtocolEnabled {
|
if n.IsProxyProtocolEnabled() {
|
||||||
// we need to wrap the listener in order to decode
|
// we need to wrap the listener in order to decode
|
||||||
// proxy protocol before handling the connection
|
// proxy protocol before handling the connection
|
||||||
conn, err = proxyList.Accept()
|
conn, err = proxyList.Accept()
|
||||||
|
|
|
@ -1,197 +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 controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/golang/glog"
|
|
||||||
"github.com/imdario/mergo"
|
|
||||||
|
|
||||||
apiv1 "k8s.io/api/core/v1"
|
|
||||||
extensions "k8s.io/api/extensions/v1beta1"
|
|
||||||
|
|
||||||
"k8s.io/ingress-nginx/internal/ingress"
|
|
||||||
"k8s.io/ingress-nginx/internal/ingress/annotations/class"
|
|
||||||
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
|
||||||
"k8s.io/ingress-nginx/internal/net/ssl"
|
|
||||||
)
|
|
||||||
|
|
||||||
// syncSecret keeps in sync Secrets used by Ingress rules with the files on
|
|
||||||
// disk to allow copy of the content of the secret to disk to be used
|
|
||||||
// by external processes.
|
|
||||||
func (ic *NGINXController) syncSecret(key string) {
|
|
||||||
glog.V(3).Infof("starting syncing of secret %v", key)
|
|
||||||
|
|
||||||
cert, err := ic.getPemCertificate(key)
|
|
||||||
if err != nil {
|
|
||||||
glog.Warningf("error obtaining PEM from secret %v: %v", key, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// create certificates and add or update the item in the store
|
|
||||||
cur, exists := ic.sslCertTracker.Get(key)
|
|
||||||
if exists {
|
|
||||||
s := cur.(*ingress.SSLCert)
|
|
||||||
if s.Equal(cert) {
|
|
||||||
// no need to update
|
|
||||||
return
|
|
||||||
}
|
|
||||||
glog.Infof("updating secret %v in the local store", key)
|
|
||||||
ic.sslCertTracker.Update(key, cert)
|
|
||||||
// this update must trigger an update
|
|
||||||
// (like an update event from a change in Ingress)
|
|
||||||
ic.syncQueue.Enqueue(&extensions.Ingress{})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
glog.Infof("adding secret %v to the local store", key)
|
|
||||||
ic.sslCertTracker.Add(key, cert)
|
|
||||||
// this update must trigger an update
|
|
||||||
// (like an update event from a change in Ingress)
|
|
||||||
ic.syncQueue.Enqueue(&extensions.Ingress{})
|
|
||||||
}
|
|
||||||
|
|
||||||
// getPemCertificate receives a secret, and creates a ingress.SSLCert as return.
|
|
||||||
// It parses the secret and verifies if it's a keypair, or a 'ca.crt' secret only.
|
|
||||||
func (ic *NGINXController) getPemCertificate(secretName string) (*ingress.SSLCert, error) {
|
|
||||||
secret, err := ic.store.GetSecret(secretName)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error retrieving secret %v: %v", secretName, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
cert, okcert := secret.Data[apiv1.TLSCertKey]
|
|
||||||
key, okkey := secret.Data[apiv1.TLSPrivateKeyKey]
|
|
||||||
ca := secret.Data["ca.crt"]
|
|
||||||
|
|
||||||
// namespace/secretName -> namespace-secretName
|
|
||||||
nsSecName := strings.Replace(secretName, "/", "-", -1)
|
|
||||||
|
|
||||||
var s *ingress.SSLCert
|
|
||||||
if okcert && okkey {
|
|
||||||
if cert == nil {
|
|
||||||
return nil, fmt.Errorf("secret %v has no 'tls.crt'", secretName)
|
|
||||||
}
|
|
||||||
if key == nil {
|
|
||||||
return nil, fmt.Errorf("secret %v has no 'tls.key'", secretName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If 'ca.crt' is also present, it will allow this secret to be used in the
|
|
||||||
// 'nginx.ingress.kubernetes.io/auth-tls-secret' annotation
|
|
||||||
s, err = ssl.AddOrUpdateCertAndKey(nsSecName, cert, key, ca, ic.fileSystem)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("unexpected error creating pem file: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
glog.V(3).Infof("found 'tls.crt' and 'tls.key', configuring %v as a TLS Secret (CN: %v)", secretName, s.CN)
|
|
||||||
if ca != nil {
|
|
||||||
glog.V(3).Infof("found 'ca.crt', secret %v can also be used for Certificate Authentication", secretName)
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if ca != nil {
|
|
||||||
s, err = ssl.AddCertAuth(nsSecName, ca, ic.fileSystem)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("unexpected error creating pem file: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// makes this secret in 'syncSecret' to be used for Certificate Authentication
|
|
||||||
// this does not enable Certificate Authentication
|
|
||||||
glog.V(3).Infof("found only 'ca.crt', configuring %v as an Certificate Authentication Secret", secretName)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return nil, fmt.Errorf("no keypair or CA cert could be found in %v", secretName)
|
|
||||||
}
|
|
||||||
|
|
||||||
s.Name = secret.Name
|
|
||||||
s.Namespace = secret.Namespace
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ic *NGINXController) checkSSLChainIssues() {
|
|
||||||
for _, secretName := range ic.sslCertTracker.ListKeys() {
|
|
||||||
s, _ := ic.sslCertTracker.Get(secretName)
|
|
||||||
secret := s.(*ingress.SSLCert)
|
|
||||||
|
|
||||||
if secret.FullChainPemFileName != "" {
|
|
||||||
// chain already checked
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := ssl.FullChainCert(secret.PemFileName, ic.fileSystem)
|
|
||||||
if err != nil {
|
|
||||||
glog.Errorf("unexpected error generating SSL certificate with full intermediate chain CA certs: %v", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
fullChainPemFileName := fmt.Sprintf("%v/%v-%v-full-chain.pem", ingress.DefaultSSLDirectory, secret.Namespace, secret.Name)
|
|
||||||
err = ioutil.WriteFile(fullChainPemFileName, data, 0655)
|
|
||||||
if err != nil {
|
|
||||||
glog.Errorf("unexpected error creating SSL certificate: %v", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
dst := &ingress.SSLCert{}
|
|
||||||
|
|
||||||
err = mergo.MergeWithOverwrite(dst, secret)
|
|
||||||
if err != nil {
|
|
||||||
glog.Errorf("unexpected error creating SSL certificate: %v", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
dst.FullChainPemFileName = fullChainPemFileName
|
|
||||||
|
|
||||||
glog.Infof("updating local copy of ssl certificate %v with missing intermediate CA certs", secretName)
|
|
||||||
ic.sslCertTracker.Update(secretName, dst)
|
|
||||||
// this update must trigger an update
|
|
||||||
// (like an update event from a change in Ingress)
|
|
||||||
ic.syncQueue.Enqueue(&extensions.Ingress{})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// checkMissingSecrets verify if one or more ingress rules contains a reference
|
|
||||||
// to a secret that is not present in the local secret store.
|
|
||||||
// In this case we call syncSecret.
|
|
||||||
func (ic *NGINXController) checkMissingSecrets() {
|
|
||||||
for _, ing := range ic.store.ListIngresses() {
|
|
||||||
if !class.IsValid(ing) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tls := range ing.Spec.TLS {
|
|
||||||
if tls.SecretName == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
key := fmt.Sprintf("%v/%v", ing.Namespace, tls.SecretName)
|
|
||||||
if _, ok := ic.sslCertTracker.Get(key); !ok {
|
|
||||||
ic.syncSecret(key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
key, _ := parser.GetStringAnnotation("auth-tls-secret", ing)
|
|
||||||
if key == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := ic.sslCertTracker.Get(key); !ok {
|
|
||||||
ic.syncSecret(key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,234 +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 (
|
|
||||||
"encoding/base64"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
|
|
||||||
apiv1 "k8s.io/api/core/v1"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
testclient "k8s.io/client-go/kubernetes/fake"
|
|
||||||
cache_client "k8s.io/client-go/tools/cache"
|
|
||||||
|
|
||||||
"k8s.io/ingress-nginx/internal/ingress"
|
|
||||||
"k8s.io/ingress-nginx/internal/ingress/store"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=nginxsvc/O=nginxsvc"
|
|
||||||
tlsCrt = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURIekNDQWdlZ0F3SUJBZ0lKQU1KZld6Mm81cWVnTUEwR0NTcUdTSWIzRFFFQkN3VUFNQ1l4RVRBUEJnTlYKQkFNTUNHNW5hVzU0YzNaak1SRXdEd1lEVlFRS0RBaHVaMmx1ZUhOMll6QWVGdzB4TnpBME1URXdNakF3TlRCYQpGdzB5TnpBME1Ea3dNakF3TlRCYU1DWXhFVEFQQmdOVkJBTU1DRzVuYVc1NGMzWmpNUkV3RHdZRFZRUUtEQWh1CloybHVlSE4yWXpDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTUgzVTYvY3ArODAKU3hJRjltSnlUcGI5RzBodnhsM0JMaGdQWDBTWjZ3d1lISGJXeTh2dmlCZjVwWTdvVHd0b2FPaTN1VFNsL2RtVwpvUi9XNm9GVWM5a2l6NlNXc3p6YWRXL2l2Q21LMmxOZUFVc2gvaXY0aTAvNXlreDJRNXZUT2tVL1dra2JPOW1OCjdSVTF0QW1KT3M0T1BVc3hZZkw2cnJJUzZPYktHS2UvYUVkek9QS2NPMDJ5NUxDeHM0TFhhWDIzU1l6TG1XYVAKYVZBallrN1NRZm1xUm5mYlF4RWlpaDFQWTFRRXgxWWs0RzA0VmtHUitrSVVMaWF0L291ZjQxY0dXRTZHMTF4NQpkV1BHeS9XcGtqRGlaM0UwekdNZnJBVUZibnErN1dhRTJCRzVoUVV3ZG9SQUtWTnMzaVhLRlRkT3hoRll5bnBwCjA3cDJVNS96ZHRrQ0F3RUFBYU5RTUU0d0hRWURWUjBPQkJZRUZCL2U5UnVna0Mwc0VNTTZ6enRCSjI1U1JxalMKTUI4R0ExVWRJd1FZTUJhQUZCL2U5UnVna0Mwc0VNTTZ6enRCSjI1U1JxalNNQXdHQTFVZEV3UUZNQU1CQWY4dwpEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBRys4MXdaSXRuMmFWSlFnejNkNmJvZW1nUXhSSHpaZDhNc1IrdFRvCnpJLy9ac1Nwc2FDR3F0TkdTaHVGKzB3TVZ4NjlpQ3lJTnJJb2J4K29NTHBsQzFQSk9uektSUUdvZEhYNFZaSUwKVlhxSFd2VStjK3ZtT0QxUEt3UjcwRi9rTXk2Yk4xMVI2amhIZ3RPZGdLKzdRczhRMVlUSC9RS2dMd3RJTFRHRwpTZlYxWFlmbnF1TXlZKzFzck00U3ZRSmRzdmFUQmJkZHE2RllpdjhXZFpIaG51ZGlSODdZcFgzOUlTSlFkOXF2CnR6OGthZTVqQVFEUWFiZnFsVWZNT1hmUnhyei96S2NvN3dMeWFMWTh1eVhEWUVIZmlHRWdablV0RjgxVlhDZUIKeU80UERBR0FuVmlXTndFM0NZcGI4RkNGelMyaVVVMDJaQWJRajlvUnYyUWNON1E9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"
|
|
||||||
tlsKey = "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2Z0lCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktnd2dnU2tBZ0VBQW9JQkFRREI5MU92M0tmdk5Fc1MKQmZaaWNrNlcvUnRJYjhaZHdTNFlEMTlFbWVzTUdCeDIxc3ZMNzRnWCthV082RThMYUdqb3Q3azBwZjNabHFFZgoxdXFCVkhQWklzK2tsck04Mm5WdjRyd3BpdHBUWGdGTElmNHIrSXRQK2NwTWRrT2IwenBGUDFwSkd6dlpqZTBWCk5iUUppVHJPRGoxTE1XSHkrcTZ5RXVqbXloaW52MmhIY3pqeW5EdE5zdVN3c2JPQzEybDl0MG1NeTVsbWoybFEKSTJKTzBrSDVxa1ozMjBNUklvb2RUMk5VQk1kV0pPQnRPRlpCa2ZwQ0ZDNG1yZjZMbitOWEJsaE9odGRjZVhWagp4c3YxcVpJdzRtZHhOTXhqSDZ3RkJXNTZ2dTFtaE5nUnVZVUZNSGFFUUNsVGJONGx5aFUzVHNZUldNcDZhZE82CmRsT2Y4M2JaQWdNQkFBRUNnZ0VBRGU1WW1XSHN3ZFpzcWQrNXdYcGFRS2Z2SkxXNmRwTmdYeVFEZ0tiWlplWDUKYldPaUFZU3pycDBra2U0SGQxZEphYVdBYk5LYk45eUV1QWUwa2hOaHVxK3dZQzdlc3JreUJCWXgwMzRBamtwTApKMzFLaHhmejBZdXNSdStialg2UFNkZnlBUnd1b1VKN1M3R3V1NXlhbDZBWU1PVmNGcHFBbjVPU0hMbFpLZnNLClN3NXZyM3NKUjNyOENNWVZoUmQ0citGam9lMXlaczJhUHl2bno5c0U3T0ZCSVRGSVBKcE4veG53VUNpWW5vSEMKV2F2TzB5RCtPeTUyN2hBQ1FwaFVMVjRaZXV2bEZwd2ZlWkZveUhnc2YrM1FxeGhpdGtJb3NGakx2Y0xlL2xjZwpSVHNRUnU5OGJNUTdSakJpYU5kaURadjBaWEMvUUMvS054SEw0bXgxTFFLQmdRRHVDY0pUM2JBZmJRY2YvSGh3CjNxRzliNE9QTXpwOTl2ajUzWU1hZHo5Vlk1dm9RR3RGeFlwbTBRVm9MR1lkQ3BHK0lXaDdVVHBMV0JUeGtMSkYKd3EwcEFmRVhmdHB0anhmcyt0OExWVUFtSXJiM2hwUjZDUjJmYjFJWVZRWUJ4dUdzN0hWMmY3NnRZMVAzSEFnNwpGTDJNTnF3ZDd5VmlsVXdSTVptcmJKV3Qwd0tCZ1FEUW1qZlgzc1NWSWZtN1FQaVQvclhSOGJMM1B3V0lNa3NOCldJTVRYeDJmaG0vd0hOL0pNdCtEK2VWbGxjSXhLMmxSYlNTQ1NwU2hzRUVsMHNxWHZUa1FFQnJxN3RFZndRWU0KbGxNbDJQb0ovV2E5c2VYSTAzWWRNeC94Vm5sbzNaUG9MUGg4UmtKekJTWkhnMlB6cCs0VmlnUklBcGdYMXo3TwpMbHg0SEVtaEl3S0JnUURES1RVdVZYL2xCQnJuV3JQVXRuT2RRU1IzNytSeENtQXZYREgxTFBlOEpxTFkxSmdlCjZFc0U2VEtwcWwwK1NrQWJ4b0JIT3QyMGtFNzdqMHJhYnpaUmZNb1NIV3N3a0RWcGtuWDBjTHpiaDNMRGxvOTkKVHFQKzUrSkRHTktIK210a3Y2bStzaFcvU3NTNHdUN3VVWjdtcXB5TEhsdGtiRXVsZlNra3B5NUJDUUtCZ0RmUwpyVk1GZUZINGI1NGV1dWJQNk5Rdi9CYVNOT2JIbnJJSmw3b2RZQTRLcWZYMXBDVnhpY01Gb3MvV2pjc2V0T1puCmNMZTFRYVVyUjZQWmp3R2dUNTd1MEdWQ1Y1QkoxVmFVKzlkTEEwNmRFMXQ4T2VQT1F2TjVkUGplalVyMDBObjIKL3VBeTVTRm1wV0hKMVh1azJ0L0V1WFNUelNQRUpEaUV5NVlRNjl0RkFvR0JBT2tDcW1jVGZGYlpPTjJRK2JqdgpvVmQvSFpLR3YrbEhqcm5maVlhODVxcUszdWJmb0FSNGppR3V3TThqc3hZZW8vb0hQdHJDTkxINndsYlZNTUFGCmlRZG80ZUF3S0xxRHo1MUx4U2hMckwzUUtNQ1FuZVhkT0VjaEdqSW9zRG5Zekd5RTBpSzJGbWNvWHVSQU1QOHgKWDFreUlkazdENDFxSjQ5WlM1OEdBbXlLCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K"
|
|
||||||
tlscaName = "ca.crt"
|
|
||||||
)
|
|
||||||
|
|
||||||
type MockQueue struct {
|
|
||||||
cache_client.Store
|
|
||||||
Synced bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *MockQueue) HasSynced() bool {
|
|
||||||
return f.Synced
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *MockQueue) AddIfNotPresent(obj interface{}) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *MockQueue) Pop(process cache_client.PopProcessFunc) (interface{}, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *MockQueue) Close() {
|
|
||||||
// just mock
|
|
||||||
}
|
|
||||||
|
|
||||||
func buildSimpleClientSetForBackendSSL() *testclient.Clientset {
|
|
||||||
return testclient.NewSimpleClientset()
|
|
||||||
}
|
|
||||||
|
|
||||||
func buildIngListenerForBackendSSL() store.IngressLister {
|
|
||||||
ingLister := store.IngressLister{}
|
|
||||||
ingLister.Store = cache_client.NewStore(cache_client.DeletionHandlingMetaNamespaceKeyFunc)
|
|
||||||
return ingLister
|
|
||||||
}
|
|
||||||
|
|
||||||
func buildSecretForBackendSSL() *apiv1.Secret {
|
|
||||||
return &apiv1.Secret{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: "foo_secret",
|
|
||||||
Namespace: metav1.NamespaceDefault,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func buildSecrListerForBackendSSL() store.SecretLister {
|
|
||||||
secrLister := store.SecretLister{}
|
|
||||||
secrLister.Store = cache_client.NewStore(cache_client.DeletionHandlingMetaNamespaceKeyFunc)
|
|
||||||
|
|
||||||
return secrLister
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
func buildListers() *ingress.StoreLister {
|
|
||||||
sl := &ingress.StoreLister{}
|
|
||||||
sl.Ingress.Store = buildIngListenerForBackendSSL()
|
|
||||||
sl.Secret.Store = buildSecrListerForBackendSSL()
|
|
||||||
return sl
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
func buildControllerForBackendSSL() cache_client.Controller {
|
|
||||||
cfg := &cache_client.Config{
|
|
||||||
Queue: &MockQueue{Synced: true},
|
|
||||||
}
|
|
||||||
|
|
||||||
return cache_client.New(cfg)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
func buildGenericControllerForBackendSSL() *NGINXController {
|
|
||||||
gc := &NGINXController{
|
|
||||||
syncRateLimiter: flowcontrol.NewTokenBucketRateLimiter(0.3, 1),
|
|
||||||
cfg: &Configuration{
|
|
||||||
Client: buildSimpleClientSetForBackendSSL(),
|
|
||||||
},
|
|
||||||
listers: buildListers(),
|
|
||||||
}
|
|
||||||
|
|
||||||
gc.syncQueue = task.NewTaskQueue(gc.syncIngress)
|
|
||||||
return gc
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
func buildCrtKeyAndCA() ([]byte, []byte, []byte, error) {
|
|
||||||
// prepare
|
|
||||||
td, err := ioutil.TempDir("", "ssl")
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, nil, fmt.Errorf("error occurs while creating temp directory: %v", err)
|
|
||||||
}
|
|
||||||
ingress.DefaultSSLDirectory = td
|
|
||||||
|
|
||||||
dCrt, err := base64.StdEncoding.DecodeString(tlsCrt)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
dKey, err := base64.StdEncoding.DecodeString(tlsKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
dCa := dCrt
|
|
||||||
|
|
||||||
return dCrt, dKey, dCa, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
func TestSyncSecret(t *testing.T) {
|
|
||||||
// prepare for test
|
|
||||||
dCrt, dKey, dCa, err := buildCrtKeyAndCA()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
foos := []struct {
|
|
||||||
tn string
|
|
||||||
secretName string
|
|
||||||
Data map[string][]byte
|
|
||||||
expectSuccess bool
|
|
||||||
}{
|
|
||||||
{"getPemCertificate_error", "default/foo_secret", map[string][]byte{apiv1.TLSPrivateKeyKey: dKey}, false},
|
|
||||||
{"normal_test", "default/foo_secret", map[string][]byte{apiv1.TLSCertKey: dCrt, apiv1.TLSPrivateKeyKey: dKey, tlscaName: dCa}, true},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, foo := range foos {
|
|
||||||
t.Run(foo.tn, func(t *testing.T) {
|
|
||||||
ic := buildGenericControllerForBackendSSL()
|
|
||||||
|
|
||||||
// init secret for getPemCertificate
|
|
||||||
secret := buildSecretForBackendSSL()
|
|
||||||
secret.SetNamespace("default")
|
|
||||||
secret.SetName("foo_secret")
|
|
||||||
secret.Data = foo.Data
|
|
||||||
ic.store..Secret.Add(secret)
|
|
||||||
|
|
||||||
key := "default/foo_secret"
|
|
||||||
// for add
|
|
||||||
ic.syncSecret(key)
|
|
||||||
if foo.expectSuccess {
|
|
||||||
// validate
|
|
||||||
_, exist := ic.sslCertTracker.Get(key)
|
|
||||||
if !exist {
|
|
||||||
t.Errorf("Failed to sync secret: %s", foo.secretName)
|
|
||||||
} else {
|
|
||||||
// for update
|
|
||||||
ic.syncSecret(key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetPemCertificate(t *testing.T) {
|
|
||||||
// prepare
|
|
||||||
dCrt, dKey, dCa, err := buildCrtKeyAndCA()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
foos := []struct {
|
|
||||||
tn string
|
|
||||||
secretName string
|
|
||||||
Data map[string][]byte
|
|
||||||
eErr bool
|
|
||||||
}{
|
|
||||||
{"sceret_not_exist", "default/foo_secret_not_exist", nil, true},
|
|
||||||
{"data_not_complete_all_not_exist", "default/foo_secret", map[string][]byte{}, true},
|
|
||||||
{"data_not_complete_TLSCertKey_not_exist", "default/foo_secret", map[string][]byte{apiv1.TLSPrivateKeyKey: dKey, tlscaName: dCa}, false},
|
|
||||||
{"data_not_complete_TLSCertKeyAndCA_not_exist", "default/foo_secret", map[string][]byte{apiv1.TLSPrivateKeyKey: dKey}, true},
|
|
||||||
{"data_not_complete_TLSPrivateKeyKey_not_exist", "default/foo_secret", map[string][]byte{apiv1.TLSCertKey: dCrt, tlscaName: dCa}, false},
|
|
||||||
{"data_not_complete_TLSPrivateKeyKeyAndCA_not_exist", "default/foo_secret", map[string][]byte{apiv1.TLSCertKey: dCrt}, true},
|
|
||||||
{"data_not_complete_CA_not_exist", "default/foo_secret", map[string][]byte{apiv1.TLSCertKey: dCrt, apiv1.TLSPrivateKeyKey: dKey}, false},
|
|
||||||
{"normal_test", "default/foo_secret", map[string][]byte{apiv1.TLSCertKey: dCrt, apiv1.TLSPrivateKeyKey: dKey, tlscaName: dCa}, false},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, foo := range foos {
|
|
||||||
t.Run(foo.tn, func(t *testing.T) {
|
|
||||||
ic := buildGenericControllerForBackendSSL()
|
|
||||||
secret := buildSecretForBackendSSL()
|
|
||||||
secret.Data = foo.Data
|
|
||||||
ic.listers.Secret.Add(secret)
|
|
||||||
sslCert, err := ic.getPemCertificate(foo.secretName)
|
|
||||||
|
|
||||||
if foo.eErr {
|
|
||||||
if err == nil {
|
|
||||||
t.Fatal("Expected error")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if sslCert == nil {
|
|
||||||
t.Error("Expected an ingress.SSLCert")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
|
@ -36,13 +36,9 @@ import (
|
||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
|
|
||||||
"k8s.io/ingress-nginx/internal/ingress"
|
"k8s.io/ingress-nginx/internal/ingress"
|
||||||
"k8s.io/ingress-nginx/internal/ingress/annotations"
|
|
||||||
"k8s.io/ingress-nginx/internal/ingress/annotations/healthcheck"
|
"k8s.io/ingress-nginx/internal/ingress/annotations/healthcheck"
|
||||||
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
|
||||||
"k8s.io/ingress-nginx/internal/ingress/annotations/proxy"
|
"k8s.io/ingress-nginx/internal/ingress/annotations/proxy"
|
||||||
ngx_config "k8s.io/ingress-nginx/internal/ingress/controller/config"
|
ngx_config "k8s.io/ingress-nginx/internal/ingress/controller/config"
|
||||||
"k8s.io/ingress-nginx/internal/ingress/defaults"
|
|
||||||
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
|
||||||
"k8s.io/ingress-nginx/internal/k8s"
|
"k8s.io/ingress-nginx/internal/k8s"
|
||||||
"k8s.io/ingress-nginx/internal/task"
|
"k8s.io/ingress-nginx/internal/task"
|
||||||
)
|
)
|
||||||
|
@ -100,11 +96,6 @@ type Configuration struct {
|
||||||
SyncRateLimit float32
|
SyncRateLimit float32
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDefaultBackend returns the default backend
|
|
||||||
func (n NGINXController) GetDefaultBackend() defaults.Backend {
|
|
||||||
return n.backendDefaults
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPublishService returns the configured service used to set ingress status
|
// GetPublishService returns the configured service used to set ingress status
|
||||||
func (n NGINXController) GetPublishService() *apiv1.Service {
|
func (n NGINXController) GetPublishService() *apiv1.Service {
|
||||||
s, err := n.store.GetService(n.cfg.PublishService)
|
s, err := n.store.GetService(n.cfg.PublishService)
|
||||||
|
@ -115,16 +106,6 @@ func (n NGINXController) GetPublishService() *apiv1.Service {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSecret searches for a secret in the local secrets Store
|
|
||||||
func (n NGINXController) GetSecret(name string) (*apiv1.Secret, error) {
|
|
||||||
return n.store.GetSecret(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetService searches for a service in the local secrets Store
|
|
||||||
func (n NGINXController) GetService(name string) (*apiv1.Service, error) {
|
|
||||||
return n.store.GetService(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// sync collects all the pieces required to assemble the configuration file and
|
// sync collects all the pieces required to assemble the configuration file and
|
||||||
// then sends the content to the backend (OnUpdate) receiving the populated
|
// then sends the content to the backend (OnUpdate) receiving the populated
|
||||||
// template as response reloading the backend if is required.
|
// template as response reloading the backend if is required.
|
||||||
|
@ -138,7 +119,7 @@ func (n *NGINXController) syncIngress(item interface{}) error {
|
||||||
if element, ok := item.(task.Element); ok {
|
if element, ok := item.(task.Element); ok {
|
||||||
if name, ok := element.Key.(string); ok {
|
if name, ok := element.Key.(string); ok {
|
||||||
if ing, err := n.store.GetIngress(name); err == nil {
|
if ing, err := n.store.GetIngress(name); err == nil {
|
||||||
n.readSecrets(ing)
|
n.store.ReadSecrets(ing)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -368,7 +349,6 @@ func (n *NGINXController) getBackendServers(ingresses []*extensions.Ingress) ([]
|
||||||
anns, err := n.store.GetIngressAnnotations(ing)
|
anns, err := n.store.GetIngressAnnotations(ing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("unexpected error reading ingress annotations: %v", err)
|
glog.Errorf("unexpected error reading ingress annotations: %v", err)
|
||||||
anns = &annotations.Ingress{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, rule := range ing.Spec.Rules {
|
for _, rule := range ing.Spec.Rules {
|
||||||
|
@ -580,29 +560,6 @@ func (n *NGINXController) getBackendServers(ingresses []*extensions.Ingress) ([]
|
||||||
return aUpstreams, aServers
|
return aUpstreams, aServers
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAuthCertificate is used by the auth-tls annotations to get a cert from a secret
|
|
||||||
func (n NGINXController) GetAuthCertificate(name string) (*resolver.AuthSSLCert, error) {
|
|
||||||
if _, exists := n.sslCertTracker.Get(name); !exists {
|
|
||||||
n.syncSecret(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := n.store.GetSecret(name)
|
|
||||||
if err != nil {
|
|
||||||
return &resolver.AuthSSLCert{}, fmt.Errorf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
bc, exists := n.sslCertTracker.Get(name)
|
|
||||||
if !exists {
|
|
||||||
return &resolver.AuthSSLCert{}, fmt.Errorf("secret %v does not exist", name)
|
|
||||||
}
|
|
||||||
cert := bc.(*ingress.SSLCert)
|
|
||||||
return &resolver.AuthSSLCert{
|
|
||||||
Secret: name,
|
|
||||||
CAFileName: cert.CAFileName,
|
|
||||||
PemSHA: cert.PemSHA,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// createUpstreams creates the NGINX upstreams for each service referenced in
|
// createUpstreams creates the NGINX upstreams for each service referenced in
|
||||||
// Ingress rules. The servers inside the upstream are endpoints.
|
// Ingress rules. The servers inside the upstream are endpoints.
|
||||||
func (n *NGINXController) createUpstreams(data []*extensions.Ingress, du *ingress.Backend) map[string]*ingress.Backend {
|
func (n *NGINXController) createUpstreams(data []*extensions.Ingress, du *ingress.Backend) map[string]*ingress.Backend {
|
||||||
|
@ -610,7 +567,10 @@ func (n *NGINXController) createUpstreams(data []*extensions.Ingress, du *ingres
|
||||||
upstreams[defUpstreamName] = du
|
upstreams[defUpstreamName] = du
|
||||||
|
|
||||||
for _, ing := range data {
|
for _, ing := range data {
|
||||||
anns := n.getIngressAnnotations(ing)
|
anns, err := n.store.GetIngressAnnotations(ing)
|
||||||
|
if err != nil {
|
||||||
|
glog.Errorf("unexpected error reading ingress annotations: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
var defBackend string
|
var defBackend string
|
||||||
if ing.Spec.Backend != nil {
|
if ing.Spec.Backend != nil {
|
||||||
|
@ -840,7 +800,7 @@ func (n *NGINXController) createServers(data []*extensions.Ingress,
|
||||||
// remove the alias to avoid conflicts.
|
// remove the alias to avoid conflicts.
|
||||||
aliases := make(map[string]string, len(data))
|
aliases := make(map[string]string, len(data))
|
||||||
|
|
||||||
bdef := n.GetDefaultBackend()
|
bdef := n.store.GetDefaultBackend()
|
||||||
ngxProxy := proxy.Config{
|
ngxProxy := proxy.Config{
|
||||||
BodySize: bdef.ProxyBodySize,
|
BodySize: bdef.ProxyBodySize,
|
||||||
ConnectTimeout: bdef.ProxyConnectTimeout,
|
ConnectTimeout: bdef.ProxyConnectTimeout,
|
||||||
|
@ -860,7 +820,7 @@ func (n *NGINXController) createServers(data []*extensions.Ingress,
|
||||||
|
|
||||||
// Tries to fetch the default Certificate from nginx configuration.
|
// Tries to fetch the default Certificate from nginx configuration.
|
||||||
// If it does not exists, use the ones generated on Start()
|
// If it does not exists, use the ones generated on Start()
|
||||||
defaultCertificate, err := n.getPemCertificate(n.cfg.DefaultSSLCertificate)
|
defaultCertificate, err := n.store.GetLocalSecret(n.cfg.DefaultSSLCertificate)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
defaultPemFileName = defaultCertificate.PemFileName
|
defaultPemFileName = defaultCertificate.PemFileName
|
||||||
defaultPemSHA = defaultCertificate.PemSHA
|
defaultPemSHA = defaultCertificate.PemSHA
|
||||||
|
@ -883,7 +843,10 @@ func (n *NGINXController) createServers(data []*extensions.Ingress,
|
||||||
|
|
||||||
// initialize all the servers
|
// initialize all the servers
|
||||||
for _, ing := range data {
|
for _, ing := range data {
|
||||||
anns := n.getIngressAnnotations(ing)
|
anns, err := n.store.GetIngressAnnotations(ing)
|
||||||
|
if err != nil {
|
||||||
|
glog.Errorf("unexpected error reading ingress annotations: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
// default upstream server
|
// default upstream server
|
||||||
un := du.Name
|
un := du.Name
|
||||||
|
@ -951,7 +914,10 @@ func (n *NGINXController) createServers(data []*extensions.Ingress,
|
||||||
|
|
||||||
// configure default location, alias, and SSL
|
// configure default location, alias, and SSL
|
||||||
for _, ing := range data {
|
for _, ing := range data {
|
||||||
anns := n.getIngressAnnotations(ing)
|
anns, err := n.store.GetIngressAnnotations(ing)
|
||||||
|
if err != nil {
|
||||||
|
glog.Errorf("unexpected error reading ingress annotations: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
for _, rule := range ing.Spec.Rules {
|
for _, rule := range ing.Spec.Rules {
|
||||||
host := rule.Host
|
host := rule.Host
|
||||||
|
@ -1016,13 +982,12 @@ func (n *NGINXController) createServers(data []*extensions.Ingress,
|
||||||
}
|
}
|
||||||
|
|
||||||
key := fmt.Sprintf("%v/%v", ing.Namespace, tlsSecretName)
|
key := fmt.Sprintf("%v/%v", ing.Namespace, tlsSecretName)
|
||||||
bc, exists := n.sslCertTracker.Get(key)
|
cert, err := n.store.GetLocalSecret(key)
|
||||||
if !exists {
|
if err != nil {
|
||||||
glog.Warningf("ssl certificate \"%v\" does not exist in local store", key)
|
glog.Warningf("ssl certificate \"%v\" does not exist in local store", key)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
cert := bc.(*ingress.SSLCert)
|
|
||||||
err = cert.Certificate.VerifyHostname(host)
|
err = cert.Certificate.VerifyHostname(host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Warningf("unexpected error validating SSL certificate %v for host %v. Reason: %v", key, host, err)
|
glog.Warningf("unexpected error validating SSL certificate %v for host %v. Reason: %v", key, host, err)
|
||||||
|
@ -1148,24 +1113,6 @@ func (n *NGINXController) getEndpoints(
|
||||||
return upsServers
|
return upsServers
|
||||||
}
|
}
|
||||||
|
|
||||||
// readSecrets extracts information about secrets from an Ingress rule
|
|
||||||
func (n *NGINXController) readSecrets(ing *extensions.Ingress) {
|
|
||||||
for _, tls := range ing.Spec.TLS {
|
|
||||||
if tls.SecretName == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
key := fmt.Sprintf("%v/%v", ing.Namespace, tls.SecretName)
|
|
||||||
n.syncSecret(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
key, _ := parser.GetStringAnnotation("auth-tls-secret", ing)
|
|
||||||
if key == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
n.syncSecret(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *NGINXController) isForceReload() bool {
|
func (n *NGINXController) isForceReload() bool {
|
||||||
return atomic.LoadInt32(&n.forceReload) != 0
|
return atomic.LoadInt32(&n.forceReload) != 0
|
||||||
}
|
}
|
||||||
|
@ -1179,24 +1126,3 @@ func (n *NGINXController) SetForceReload(shouldReload bool) {
|
||||||
atomic.StoreInt32(&n.forceReload, 0)
|
atomic.StoreInt32(&n.forceReload, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *NGINXController) extractAnnotations(ing *extensions.Ingress) {
|
|
||||||
glog.V(3).Infof("updating annotations information for ingress %v/%v", ing.Namespace, ing.Name)
|
|
||||||
anns := n.annotations.Extract(ing)
|
|
||||||
err := n.store.UpdateIngressAnnotation(anns)
|
|
||||||
if err != nil {
|
|
||||||
glog.Errorf("unexpected error updating annotations information for ingress %v/%v: %v", anns.Namespace, anns.Name, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// getByIngress returns the parsed annotations from an Ingress
|
|
||||||
func (n *NGINXController) getIngressAnnotations(ing *extensions.Ingress) *annotations.Ingress {
|
|
||||||
key := fmt.Sprintf("%v/%v", ing.Namespace, ing.Name)
|
|
||||||
item, err := n.store.GetIngressAnnotations(ing)
|
|
||||||
if err != nil {
|
|
||||||
glog.Errorf("unexpected error getting ingress annotation %v: %v", key, err)
|
|
||||||
return &annotations.Ingress{}
|
|
||||||
}
|
|
||||||
|
|
||||||
return item
|
|
||||||
}
|
|
||||||
|
|
|
@ -18,7 +18,6 @@ package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/base64"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
@ -35,7 +34,6 @@ import (
|
||||||
|
|
||||||
apiv1 "k8s.io/api/core/v1"
|
apiv1 "k8s.io/api/core/v1"
|
||||||
extensions "k8s.io/api/extensions/v1beta1"
|
extensions "k8s.io/api/extensions/v1beta1"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
|
||||||
"k8s.io/client-go/kubernetes/scheme"
|
"k8s.io/client-go/kubernetes/scheme"
|
||||||
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
|
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||||
"k8s.io/client-go/tools/record"
|
"k8s.io/client-go/tools/record"
|
||||||
|
@ -50,7 +48,6 @@ import (
|
||||||
"k8s.io/ingress-nginx/internal/ingress/controller/process"
|
"k8s.io/ingress-nginx/internal/ingress/controller/process"
|
||||||
"k8s.io/ingress-nginx/internal/ingress/controller/store"
|
"k8s.io/ingress-nginx/internal/ingress/controller/store"
|
||||||
ngx_template "k8s.io/ingress-nginx/internal/ingress/controller/template"
|
ngx_template "k8s.io/ingress-nginx/internal/ingress/controller/template"
|
||||||
"k8s.io/ingress-nginx/internal/ingress/defaults"
|
|
||||||
"k8s.io/ingress-nginx/internal/ingress/status"
|
"k8s.io/ingress-nginx/internal/ingress/status"
|
||||||
ing_net "k8s.io/ingress-nginx/internal/net"
|
ing_net "k8s.io/ingress-nginx/internal/net"
|
||||||
"k8s.io/ingress-nginx/internal/net/dns"
|
"k8s.io/ingress-nginx/internal/net/dns"
|
||||||
|
@ -95,16 +92,12 @@ func NewNGINXController(config *Configuration, fs file.Filesystem) *NGINXControl
|
||||||
}
|
}
|
||||||
|
|
||||||
n := &NGINXController{
|
n := &NGINXController{
|
||||||
backendDefaults: ngx_config.NewDefault().Backend,
|
|
||||||
binary: ngx,
|
binary: ngx,
|
||||||
|
|
||||||
configmap: &apiv1.ConfigMap{},
|
|
||||||
|
|
||||||
isIPV6Enabled: ing_net.IsIPv6Enabled(),
|
isIPV6Enabled: ing_net.IsIPv6Enabled(),
|
||||||
|
|
||||||
resolver: h,
|
resolver: h,
|
||||||
cfg: config,
|
cfg: config,
|
||||||
sslCertTracker: store.NewSSLCertTracker(),
|
|
||||||
syncRateLimiter: flowcontrol.NewTokenBucketRateLimiter(config.SyncRateLimit, 1),
|
syncRateLimiter: flowcontrol.NewTokenBucketRateLimiter(config.SyncRateLimit, 1),
|
||||||
|
|
||||||
recorder: eventBroadcaster.NewRecorder(scheme.Scheme, apiv1.EventSource{
|
recorder: eventBroadcaster.NewRecorder(scheme.Scheme, apiv1.EventSource{
|
||||||
|
@ -112,7 +105,7 @@ func NewNGINXController(config *Configuration, fs file.Filesystem) *NGINXControl
|
||||||
}),
|
}),
|
||||||
|
|
||||||
stopCh: make(chan struct{}),
|
stopCh: make(chan struct{}),
|
||||||
updateCh: make(chan store.Event),
|
updateCh: make(chan store.Event, 1024),
|
||||||
|
|
||||||
stopLock: &sync.Mutex{},
|
stopLock: &sync.Mutex{},
|
||||||
|
|
||||||
|
@ -136,7 +129,7 @@ func NewNGINXController(config *Configuration, fs file.Filesystem) *NGINXControl
|
||||||
|
|
||||||
n.syncQueue = task.NewTaskQueue(n.syncIngress)
|
n.syncQueue = task.NewTaskQueue(n.syncIngress)
|
||||||
|
|
||||||
n.annotations = annotations.NewAnnotationExtractor(n)
|
n.annotations = annotations.NewAnnotationExtractor(n.store)
|
||||||
|
|
||||||
if config.UpdateStatus {
|
if config.UpdateStatus {
|
||||||
n.syncStatus = status.NewStatusSyncer(status.Config{
|
n.syncStatus = status.NewStatusSyncer(status.Config{
|
||||||
|
@ -203,10 +196,6 @@ type NGINXController struct {
|
||||||
|
|
||||||
syncStatus status.Sync
|
syncStatus status.Sync
|
||||||
|
|
||||||
// local store of SSL certificates
|
|
||||||
// (only certificates used in ingress)
|
|
||||||
sslCertTracker *store.SSLCertTracker
|
|
||||||
|
|
||||||
syncRateLimiter flowcontrol.RateLimiter
|
syncRateLimiter flowcontrol.RateLimiter
|
||||||
|
|
||||||
// stopLock is used to enforce only a single call to Stop is active.
|
// stopLock is used to enforce only a single call to Stop is active.
|
||||||
|
@ -227,8 +216,6 @@ type NGINXController struct {
|
||||||
|
|
||||||
t *ngx_template.Template
|
t *ngx_template.Template
|
||||||
|
|
||||||
configmap *apiv1.ConfigMap
|
|
||||||
|
|
||||||
binary string
|
binary string
|
||||||
resolver []net.IP
|
resolver []net.IP
|
||||||
|
|
||||||
|
@ -238,15 +225,8 @@ type NGINXController struct {
|
||||||
// returns true if IPV6 is enabled in the pod
|
// returns true if IPV6 is enabled in the pod
|
||||||
isIPV6Enabled bool
|
isIPV6Enabled bool
|
||||||
|
|
||||||
// returns true if proxy protocol es enabled
|
|
||||||
IsProxyProtocolEnabled bool
|
|
||||||
|
|
||||||
isShuttingDown bool
|
isShuttingDown bool
|
||||||
|
|
||||||
Proxy *TCPProxy
|
|
||||||
|
|
||||||
backendDefaults defaults.Backend
|
|
||||||
|
|
||||||
store store.Storer
|
store store.Storer
|
||||||
|
|
||||||
fileSystem filesystem.Filesystem
|
fileSystem filesystem.Filesystem
|
||||||
|
@ -258,28 +238,10 @@ func (n *NGINXController) Start() {
|
||||||
|
|
||||||
n.store.Run(n.stopCh)
|
n.store.Run(n.stopCh)
|
||||||
|
|
||||||
// initial sync of secrets to avoid unnecessary reloads
|
|
||||||
glog.Info("running initial sync of secrets")
|
|
||||||
for _, ing := range n.store.ListIngresses() {
|
|
||||||
if !class.IsValid(ing) {
|
|
||||||
a := ing.GetAnnotations()[class.IngressKey]
|
|
||||||
glog.Infof("ignoring add for ingress %v based on annotation %v with value %v", ing.Name, class.IngressKey, a)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
n.readSecrets(ing)
|
|
||||||
}
|
|
||||||
|
|
||||||
if n.cfg.EnableSSLChainCompletion {
|
|
||||||
go wait.Until(n.checkSSLChainIssues, 60*time.Second, n.stopCh)
|
|
||||||
}
|
|
||||||
|
|
||||||
if n.syncStatus != nil {
|
if n.syncStatus != nil {
|
||||||
go n.syncStatus.Run()
|
go n.syncStatus.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
go wait.Until(n.checkMissingSecrets, 30*time.Second, n.stopCh)
|
|
||||||
|
|
||||||
done := make(chan error, 1)
|
done := make(chan error, 1)
|
||||||
cmd := exec.Command(n.binary, "-c", cfgPath)
|
cmd := exec.Command(n.binary, "-c", cfgPath)
|
||||||
|
|
||||||
|
@ -293,21 +255,6 @@ func (n *NGINXController) Start() {
|
||||||
glog.Info("starting NGINX process...")
|
glog.Info("starting NGINX process...")
|
||||||
n.start(cmd)
|
n.start(cmd)
|
||||||
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case evt := <-n.updateCh:
|
|
||||||
if n.isShuttingDown {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
glog.Infof("Event %v received - object %v", evt.Type, evt.Obj)
|
|
||||||
n.syncQueue.Enqueue(evt.Obj)
|
|
||||||
case <-n.stopCh:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
go n.syncQueue.Run(time.Second, n.stopCh)
|
go n.syncQueue.Run(time.Second, n.stopCh)
|
||||||
// force initial sync
|
// force initial sync
|
||||||
n.syncQueue.Enqueue(&extensions.Ingress{})
|
n.syncQueue.Enqueue(&extensions.Ingress{})
|
||||||
|
@ -332,6 +279,12 @@ func (n *NGINXController) Start() {
|
||||||
// start a new nginx master process if the controller is not being stopped
|
// start a new nginx master process if the controller is not being stopped
|
||||||
n.start(cmd)
|
n.start(cmd)
|
||||||
}
|
}
|
||||||
|
case evt := <-n.updateCh:
|
||||||
|
if n.isShuttingDown {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
glog.V(3).Infof("Event %v received - object %v", evt.Type, evt.Obj)
|
||||||
|
n.syncQueue.Enqueue(evt.Obj)
|
||||||
case <-n.stopCh:
|
case <-n.stopCh:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -434,37 +387,6 @@ Error: %v
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetConfig sets the configured configmap
|
|
||||||
func (n *NGINXController) SetConfig(cmap *apiv1.ConfigMap) {
|
|
||||||
n.configmap = cmap
|
|
||||||
n.IsProxyProtocolEnabled = false
|
|
||||||
|
|
||||||
m := map[string]string{}
|
|
||||||
if cmap != nil {
|
|
||||||
m = cmap.Data
|
|
||||||
}
|
|
||||||
|
|
||||||
val, ok := m["use-proxy-protocol"]
|
|
||||||
if ok {
|
|
||||||
b, err := strconv.ParseBool(val)
|
|
||||||
if err == nil {
|
|
||||||
n.IsProxyProtocolEnabled = b
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
c := ngx_template.ReadConfig(m)
|
|
||||||
if c.SSLSessionTicketKey != "" {
|
|
||||||
d, err := base64.StdEncoding.DecodeString(c.SSLSessionTicketKey)
|
|
||||||
if err != nil {
|
|
||||||
glog.Warningf("unexpected error decoding key ssl-session-ticket-key: %v", err)
|
|
||||||
c.SSLSessionTicketKey = ""
|
|
||||||
}
|
|
||||||
ioutil.WriteFile("/etc/nginx/tickets.key", d, 0644)
|
|
||||||
}
|
|
||||||
|
|
||||||
n.backendDefaults = c.Backend
|
|
||||||
}
|
|
||||||
|
|
||||||
// OnUpdate is called periodically by syncQueue to keep the configuration in sync.
|
// OnUpdate is called periodically by syncQueue to keep the configuration in sync.
|
||||||
//
|
//
|
||||||
// 1. converts configmap configuration to custom configuration object
|
// 1. converts configmap configuration to custom configuration object
|
||||||
|
@ -474,9 +396,10 @@ func (n *NGINXController) SetConfig(cmap *apiv1.ConfigMap) {
|
||||||
// returning nill implies the backend will be reloaded.
|
// returning nill implies the backend will be reloaded.
|
||||||
// if an error is returned means requeue the update
|
// if an error is returned means requeue the update
|
||||||
func (n *NGINXController) OnUpdate(ingressCfg ingress.Configuration) error {
|
func (n *NGINXController) OnUpdate(ingressCfg ingress.Configuration) error {
|
||||||
cfg := ngx_template.ReadConfig(n.configmap.Data)
|
cfg := n.store.GetBackendConfiguration()
|
||||||
cfg.Resolver = n.resolver
|
cfg.Resolver = n.resolver
|
||||||
|
|
||||||
|
/*
|
||||||
servers := []*TCPServer{}
|
servers := []*TCPServer{}
|
||||||
for _, pb := range ingressCfg.PassthroughBackends {
|
for _, pb := range ingressCfg.PassthroughBackends {
|
||||||
svc := pb.Service
|
svc := pb.Service
|
||||||
|
@ -509,10 +432,7 @@ func (n *NGINXController) OnUpdate(ingressCfg ingress.Configuration) error {
|
||||||
ProxyProtocol: false,
|
ProxyProtocol: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
if n.cfg.EnableSSLPassthrough {
|
|
||||||
n.Proxy.ServerList = servers
|
|
||||||
}
|
|
||||||
|
|
||||||
// we need to check if the status module configuration changed
|
// we need to check if the status module configuration changed
|
||||||
if cfg.EnableVtsStatus {
|
if cfg.EnableVtsStatus {
|
||||||
|
|
|
@ -201,8 +201,8 @@ func (s k8sStore) checkMissingSecrets() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// readSecrets extracts information about secrets from an Ingress rule
|
// ReadSecrets extracts information about secrets from an Ingress rule
|
||||||
func (s k8sStore) readSecrets(ing *extensions.Ingress) {
|
func (s k8sStore) ReadSecrets(ing *extensions.Ingress) {
|
||||||
for _, tls := range ing.Spec.TLS {
|
for _, tls := range ing.Spec.TLS {
|
||||||
if tls.SecretName == "" {
|
if tls.SecretName == "" {
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -17,7 +17,9 @@ limitations under the License.
|
||||||
package store
|
package store
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"reflect"
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -41,6 +43,8 @@ import (
|
||||||
"k8s.io/ingress-nginx/internal/ingress/annotations"
|
"k8s.io/ingress-nginx/internal/ingress/annotations"
|
||||||
"k8s.io/ingress-nginx/internal/ingress/annotations/class"
|
"k8s.io/ingress-nginx/internal/ingress/annotations/class"
|
||||||
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
||||||
|
ngx_config "k8s.io/ingress-nginx/internal/ingress/controller/config"
|
||||||
|
ngx_template "k8s.io/ingress-nginx/internal/ingress/controller/template"
|
||||||
"k8s.io/ingress-nginx/internal/ingress/defaults"
|
"k8s.io/ingress-nginx/internal/ingress/defaults"
|
||||||
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
||||||
"k8s.io/ingress-nginx/internal/k8s"
|
"k8s.io/ingress-nginx/internal/k8s"
|
||||||
|
@ -49,6 +53,9 @@ import (
|
||||||
// Storer is the interface that wraps the required methods to gather information
|
// Storer is the interface that wraps the required methods to gather information
|
||||||
// about ingresses, services, secrets and ingress annotations.
|
// about ingresses, services, secrets and ingress annotations.
|
||||||
type Storer interface {
|
type Storer interface {
|
||||||
|
// GetBackendConfiguration returns the nginx configuration stored in a configmap
|
||||||
|
GetBackendConfiguration() ngx_config.Configuration
|
||||||
|
|
||||||
// GetConfigMap returns a ConfigmMap using the namespace and name as key
|
// GetConfigMap returns a ConfigmMap using the namespace and name as key
|
||||||
GetConfigMap(key string) (*apiv1.ConfigMap, error)
|
GetConfigMap(key string) (*apiv1.ConfigMap, error)
|
||||||
|
|
||||||
|
@ -69,9 +76,6 @@ type Storer interface {
|
||||||
// GetIngressAnnotations returns the annotations associated to an Ingress
|
// GetIngressAnnotations returns the annotations associated to an Ingress
|
||||||
GetIngressAnnotations(ing *extensions.Ingress) (*annotations.Ingress, error)
|
GetIngressAnnotations(ing *extensions.Ingress) (*annotations.Ingress, error)
|
||||||
|
|
||||||
// UpdateIngressAnnotation updates the annotations associated to an Ingress
|
|
||||||
UpdateIngressAnnotation(ing *annotations.Ingress) error
|
|
||||||
|
|
||||||
// GetLocalSecret returns the local copy of a Secret
|
// GetLocalSecret returns the local copy of a Secret
|
||||||
GetLocalSecret(name string) (*ingress.SSLCert, error)
|
GetLocalSecret(name string) (*ingress.SSLCert, error)
|
||||||
|
|
||||||
|
@ -86,11 +90,11 @@ type Storer interface {
|
||||||
// GetDefaultBackend returns the default backend configuration
|
// GetDefaultBackend returns the default backend configuration
|
||||||
GetDefaultBackend() defaults.Backend
|
GetDefaultBackend() defaults.Backend
|
||||||
|
|
||||||
// SetDefaultBackend sets the default backend configuration
|
|
||||||
SetDefaultBackend(defaults.Backend)
|
|
||||||
|
|
||||||
// Run initiates the synchronization of the controllers
|
// Run initiates the synchronization of the controllers
|
||||||
Run(stopCh chan struct{})
|
Run(stopCh chan struct{})
|
||||||
|
|
||||||
|
// ReadSecrets extracts information about secrets from an Ingress rule
|
||||||
|
ReadSecrets(*extensions.Ingress)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EventType type of event associated with an informer
|
// EventType type of event associated with an informer
|
||||||
|
@ -162,7 +166,7 @@ func (c *Controller) Run(stopCh chan struct{}) {
|
||||||
type k8sStore struct {
|
type k8sStore struct {
|
||||||
isOCSPCheckEnabled bool
|
isOCSPCheckEnabled bool
|
||||||
|
|
||||||
backendDefaults defaults.Backend
|
backendConfig ngx_config.Configuration
|
||||||
|
|
||||||
cache *Controller
|
cache *Controller
|
||||||
// listers
|
// listers
|
||||||
|
@ -195,6 +199,7 @@ func New(checkOCSP bool,
|
||||||
sslStore: NewSSLCertTracker(),
|
sslStore: NewSSLCertTracker(),
|
||||||
filesystem: fs,
|
filesystem: fs,
|
||||||
updateCh: updateCh,
|
updateCh: updateCh,
|
||||||
|
backendConfig: ngx_config.NewDefault(),
|
||||||
}
|
}
|
||||||
|
|
||||||
eventBroadcaster := record.NewBroadcaster()
|
eventBroadcaster := record.NewBroadcaster()
|
||||||
|
@ -337,10 +342,11 @@ func New(checkOCSP bool,
|
||||||
|
|
||||||
mapEventHandler := cache.ResourceEventHandlerFuncs{
|
mapEventHandler := cache.ResourceEventHandlerFuncs{
|
||||||
AddFunc: func(obj interface{}) {
|
AddFunc: func(obj interface{}) {
|
||||||
upCmap := obj.(*apiv1.ConfigMap)
|
m := obj.(*apiv1.ConfigMap)
|
||||||
mapKey := fmt.Sprintf("%s/%s", upCmap.Namespace, upCmap.Name)
|
mapKey := fmt.Sprintf("%s/%s", m.Namespace, m.Name)
|
||||||
if mapKey == configmap {
|
if mapKey == configmap {
|
||||||
glog.V(2).Infof("adding configmap %v to backend", mapKey)
|
glog.V(2).Infof("adding configmap %v to backend", mapKey)
|
||||||
|
store.setConfig(m)
|
||||||
updateCh <- Event{
|
updateCh <- Event{
|
||||||
Type: CreateEvent,
|
Type: CreateEvent,
|
||||||
Obj: obj,
|
Obj: obj,
|
||||||
|
@ -349,10 +355,11 @@ func New(checkOCSP bool,
|
||||||
},
|
},
|
||||||
UpdateFunc: func(old, cur interface{}) {
|
UpdateFunc: func(old, cur interface{}) {
|
||||||
if !reflect.DeepEqual(old, cur) {
|
if !reflect.DeepEqual(old, cur) {
|
||||||
upCmap := cur.(*apiv1.ConfigMap)
|
m := cur.(*apiv1.ConfigMap)
|
||||||
mapKey := fmt.Sprintf("%s/%s", upCmap.Namespace, upCmap.Name)
|
mapKey := fmt.Sprintf("%s/%s", m.Namespace, m.Name)
|
||||||
if mapKey == configmap {
|
if mapKey == configmap {
|
||||||
glog.V(2).Infof("updating configmap backend (%v)", mapKey)
|
glog.V(2).Infof("updating configmap backend (%v)", mapKey)
|
||||||
|
store.setConfig(m)
|
||||||
updateCh <- Event{
|
updateCh <- Event{
|
||||||
Type: UpdateEvent,
|
Type: UpdateEvent,
|
||||||
Obj: cur,
|
Obj: cur,
|
||||||
|
@ -360,7 +367,7 @@ func New(checkOCSP bool,
|
||||||
}
|
}
|
||||||
// updates to configuration configmaps can trigger an update
|
// updates to configuration configmaps can trigger an update
|
||||||
if mapKey == configmap || mapKey == tcp || mapKey == udp {
|
if mapKey == configmap || mapKey == tcp || mapKey == udp {
|
||||||
recorder.Eventf(upCmap, apiv1.EventTypeNormal, "UPDATE", fmt.Sprintf("ConfigMap %v", mapKey))
|
recorder.Eventf(m, apiv1.EventTypeNormal, "UPDATE", fmt.Sprintf("ConfigMap %v", mapKey))
|
||||||
updateCh <- Event{
|
updateCh <- Event{
|
||||||
Type: UpdateEvent,
|
Type: UpdateEvent,
|
||||||
Obj: cur,
|
Obj: cur,
|
||||||
|
@ -452,20 +459,14 @@ func (s k8sStore) GetIngressAnnotations(ing *extensions.Ingress) (*annotations.I
|
||||||
key := fmt.Sprintf("%v/%v", ing.Namespace, ing.Name)
|
key := fmt.Sprintf("%v/%v", ing.Namespace, ing.Name)
|
||||||
item, exists, err := s.listers.IngressAnnotation.GetByKey(key)
|
item, exists, err := s.listers.IngressAnnotation.GetByKey(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unexpected error getting ingress annotation %v: %v", key, err)
|
return &annotations.Ingress{}, fmt.Errorf("unexpected error getting ingress annotation %v: %v", key, err)
|
||||||
}
|
}
|
||||||
if !exists {
|
if !exists {
|
||||||
return nil, fmt.Errorf("ingress annotation %v was not found", key)
|
return &annotations.Ingress{}, fmt.Errorf("ingress annotations %v was not found", key)
|
||||||
}
|
}
|
||||||
return item.(*annotations.Ingress), nil
|
return item.(*annotations.Ingress), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateIngressAnnotation updates the annotations associated to an Ingress
|
|
||||||
func (s k8sStore) UpdateIngressAnnotation(ing *annotations.Ingress) error {
|
|
||||||
key := fmt.Sprintf("%v/%v", ing.Namespace, ing.Name)
|
|
||||||
return s.listers.IngressAnnotation.Update(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetLocalSecret returns the local copy of a Secret
|
// GetLocalSecret returns the local copy of a Secret
|
||||||
func (s k8sStore) GetLocalSecret(key string) (*ingress.SSLCert, error) {
|
func (s k8sStore) GetLocalSecret(key string) (*ingress.SSLCert, error) {
|
||||||
return s.sslStore.ByKey(key)
|
return s.sslStore.ByKey(key)
|
||||||
|
@ -499,11 +500,25 @@ func (s k8sStore) GetAuthCertificate(name string) (*resolver.AuthSSLCert, error)
|
||||||
|
|
||||||
// GetDefaultBackend returns the default backend
|
// GetDefaultBackend returns the default backend
|
||||||
func (s k8sStore) GetDefaultBackend() defaults.Backend {
|
func (s k8sStore) GetDefaultBackend() defaults.Backend {
|
||||||
return s.backendDefaults
|
return s.backendConfig.Backend
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *k8sStore) SetDefaultBackend(bd defaults.Backend) {
|
func (s k8sStore) GetBackendConfiguration() ngx_config.Configuration {
|
||||||
s.backendDefaults = bd
|
return s.backendConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *k8sStore) setConfig(cmap *apiv1.ConfigMap) {
|
||||||
|
s.backendConfig = ngx_template.ReadConfig(cmap.Data)
|
||||||
|
|
||||||
|
// TODO: this should not be done here
|
||||||
|
if s.backendConfig.SSLSessionTicketKey != "" {
|
||||||
|
d, err := base64.StdEncoding.DecodeString(s.backendConfig.SSLSessionTicketKey)
|
||||||
|
if err != nil {
|
||||||
|
glog.Warningf("unexpected error decoding key ssl-session-ticket-key: %v", err)
|
||||||
|
s.backendConfig.SSLSessionTicketKey = ""
|
||||||
|
}
|
||||||
|
ioutil.WriteFile("/etc/nginx/tickets.key", d, 0644)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run initiates the synchronization of the controllers
|
// Run initiates the synchronization of the controllers
|
||||||
|
@ -515,7 +530,7 @@ func (s k8sStore) Run(stopCh chan struct{}) {
|
||||||
// initial sync of secrets to avoid unnecessary reloads
|
// initial sync of secrets to avoid unnecessary reloads
|
||||||
glog.Info("running initial sync of secrets")
|
glog.Info("running initial sync of secrets")
|
||||||
for _, ing := range s.ListIngresses() {
|
for _, ing := range s.ListIngresses() {
|
||||||
s.readSecrets(ing)
|
s.ReadSecrets(ing)
|
||||||
}
|
}
|
||||||
|
|
||||||
// start goroutine to check for missing local secrets
|
// start goroutine to check for missing local secrets
|
||||||
|
|
|
@ -1,113 +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 store
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
apiv1 "k8s.io/api/core/v1"
|
|
||||||
"k8s.io/client-go/tools/cache"
|
|
||||||
)
|
|
||||||
|
|
||||||
// IngressLister makes a Store that lists Ingress.
|
|
||||||
type IngressLister struct {
|
|
||||||
cache.Store
|
|
||||||
}
|
|
||||||
|
|
||||||
// IngressAnnotationsLister makes a Store that lists annotations in Ingress rules.
|
|
||||||
type IngressAnnotationsLister struct {
|
|
||||||
cache.Store
|
|
||||||
}
|
|
||||||
|
|
||||||
// SecretLister makes a Store that lists Secrets.
|
|
||||||
type SecretLister struct {
|
|
||||||
cache.Store
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetByName searches for a secret in the local secrets Store
|
|
||||||
func (sl *SecretLister) GetByName(name string) (*apiv1.Secret, error) {
|
|
||||||
s, exists, err := sl.GetByKey(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if !exists {
|
|
||||||
return nil, fmt.Errorf("secret %v was not found", name)
|
|
||||||
}
|
|
||||||
return s.(*apiv1.Secret), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConfigMapLister makes a Store that lists Configmaps.
|
|
||||||
type ConfigMapLister struct {
|
|
||||||
cache.Store
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetByName searches for a configmap in the local configmaps Store
|
|
||||||
func (cml *ConfigMapLister) GetByName(name string) (*apiv1.ConfigMap, error) {
|
|
||||||
s, exists, err := cml.GetByKey(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if !exists {
|
|
||||||
return nil, fmt.Errorf("configmap %v was not found", name)
|
|
||||||
}
|
|
||||||
return s.(*apiv1.ConfigMap), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ServiceLister makes a Store that lists Services.
|
|
||||||
type ServiceLister struct {
|
|
||||||
cache.Store
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetByName searches for a service in the local secrets Store
|
|
||||||
func (sl *ServiceLister) GetByName(name string) (*apiv1.Service, error) {
|
|
||||||
s, exists, err := sl.GetByKey(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if !exists {
|
|
||||||
return nil, fmt.Errorf("service %v was not found", name)
|
|
||||||
}
|
|
||||||
return s.(*apiv1.Service), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// EndpointLister makes a Store that lists Endpoints.
|
|
||||||
type EndpointLister struct {
|
|
||||||
cache.Store
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetServiceEndpoints returns the endpoints of a service, matched on service name.
|
|
||||||
func (s *EndpointLister) GetServiceEndpoints(svc *apiv1.Service) (*apiv1.Endpoints, error) {
|
|
||||||
for _, m := range s.Store.List() {
|
|
||||||
ep := m.(*apiv1.Endpoints)
|
|
||||||
if svc.Name == ep.Name && svc.Namespace == ep.Namespace {
|
|
||||||
return ep, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("could not find endpoints for service: %v", svc.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SSLCertTracker holds a store of referenced Secrets in Ingress rules
|
|
||||||
type SSLCertTracker struct {
|
|
||||||
cache.ThreadSafeStore
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewSSLCertTracker creates a new SSLCertTracker store
|
|
||||||
func NewSSLCertTracker() *SSLCertTracker {
|
|
||||||
return &SSLCertTracker{
|
|
||||||
cache.NewThreadSafeStore(cache.Indexers{}, cache.Indices{}),
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue