mirror of
https://github.com/wahyd4/cert-manager.git
synced 2026-08-09 05:06:38 +10:00
gateway-shim: add the gateway-shim controller
Note that the gateway-shim is only half the work for supporting the Gateway API in cert-manager. The other half is the HTTP01 solver support, which is still worked on. The Gateway API in cert-manager is releases as an experimental feature and needs to be enabled manually with the following flag: --controllers=*,gateway-shim All the annotations supported by ingress-shim are also supported by gateway-shim, with some exceptions: "acme.cert-manager.io/http01-ingress-class" This annotation is not supported on the Gateway resource. Although the Gateway resource also has a "gatewayClass" field, we will need to add another field instead of "ingress-class" to avoid confusion with the ingress-shim. "acme.cert-manager.io/http01-edit-in-place" This annotation is not supported because it is specific to some ingress controllers like ingress-gce. "kubernetes.io/tls-acme" This annotation is not supported because it is a behavior inherited from kube-lego and we chose not to keep this behavior with the Gateway API. Unlike the ingress-shim, you can reuse the same Secret name in multiple TLS configurations on the same Gateway resource. The ingress-shim now shows the exact location of the duplicate secretName when the user gives the same secretName in two separate TLS blocks. Signed-off-by: Maël Valais <mael@vls.dev> Co-authored-by: Jake Sanders <i@am.so-aweso.me>
This commit is contained in:
co-authored by
Jake Sanders
parent
1cd44fa730
commit
30f9c123d3
@@ -16651,35 +16651,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
================================================================================
|
||||
|
||||
|
||||
================================================================================
|
||||
= vendor/github.com/shurcooL/sanitized_anchor_name licensed under: =
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2015 Dmitri Shuralyov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
= vendor/github.com/shurcooL/sanitized_anchor_name/LICENSE c670c44b8d826e9b7b99077e5c7ba283
|
||||
================================================================================
|
||||
|
||||
|
||||
================================================================================
|
||||
= vendor/github.com/sirupsen/logrus licensed under: =
|
||||
|
||||
@@ -24285,6 +24256,215 @@ third-party archives.
|
||||
================================================================================
|
||||
|
||||
|
||||
================================================================================
|
||||
= vendor/sigs.k8s.io/gateway-api licensed under: =
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2020 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.
|
||||
|
||||
= vendor/sigs.k8s.io/gateway-api/LICENSE 2a0fcf36e548ee863cd9e49f96dcd666
|
||||
================================================================================
|
||||
|
||||
|
||||
================================================================================
|
||||
= vendor/sigs.k8s.io/kustomize/api licensed under: =
|
||||
|
||||
|
||||
@@ -17,9 +17,10 @@ go_library(
|
||||
"//pkg/controller:go_default_library",
|
||||
"//pkg/controller/acmechallenges:go_default_library",
|
||||
"//pkg/controller/acmeorders:go_default_library",
|
||||
"//pkg/controller/certificate-shim/gateways:go_default_library",
|
||||
"//pkg/controller/certificate-shim/ingresses:go_default_library",
|
||||
"//pkg/controller/certificates/trigger:go_default_library",
|
||||
"//pkg/controller/clusterissuers:go_default_library",
|
||||
"//pkg/controller/ingress-shim:go_default_library",
|
||||
"//pkg/controller/issuers:go_default_library",
|
||||
"//pkg/issuer/acme:go_default_library",
|
||||
"//pkg/issuer/acme/dns/util:go_default_library",
|
||||
@@ -45,6 +46,10 @@ go_library(
|
||||
"@io_k8s_client_go//tools/leaderelection:go_default_library",
|
||||
"@io_k8s_client_go//tools/leaderelection/resourcelock:go_default_library",
|
||||
"@io_k8s_client_go//tools/record:go_default_library",
|
||||
"@io_k8s_sigs_gateway_api//apis/v1alpha1:go_default_library",
|
||||
"@io_k8s_sigs_gateway_api//pkg/client/clientset/versioned:go_default_library",
|
||||
"@io_k8s_sigs_gateway_api//pkg/client/clientset/versioned/scheme:go_default_library",
|
||||
"@io_k8s_sigs_gateway_api//pkg/client/informers/externalversions:go_default_library",
|
||||
"@io_k8s_utils//clock:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -35,6 +35,10 @@ import (
|
||||
"k8s.io/client-go/tools/leaderelection/resourcelock"
|
||||
"k8s.io/client-go/tools/record"
|
||||
"k8s.io/utils/clock"
|
||||
gwapi "sigs.k8s.io/gateway-api/apis/v1alpha1"
|
||||
gwclient "sigs.k8s.io/gateway-api/pkg/client/clientset/versioned"
|
||||
gwscheme "sigs.k8s.io/gateway-api/pkg/client/clientset/versioned/scheme"
|
||||
gwinformers "sigs.k8s.io/gateway-api/pkg/client/informers/externalversions"
|
||||
|
||||
"github.com/jetstack/cert-manager/cmd/controller/app/options"
|
||||
"github.com/jetstack/cert-manager/pkg/acme/accounts"
|
||||
@@ -116,6 +120,7 @@ func Run(opts *options.ControllerOptions, stopCh <-chan struct{}) {
|
||||
log.V(logf.DebugLevel).Info("starting shared informer factories")
|
||||
ctx.SharedInformerFactory.Start(stopCh)
|
||||
ctx.KubeSharedInformerFactory.Start(stopCh)
|
||||
ctx.GWShared.Start(stopCh)
|
||||
wg.Wait()
|
||||
log.V(logf.InfoLevel).Info("control loops exited")
|
||||
ctx.Metrics.Shutdown(metricsServer)
|
||||
@@ -163,6 +168,24 @@ func buildControllerContext(ctx context.Context, stopCh <-chan struct{}, opts *o
|
||||
return nil, nil, fmt.Errorf("error creating kubernetes client: %s", err.Error())
|
||||
}
|
||||
|
||||
// The user may have enabled the gateway-shim controller but forgotten to
|
||||
// install the Gateway API CRDs. Failing here will cause cert-manager to go
|
||||
// into CrashLoopBackoff which is nice and obvious.
|
||||
d := cl.Discovery()
|
||||
resources, err := d.ServerResourcesForGroupVersion(gwapi.GroupVersion.String())
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("couldn't discover Gateway API resources (are the Gateway API CRDs installed?): %w", err)
|
||||
}
|
||||
if len(resources.APIResources) == 0 {
|
||||
return nil, nil, fmt.Errorf("no gateway API resources were discovered (are the Gateway API CRDs installed?)")
|
||||
}
|
||||
|
||||
// Create a GatewayAPI client
|
||||
gwcl, err := gwclient.NewForConfig(kubeCfg)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("error creating kubernetes client: %s", err.Error())
|
||||
}
|
||||
|
||||
nameservers := opts.DNS01RecursiveNameservers
|
||||
if len(nameservers) == 0 {
|
||||
nameservers = dnsutil.RecursiveNameservers
|
||||
@@ -193,6 +216,7 @@ func buildControllerContext(ctx context.Context, stopCh <-chan struct{}, opts *o
|
||||
// Add cert-manager types to the default Kubernetes Scheme so Events can be
|
||||
// logged properly
|
||||
intscheme.AddToScheme(scheme.Scheme)
|
||||
gwscheme.AddToScheme(scheme.Scheme)
|
||||
log.V(logf.DebugLevel).Info("creating event broadcaster")
|
||||
eventBroadcaster := record.NewBroadcaster()
|
||||
eventBroadcaster.StartLogging(logf.WithInfof(log.V(logf.DebugLevel)).Infof)
|
||||
@@ -201,6 +225,7 @@ func buildControllerContext(ctx context.Context, stopCh <-chan struct{}, opts *o
|
||||
|
||||
sharedInformerFactory := informers.NewSharedInformerFactoryWithOptions(intcl, resyncPeriod, informers.WithNamespace(opts.Namespace))
|
||||
kubeSharedInformerFactory := kubeinformers.NewSharedInformerFactoryWithOptions(cl, resyncPeriod, kubeinformers.WithNamespace(opts.Namespace))
|
||||
gwSharedInformerFactory := gwinformers.NewSharedInformerFactoryWithOptions(gwcl, resyncPeriod, gwinformers.WithNamespace(opts.Namespace))
|
||||
|
||||
acmeAccountRegistry := accounts.NewDefaultRegistry()
|
||||
|
||||
@@ -210,9 +235,11 @@ func buildControllerContext(ctx context.Context, stopCh <-chan struct{}, opts *o
|
||||
RESTConfig: kubeCfg,
|
||||
Client: cl,
|
||||
CMClient: intcl,
|
||||
GWClient: gwcl,
|
||||
Recorder: recorder,
|
||||
KubeSharedInformerFactory: kubeSharedInformerFactory,
|
||||
SharedInformerFactory: sharedInformerFactory,
|
||||
GWShared: gwSharedInformerFactory,
|
||||
Namespace: opts.Namespace,
|
||||
Clock: clock.RealClock{},
|
||||
Metrics: metrics.New(log, clock.RealClock{}),
|
||||
|
||||
@@ -9,6 +9,8 @@ go_library(
|
||||
"//pkg/apis/certmanager:go_default_library",
|
||||
"//pkg/controller/acmechallenges:go_default_library",
|
||||
"//pkg/controller/acmeorders:go_default_library",
|
||||
"//pkg/controller/certificate-shim/gateways:go_default_library",
|
||||
"//pkg/controller/certificate-shim/ingresses:go_default_library",
|
||||
"//pkg/controller/certificaterequests/acme:go_default_library",
|
||||
"//pkg/controller/certificaterequests/approver:go_default_library",
|
||||
"//pkg/controller/certificaterequests/ca:go_default_library",
|
||||
@@ -26,7 +28,6 @@ go_library(
|
||||
"//pkg/controller/certificatesigningrequests/selfsigned:go_default_library",
|
||||
"//pkg/controller/certificatesigningrequests/vault:go_default_library",
|
||||
"//pkg/controller/clusterissuers:go_default_library",
|
||||
"//pkg/controller/ingress-shim:go_default_library",
|
||||
"//pkg/controller/issuers:go_default_library",
|
||||
"//pkg/feature:go_default_library",
|
||||
"//pkg/logs:go_default_library",
|
||||
|
||||
@@ -28,6 +28,8 @@ import (
|
||||
cm "github.com/jetstack/cert-manager/pkg/apis/certmanager"
|
||||
challengescontroller "github.com/jetstack/cert-manager/pkg/controller/acmechallenges"
|
||||
orderscontroller "github.com/jetstack/cert-manager/pkg/controller/acmeorders"
|
||||
shimgatewaycontroller "github.com/jetstack/cert-manager/pkg/controller/certificate-shim/gateways"
|
||||
shimingresscontroller "github.com/jetstack/cert-manager/pkg/controller/certificate-shim/ingresses"
|
||||
cracmecontroller "github.com/jetstack/cert-manager/pkg/controller/certificaterequests/acme"
|
||||
crapprovercontroller "github.com/jetstack/cert-manager/pkg/controller/certificaterequests/approver"
|
||||
crcacontroller "github.com/jetstack/cert-manager/pkg/controller/certificaterequests/ca"
|
||||
@@ -45,7 +47,6 @@ import (
|
||||
csrselfsignedcontroller "github.com/jetstack/cert-manager/pkg/controller/certificatesigningrequests/selfsigned"
|
||||
csrvaultcontroller "github.com/jetstack/cert-manager/pkg/controller/certificatesigningrequests/vault"
|
||||
clusterissuerscontroller "github.com/jetstack/cert-manager/pkg/controller/clusterissuers"
|
||||
ingressshimcontroller "github.com/jetstack/cert-manager/pkg/controller/ingress-shim"
|
||||
issuerscontroller "github.com/jetstack/cert-manager/pkg/controller/issuers"
|
||||
"github.com/jetstack/cert-manager/pkg/feature"
|
||||
logf "github.com/jetstack/cert-manager/pkg/logs"
|
||||
@@ -150,7 +151,8 @@ var (
|
||||
issuerscontroller.ControllerName,
|
||||
clusterissuerscontroller.ControllerName,
|
||||
certificatesmetricscontroller.ControllerName,
|
||||
ingressshimcontroller.ControllerName,
|
||||
shimingresscontroller.ControllerName,
|
||||
shimgatewaycontroller.ControllerName,
|
||||
orderscontroller.ControllerName,
|
||||
challengescontroller.ControllerName,
|
||||
cracmecontroller.CRControllerName,
|
||||
@@ -172,7 +174,7 @@ var (
|
||||
issuerscontroller.ControllerName,
|
||||
clusterissuerscontroller.ControllerName,
|
||||
certificatesmetricscontroller.ControllerName,
|
||||
ingressshimcontroller.ControllerName,
|
||||
shimingresscontroller.ControllerName,
|
||||
orderscontroller.ControllerName,
|
||||
challengescontroller.ControllerName,
|
||||
cracmecontroller.CRControllerName,
|
||||
|
||||
@@ -26,9 +26,10 @@ import (
|
||||
"github.com/jetstack/cert-manager/cmd/controller/app/options"
|
||||
_ "github.com/jetstack/cert-manager/pkg/controller/acmechallenges"
|
||||
_ "github.com/jetstack/cert-manager/pkg/controller/acmeorders"
|
||||
_ "github.com/jetstack/cert-manager/pkg/controller/certificate-shim/gateways"
|
||||
_ "github.com/jetstack/cert-manager/pkg/controller/certificate-shim/ingresses"
|
||||
_ "github.com/jetstack/cert-manager/pkg/controller/certificates/trigger"
|
||||
_ "github.com/jetstack/cert-manager/pkg/controller/clusterissuers"
|
||||
_ "github.com/jetstack/cert-manager/pkg/controller/ingress-shim"
|
||||
_ "github.com/jetstack/cert-manager/pkg/controller/issuers"
|
||||
_ "github.com/jetstack/cert-manager/pkg/issuer/acme"
|
||||
_ "github.com/jetstack/cert-manager/pkg/issuer/ca"
|
||||
|
||||
@@ -269,6 +269,12 @@ rules:
|
||||
- apiGroups: ["networking.k8s.io"]
|
||||
resources: ["ingresses/finalizers"]
|
||||
verbs: ["update"]
|
||||
- apiGroups: ["networking.x-k8s.io"]
|
||||
resources: ["gateways"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiGroups: ["networking.x-k8s.io"]
|
||||
resources: ["gateways/finalizers"]
|
||||
verbs: ["update"]
|
||||
- apiGroups: [""]
|
||||
resources: ["events"]
|
||||
verbs: ["create", "patch"]
|
||||
|
||||
@@ -62,6 +62,6 @@ helm upgrade \
|
||||
--set webhook.image.tag="${APP_VERSION}" \
|
||||
--set installCRDs=true \
|
||||
--set featureGates="${FEATURE_GATES:-}" \
|
||||
--set "extraArgs={--dns01-recursive-nameservers=${SERVICE_IP_PREFIX}.16:53,--dns01-recursive-nameservers-only=true}" \
|
||||
--set "extraArgs={--dns01-recursive-nameservers=${SERVICE_IP_PREFIX}.16:53,--dns01-recursive-nameservers-only=true,--controllers=*\,gateway-shim}" \
|
||||
"$RELEASE_NAME" \
|
||||
"$REPO_ROOT/bazel-bin/deploy/charts/cert-manager/cert-manager.tgz"
|
||||
|
||||
@@ -62,6 +62,7 @@ require (
|
||||
rsc.io/letsencrypt v0.0.3 // indirect
|
||||
sigs.k8s.io/controller-runtime v0.9.2
|
||||
sigs.k8s.io/controller-tools v0.6.0
|
||||
sigs.k8s.io/gateway-api v0.3.0
|
||||
sigs.k8s.io/yaml v1.2.0
|
||||
software.sslmate.com/src/go-pkcs12 v0.0.0-20200830195227-52f69702a001
|
||||
)
|
||||
|
||||
@@ -33,9 +33,11 @@ github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSW
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
||||
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
|
||||
github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw=
|
||||
github.com/Azure/go-autorest/autorest v0.11.12 h1:gI8ytXbxMfI+IVbI9mP2JGCTXIuhHLgRlvQ9X4PsnHE=
|
||||
github.com/Azure/go-autorest/autorest v0.11.12/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.5 h1:Y3bBUV4rTuxenJJs41HU3qmqsb+auo+a3Lz+PlJPpL0=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A=
|
||||
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
|
||||
@@ -43,6 +45,7 @@ github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8K
|
||||
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
|
||||
github.com/Azure/go-autorest/autorest/to v0.2.0 h1:nQOZzFCudTh+TvquAtCRjM01VEYx85e9qbwt5ncW4L8=
|
||||
@@ -95,6 +98,7 @@ github.com/Venafi/vcert/v4 v4.13.1/go.mod h1:Z3sJFoAurFNXPpoSUSHq46aIeHLiGQEMDhp
|
||||
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
||||
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
|
||||
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
|
||||
github.com/ahmetb/gen-crd-api-reference-docs v0.2.1-0.20201224172655-df869c1245d4/go.mod h1:TdjdkYhlOifCQWPs1UdTma97kQQMozf5h26hTuG70u8=
|
||||
github.com/akamai/AkamaiOPEN-edgegrid-golang v1.1.0 h1:NNsy0ugDFZbu6S11NlsR4Kmko9hJ00gv9U2JHbwpf3g=
|
||||
github.com/akamai/AkamaiOPEN-edgegrid-golang v1.1.0/go.mod h1:kX6YddBkXqqywAe8c9LyvgTCyFuZCTMF4cRPQhc3Fy8=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
@@ -266,6 +270,7 @@ github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZM
|
||||
github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8=
|
||||
github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc=
|
||||
github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
|
||||
@@ -299,8 +304,10 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
|
||||
github.com/go-logr/logr v0.3.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
|
||||
github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc=
|
||||
github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
|
||||
github.com/go-logr/zapr v0.2.0/go.mod h1:qhKdvif7YF5GI9NWEpyxTSSBdGmzkNguibrdCNVPunU=
|
||||
github.com/go-logr/zapr v0.4.0 h1:uc1uML3hRYL9/ZZPdgHS/n8Nzo+eaYL/Efxkkamf7OM=
|
||||
github.com/go-logr/zapr v0.4.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
|
||||
github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
|
||||
@@ -534,6 +541,7 @@ github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq
|
||||
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
@@ -612,10 +620,13 @@ github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7
|
||||
github.com/markbates/pkger v0.17.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI=
|
||||
github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-oci8 v0.0.7/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI=
|
||||
@@ -655,6 +666,7 @@ github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY7
|
||||
github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
|
||||
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
|
||||
github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo=
|
||||
github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 h1:rzf0wL0CHVc8CEsgyygG0Mn9CNCCPZqOPaz8RiiHYQk=
|
||||
github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
@@ -701,6 +713,7 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
|
||||
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
@@ -709,6 +722,7 @@ github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa
|
||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
|
||||
github.com/onsi/gomega v1.14.0 h1:ep6kpPVwmr/nTbklSx2nrLNSIO62DoYAhnPNIMhK8gI=
|
||||
github.com/onsi/gomega v1.14.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
|
||||
@@ -807,8 +821,9 @@ github.com/rubenv/sql-migrate v0.0.0-20200616145509-8d140a17f351 h1:HXr/qUllAWv9
|
||||
github.com/rubenv/sql-migrate v0.0.0-20200616145509-8d140a17f351/go.mod h1:DCgfY80j8GYL7MLEfvcpSFvjD0L5yZq/aZUJmhZklyg=
|
||||
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
|
||||
@@ -821,7 +836,6 @@ github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
|
||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
@@ -934,17 +948,21 @@ go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0H
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0=
|
||||
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.8.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||
go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
|
||||
go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U=
|
||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
@@ -1011,6 +1029,7 @@ golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5h
|
||||
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -1047,9 +1066,11 @@ golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -1125,6 +1146,7 @@ golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapK
|
||||
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
@@ -1136,6 +1158,7 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gomodules.xyz/jsonpatch/v2 v2.1.0/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU=
|
||||
gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY=
|
||||
gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY=
|
||||
google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||
@@ -1157,6 +1180,7 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk=
|
||||
@@ -1253,6 +1277,7 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||
@@ -1270,21 +1295,29 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
k8s.io/api v0.18.0/go.mod h1:q2HRQkfDzHMBZL9l/y9rH63PkQl4vae0xRT+8prbrK8=
|
||||
k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo=
|
||||
k8s.io/api v0.20.2/go.mod h1:d7n6Ehyzx+S+cE3VhTGfVNNqtGc/oL9DCdYYahlurV8=
|
||||
k8s.io/api v0.21.0/go.mod h1:+YbrhBBGgsxbF6o6Kj4KJPJnBmAKuXDeS3E18bgHNVU=
|
||||
k8s.io/api v0.21.1/go.mod h1:FstGROTmsSHBarKc8bylzXih8BLNYTiS3TZcsoEDg2s=
|
||||
k8s.io/api v0.21.2 h1:vz7DqmRsXTCSa6pNxXwQ1IYeAZgdIsua+DZU+o+SX3Y=
|
||||
k8s.io/api v0.21.2/go.mod h1:Lv6UGJZ1rlMI1qusN8ruAp9PUBFyBwpEHAdG24vIsiU=
|
||||
k8s.io/apiextensions-apiserver v0.18.0/go.mod h1:18Cwn1Xws4xnWQNC00FLq1E350b9lUF+aOdIWDOZxgo=
|
||||
k8s.io/apiextensions-apiserver v0.20.1/go.mod h1:ntnrZV+6a3dB504qwC5PN/Yg9PBiDNt1EVqbW2kORVk=
|
||||
k8s.io/apiextensions-apiserver v0.20.2/go.mod h1:F6TXp389Xntt+LUq3vw6HFOLttPa0V8821ogLGwb6Zs=
|
||||
k8s.io/apiextensions-apiserver v0.21.0/go.mod h1:gsQGNtGkc/YoDG9loKI0V+oLZM4ljRPjc/sql5tmvzc=
|
||||
k8s.io/apiextensions-apiserver v0.21.1/go.mod h1:KESQFCGjqVcVsZ9g0xX5bacMjyX5emuWcS2arzdEouA=
|
||||
k8s.io/apiextensions-apiserver v0.21.2 h1:+exKMRep4pDrphEafRvpEi79wTnCFMqKf8LBtlA3yrE=
|
||||
k8s.io/apiextensions-apiserver v0.21.2/go.mod h1:+Axoz5/l3AYpGLlhJDfcVQzCerVYq3K3CvDMvw6X1RA=
|
||||
k8s.io/apimachinery v0.18.0/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA=
|
||||
k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
|
||||
k8s.io/apimachinery v0.20.2/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
|
||||
k8s.io/apimachinery v0.21.0/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswPY=
|
||||
k8s.io/apimachinery v0.21.1/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswPY=
|
||||
k8s.io/apimachinery v0.21.2 h1:vezUc/BHqWlQDnZ+XkrpXSmnANSLbpnlpwo0Lhk0gpc=
|
||||
k8s.io/apimachinery v0.21.2/go.mod h1:CdTY8fU/BlvAbJ2z/8kBwimGki5Zp8/fbVuLY8gJumM=
|
||||
k8s.io/apiserver v0.18.0/go.mod h1:3S2O6FeBBd6XTo0njUrLxiqk8GNy6wWOftjhJcXYnjw=
|
||||
k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU=
|
||||
k8s.io/apiserver v0.20.2/go.mod h1:2nKd93WyMhZx4Hp3RfgH2K5PhwyTrprrkWYnI7id7jA=
|
||||
k8s.io/apiserver v0.21.0/go.mod h1:w2YSn4/WIwYuxG5zJmcqtRdtqgW/J2JRgFAqps3bBpg=
|
||||
k8s.io/apiserver v0.21.1/go.mod h1:nLLYZvMWn35glJ4/FZRhzLG/3MPxAaZTgV4FJZdr+tY=
|
||||
k8s.io/apiserver v0.21.2 h1:vfGLD8biFXHzbcIEXyW3652lDwkV8tZEFJAaS2iuJlw=
|
||||
@@ -1293,22 +1326,28 @@ k8s.io/cli-runtime v0.21.0/go.mod h1:XoaHP93mGPF37MkLbjGVYqg3S1MnsFdKtiA/RZzzxOo
|
||||
k8s.io/cli-runtime v0.21.1 h1:Oj/iZxa7LLXrhzShaLNF4rFJEIEBTDHj0dJw4ra2vX4=
|
||||
k8s.io/cli-runtime v0.21.1/go.mod h1:TI9Bvl8lQWZB2KqE91QLCp9AZE4l29zNFnj/x4IX4Fw=
|
||||
k8s.io/client-go v0.18.0/go.mod h1:uQSYDYs4WhVZ9i6AIoEZuwUggLVEF64HOD37boKAtF8=
|
||||
k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y=
|
||||
k8s.io/client-go v0.20.2/go.mod h1:kH5brqWqp7HDxUFKoEgiI4v8G1xzbe9giaCenUWJzgE=
|
||||
k8s.io/client-go v0.21.0/go.mod h1:nNBytTF9qPFDEhoqgEPaarobC8QPae13bElIVHzIglA=
|
||||
k8s.io/client-go v0.21.1/go.mod h1:/kEw4RgW+3xnBGzvp9IWxKSNA+lXn3A7AuH3gdOAzLs=
|
||||
k8s.io/client-go v0.21.2 h1:Q1j4L/iMN4pTw6Y4DWppBoUxgKO8LbffEMVEV00MUp0=
|
||||
k8s.io/client-go v0.21.2/go.mod h1:HdJ9iknWpbl3vMGtib6T2PyI/VYxiZfq936WNVHBRrA=
|
||||
k8s.io/component-base v0.18.0/go.mod h1:u3BCg0z1uskkzrnAKFzulmYaEpZF7XC9Pf/uFyb1v2c=
|
||||
k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk=
|
||||
k8s.io/component-base v0.20.2/go.mod h1:pzFtCiwe/ASD0iV7ySMu8SYVJjCapNM9bjvk7ptpKh0=
|
||||
k8s.io/component-base v0.21.0/go.mod h1:qvtjz6X0USWXbgmbfXR+Agik4RZ3jv2Bgr5QnZzdPYw=
|
||||
k8s.io/component-base v0.21.1/go.mod h1:NgzFZ2qu4m1juby4TnrmpR8adRk6ka62YdH5DkIIyKA=
|
||||
k8s.io/component-base v0.21.2 h1:EsnmFFoJ86cEywC0DoIkAUiEV6fjgauNugiw1lmIjs4=
|
||||
k8s.io/component-base v0.21.2/go.mod h1:9lvmIThzdlrJj5Hp8Z/TOgIkdfsNARQ1pT+3PByuiuc=
|
||||
k8s.io/component-helpers v0.21.0/go.mod h1:tezqefP7lxfvJyR+0a+6QtVrkZ/wIkyMLK4WcQ3Cj8U=
|
||||
k8s.io/component-helpers v0.21.1/go.mod h1:FtC1flbiQlosHQrLrRUulnKxE4ajgWCGy/67fT2GRlQ=
|
||||
k8s.io/klog v0.2.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||
k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
|
||||
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
|
||||
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
||||
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||
k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||
k8s.io/klog/v2 v2.8.0 h1:Q3gmuM9hKEjefWFFYF0Mat+YyFJvsUyYuwyNNJ5C9Ts=
|
||||
k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec=
|
||||
k8s.io/kube-aggregator v0.21.0 h1:my2WYu8RJcj/ZzWAjPPnmxNRELk/iCdPjMaOmsZOeBU=
|
||||
@@ -1322,6 +1361,8 @@ k8s.io/metrics v0.21.0/go.mod h1:L3Ji9EGPP1YBbfm9sPfEXSpnj8i24bfQbAFAsW0NueQ=
|
||||
k8s.io/metrics v0.21.1/go.mod h1:pyDVLsLe++FIGDBFU80NcW4xMFsuiVTWL8Zfi7+PpNo=
|
||||
k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||
k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20210111153108-fddb29f9d009/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20210305010621-2afb4311ab10/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20210527160623-6fdb442a123b h1:MSqsVQ3pZvPGTqCjptfimO2WjG7A9un2zcpiHkA6M/s=
|
||||
k8s.io/utils v0.0.0-20210527160623-6fdb442a123b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
@@ -1330,13 +1371,18 @@ rsc.io/letsencrypt v0.0.3/go.mod h1:buyQKZ6IXrRnB7TdkHP0RyEybLx18HHyOSoTyoOLqNY=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT7lCHcxMU+mDHEm+nx46H4zuuHZkDP6icnhu0=
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.19 h1:0jaDAAxtqIrrqas4vtTqxct4xS5kHfRNycTRLTyJmVM=
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.19/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
|
||||
sigs.k8s.io/controller-runtime v0.8.3/go.mod h1:U/l+DUopBc1ecfRZ5aviA9JDmGFQKvLf5YkZNx2e0sU=
|
||||
sigs.k8s.io/controller-runtime v0.9.2 h1:MnCAsopQno6+hI9SgJHKddzXpmv2wtouZz6931Eax+Q=
|
||||
sigs.k8s.io/controller-runtime v0.9.2/go.mod h1:TxzMCHyEUpaeuOiZx/bIdc2T81vfs/aKdvJt9wuu0zk=
|
||||
sigs.k8s.io/controller-tools v0.5.0/go.mod h1:JTsstrMpxs+9BUj6eGuAaEb6SDSPTeVtUyp0jmnAM/I=
|
||||
sigs.k8s.io/controller-tools v0.6.0 h1:o2Fm1K7CmIp8OVaBtXsWB/ssBAzyoKZPPAGR3VuxaKs=
|
||||
sigs.k8s.io/controller-tools v0.6.0/go.mod h1:baRMVPrctU77F+rfAuH2uPqW93k6yQnZA2dhUOr7ihc=
|
||||
sigs.k8s.io/gateway-api v0.3.0 h1:mKbQRlRIIY3dsCCbNF9Jv30V9vvOf6SRG82l0MfJQ9U=
|
||||
sigs.k8s.io/gateway-api v0.3.0/go.mod h1:Wb8bx7QhGVZxOSEU3i9vw/JqTB5Nlai9MLMYVZeDmRQ=
|
||||
sigs.k8s.io/kustomize/api v0.8.5/go.mod h1:M377apnKT5ZHJS++6H4rQoCHmWtt6qTpp3mbe7p6OLY=
|
||||
sigs.k8s.io/kustomize/api v0.8.8 h1:G2z6JPSSjtWWgMeWSoHdXqyftJNmMmyxXpwENGoOtGE=
|
||||
sigs.k8s.io/kustomize/api v0.8.8/go.mod h1:He1zoK0nk43Pc6NlV085xDXDXTNprtcyKZVm3swsdNY=
|
||||
|
||||
+19
-2
@@ -58,6 +58,15 @@ def go_repositories():
|
||||
sum = "h1:3oJU7J3FGFmyhn8KHjmVaZCN5hxTr7GxgRue+sxIXdQ=",
|
||||
version = "v1.0.1",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_ahmetb_gen_crd_api_reference_docs",
|
||||
build_file_generation = "on",
|
||||
build_file_proto_mode = "disable",
|
||||
importpath = "github.com/ahmetb/gen-crd-api-reference-docs",
|
||||
sum = "h1:Gz+Wcvp8CATSZBy3a2yj2IdkK1/LaVfy4JJlzxdmETY=",
|
||||
version = "v0.2.1-0.20201224172655-df869c1245d4",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_akamai_akamaiopen_edgegrid_golang",
|
||||
build_file_generation = "on",
|
||||
@@ -2860,8 +2869,8 @@ def go_repositories():
|
||||
build_file_generation = "on",
|
||||
build_file_proto_mode = "disable",
|
||||
importpath = "github.com/russross/blackfriday/v2",
|
||||
sum = "h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=",
|
||||
version = "v2.0.1",
|
||||
sum = "h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=",
|
||||
version = "v2.1.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_ryanuber_columnize",
|
||||
@@ -3673,6 +3682,14 @@ def go_repositories():
|
||||
sum = "h1:o2Fm1K7CmIp8OVaBtXsWB/ssBAzyoKZPPAGR3VuxaKs=",
|
||||
version = "v0.6.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "io_k8s_sigs_gateway_api",
|
||||
build_file_generation = "on",
|
||||
build_file_proto_mode = "disable",
|
||||
importpath = "sigs.k8s.io/gateway-api",
|
||||
sum = "h1:mKbQRlRIIY3dsCCbNF9Jv30V9vvOf6SRG82l0MfJQ9U=",
|
||||
version = "v0.3.0",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "io_k8s_sigs_kustomize_api",
|
||||
|
||||
@@ -32,6 +32,8 @@ go_library(
|
||||
"@io_k8s_client_go//tools/cache:go_default_library",
|
||||
"@io_k8s_client_go//tools/record:go_default_library",
|
||||
"@io_k8s_client_go//util/workqueue:go_default_library",
|
||||
"@io_k8s_sigs_gateway_api//pkg/client/clientset/versioned:go_default_library",
|
||||
"@io_k8s_sigs_gateway_api//pkg/client/informers/externalversions:go_default_library",
|
||||
"@io_k8s_utils//clock:go_default_library",
|
||||
],
|
||||
)
|
||||
@@ -50,11 +52,11 @@ filegroup(
|
||||
"//pkg/controller/acmechallenges:all-srcs",
|
||||
"//pkg/controller/acmeorders:all-srcs",
|
||||
"//pkg/controller/cainjector:all-srcs",
|
||||
"//pkg/controller/certificate-shim:all-srcs",
|
||||
"//pkg/controller/certificaterequests:all-srcs",
|
||||
"//pkg/controller/certificates:all-srcs",
|
||||
"//pkg/controller/certificatesigningrequests:all-srcs",
|
||||
"//pkg/controller/clusterissuers:all-srcs",
|
||||
"//pkg/controller/ingress-shim:all-srcs",
|
||||
"//pkg/controller/issuers:all-srcs",
|
||||
"//pkg/controller/test:all-srcs",
|
||||
],
|
||||
|
||||
+14
-13
@@ -3,11 +3,10 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"controller.go",
|
||||
"helper.go",
|
||||
"sync.go",
|
||||
],
|
||||
importpath = "github.com/jetstack/cert-manager/pkg/controller/ingress-shim",
|
||||
importpath = "github.com/jetstack/cert-manager/pkg/controller/certificate-shim",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//pkg/api/util:go_default_library",
|
||||
@@ -24,20 +23,17 @@ go_library(
|
||||
"@io_k8s_apimachinery//pkg/api/errors:go_default_library",
|
||||
"@io_k8s_apimachinery//pkg/apis/meta/v1:go_default_library",
|
||||
"@io_k8s_apimachinery//pkg/labels:go_default_library",
|
||||
"@io_k8s_apimachinery//pkg/util/errors:go_default_library",
|
||||
"@io_k8s_apimachinery//pkg/util/runtime:go_default_library",
|
||||
"@io_k8s_client_go//kubernetes:go_default_library",
|
||||
"@io_k8s_client_go//listers/networking/v1beta1:go_default_library",
|
||||
"@io_k8s_client_go//tools/cache:go_default_library",
|
||||
"@io_k8s_apimachinery//pkg/runtime:go_default_library",
|
||||
"@io_k8s_apimachinery//pkg/runtime/schema:go_default_library",
|
||||
"@io_k8s_apimachinery//pkg/util/validation/field:go_default_library",
|
||||
"@io_k8s_client_go//tools/record:go_default_library",
|
||||
"@io_k8s_client_go//util/workqueue:go_default_library",
|
||||
"@io_k8s_sigs_gateway_api//apis/v1alpha1:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"controller_test.go",
|
||||
"helper_test.go",
|
||||
"sync_test.go",
|
||||
],
|
||||
@@ -46,17 +42,18 @@ go_test(
|
||||
"//pkg/apis/acme/v1:go_default_library",
|
||||
"//pkg/apis/certmanager/v1:go_default_library",
|
||||
"//pkg/apis/meta/v1:go_default_library",
|
||||
"//pkg/client/clientset/versioned:go_default_library",
|
||||
"//pkg/controller:go_default_library",
|
||||
"//pkg/controller/test:go_default_library",
|
||||
"//test/unit/gen:go_default_library",
|
||||
"@com_github_go_logr_logr//:go_default_library",
|
||||
"@com_github_stretchr_testify//assert:go_default_library",
|
||||
"@com_github_stretchr_testify//require:go_default_library",
|
||||
"@io_k8s_api//networking/v1beta1:go_default_library",
|
||||
"@io_k8s_apimachinery//pkg/apis/meta/v1:go_default_library",
|
||||
"@io_k8s_apimachinery//pkg/runtime:go_default_library",
|
||||
"@io_k8s_apimachinery//pkg/types:go_default_library",
|
||||
"@io_k8s_client_go//kubernetes:go_default_library",
|
||||
"@io_k8s_apimachinery//pkg/util/validation/field:go_default_library",
|
||||
"@io_k8s_client_go//testing:go_default_library",
|
||||
"@io_k8s_sigs_gateway_api//apis/v1alpha1:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -69,7 +66,11 @@ filegroup(
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//pkg/controller/certificate-shim/gateways:all-srcs",
|
||||
"//pkg/controller/certificate-shim/ingresses:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
@@ -0,0 +1,51 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["controller.go"],
|
||||
importpath = "github.com/jetstack/cert-manager/pkg/controller/certificate-shim/gateways",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//pkg/apis/certmanager/v1:go_default_library",
|
||||
"//pkg/controller:go_default_library",
|
||||
"//pkg/controller/certificate-shim:go_default_library",
|
||||
"//pkg/logs:go_default_library",
|
||||
"@io_k8s_apimachinery//pkg/api/errors:go_default_library",
|
||||
"@io_k8s_apimachinery//pkg/apis/meta/v1:go_default_library",
|
||||
"@io_k8s_apimachinery//pkg/util/runtime:go_default_library",
|
||||
"@io_k8s_client_go//tools/cache:go_default_library",
|
||||
"@io_k8s_client_go//util/workqueue:go_default_library",
|
||||
"@io_k8s_sigs_gateway_api//pkg/client/listers/apis/v1alpha1:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["controller_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/apis/certmanager/v1:go_default_library",
|
||||
"//pkg/client/clientset/versioned:go_default_library",
|
||||
"//pkg/controller/test:go_default_library",
|
||||
"@com_github_stretchr_testify//assert:go_default_library",
|
||||
"@com_github_stretchr_testify//require:go_default_library",
|
||||
"@io_k8s_apimachinery//pkg/apis/meta/v1:go_default_library",
|
||||
"@io_k8s_apimachinery//pkg/runtime:go_default_library",
|
||||
"@io_k8s_sigs_gateway_api//apis/v1alpha1:go_default_library",
|
||||
"@io_k8s_sigs_gateway_api//pkg/client/clientset/versioned:go_default_library",
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
Copyright 2020 The cert-manager 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 (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
k8sErrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
gwlisters "sigs.k8s.io/gateway-api/pkg/client/listers/apis/v1alpha1"
|
||||
|
||||
cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
|
||||
controllerpkg "github.com/jetstack/cert-manager/pkg/controller"
|
||||
shimhelper "github.com/jetstack/cert-manager/pkg/controller/certificate-shim"
|
||||
logf "github.com/jetstack/cert-manager/pkg/logs"
|
||||
)
|
||||
|
||||
const (
|
||||
ControllerName = "gateway-shim"
|
||||
|
||||
// resyncPeriod is set to 10 hours across cert-manager. These 10 hours come
|
||||
// from a discussion on the controller-runtime project that boils down to:
|
||||
// never change this without an explicit reason.
|
||||
// https://github.com/kubernetes-sigs/controller-runtime/pull/88#issuecomment-408500629
|
||||
resyncPeriod = 10 * time.Hour
|
||||
)
|
||||
|
||||
type controller struct {
|
||||
gatewayLister gwlisters.GatewayLister
|
||||
sync shimhelper.SyncFn
|
||||
|
||||
// For testing purposes.
|
||||
queue workqueue.RateLimitingInterface
|
||||
}
|
||||
|
||||
func (c *controller) Register(ctx *controllerpkg.Context) (workqueue.RateLimitingInterface, []cache.InformerSynced, error) {
|
||||
c.gatewayLister = ctx.GWShared.Networking().V1alpha1().Gateways().Lister()
|
||||
log := logf.FromContext(ctx.RootContext, ControllerName)
|
||||
c.sync = shimhelper.SyncFnFor(ctx.Recorder, log, ctx.CMClient, ctx.SharedInformerFactory.Certmanager().V1().Certificates().Lister(), ctx.IngressShimOptions)
|
||||
|
||||
// We don't need to requeue Gateways on "Deleted" events, since our Sync
|
||||
// function does nothing when the Gateway lister returns "not found". But we
|
||||
// still do it for consistency with the rest of the controllers.
|
||||
ctx.GWShared.Networking().V1alpha1().Gateways().Informer().AddEventHandler(&controllerpkg.QueuingEventHandler{
|
||||
Queue: c.queue,
|
||||
})
|
||||
|
||||
// Even thought the Gateway controller already re-queues the Gateway after
|
||||
// creating a child Certificate, we still re-queue the Gateway when we
|
||||
// receive an "Add" event for the Certificate (the workqueue de-duplicates
|
||||
// keys, so we should not worry).
|
||||
//
|
||||
// Regarding "Update" events on Certificates, we need to requeue the parent
|
||||
// Gateway because we need to check if the Certificate is still up to date.
|
||||
//
|
||||
// Regarding "Deleted" events on Certificates, we requeue the parent Gateway
|
||||
// to immediately recreate the Certificate when the Certificate is deleted.
|
||||
ctx.SharedInformerFactory.Certmanager().V1().Certificates().Informer().AddEventHandler(&controllerpkg.BlockingEventHandler{
|
||||
WorkFunc: certificateHandler(c.queue),
|
||||
})
|
||||
|
||||
mustSync := []cache.InformerSynced{
|
||||
ctx.GWShared.Networking().V1alpha1().Gateways().Informer().HasSynced,
|
||||
ctx.SharedInformerFactory.Certmanager().V1().Certificates().Informer().HasSynced,
|
||||
}
|
||||
|
||||
return c.queue, mustSync, nil
|
||||
}
|
||||
|
||||
func (c *controller) ProcessItem(ctx context.Context, key string) error {
|
||||
namespace, name, err := cache.SplitMetaNamespaceKey(key)
|
||||
if err != nil {
|
||||
runtime.HandleError(fmt.Errorf("invalid resource key: %s", key))
|
||||
return nil
|
||||
}
|
||||
|
||||
crt, err := c.gatewayLister.Gateways(namespace).Get(name)
|
||||
|
||||
if err != nil {
|
||||
if k8sErrors.IsNotFound(err) {
|
||||
runtime.HandleError(fmt.Errorf("Gateway '%s' in work queue no longer exists", key))
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
return c.sync(ctx, crt)
|
||||
}
|
||||
|
||||
// Whenever a Certificate gets updated, added or deleted, we want to reconcile
|
||||
// its parent Gateway. This parent Gateway is called "controller object". For
|
||||
// example, the following Certificate "cert-1" is controlled by the Gateway
|
||||
// "gateway-1":
|
||||
//
|
||||
// kind: Certificate
|
||||
// metadata: Note that the owner
|
||||
// namespace: cert-1 reference does not
|
||||
// ownerReferences: have a namespace,
|
||||
// - controller: true since owner refs
|
||||
// apiVersion: networking.x-k8s.io/v1alpha1 only work inside
|
||||
// kind: Gateway the same namespace.
|
||||
// name: gateway-1
|
||||
// blockOwnerDeletion: true
|
||||
// uid: 7d3897c2-ce27-4144-883a-e1b5f89bd65a
|
||||
func certificateHandler(queue workqueue.RateLimitingInterface) func(obj interface{}) {
|
||||
return func(obj interface{}) {
|
||||
crt, ok := obj.(*cmapi.Certificate)
|
||||
if !ok {
|
||||
runtime.HandleError(fmt.Errorf("not a Certificate object: %#v", obj))
|
||||
return
|
||||
}
|
||||
|
||||
ref := metav1.GetControllerOf(crt)
|
||||
if ref == nil {
|
||||
// No controller should care about orphans being deleted or
|
||||
// updated.
|
||||
return
|
||||
}
|
||||
|
||||
// We don't check the apiVersion e.g. "networking.x-k8s.io/v1alpha1"
|
||||
// because there is no chance that another object called "Gateway" be
|
||||
// the controller of a Certificate.
|
||||
if ref.Kind != "Gateway" {
|
||||
return
|
||||
}
|
||||
|
||||
queue.Add(crt.Namespace + "/" + ref.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
controllerpkg.Register(ControllerName, func(ctx *controllerpkg.Context) (controllerpkg.Interface, error) {
|
||||
return controllerpkg.NewBuilder(ctx, ControllerName).
|
||||
For(&controller{queue: workqueue.NewNamedRateLimitingQueue(controllerpkg.DefaultItemBasedRateLimiter(), ControllerName)}).
|
||||
Complete()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
Copyright 2020 The cert-manager 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 (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
testpkg "github.com/jetstack/cert-manager/pkg/controller/test"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
gwapi "sigs.k8s.io/gateway-api/apis/v1alpha1"
|
||||
gwclient "sigs.k8s.io/gateway-api/pkg/client/clientset/versioned"
|
||||
|
||||
cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
|
||||
cmclient "github.com/jetstack/cert-manager/pkg/client/clientset/versioned"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
var gatewayGVK = gwapi.SchemeGroupVersion.WithKind("Gateway")
|
||||
|
||||
func Test_controller_Register(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
existingCert *cmapi.Certificate
|
||||
givenCall func(*testing.T, cmclient.Interface, gwclient.Interface)
|
||||
expectAddCalls []interface{}
|
||||
}{
|
||||
{
|
||||
name: "gateway is re-queued when an 'Added' event is received for this gateway",
|
||||
givenCall: func(t *testing.T, _ cmclient.Interface, c gwclient.Interface) {
|
||||
_, err := c.NetworkingV1alpha1().Gateways("namespace-1").Create(context.Background(), &gwapi.Gateway{ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "namespace-1", Name: "gateway-1",
|
||||
}}, metav1.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
},
|
||||
expectAddCalls: []interface{}{"namespace-1/gateway-1"},
|
||||
},
|
||||
{
|
||||
name: "gateway is re-queued when an 'Updated' event is received for this gateway",
|
||||
givenCall: func(t *testing.T, _ cmclient.Interface, c gwclient.Interface) {
|
||||
// We can't use the gateway-api fake.NewSimpleClientset due to
|
||||
// Gateway being pluralized as "gatewaies" instead of
|
||||
// "gateways". The trick is thus to use Create instead.
|
||||
_, err := c.NetworkingV1alpha1().Gateways("namespace-1").Create(context.Background(), &gwapi.Gateway{ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "namespace-1", Name: "gateway-1",
|
||||
}}, metav1.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = c.NetworkingV1alpha1().Gateways("namespace-1").Update(context.Background(), &gwapi.Gateway{ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "namespace-1", Name: "gateway-1", Labels: map[string]string{"foo": "bar"},
|
||||
}}, metav1.UpdateOptions{})
|
||||
require.NoError(t, err)
|
||||
},
|
||||
expectAddCalls: []interface{}{"namespace-1/gateway-1", "namespace-1/gateway-1"},
|
||||
// <----- Create ------> <------ Update ----->
|
||||
},
|
||||
{
|
||||
name: "gateway is re-queued when a 'Deleted' event is received for this gateway",
|
||||
givenCall: func(t *testing.T, _ cmclient.Interface, c gwclient.Interface) {
|
||||
_, err := c.NetworkingV1alpha1().Gateways("namespace-1").Create(context.Background(), &gwapi.Gateway{ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "namespace-1", Name: "gateway-1",
|
||||
}}, metav1.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
err = c.NetworkingV1alpha1().Gateways("namespace-1").Delete(context.Background(), "gateway-1", metav1.DeleteOptions{})
|
||||
require.NoError(t, err)
|
||||
},
|
||||
expectAddCalls: []interface{}{"namespace-1/gateway-1", "namespace-1/gateway-1"},
|
||||
// <----- Create ------> <------ Delete ----->
|
||||
},
|
||||
{
|
||||
name: "gateway is re-queued when an 'Added' event is received for its child Certificate",
|
||||
givenCall: func(t *testing.T, c cmclient.Interface, _ gwclient.Interface) {
|
||||
_, err := c.CertmanagerV1().Certificates("namespace-1").Create(context.Background(), &cmapi.Certificate{ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "namespace-1", Name: "cert-1",
|
||||
OwnerReferences: []metav1.OwnerReference{*metav1.NewControllerRef(&gwapi.Gateway{ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "namespace-1", Name: "gateway-2",
|
||||
}}, gatewayGVK)},
|
||||
}}, metav1.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
},
|
||||
expectAddCalls: []interface{}{"namespace-1/gateway-2"},
|
||||
},
|
||||
{
|
||||
name: "gateway is re-queued when an 'Updated' event is received for its child Certificate",
|
||||
existingCert: &cmapi.Certificate{ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "namespace-1", Name: "cert-1",
|
||||
OwnerReferences: []metav1.OwnerReference{*metav1.NewControllerRef(&gwapi.Gateway{ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "namespace-1", Name: "gateway-2",
|
||||
}}, gatewayGVK)},
|
||||
}},
|
||||
givenCall: func(t *testing.T, c cmclient.Interface, _ gwclient.Interface) {
|
||||
_, err := c.CertmanagerV1().Certificates("namespace-1").Update(context.Background(), &cmapi.Certificate{ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "namespace-1", Name: "cert-1",
|
||||
OwnerReferences: []metav1.OwnerReference{*metav1.NewControllerRef(&gwapi.Gateway{ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "namespace-1", Name: "gateway-2",
|
||||
}}, gatewayGVK)},
|
||||
}}, metav1.UpdateOptions{})
|
||||
require.NoError(t, err)
|
||||
},
|
||||
expectAddCalls: []interface{}{"namespace-1/gateway-2"},
|
||||
},
|
||||
{
|
||||
name: "gateway is re-queued when a 'Deleted' event is received for its child Certificate",
|
||||
existingCert: &cmapi.Certificate{ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "namespace-1", Name: "cert-1",
|
||||
OwnerReferences: []metav1.OwnerReference{*metav1.NewControllerRef(&gwapi.Gateway{ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "namespace-1", Name: "gateway-2",
|
||||
}}, gatewayGVK)},
|
||||
}},
|
||||
givenCall: func(t *testing.T, c cmclient.Interface, _ gwclient.Interface) {
|
||||
// err := c.CertmanagerV1().Certificates("namespace-1").Delete(context.Background(), "cert-1", metav1.DeleteOptions{})
|
||||
// require.NoError(t, err)
|
||||
},
|
||||
expectAddCalls: []interface{}{"namespace-1/gateway-2"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
|
||||
var o []runtime.Object
|
||||
if test.existingCert != nil {
|
||||
o = append(o, test.existingCert)
|
||||
}
|
||||
|
||||
// NOTE(mael): we can't use Gateway with GWObjects because of a
|
||||
// limitation in client-go's NewSimpleClientset. It uses a heuristic
|
||||
// that wrongly guesses the resource from the Gateway kind
|
||||
// ("gatewaies" instead of "gateways"). To work around this, the
|
||||
// only way is to either use a real apiserver or to use call Create
|
||||
// instead of setting existing objects with NewSimpleClientset. See:
|
||||
// https://github.com/kubernetes/client-go/blob/7a90b0858/testing/fixture.go#L326-L331
|
||||
b := &testpkg.Builder{T: t, CertManagerObjects: o}
|
||||
|
||||
b.Init()
|
||||
|
||||
// We don't care about the HasSynced functions since we already know
|
||||
// whether they have been properly "used": if no Gateway or
|
||||
// Certificate event is received then HasSynced has not been setup
|
||||
// properly.
|
||||
mock := &mockWorkqueue{t: t}
|
||||
_, _, err := (&controller{queue: mock}).Register(b.Context)
|
||||
require.NoError(t, err)
|
||||
|
||||
b.Start()
|
||||
defer b.Stop()
|
||||
|
||||
test.givenCall(t, b.CMClient, b.GWClient)
|
||||
|
||||
// We have no way of knowing when the informers will be done adding
|
||||
// items to the queue due to the "shared informer" architecture:
|
||||
// Start(stop) does not allow you to wait for the informers to be
|
||||
// done.
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
|
||||
// We only expect 0 or 1 keys received in the queue, or 2 keys when
|
||||
// we have to create a Gateway before deleting or updating it.
|
||||
assert.Equal(t, test.expectAddCalls, mock.callsToAdd)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type mockWorkqueue struct {
|
||||
t *testing.T
|
||||
callsToAdd []interface{}
|
||||
}
|
||||
|
||||
func (m *mockWorkqueue) Add(arg0 interface{}) {
|
||||
m.callsToAdd = append(m.callsToAdd, arg0)
|
||||
}
|
||||
|
||||
func (m *mockWorkqueue) AddAfter(arg0 interface{}, arg1 time.Duration) {
|
||||
m.t.Error("workqueue.AddAfter was called but was not expected to be called")
|
||||
}
|
||||
|
||||
func (m *mockWorkqueue) AddRateLimited(arg0 interface{}) {
|
||||
m.t.Error("workqueue.AddRateLimited was called but was not expected to be called")
|
||||
}
|
||||
|
||||
func (m *mockWorkqueue) Done(arg0 interface{}) {
|
||||
m.t.Error("workqueue.Done was called but was not expected to be called")
|
||||
}
|
||||
|
||||
func (m *mockWorkqueue) Forget(arg0 interface{}) {
|
||||
m.t.Error("workqueue.Forget was called but was not expected to be called")
|
||||
}
|
||||
|
||||
func (m *mockWorkqueue) Get() (interface{}, bool) {
|
||||
m.t.Error("workqueue.Get was called but was not expected to be called")
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (m *mockWorkqueue) Len() int {
|
||||
m.t.Error("workqueue.Len was called but was not expected to be called")
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *mockWorkqueue) NumRequeues(arg0 interface{}) int {
|
||||
m.t.Error("workqueue.NumRequeues was called but was not expected to be called")
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *mockWorkqueue) ShutDown() {
|
||||
m.t.Error("workqueue.NumRequeues was called but was not expected to be called")
|
||||
}
|
||||
|
||||
func (m *mockWorkqueue) ShuttingDown() bool {
|
||||
m.t.Error("workqueue.NumRequeues was called but was not expected to be called")
|
||||
return false
|
||||
}
|
||||
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controller
|
||||
package shimhelper
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -33,7 +33,7 @@ var (
|
||||
errInvalidIngressAnnotation = errors.New("invalid ingress annotation")
|
||||
)
|
||||
|
||||
func translateIngressAnnotations(crt *cmapi.Certificate, annotations map[string]string) error {
|
||||
func translateAnnotations(crt *cmapi.Certificate, annotations map[string]string) error {
|
||||
if crt == nil {
|
||||
return errNilCertificate
|
||||
}
|
||||
+2
-2
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controller
|
||||
package shimhelper
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -110,7 +110,7 @@ func TestTranslateIngressAnnotations(t *testing.T) {
|
||||
}
|
||||
crt := tc.crt.DeepCopy()
|
||||
|
||||
err := translateIngressAnnotations(crt, tc.annotations)
|
||||
err := translateAnnotations(crt, tc.annotations)
|
||||
|
||||
if tc.expectedError != nil {
|
||||
assertErrorIs(t, err, tc.expectedError)
|
||||
@@ -0,0 +1,51 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["controller.go"],
|
||||
importpath = "github.com/jetstack/cert-manager/pkg/controller/certificate-shim/ingresses",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//pkg/apis/certmanager/v1:go_default_library",
|
||||
"//pkg/controller:go_default_library",
|
||||
"//pkg/controller/certificate-shim:go_default_library",
|
||||
"//pkg/logs:go_default_library",
|
||||
"@io_k8s_apimachinery//pkg/api/errors:go_default_library",
|
||||
"@io_k8s_apimachinery//pkg/apis/meta/v1:go_default_library",
|
||||
"@io_k8s_apimachinery//pkg/util/runtime:go_default_library",
|
||||
"@io_k8s_client_go//listers/networking/v1beta1:go_default_library",
|
||||
"@io_k8s_client_go//tools/cache:go_default_library",
|
||||
"@io_k8s_client_go//util/workqueue:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["controller_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/apis/certmanager/v1:go_default_library",
|
||||
"//pkg/client/clientset/versioned:go_default_library",
|
||||
"//pkg/controller/test:go_default_library",
|
||||
"@com_github_stretchr_testify//assert:go_default_library",
|
||||
"@com_github_stretchr_testify//require:go_default_library",
|
||||
"@io_k8s_api//networking/v1beta1:go_default_library",
|
||||
"@io_k8s_apimachinery//pkg/apis/meta/v1:go_default_library",
|
||||
"@io_k8s_apimachinery//pkg/runtime:go_default_library",
|
||||
"@io_k8s_client_go//kubernetes:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
+12
-40
@@ -20,20 +20,16 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
k8sErrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
networkinglisters "k8s.io/client-go/listers/networking/v1beta1"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/tools/record"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
|
||||
cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
|
||||
clientset "github.com/jetstack/cert-manager/pkg/client/clientset/versioned"
|
||||
cmlisters "github.com/jetstack/cert-manager/pkg/client/listers/certmanager/v1"
|
||||
controllerpkg "github.com/jetstack/cert-manager/pkg/controller"
|
||||
shimhelper "github.com/jetstack/cert-manager/pkg/controller/certificate-shim"
|
||||
logf "github.com/jetstack/cert-manager/pkg/logs"
|
||||
)
|
||||
|
||||
@@ -41,32 +37,20 @@ const (
|
||||
ControllerName = "ingress-shim"
|
||||
)
|
||||
|
||||
type defaults struct {
|
||||
autoCertificateAnnotations []string
|
||||
issuerName, issuerKind, issuerGroup string
|
||||
}
|
||||
|
||||
type controller struct {
|
||||
kClient kubernetes.Interface
|
||||
cmClient clientset.Interface
|
||||
|
||||
recorder record.EventRecorder
|
||||
log logr.Logger
|
||||
|
||||
ingressLister networkinglisters.IngressLister
|
||||
certificateLister cmlisters.CertificateLister
|
||||
|
||||
defaults defaults
|
||||
ingressLister networkinglisters.IngressLister
|
||||
sync shimhelper.SyncFn
|
||||
}
|
||||
|
||||
// Register registers and constructs the controller using the provided context.
|
||||
// It returns the workqueue to be used to enqueue items, a list of
|
||||
// InformerSynced functions that must be synced, or an error.
|
||||
func (c *controller) Register(ctx *controllerpkg.Context) (workqueue.RateLimitingInterface, []cache.InformerSynced, error) {
|
||||
kShared := ctx.KubeSharedInformerFactory
|
||||
cmShared := ctx.SharedInformerFactory
|
||||
|
||||
c.log = logf.FromContext(ctx.RootContext, ControllerName)
|
||||
c.ingressLister = kShared.Networking().V1beta1().Ingresses().Lister()
|
||||
|
||||
log := logf.FromContext(ctx.RootContext, ControllerName)
|
||||
c.sync = shimhelper.SyncFnFor(ctx.Recorder, log, ctx.CMClient, cmShared.Certmanager().V1().Certificates().Lister(), ctx.IngressShimOptions)
|
||||
|
||||
queue := workqueue.NewNamedRateLimitingQueue(controllerpkg.DefaultItemBasedRateLimiter(), ControllerName)
|
||||
|
||||
mustSync := []cache.InformerSynced{
|
||||
@@ -74,9 +58,6 @@ func (c *controller) Register(ctx *controllerpkg.Context) (workqueue.RateLimitin
|
||||
cmShared.Certmanager().V1().Certificates().Informer().HasSynced,
|
||||
}
|
||||
|
||||
c.ingressLister = kShared.Networking().V1beta1().Ingresses().Lister()
|
||||
c.certificateLister = cmShared.Certmanager().V1().Certificates().Lister()
|
||||
|
||||
// We still requeue on "Deleted" for consistency with the rest of the
|
||||
// controllers, but we don't actually need to. "Deleted" is only emitted
|
||||
// after the apiserver has removed the object entirely from etcd; if we had
|
||||
@@ -100,16 +81,6 @@ func (c *controller) Register(ctx *controllerpkg.Context) (workqueue.RateLimitin
|
||||
WorkFunc: certificateHandler(queue),
|
||||
})
|
||||
|
||||
c.kClient = ctx.Client
|
||||
c.cmClient = ctx.CMClient
|
||||
c.recorder = ctx.Recorder
|
||||
c.defaults = defaults{
|
||||
ctx.DefaultAutoCertificateAnnotations,
|
||||
ctx.DefaultIssuerName,
|
||||
ctx.DefaultIssuerKind,
|
||||
ctx.DefaultIssuerGroup,
|
||||
}
|
||||
|
||||
return queue, mustSync, nil
|
||||
}
|
||||
|
||||
@@ -136,16 +107,17 @@ func (c *controller) ProcessItem(ctx context.Context, key string) error {
|
||||
|
||||
// Whenever a Certificate gets updated, added or deleted, we want to reconcile
|
||||
// its parent Ingress. This parent Ingress is called "controller object". For
|
||||
// example, the following Certificate is controlled by the Ingress "example":
|
||||
// example, the following Certificate "cert-1" is controlled by the Ingress
|
||||
// "ingress-1":
|
||||
//
|
||||
// kind: Certificate
|
||||
// metadata: Note that the owner
|
||||
// namespace: cert-that-was-deleted reference does not
|
||||
// namespace: cert-1 reference does not
|
||||
// ownerReferences: have a namespace,
|
||||
// - controller: true since owner refs
|
||||
// apiVersion: networking.k8s.io/v1beta1 only work inside
|
||||
// kind: Ingress the same namespace.
|
||||
// name: example
|
||||
// name: ingress-1
|
||||
// blockOwnerDeletion: true
|
||||
// uid: 7d3897c2-ce27-4144-883a-e1b5f89bd65a
|
||||
func certificateHandler(queue workqueue.RateLimitingInterface) func(obj interface{}) {
|
||||
+3
-1
@@ -33,6 +33,8 @@ import (
|
||||
cmclient "github.com/jetstack/cert-manager/pkg/client/clientset/versioned"
|
||||
)
|
||||
|
||||
var ingressGVK = networkingv1beta1.SchemeGroupVersion.WithKind("Ingress")
|
||||
|
||||
func Test_controller_Register(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -129,7 +131,7 @@ func Test_controller_Register(t *testing.T) {
|
||||
b.Init()
|
||||
|
||||
// We don't care about the HasSynced functions since we already know
|
||||
// whether they have been properly "used": if no Ingress or
|
||||
// whether they have been properly "used": if no Gateway or
|
||||
// Certificate event is received then HasSynced has not been setup
|
||||
// properly.
|
||||
queue, _, err := (&controller{}).Register(b.Context)
|
||||
@@ -0,0 +1,598 @@
|
||||
/*
|
||||
Copyright 2020 The cert-manager 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 shimhelper
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
networkingv1beta1 "k8s.io/api/networking/v1beta1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/tools/record"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
cmacme "github.com/jetstack/cert-manager/pkg/apis/acme/v1"
|
||||
cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
|
||||
cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1"
|
||||
clientset "github.com/jetstack/cert-manager/pkg/client/clientset/versioned"
|
||||
cmlisters "github.com/jetstack/cert-manager/pkg/client/listers/certmanager/v1"
|
||||
"github.com/jetstack/cert-manager/pkg/controller"
|
||||
logf "github.com/jetstack/cert-manager/pkg/logs"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
gwapi "sigs.k8s.io/gateway-api/apis/v1alpha1"
|
||||
)
|
||||
|
||||
const (
|
||||
reasonBadConfig = "BadConfig"
|
||||
reasonCreateCertificate = "CreateCertificate"
|
||||
reasonUpdateCertificate = "UpdateCertificate"
|
||||
reasonDeleteCertificate = "DeleteCertificate"
|
||||
)
|
||||
|
||||
var ingressGVK = networkingv1beta1.SchemeGroupVersion.WithKind("Ingress")
|
||||
var gatewayGVK = gwapi.SchemeGroupVersion.WithKind("Gateway")
|
||||
|
||||
// SyncFn is the reconciliation function passed to a certificate-shim's
|
||||
// controller.
|
||||
type SyncFn func(context.Context, metav1.Object) error
|
||||
|
||||
// SyncFnFor contains logic to reconcile any "Ingress-like" object.
|
||||
//
|
||||
// An "Ingress-like" object is a resource such as an Ingress, a Gateway or an
|
||||
// HTTPRoute. Due to their similarity, the reconciliation function for them is
|
||||
// common. Reconciling an Ingress-like object means looking at its annotations
|
||||
// and creating a Certificate with matching DNS names and secretNames from the
|
||||
// TLS configuration of the Ingress-like object.
|
||||
func SyncFnFor(
|
||||
rec record.EventRecorder,
|
||||
log logr.Logger,
|
||||
cmClient clientset.Interface,
|
||||
cmLister cmlisters.CertificateLister,
|
||||
defaults controller.IngressShimOptions,
|
||||
) SyncFn {
|
||||
return func(ctx context.Context, ingLike metav1.Object) error {
|
||||
log := logf.WithResource(log, ingLike)
|
||||
ctx = logf.NewContext(ctx, log)
|
||||
|
||||
// rec.Eventf requires a runtime.Object, not a metav1.Object.
|
||||
ingLikeObj, ok := ingLike.(runtime.Object)
|
||||
if !ok {
|
||||
return fmt.Errorf("programmer mistake: %T was expected to be a runtime.Object", ingLike)
|
||||
}
|
||||
|
||||
// The flag --auto-certificate-annotations as well as the default
|
||||
// "kubernetes.io/tls-acme" annotation are only enabled for the Ingress
|
||||
// resource.
|
||||
var autoAnnotations []string
|
||||
switch ingLike.(type) {
|
||||
case *networkingv1beta1.Ingress:
|
||||
autoAnnotations = defaults.DefaultAutoCertificateAnnotations
|
||||
}
|
||||
|
||||
if !hasShimAnnotation(ingLike, autoAnnotations) {
|
||||
logf.V(logf.DebugLevel).Infof("not syncing ingress resource as it does not contain a %q or %q annotation",
|
||||
cmapi.IngressIssuerNameAnnotationKey, cmapi.IngressClusterIssuerNameAnnotationKey)
|
||||
return nil
|
||||
}
|
||||
|
||||
issuerName, issuerKind, issuerGroup, err := issuerForIngressLike(defaults, ingLike)
|
||||
if err != nil {
|
||||
log.Error(err, "failed to determine issuer to be used for ingress resource")
|
||||
rec.Eventf(ingLikeObj, corev1.EventTypeWarning, reasonBadConfig, "Could not determine issuer for ingress due to bad annotations: %s",
|
||||
err)
|
||||
return nil
|
||||
}
|
||||
|
||||
err = validateIngressLike(ingLike).ToAggregate()
|
||||
if err != nil {
|
||||
rec.Eventf(ingLikeObj, corev1.EventTypeWarning, reasonBadConfig, err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
newCrts, updateCrts, err := buildCertificates(rec, log, cmLister, ingLike, issuerName, issuerKind, issuerGroup)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, crt := range newCrts {
|
||||
_, err := cmClient.CertmanagerV1().Certificates(crt.Namespace).Create(ctx, crt, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rec.Eventf(ingLikeObj, corev1.EventTypeNormal, reasonCreateCertificate, "Successfully created Certificate %q", crt.Name)
|
||||
}
|
||||
|
||||
for _, crt := range updateCrts {
|
||||
_, err := cmClient.CertmanagerV1().Certificates(crt.Namespace).Update(ctx, crt, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rec.Eventf(ingLikeObj, corev1.EventTypeNormal, reasonUpdateCertificate, "Successfully updated Certificate %q", crt.Name)
|
||||
}
|
||||
|
||||
unrequiredCrts, err := findUnrequiredCertificates(cmLister, ingLike)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, crt := range unrequiredCrts {
|
||||
err = cmClient.CertmanagerV1().Certificates(crt.Namespace).Delete(ctx, crt.Name, metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rec.Eventf(ingLikeObj, corev1.EventTypeNormal, reasonDeleteCertificate, "Successfully deleted unrequired Certificate %q", crt.Name)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func validateIngressLike(ingLike metav1.Object) field.ErrorList {
|
||||
switch o := ingLike.(type) {
|
||||
case *networkingv1beta1.Ingress:
|
||||
return checkForDuplicateSecretNames(field.NewPath("spec", "tls"), o.Spec.TLS)
|
||||
case *gwapi.Gateway:
|
||||
return nil
|
||||
default:
|
||||
panic(fmt.Errorf("programmer mistake: validateIngressLike can't handle %T, expected Ingress or Gateway", ingLike))
|
||||
}
|
||||
}
|
||||
|
||||
func checkForDuplicateSecretNames(path *field.Path, tlsBlocks []networkingv1beta1.IngressTLS) field.ErrorList {
|
||||
var errs field.ErrorList
|
||||
// We can't let two TLS blocks share the same secretName because we decided
|
||||
// to create one Certificate for each TLS block. For example:
|
||||
//
|
||||
// kind: Ingress
|
||||
// spec:
|
||||
// tls:
|
||||
// - hosts: [example.com]
|
||||
// secretName: example-tls
|
||||
// - hosts: [www.example.com]
|
||||
// secretName: example-tls
|
||||
//
|
||||
// With this Ingress, cert-manager would create two Certificates with the
|
||||
// same name, which would fail.
|
||||
//
|
||||
// We keep track of the order of the secret names due to Go iterating on
|
||||
// maps in a non-deterministic way. We also keep track of each secretName's
|
||||
// JSON path just so that we can give a nice error message.
|
||||
var secretNames []string
|
||||
secretPaths := make(map[string][]*field.Path)
|
||||
for i, tls := range tlsBlocks {
|
||||
if _, already := secretPaths[tls.SecretName]; !already {
|
||||
secretNames = append(secretNames, tls.SecretName)
|
||||
}
|
||||
secretPaths[tls.SecretName] = append(secretPaths[tls.SecretName], path.Index(i).Child("secretName"))
|
||||
}
|
||||
|
||||
for _, name := range secretNames {
|
||||
paths := secretPaths[name]
|
||||
if len(paths) > 1 {
|
||||
// We could use field.Duplicate, but that would prevent us from
|
||||
// giving details as to what this duplicate is about.
|
||||
errs = append(errs, field.Invalid(paths[0], name,
|
||||
fmt.Sprintf("this secret name must only appear in a single TLS entry but is also used in %s", paths[1])))
|
||||
}
|
||||
}
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
func validateIngressTLSBlock(path *field.Path, tlsBlock networkingv1beta1.IngressTLS) field.ErrorList {
|
||||
var errs field.ErrorList
|
||||
|
||||
if len(tlsBlock.Hosts) == 0 {
|
||||
errs = append(errs, field.Required(path.Child("hosts"), ""))
|
||||
}
|
||||
if tlsBlock.SecretName == "" {
|
||||
errs = append(errs, field.Required(path.Child("secretName"), ""))
|
||||
}
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
func validateGatewayListenerBlock(path *field.Path, l gwapi.Listener) field.ErrorList {
|
||||
var errs field.ErrorList
|
||||
|
||||
if l.Hostname == nil || *l.Hostname == "" {
|
||||
errs = append(errs, field.Required(path.Child("hostname"), "the hostname cannot be empty"))
|
||||
}
|
||||
|
||||
if l.TLS == nil {
|
||||
errs = append(errs, field.Required(path.Child("tls"), "the TLS block cannot be empty"))
|
||||
return errs
|
||||
}
|
||||
|
||||
if l.TLS.CertificateRef == nil {
|
||||
errs = append(errs, field.Required(path.Child("tls").Child("certificateRef"),
|
||||
"listener is missing a certificateRef"))
|
||||
} else {
|
||||
if l.TLS.CertificateRef.Group != "core" {
|
||||
errs = append(errs, field.NotSupported(path.Child("tls").Child("certificateRef").Child("group"),
|
||||
l.TLS.CertificateRef.Group, []string{"core"}))
|
||||
}
|
||||
|
||||
if l.TLS.CertificateRef.Kind != "Secret" {
|
||||
errs = append(errs, field.NotSupported(path.Child("tls").Child("certificateRef").Child("kind"),
|
||||
l.TLS.CertificateRef.Kind, []string{"Secret"}))
|
||||
}
|
||||
|
||||
if l.TLS.CertificateRef.Name == "" {
|
||||
errs = append(errs, field.Required(path.Child("tls").Child("certificateRef").Child("name"),
|
||||
"the Secret name cannot be empty"))
|
||||
}
|
||||
}
|
||||
|
||||
if l.TLS.Mode == nil {
|
||||
errs = append(errs, field.Required(path.Child("tls").Child("mode"),
|
||||
"the mode field is required"))
|
||||
} else {
|
||||
if *l.TLS.Mode != gwapi.TLSModeTerminate {
|
||||
errs = append(errs, field.NotSupported(path.Child("tls").Child("mode"),
|
||||
*l.TLS.Mode, []string{string(gwapi.TLSModeTerminate)}))
|
||||
}
|
||||
}
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
func buildCertificates(
|
||||
rec record.EventRecorder,
|
||||
log logr.Logger,
|
||||
cmLister cmlisters.CertificateLister,
|
||||
ingLike metav1.Object,
|
||||
issuerName, issuerKind, issuerGroup string,
|
||||
) (new, update []*cmapi.Certificate, _ error) {
|
||||
|
||||
var newCrts []*cmapi.Certificate
|
||||
var updateCrts []*cmapi.Certificate
|
||||
|
||||
type certificateShimInfo struct {
|
||||
// tlsHosts key = secret ref, value = dns host names
|
||||
|
||||
gvk schema.GroupVersionKind
|
||||
}
|
||||
|
||||
tlsHosts := make(map[corev1.ObjectReference][]string)
|
||||
switch ingLike := ingLike.(type) {
|
||||
case *networkingv1beta1.Ingress:
|
||||
for i, tls := range ingLike.Spec.TLS {
|
||||
path := field.NewPath("spec", "tls").Index(i)
|
||||
err := validateIngressTLSBlock(path, tls).ToAggregate()
|
||||
if err != nil {
|
||||
rec.Eventf(ingLike, corev1.EventTypeWarning, reasonBadConfig, "Skipped a TLS block: "+err.Error())
|
||||
continue
|
||||
}
|
||||
tlsHosts[corev1.ObjectReference{
|
||||
Namespace: ingLike.Namespace,
|
||||
Name: tls.SecretName,
|
||||
}] = tls.Hosts
|
||||
}
|
||||
case *gwapi.Gateway:
|
||||
for i, l := range ingLike.Spec.Listeners {
|
||||
err := validateGatewayListenerBlock(field.NewPath("spec", "listeners").Index(i), l).ToAggregate()
|
||||
if err != nil {
|
||||
rec.Eventf(ingLike, corev1.EventTypeWarning, reasonBadConfig, "Skipped a listener block: "+err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
secretRef := corev1.ObjectReference{
|
||||
Namespace: ingLike.Namespace,
|
||||
Name: l.TLS.CertificateRef.Name,
|
||||
}
|
||||
// Gateway API hostname explicitly disallows IP addresses, so this
|
||||
// should be OK.
|
||||
tlsHosts[secretRef] = append(tlsHosts[secretRef], fmt.Sprintf("%s", *l.Hostname))
|
||||
}
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("buildCertificates: expected ingress or gateway, got %T", ingLike)
|
||||
}
|
||||
|
||||
for secretRef, hosts := range tlsHosts {
|
||||
existingCrt, err := cmLister.Certificates(secretRef.Namespace).Get(secretRef.Name)
|
||||
if !apierrors.IsNotFound(err) && err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var controllerGVK schema.GroupVersionKind
|
||||
switch ingLike.(type) {
|
||||
case *networkingv1beta1.Ingress:
|
||||
controllerGVK = ingressGVK
|
||||
case *gwapi.Gateway:
|
||||
controllerGVK = gatewayGVK
|
||||
}
|
||||
|
||||
crt := &cmapi.Certificate{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: secretRef.Name,
|
||||
Namespace: secretRef.Namespace,
|
||||
Labels: ingLike.GetLabels(),
|
||||
OwnerReferences: []metav1.OwnerReference{*metav1.NewControllerRef(ingLike, controllerGVK)},
|
||||
},
|
||||
Spec: cmapi.CertificateSpec{
|
||||
DNSNames: hosts,
|
||||
SecretName: secretRef.Name,
|
||||
IssuerRef: cmmeta.ObjectReference{
|
||||
Name: issuerName,
|
||||
Kind: issuerKind,
|
||||
Group: issuerGroup,
|
||||
},
|
||||
Usages: cmapi.DefaultKeyUsages(),
|
||||
},
|
||||
}
|
||||
|
||||
switch o := ingLike.(type) {
|
||||
case *networkingv1beta1.Ingress:
|
||||
ingLike = o.DeepCopy()
|
||||
case *gwapi.Gateway:
|
||||
ingLike = o.DeepCopy()
|
||||
}
|
||||
setIssuerSpecificConfig(crt, ingLike)
|
||||
|
||||
if err := translateAnnotations(crt, ingLike.GetAnnotations()); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// check if a Certificate for this TLS entry already exists, and if it
|
||||
// does then skip this entry
|
||||
if existingCrt != nil {
|
||||
log := logf.WithRelatedResource(log, existingCrt)
|
||||
log.V(logf.DebugLevel).Info("certificate already exists for this object, ensuring it is up to date")
|
||||
|
||||
if metav1.GetControllerOf(existingCrt) == nil {
|
||||
log.V(logf.InfoLevel).Info("certificate resource has no owner. refusing to update non-owned certificate resource for object")
|
||||
continue
|
||||
}
|
||||
|
||||
if !metav1.IsControlledBy(existingCrt, ingLike) {
|
||||
log.V(logf.InfoLevel).Info("certificate resource is not owned by this object. refusing to update non-owned certificate resource for object")
|
||||
continue
|
||||
}
|
||||
|
||||
if !certNeedsUpdate(existingCrt, crt) {
|
||||
log.V(logf.DebugLevel).Info("certificate resource is already up to date for object")
|
||||
continue
|
||||
}
|
||||
|
||||
updateCrt := existingCrt.DeepCopy()
|
||||
|
||||
updateCrt.Spec = crt.Spec
|
||||
updateCrt.Labels = crt.Labels
|
||||
|
||||
setIssuerSpecificConfig(crt, ingLike)
|
||||
|
||||
updateCrts = append(updateCrts, updateCrt)
|
||||
} else {
|
||||
|
||||
newCrts = append(newCrts, crt)
|
||||
}
|
||||
}
|
||||
return newCrts, updateCrts, nil
|
||||
}
|
||||
|
||||
func findUnrequiredCertificates(list cmlisters.CertificateLister, ingLike metav1.Object) ([]*cmapi.Certificate, error) {
|
||||
crts, err := list.Certificates(ingLike.GetNamespace()).List(labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var unrequired []*cmapi.Certificate
|
||||
for _, crt := range crts {
|
||||
if isUnrequiredCertificate(crt, ingLike) {
|
||||
unrequired = append(unrequired, crt)
|
||||
}
|
||||
}
|
||||
|
||||
return unrequired, nil
|
||||
}
|
||||
|
||||
func isUnrequiredCertificate(crt *cmapi.Certificate, ingLike metav1.Object) bool {
|
||||
if !metav1.IsControlledBy(crt, ingLike) {
|
||||
return false
|
||||
}
|
||||
|
||||
switch o := ingLike.(type) {
|
||||
case *networkingv1beta1.Ingress:
|
||||
for _, tls := range o.Spec.TLS {
|
||||
if crt.Spec.SecretName == tls.SecretName {
|
||||
return false
|
||||
}
|
||||
}
|
||||
case *gwapi.Gateway:
|
||||
for _, l := range o.Spec.Listeners {
|
||||
if crt.Spec.SecretName == l.TLS.CertificateRef.Name {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// certNeedsUpdate checks and returns true if two Certificates differ.
|
||||
func certNeedsUpdate(a, b *cmapi.Certificate) bool {
|
||||
if a.Name != b.Name {
|
||||
return true
|
||||
}
|
||||
|
||||
// TODO: we may need to allow users to edit the managed Certificate resources
|
||||
// to add their own labels directly.
|
||||
// Right now, we'll reset/remove the label values back automatically.
|
||||
// Let's hope no other controllers do this automatically, else we'll start fighting...
|
||||
if !reflect.DeepEqual(a.Labels, b.Labels) {
|
||||
return true
|
||||
}
|
||||
|
||||
if a.Spec.CommonName != b.Spec.CommonName {
|
||||
return true
|
||||
}
|
||||
|
||||
if len(a.Spec.DNSNames) != len(b.Spec.DNSNames) {
|
||||
return true
|
||||
}
|
||||
|
||||
for i := range a.Spec.DNSNames {
|
||||
if a.Spec.DNSNames[i] != b.Spec.DNSNames[i] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if a.Spec.SecretName != b.Spec.SecretName {
|
||||
return true
|
||||
}
|
||||
|
||||
if a.Spec.IssuerRef.Name != b.Spec.IssuerRef.Name {
|
||||
return true
|
||||
}
|
||||
|
||||
if a.Spec.IssuerRef.Kind != b.Spec.IssuerRef.Kind {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func setIssuerSpecificConfig(crt *cmapi.Certificate, ingLike metav1.Object) {
|
||||
ingAnnotations := ingLike.GetAnnotations()
|
||||
if ingAnnotations == nil {
|
||||
ingAnnotations = map[string]string{}
|
||||
}
|
||||
|
||||
// for ACME issuers
|
||||
editInPlaceVal := ingAnnotations[cmacme.IngressEditInPlaceAnnotationKey]
|
||||
editInPlace := editInPlaceVal == "true"
|
||||
if editInPlace {
|
||||
if crt.Annotations == nil {
|
||||
crt.Annotations = make(map[string]string)
|
||||
}
|
||||
crt.Annotations[cmacme.ACMECertificateHTTP01IngressNameOverride] = ingLike.GetName()
|
||||
// set IssueTemporaryCertificateAnnotation to true in order to behave
|
||||
// better when ingress-gce is being used.
|
||||
crt.Annotations[cmapi.IssueTemporaryCertificateAnnotation] = "true"
|
||||
}
|
||||
|
||||
ingressClassVal, hasIngressClassVal := ingAnnotations[cmapi.IngressACMEIssuerHTTP01IngressClassAnnotationKey]
|
||||
if hasIngressClassVal {
|
||||
if crt.Annotations == nil {
|
||||
crt.Annotations = make(map[string]string)
|
||||
}
|
||||
crt.Annotations[cmacme.ACMECertificateHTTP01IngressClassOverride] = ingressClassVal
|
||||
}
|
||||
|
||||
ingLike.SetAnnotations(ingAnnotations)
|
||||
}
|
||||
|
||||
// hasShimAnnotation returns true if this ingress-like object contains one of
|
||||
// the annotations "cert-manager.io/issuer", "cert-manager.io/cluster-issuer",
|
||||
// or one of the annotations provided with --auto-certificate-annotations (which
|
||||
// default to "kubernetes.io/tls-acme").
|
||||
func hasShimAnnotation(ingLike metav1.Object, autoCertificateAnnotations []string) bool {
|
||||
annotations := ingLike.GetAnnotations()
|
||||
if annotations == nil {
|
||||
annotations = map[string]string{}
|
||||
}
|
||||
if _, ok := annotations[cmapi.IngressIssuerNameAnnotationKey]; ok {
|
||||
return true
|
||||
}
|
||||
if _, ok := annotations[cmapi.IngressClusterIssuerNameAnnotationKey]; ok {
|
||||
return true
|
||||
}
|
||||
for _, x := range autoCertificateAnnotations {
|
||||
if s, ok := annotations[x]; ok {
|
||||
if b, _ := strconv.ParseBool(s); b {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// issuerForIngressLike determines the Issuer that should be specified on a
|
||||
// Certificate created for the given ingress-like resource. If one is not set,
|
||||
// the default issuer given to the controller is used.
|
||||
func issuerForIngressLike(defaults controller.IngressShimOptions, ingLike metav1.Object) (name, kind, group string, err error) {
|
||||
var errs []string
|
||||
|
||||
name = defaults.DefaultIssuerName
|
||||
kind = defaults.DefaultIssuerKind
|
||||
group = defaults.DefaultIssuerGroup
|
||||
|
||||
annotations := ingLike.GetAnnotations()
|
||||
|
||||
if annotations == nil {
|
||||
annotations = map[string]string{}
|
||||
}
|
||||
|
||||
issuerName, issuerNameOK := annotations[cmapi.IngressIssuerNameAnnotationKey]
|
||||
if issuerNameOK {
|
||||
name = issuerName
|
||||
kind = cmapi.IssuerKind
|
||||
}
|
||||
|
||||
clusterIssuerName, clusterIssuerNameOK := annotations[cmapi.IngressClusterIssuerNameAnnotationKey]
|
||||
if clusterIssuerNameOK {
|
||||
name = clusterIssuerName
|
||||
kind = cmapi.ClusterIssuerKind
|
||||
}
|
||||
|
||||
kindName, kindNameOK := annotations[cmapi.IssuerKindAnnotationKey]
|
||||
if kindNameOK {
|
||||
kind = kindName
|
||||
}
|
||||
|
||||
groupName, groupNameOK := annotations[cmapi.IssuerGroupAnnotationKey]
|
||||
if groupNameOK {
|
||||
group = groupName
|
||||
}
|
||||
|
||||
if len(name) == 0 {
|
||||
errs = append(errs, "failed to determine issuer name to be used for ingress resource")
|
||||
}
|
||||
|
||||
if issuerNameOK && clusterIssuerNameOK {
|
||||
errs = append(errs,
|
||||
fmt.Sprintf("both %q and %q may not be set",
|
||||
cmapi.IngressIssuerNameAnnotationKey, cmapi.IngressClusterIssuerNameAnnotationKey))
|
||||
}
|
||||
|
||||
if clusterIssuerNameOK && groupNameOK {
|
||||
errs = append(errs,
|
||||
fmt.Sprintf("both %q and %q may not be set",
|
||||
cmapi.IngressClusterIssuerNameAnnotationKey, cmapi.IssuerGroupAnnotationKey))
|
||||
}
|
||||
|
||||
if clusterIssuerNameOK && kindNameOK {
|
||||
errs = append(errs,
|
||||
fmt.Sprintf("both %q and %q may not be set",
|
||||
cmapi.IngressClusterIssuerNameAnnotationKey, cmapi.IssuerKindAnnotationKey))
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
return "", "", "", errors.New(strings.Join(errs, ", "))
|
||||
}
|
||||
|
||||
return name, kind, group, nil
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -26,6 +26,8 @@ import (
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/record"
|
||||
"k8s.io/utils/clock"
|
||||
gwclient "sigs.k8s.io/gateway-api/pkg/client/clientset/versioned"
|
||||
gwinformers "sigs.k8s.io/gateway-api/pkg/client/informers/externalversions"
|
||||
|
||||
"github.com/jetstack/cert-manager/pkg/acme/accounts"
|
||||
clientset "github.com/jetstack/cert-manager/pkg/client/clientset/versioned"
|
||||
@@ -50,6 +52,9 @@ type Context struct {
|
||||
Client kubernetes.Interface
|
||||
// CMClient is a cert-manager clientset
|
||||
CMClient clientset.Interface
|
||||
// GWClient is a GatewayAPI clientset.
|
||||
GWClient gwclient.Interface
|
||||
|
||||
// Recorder to record events to
|
||||
Recorder record.EventRecorder
|
||||
|
||||
@@ -60,6 +65,10 @@ type Context struct {
|
||||
// instances
|
||||
SharedInformerFactory informers.SharedInformerFactory
|
||||
|
||||
// The Gateway API is an external CRD, which means its shared informers are
|
||||
// not available in controllerpkg.Context.
|
||||
GWShared gwinformers.SharedInformerFactory
|
||||
|
||||
// Namespace is the namespace to operate within.
|
||||
// If unset, operates on all namespaces
|
||||
Namespace string
|
||||
@@ -126,8 +135,10 @@ type ACMEOptions struct {
|
||||
DNS01CheckRetryPeriod time.Duration
|
||||
}
|
||||
|
||||
// IngressShimOptions contain default Issuer GVK config for the certificate-shim controllers.
|
||||
// These are set from the cmd cli flags, allowing the controllers to support legacy annotations
|
||||
// such as `kubernetes.io/tls-acme`.
|
||||
type IngressShimOptions struct {
|
||||
// Default issuer/certificates details consumed by ingress-shim
|
||||
DefaultIssuerName string
|
||||
DefaultIssuerKind string
|
||||
DefaultIssuerGroup string
|
||||
|
||||
@@ -1,408 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The cert-manager 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 (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
networkingv1beta1 "k8s.io/api/networking/v1beta1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
|
||||
cmacme "github.com/jetstack/cert-manager/pkg/apis/acme/v1"
|
||||
cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
|
||||
cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1"
|
||||
logf "github.com/jetstack/cert-manager/pkg/logs"
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
reasonBadConfig = "BadConfig"
|
||||
reasonCreateCertificate = "CreateCertificate"
|
||||
reasonUpdateCertificate = "UpdateCertificate"
|
||||
reasonDeleteCertificate = "DeleteCertificate"
|
||||
)
|
||||
|
||||
var ingressGVK = networkingv1beta1.SchemeGroupVersion.WithKind("Ingress")
|
||||
|
||||
func (c *controller) sync(ctx context.Context, ing *networkingv1beta1.Ingress) error {
|
||||
log := logf.WithResource(logf.FromContext(ctx), ing)
|
||||
ctx = logf.NewContext(ctx, log)
|
||||
|
||||
if !shouldSync(ing, c.defaults.autoCertificateAnnotations) {
|
||||
logf.V(logf.DebugLevel).Infof("not syncing ingress resource as it does not contain a %q or %q annotation",
|
||||
cmapi.IngressIssuerNameAnnotationKey, cmapi.IngressClusterIssuerNameAnnotationKey)
|
||||
return nil
|
||||
}
|
||||
|
||||
issuerName, issuerKind, issuerGroup, err := c.issuerForIngress(ing)
|
||||
if err != nil {
|
||||
log.Error(err, "failed to determine issuer to be used for ingress resource")
|
||||
c.recorder.Eventf(ing, corev1.EventTypeWarning, reasonBadConfig, "Could not determine issuer for ingress due to bad annotations: %s",
|
||||
err)
|
||||
return nil
|
||||
}
|
||||
|
||||
errs := c.validateIngress(ing)
|
||||
if len(errs) > 0 {
|
||||
errMsg := errs[0].Error()
|
||||
if len(errs) > 1 {
|
||||
errMsg = utilerrors.NewAggregate(errs).Error()
|
||||
}
|
||||
c.recorder.Eventf(ing, corev1.EventTypeWarning, reasonBadConfig, errMsg)
|
||||
return nil
|
||||
}
|
||||
|
||||
newCrts, updateCrts, err := c.buildCertificates(ctx, ing, issuerName, issuerKind, issuerGroup)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, crt := range newCrts {
|
||||
_, err := c.cmClient.CertmanagerV1().Certificates(crt.Namespace).Create(ctx, crt, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.recorder.Eventf(ing, corev1.EventTypeNormal, reasonCreateCertificate, "Successfully created Certificate %q", crt.Name)
|
||||
}
|
||||
|
||||
for _, crt := range updateCrts {
|
||||
_, err := c.cmClient.CertmanagerV1().Certificates(crt.Namespace).Update(ctx, crt, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.recorder.Eventf(ing, corev1.EventTypeNormal, reasonUpdateCertificate, "Successfully updated Certificate %q", crt.Name)
|
||||
}
|
||||
|
||||
unrequiredCrts, err := c.findUnrequiredCertificates(ing)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, crt := range unrequiredCrts {
|
||||
err = c.cmClient.CertmanagerV1().Certificates(crt.Namespace).Delete(ctx, crt.Name, metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.recorder.Eventf(ing, corev1.EventTypeNormal, reasonDeleteCertificate, "Successfully deleted unrequired Certificate %q", crt.Name)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *controller) validateIngress(ing *networkingv1beta1.Ingress) []error {
|
||||
// check for duplicate values of networkingv1beta1.IngressTLS.SecretName
|
||||
var errs []error
|
||||
namedSecrets := make(map[string]int)
|
||||
for _, tls := range ing.Spec.TLS {
|
||||
namedSecrets[tls.SecretName]++
|
||||
}
|
||||
// not doing this in the previous for-loop to avoid erroring more than once for the same SecretName
|
||||
for name, n := range namedSecrets {
|
||||
if n > 1 {
|
||||
errs = append(errs, fmt.Errorf("Duplicate TLS entry for secretName %q", name))
|
||||
}
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
func validateIngressTLSBlock(tlsBlock networkingv1beta1.IngressTLS) []error {
|
||||
// unlikely that _both_ SecretName and Hosts would be empty, but still returning []error for consistency
|
||||
var errs []error
|
||||
|
||||
if len(tlsBlock.Hosts) == 0 {
|
||||
errs = append(errs, fmt.Errorf("secret %q for ingress TLS has no hosts specified", tlsBlock.SecretName))
|
||||
}
|
||||
if tlsBlock.SecretName == "" {
|
||||
errs = append(errs, fmt.Errorf("TLS entry for hosts %v must specify a secretName", tlsBlock.Hosts))
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
func (c *controller) buildCertificates(ctx context.Context, ing *networkingv1beta1.Ingress,
|
||||
issuerName, issuerKind, issuerGroup string) (new, update []*cmapi.Certificate, _ error) {
|
||||
log := logf.FromContext(ctx)
|
||||
|
||||
var newCrts []*cmapi.Certificate
|
||||
var updateCrts []*cmapi.Certificate
|
||||
for i, tls := range ing.Spec.TLS {
|
||||
errs := validateIngressTLSBlock(tls)
|
||||
// if this tls entry is invalid, record an error event on Ingress object and continue to the next tls entry
|
||||
if len(errs) > 0 {
|
||||
errMsg := utilerrors.NewAggregate(errs).Error()
|
||||
c.recorder.Eventf(ing, corev1.EventTypeWarning, reasonBadConfig, fmt.Sprintf("TLS entry %d is invalid: %s", i, errMsg))
|
||||
continue
|
||||
}
|
||||
existingCrt, err := c.certificateLister.Certificates(ing.Namespace).Get(tls.SecretName)
|
||||
if !apierrors.IsNotFound(err) && err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
crt := &cmapi.Certificate{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: tls.SecretName,
|
||||
Namespace: ing.Namespace,
|
||||
Labels: ing.Labels,
|
||||
OwnerReferences: []metav1.OwnerReference{*metav1.NewControllerRef(ing, ingressGVK)},
|
||||
},
|
||||
Spec: cmapi.CertificateSpec{
|
||||
DNSNames: tls.Hosts,
|
||||
SecretName: tls.SecretName,
|
||||
IssuerRef: cmmeta.ObjectReference{
|
||||
Name: issuerName,
|
||||
Kind: issuerKind,
|
||||
Group: issuerGroup,
|
||||
},
|
||||
Usages: cmapi.DefaultKeyUsages(),
|
||||
},
|
||||
}
|
||||
|
||||
setIssuerSpecificConfig(crt, ing)
|
||||
if err := translateIngressAnnotations(crt, ing.Annotations); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// check if a Certificate for this TLS entry already exists, and if it
|
||||
// does then skip this entry
|
||||
if existingCrt != nil {
|
||||
log := logf.WithRelatedResource(log, existingCrt)
|
||||
log.V(logf.DebugLevel).Info("certificate already exists for ingress resource, ensuring it is up to date")
|
||||
|
||||
if metav1.GetControllerOf(existingCrt) == nil {
|
||||
log.V(logf.InfoLevel).Info("certificate resource has no owner. refusing to update non-owned certificate resource for ingress")
|
||||
continue
|
||||
}
|
||||
|
||||
if !metav1.IsControlledBy(existingCrt, ing) {
|
||||
log.V(logf.InfoLevel).Info("certificate resource is not owned by this ingress. refusing to update non-owned certificate resource for ingress")
|
||||
continue
|
||||
}
|
||||
|
||||
if !certNeedsUpdate(existingCrt, crt) {
|
||||
log.V(logf.DebugLevel).Info("certificate resource is already up to date for ingress")
|
||||
continue
|
||||
}
|
||||
|
||||
updateCrt := existingCrt.DeepCopy()
|
||||
|
||||
updateCrt.Spec = crt.Spec
|
||||
updateCrt.Labels = crt.Labels
|
||||
setIssuerSpecificConfig(updateCrt, ing)
|
||||
updateCrts = append(updateCrts, updateCrt)
|
||||
} else {
|
||||
newCrts = append(newCrts, crt)
|
||||
}
|
||||
}
|
||||
return newCrts, updateCrts, nil
|
||||
}
|
||||
|
||||
func (c *controller) findUnrequiredCertificates(ing *networkingv1beta1.Ingress) ([]*cmapi.Certificate, error) {
|
||||
var unrequired []*cmapi.Certificate
|
||||
// TODO: investigate selector which filters for certificates controlled by the ingress
|
||||
crts, err := c.certificateLister.Certificates(ing.Namespace).List(labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, crt := range crts {
|
||||
if isUnrequiredCertificate(crt, ing) {
|
||||
unrequired = append(unrequired, crt)
|
||||
}
|
||||
}
|
||||
|
||||
return unrequired, nil
|
||||
}
|
||||
|
||||
func isUnrequiredCertificate(crt *cmapi.Certificate, ing *networkingv1beta1.Ingress) bool {
|
||||
if !metav1.IsControlledBy(crt, ing) {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, tls := range ing.Spec.TLS {
|
||||
if crt.Spec.SecretName == tls.SecretName {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// certNeedsUpdate checks and returns true if two Certificates differ
|
||||
func certNeedsUpdate(a, b *cmapi.Certificate) bool {
|
||||
if a.Name != b.Name {
|
||||
return true
|
||||
}
|
||||
|
||||
// TODO: we may need to allow users to edit the managed Certificate resources
|
||||
// to add their own labels directly.
|
||||
// Right now, we'll reset/remove the label values back automatically.
|
||||
// Let's hope no other controllers do this automatically, else we'll start fighting...
|
||||
if !reflect.DeepEqual(a.Labels, b.Labels) {
|
||||
return true
|
||||
}
|
||||
|
||||
if a.Spec.CommonName != b.Spec.CommonName {
|
||||
return true
|
||||
}
|
||||
|
||||
if len(a.Spec.DNSNames) != len(b.Spec.DNSNames) {
|
||||
return true
|
||||
}
|
||||
|
||||
for i := range a.Spec.DNSNames {
|
||||
if a.Spec.DNSNames[i] != b.Spec.DNSNames[i] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if a.Spec.SecretName != b.Spec.SecretName {
|
||||
return true
|
||||
}
|
||||
|
||||
if a.Spec.IssuerRef.Name != b.Spec.IssuerRef.Name {
|
||||
return true
|
||||
}
|
||||
|
||||
if a.Spec.IssuerRef.Kind != b.Spec.IssuerRef.Kind {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func setIssuerSpecificConfig(crt *cmapi.Certificate, ing *networkingv1beta1.Ingress) {
|
||||
ingAnnotations := ing.Annotations
|
||||
if ingAnnotations == nil {
|
||||
ingAnnotations = map[string]string{}
|
||||
}
|
||||
|
||||
// for ACME issuers
|
||||
editInPlaceVal := ingAnnotations[cmacme.IngressEditInPlaceAnnotationKey]
|
||||
editInPlace := editInPlaceVal == "true"
|
||||
if editInPlace {
|
||||
if crt.Annotations == nil {
|
||||
crt.Annotations = make(map[string]string)
|
||||
}
|
||||
crt.Annotations[cmacme.ACMECertificateHTTP01IngressNameOverride] = ing.Name
|
||||
// set IssueTemporaryCertificateAnnotation to true in order to behave
|
||||
// better when ingress-gce is being used.
|
||||
crt.Annotations[cmapi.IssueTemporaryCertificateAnnotation] = "true"
|
||||
}
|
||||
|
||||
ingressClassVal, hasIngressClassVal := ingAnnotations[cmapi.IngressACMEIssuerHTTP01IngressClassAnnotationKey]
|
||||
if hasIngressClassVal {
|
||||
if crt.Annotations == nil {
|
||||
crt.Annotations = make(map[string]string)
|
||||
}
|
||||
crt.Annotations[cmacme.ACMECertificateHTTP01IngressClassOverride] = ingressClassVal
|
||||
}
|
||||
}
|
||||
|
||||
// shouldSync returns true if this ingress should have a Certificate resource
|
||||
// created for it
|
||||
func shouldSync(ing *networkingv1beta1.Ingress, autoCertificateAnnotations []string) bool {
|
||||
annotations := ing.Annotations
|
||||
if annotations == nil {
|
||||
annotations = map[string]string{}
|
||||
}
|
||||
if _, ok := annotations[cmapi.IngressIssuerNameAnnotationKey]; ok {
|
||||
return true
|
||||
}
|
||||
if _, ok := annotations[cmapi.IngressClusterIssuerNameAnnotationKey]; ok {
|
||||
return true
|
||||
}
|
||||
for _, x := range autoCertificateAnnotations {
|
||||
if s, ok := annotations[x]; ok {
|
||||
if b, _ := strconv.ParseBool(s); b {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// issuerForIngress will determine the issuer that should be specified on a
|
||||
// Certificate created for the given Ingress resource. If one is not set, the
|
||||
// default issuer given to the controller will be used.
|
||||
func (c *controller) issuerForIngress(ing *networkingv1beta1.Ingress) (name, kind, group string, err error) {
|
||||
var errs []string
|
||||
|
||||
name = c.defaults.issuerName
|
||||
kind = c.defaults.issuerKind
|
||||
group = c.defaults.issuerGroup
|
||||
annotations := ing.Annotations
|
||||
|
||||
if annotations == nil {
|
||||
annotations = map[string]string{}
|
||||
}
|
||||
|
||||
issuerName, issuerNameOK := annotations[cmapi.IngressIssuerNameAnnotationKey]
|
||||
if issuerNameOK {
|
||||
name = issuerName
|
||||
kind = cmapi.IssuerKind
|
||||
}
|
||||
|
||||
clusterIssuerName, clusterIssuerNameOK := annotations[cmapi.IngressClusterIssuerNameAnnotationKey]
|
||||
if clusterIssuerNameOK {
|
||||
name = clusterIssuerName
|
||||
kind = cmapi.ClusterIssuerKind
|
||||
}
|
||||
|
||||
kindName, kindNameOK := annotations[cmapi.IssuerKindAnnotationKey]
|
||||
if kindNameOK {
|
||||
kind = kindName
|
||||
}
|
||||
|
||||
groupName, groupNameOK := annotations[cmapi.IssuerGroupAnnotationKey]
|
||||
if groupNameOK {
|
||||
group = groupName
|
||||
}
|
||||
|
||||
if len(name) == 0 {
|
||||
errs = append(errs, "failed to determine issuer name to be used for ingress resource")
|
||||
}
|
||||
|
||||
if issuerNameOK && clusterIssuerNameOK {
|
||||
errs = append(errs,
|
||||
fmt.Sprintf("both %q and %q may not be set",
|
||||
cmapi.IngressIssuerNameAnnotationKey, cmapi.IngressClusterIssuerNameAnnotationKey))
|
||||
}
|
||||
|
||||
if clusterIssuerNameOK && groupNameOK {
|
||||
errs = append(errs,
|
||||
fmt.Sprintf("both %q and %q may not be set",
|
||||
cmapi.IngressClusterIssuerNameAnnotationKey, cmapi.IssuerGroupAnnotationKey))
|
||||
}
|
||||
|
||||
if clusterIssuerNameOK && kindNameOK {
|
||||
errs = append(errs,
|
||||
fmt.Sprintf("both %q and %q may not be set",
|
||||
cmapi.IngressClusterIssuerNameAnnotationKey, cmapi.IssuerKindAnnotationKey))
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
return "", "", "", errors.New(strings.Join(errs, ", "))
|
||||
}
|
||||
|
||||
return name, kind, group, nil
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -28,6 +28,8 @@ go_library(
|
||||
"@io_k8s_client_go//kubernetes/fake:go_default_library",
|
||||
"@io_k8s_client_go//testing:go_default_library",
|
||||
"@io_k8s_client_go//tools/cache:go_default_library",
|
||||
"@io_k8s_sigs_gateway_api//pkg/client/clientset/versioned/fake:go_default_library",
|
||||
"@io_k8s_sigs_gateway_api//pkg/client/informers/externalversions:go_default_library",
|
||||
"@io_k8s_utils//clock:go_default_library",
|
||||
"@io_k8s_utils//clock/testing:go_default_library",
|
||||
],
|
||||
|
||||
@@ -33,6 +33,8 @@ import (
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/utils/clock"
|
||||
fakeclock "k8s.io/utils/clock/testing"
|
||||
gwfake "sigs.k8s.io/gateway-api/pkg/client/clientset/versioned/fake"
|
||||
gwinformers "sigs.k8s.io/gateway-api/pkg/client/informers/externalversions"
|
||||
|
||||
apiutil "github.com/jetstack/cert-manager/pkg/api/util"
|
||||
cmfake "github.com/jetstack/cert-manager/pkg/client/clientset/versioned/fake"
|
||||
@@ -50,14 +52,15 @@ func init() {
|
||||
}
|
||||
|
||||
// Builder is a structure used to construct new Contexts for use during tests.
|
||||
// Currently, only KubeObjects and CertManagerObjects can be specified.
|
||||
// These will be auto loaded into the constructed fake Clientsets.
|
||||
// Currently, only KubeObjects, CertManagerObjects and GWObjects can be
|
||||
// specified. These will be auto loaded into the constructed fake Clientsets.
|
||||
// Call ToContext() to construct a new context using the given values.
|
||||
type Builder struct {
|
||||
T *testing.T
|
||||
|
||||
KubeObjects []runtime.Object
|
||||
CertManagerObjects []runtime.Object
|
||||
GWObjects []runtime.Object
|
||||
ExpectedActions []Action
|
||||
ExpectedEvents []string
|
||||
StringGenerator StringGenerator
|
||||
@@ -107,12 +110,14 @@ func (b *Builder) Init() {
|
||||
b.requiredReactors = make(map[string]bool)
|
||||
b.Client = kubefake.NewSimpleClientset(b.KubeObjects...)
|
||||
b.CMClient = cmfake.NewSimpleClientset(b.CertManagerObjects...)
|
||||
b.GWClient = gwfake.NewSimpleClientset(b.GWObjects...)
|
||||
b.Recorder = new(FakeRecorder)
|
||||
|
||||
b.FakeKubeClient().PrependReactor("create", "*", b.generateNameReactor)
|
||||
b.FakeCMClient().PrependReactor("create", "*", b.generateNameReactor)
|
||||
b.FakeGWClient().PrependReactor("create", "*", b.generateNameReactor)
|
||||
b.KubeSharedInformerFactory = kubeinformers.NewSharedInformerFactory(b.Client, informerResyncPeriod)
|
||||
b.SharedInformerFactory = informers.NewSharedInformerFactory(b.CMClient, informerResyncPeriod)
|
||||
b.GWShared = gwinformers.NewSharedInformerFactory(b.GWClient, informerResyncPeriod)
|
||||
b.stopCh = make(chan struct{})
|
||||
b.Metrics = metrics.New(logs.Log, clock.RealClock{})
|
||||
|
||||
@@ -139,6 +144,10 @@ func (b *Builder) FakeCMClient() *cmfake.Clientset {
|
||||
return b.Context.CMClient.(*cmfake.Clientset)
|
||||
}
|
||||
|
||||
func (b *Builder) FakeGWClient() *gwfake.Clientset {
|
||||
return b.Context.GWClient.(*gwfake.Clientset)
|
||||
}
|
||||
|
||||
func (b *Builder) FakeCMInformerFactory() informers.SharedInformerFactory {
|
||||
return b.Context.SharedInformerFactory
|
||||
}
|
||||
@@ -202,6 +211,7 @@ func (b *Builder) AllEventsCalled() error {
|
||||
func (b *Builder) AllActionsExecuted() error {
|
||||
firedActions := b.FakeCMClient().Actions()
|
||||
firedActions = append(firedActions, b.FakeKubeClient().Actions()...)
|
||||
firedActions = append(firedActions, b.FakeGWClient().Actions()...)
|
||||
|
||||
var unexpectedActions []coretesting.Action
|
||||
var errs []error
|
||||
@@ -270,6 +280,8 @@ func (b *Builder) Stop() {
|
||||
func (b *Builder) Start() {
|
||||
b.KubeSharedInformerFactory.Start(b.stopCh)
|
||||
b.SharedInformerFactory.Start(b.stopCh)
|
||||
b.GWShared.Start(b.stopCh)
|
||||
|
||||
// wait for caches to sync
|
||||
b.Sync()
|
||||
}
|
||||
@@ -281,6 +293,9 @@ func (b *Builder) Sync() {
|
||||
if err := mustAllSync(b.SharedInformerFactory.WaitForCacheSync(b.stopCh)); err != nil {
|
||||
panic("Error waiting for SharedInformerFactory to sync: " + err.Error())
|
||||
}
|
||||
if err := mustAllSync(b.GWShared.WaitForCacheSync(b.stopCh)); err != nil {
|
||||
panic("Error waiting for GWShared to sync: " + err.Error())
|
||||
}
|
||||
if b.additionalSyncFuncs != nil {
|
||||
cache.WaitForCacheSync(b.stopCh, b.additionalSyncFuncs...)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user