cert-manager/pkg/controller/cainjector/indexers.go
Ingo Gottwald be3f1e3fd2 Remove use of deprecated client.MatchingField
Signed-off-by: Ingo Gottwald <in.gottwald@gmail.com>
2019-10-02 20:47:58 +02:00

215 lines
7.2 KiB
Go

/*
Copyright 2019 The Jetstack cert-manager contributors.
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 cainjector
import (
"context"
"github.com/go-logr/logr"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/handler"
cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha2"
)
// setup for indexers used to trigger reconciliation on injected CA data.
// certificateToInjectableFunc converts a given certificate to the reconcile requests for the corresponding injectables
// (webhooks, api services, etc) that reference it.
type certificateToInjectableFunc func(log logr.Logger, cl client.Client, certName types.NamespacedName) []ctrl.Request
// buildCertToInjectableFunc creates a certificateToInjectableFunc that maps from certificates to the given type of injectable.
func buildCertToInjectableFunc(listTyp runtime.Object, resourceName string) certificateToInjectableFunc {
return func(log logr.Logger, cl client.Client, certName types.NamespacedName) []ctrl.Request {
log = log.WithValues("type", resourceName)
objs := listTyp.DeepCopyObject()
if err := cl.List(context.Background(), objs, client.MatchingFields{injectFromPath: certName.String()}); err != nil {
log.Error(err, "unable to fetch injectables associated with certificate")
return nil
}
var reqs []ctrl.Request
if err := meta.EachListItem(objs, func(obj runtime.Object) error {
metaInfo, err := meta.Accessor(obj)
if err != nil {
log.Error(err, "unable to get metadata from list item")
// continue on error
return nil
}
reqs = append(reqs, ctrl.Request{NamespacedName: types.NamespacedName{
Name: metaInfo.GetName(),
Namespace: metaInfo.GetNamespace(),
}})
return nil
}); err != nil {
log.Error(err, "unable get items from list")
return nil
}
return reqs
}
}
// secretForCertificateMapper is a Mapper that converts secrets up to injectables, through certificates.
type secretForCertificateMapper struct {
client.Client
log logr.Logger
certificateToInjectable certificateToInjectableFunc
}
func (m *secretForCertificateMapper) Map(obj handler.MapObject) []ctrl.Request {
// grab the certificate, if it exists
certName := OwningCertForSecret(obj.Object.(*corev1.Secret))
if certName == nil {
return nil
}
secretName := types.NamespacedName{Name: obj.Meta.GetName(), Namespace: obj.Meta.GetNamespace()}
log := m.log.WithValues("secret", secretName, "certificate", *certName)
var cert cmapi.Certificate
// confirm that a service owns this cert
if err := m.Client.Get(context.Background(), *certName, &cert); err != nil {
// TODO(directxman12): check for not found error?
log.Error(err, "unable to fetch certificate that owns the secret")
return nil
}
return m.certificateToInjectable(log, m.Client, *certName)
}
// certMapper is a mapper that converts Certificates up to injectables
type certMapper struct {
client.Client
log logr.Logger
toInjectable certificateToInjectableFunc
}
func (m *certMapper) Map(obj handler.MapObject) []ctrl.Request {
certName := types.NamespacedName{Name: obj.Meta.GetName(), Namespace: obj.Meta.GetNamespace()}
log := m.log.WithValues("certificate", certName)
return m.toInjectable(log, m.Client, certName)
}
var (
// injectFromPath is the index key used to look up the value of inject-ca-from on targeted objects
injectFromPath = ".metadata.annotations.inject-ca-from"
)
// injectableCAFromIndexer is an IndexerFunc indexing on certificates
// referenced by injectables.
func injectableCAFromIndexer(rawObj runtime.Object) []string {
metaInfo, err := meta.Accessor(rawObj)
if err != nil {
return nil
}
// skip invalid certificate names
certNameRaw := metaInfo.GetAnnotations()[cmapi.WantInjectAnnotation]
if certNameRaw == "" {
return nil
}
certName := splitNamespacedName(certNameRaw)
if certName.Namespace == "" {
return nil
}
return []string{certNameRaw}
}
// secretToInjectableFunc converts a given certificate to the reconcile requests for the corresponding injectables
// (webhooks, api services, etc) that reference it.
type secretToInjectableFunc func(log logr.Logger, cl client.Client, certName types.NamespacedName) []ctrl.Request
// buildSecretToInjectableFunc creates a certificateToInjectableFunc that maps from certificates to the given type of injectable.
func buildSecretToInjectableFunc(listTyp runtime.Object, resourceName string) secretToInjectableFunc {
return func(log logr.Logger, cl client.Client, secretName types.NamespacedName) []ctrl.Request {
log = log.WithValues("type", resourceName)
objs := listTyp.DeepCopyObject()
if err := cl.List(context.Background(), objs, client.MatchingFields{injectFromSecretPath: secretName.String()}); err != nil {
log.Error(err, "unable to fetch injectables associated with secret")
return nil
}
var reqs []ctrl.Request
if err := meta.EachListItem(objs, func(obj runtime.Object) error {
metaInfo, err := meta.Accessor(obj)
if err != nil {
log.Error(err, "unable to get metadata from list item")
// continue on error
return nil
}
reqs = append(reqs, ctrl.Request{NamespacedName: types.NamespacedName{
Name: metaInfo.GetName(),
Namespace: metaInfo.GetNamespace(),
}})
return nil
}); err != nil {
log.Error(err, "unable get items from list")
return nil
}
return reqs
}
}
// secretForInjectableMapper is a Mapper that converts secrets to injectables
// via the 'inject-ca-from-secret' annotation
type secretForInjectableMapper struct {
client.Client
log logr.Logger
secretToInjectable secretToInjectableFunc
}
func (m *secretForInjectableMapper) Map(obj handler.MapObject) []ctrl.Request {
secretName := types.NamespacedName{Namespace: obj.Meta.GetNamespace(), Name: obj.Meta.GetName()}
log := m.log.WithValues("secret", secretName)
return m.secretToInjectable(log, m.Client, secretName)
}
var (
// injectFromSecretPath is the index key used to look up the value of
// inject-ca-from-secret on targeted objects
injectFromSecretPath = ".metadata.annotations.inject-ca-from-secret"
)
// injectableCAFromSecretIndexer is an IndexerFunc indexing on secrets
// referenced by injectables.
func injectableCAFromSecretIndexer(rawObj runtime.Object) []string {
metaInfo, err := meta.Accessor(rawObj)
if err != nil {
return nil
}
// skip invalid secret names
secretNameRaw := metaInfo.GetAnnotations()[cmapi.WantInjectFromSecretAnnotation]
if secretNameRaw == "" {
return nil
}
secretName := splitNamespacedName(secretNameRaw)
if secretName.Namespace == "" {
return nil
}
return []string{secretNameRaw}
}