Adds acme CertificateRequest controller with unit tests

Signed-off-by: JoshVanL <vleeuwenjoshua@gmail.com>
This commit is contained in:
JoshVanL 2019-07-30 18:40:18 +01:00
parent d4a675ee66
commit e2b9b21766
12 changed files with 604 additions and 4 deletions

View File

@ -11,6 +11,7 @@ go_library(
"//pkg/client/clientset/versioned/scheme:go_default_library",
"//pkg/client/informers/externalversions:go_default_library",
"//pkg/controller:go_default_library",
"//pkg/controller/certificaterequests/acme:go_default_library",
"//pkg/controller/certificaterequests/ca:go_default_library",
"//pkg/controller/certificaterequests/selfsigned:go_default_library",
"//pkg/controller/certificaterequests/vault:go_default_library",

View File

@ -42,6 +42,7 @@ import (
intscheme "github.com/jetstack/cert-manager/pkg/client/clientset/versioned/scheme"
informers "github.com/jetstack/cert-manager/pkg/client/informers/externalversions"
"github.com/jetstack/cert-manager/pkg/controller"
cracmecontroller "github.com/jetstack/cert-manager/pkg/controller/certificaterequests/acme"
crcacontroller "github.com/jetstack/cert-manager/pkg/controller/certificaterequests/ca"
crselfsignedcontroller "github.com/jetstack/cert-manager/pkg/controller/certificaterequests/selfsigned"
crvaultcontroller "github.com/jetstack/cert-manager/pkg/controller/certificaterequests/vault"
@ -80,6 +81,7 @@ func Run(opts *options.ControllerOptions, stopCh <-chan struct{}) {
if utilfeature.DefaultFeatureGate.Enabled(feature.CertificateRequestControllers) {
opts.EnabledControllers = append(opts.EnabledControllers, []string{
cracmecontroller.CRControllerName,
crcacontroller.CRControllerName,
crselfsignedcontroller.CRControllerName,
crvaultcontroller.CRControllerName,

View File

@ -66,6 +66,7 @@ filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//pkg/controller/certificaterequests/acme:all-srcs",
"//pkg/controller/certificaterequests/ca:all-srcs",
"//pkg/controller/certificaterequests/fake:all-srcs",
"//pkg/controller/certificaterequests/selfsigned:all-srcs",

View File

@ -0,0 +1,56 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = ["acme.go"],
importpath = "github.com/jetstack/cert-manager/pkg/controller/certificaterequests/acme",
visibility = ["//visibility:public"],
deps = [
"//pkg/acme:go_default_library",
"//pkg/api/util:go_default_library",
"//pkg/apis/certmanager/v1alpha1:go_default_library",
"//pkg/client/clientset/versioned/typed/certmanager/v1alpha1:go_default_library",
"//pkg/client/listers/certmanager/v1alpha1:go_default_library",
"//pkg/controller:go_default_library",
"//pkg/controller/certificaterequests:go_default_library",
"//pkg/controller/certificaterequests/util:go_default_library",
"//pkg/issuer:go_default_library",
"//pkg/logs:go_default_library",
"//pkg/util/pki:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/client-go/tools/record:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["acme_test.go"],
embed = [":go_default_library"],
deps = [
"//pkg/apis/certmanager:go_default_library",
"//pkg/apis/certmanager/v1alpha1:go_default_library",
"//pkg/client/listers/certmanager/v1alpha1:go_default_library",
"//pkg/controller/certificaterequests/test:go_default_library",
"//pkg/controller/test:go_default_library",
"//pkg/controller/test/fake:go_default_library",
"//test/unit/gen:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/client-go/testing: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"],
)

View File

@ -0,0 +1,194 @@
/*
Copyright 2019 The Jetstack cert-manager contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package acme
import (
"context"
"crypto/x509"
"encoding/json"
"fmt"
"hash/fnv"
k8sErrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/record"
"github.com/jetstack/cert-manager/pkg/acme"
apiutil "github.com/jetstack/cert-manager/pkg/api/util"
"github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1"
cmclientset "github.com/jetstack/cert-manager/pkg/client/clientset/versioned/typed/certmanager/v1alpha1"
cmlisters "github.com/jetstack/cert-manager/pkg/client/listers/certmanager/v1alpha1"
controllerpkg "github.com/jetstack/cert-manager/pkg/controller"
"github.com/jetstack/cert-manager/pkg/controller/certificaterequests"
crutil "github.com/jetstack/cert-manager/pkg/controller/certificaterequests/util"
issuerpkg "github.com/jetstack/cert-manager/pkg/issuer"
logf "github.com/jetstack/cert-manager/pkg/logs"
"github.com/jetstack/cert-manager/pkg/util/pki"
)
const (
CRControllerName = "certificaterequests-issuer-acme"
)
type ACME struct {
// used to record Events about resources to the API
recorder record.EventRecorder
issuerOptions controllerpkg.IssuerOptions
orderLister cmlisters.OrderLister
cmClientV cmclientset.CertmanagerV1alpha1Interface
helper issuerpkg.Helper
}
func init() {
// create certificate request controller for acme issuer
controllerpkg.Register(CRControllerName, func(ctx *controllerpkg.Context) (controllerpkg.Interface, error) {
acme := NewACME(ctx)
orderInformer := ctx.SharedInformerFactory.Certmanager().V1alpha1().Orders().Informer()
controller := certificaterequests.New(apiutil.IssuerACME, acme, orderInformer)
c, err := controllerpkg.New(ctx, CRControllerName, controller)
if err != nil {
return nil, err
}
return c.Run, nil
})
}
func NewACME(ctx *controllerpkg.Context) *ACME {
ctx.CMClient.CertmanagerV1alpha1()
return &ACME{
recorder: ctx.Recorder,
issuerOptions: ctx.IssuerOptions,
orderLister: ctx.SharedInformerFactory.Certmanager().V1alpha1().Orders().Lister(),
cmClientV: ctx.CMClient.CertmanagerV1alpha1(),
}
}
func (a *ACME) Sign(ctx context.Context, cr *v1alpha1.CertificateRequest, issuer v1alpha1.GenericIssuer) (*issuerpkg.IssueResponse, error) {
log := logf.FromContext(ctx, "sign")
reporter := crutil.NewReporter(cr, a.recorder)
resourceNamespace := a.issuerOptions.ResourceNamespace(issuer)
// If we can't decode the CSR PEM we have to hard fail
csr, err := pki.DecodeX509CertificateRequestBytes(cr.Spec.CSRPEM)
if err != nil {
reporter.Failed(err, "ErrorParsingCSR", "Failed to decode CSR in spec")
return nil, nil
}
// If we fail to build the order we have to hard fail.
expectedOrder, err := buildOrder(cr, csr)
if err != nil {
reporter.Failed(err, "ErrorBuildingOrder", "Failed to build order")
return nil, nil
}
order, err := a.orderLister.Orders(expectedOrder.Namespace).Get(expectedOrder.Name)
if err != nil {
if k8sErrors.IsNotFound(err) {
// Failing to create the order here is most likely network related.
// We should backoff and keep trying.
order, err = a.cmClientV.Orders(resourceNamespace).Create(expectedOrder)
if err != nil {
reporter.Pending(err, "ErrorCreatingOrder",
fmt.Sprintf("Failed create new order resource %s/%s", resourceNamespace, expectedOrder.Name))
return nil, err
}
} else {
// We are probably in a network error here so we should backoff and retry
reporter.Pending(err, "ErrorGettingOrder",
fmt.Sprintf("Failed to get order resource %s/%s", resourceNamespace, expectedOrder.Name))
return nil, err
}
}
// If the acme order has failed then so too does the CertificateRequest meet the same fate.
if acme.IsFailureState(order.Status.State) {
reporter.Failed(fmt.Errorf("order is in failure state %q", order.Status.State), "OrderFailed",
fmt.Sprintf("Failed to resolve order resource %s/%s", resourceNamespace, expectedOrder.Name))
return nil, nil
}
// Order valid, return cert. The calling controller will update with ready if it's happy with the cert.
if order.Status.State == v1alpha1.Valid {
log.Info("certificate issued")
return &issuerpkg.IssueResponse{
Certificate: order.Status.Certificate,
}, nil
}
// We update here to just normal pending while we wait for the order to be resolved.
reporter.Pending(fmt.Errorf("order is currently pending: %q", order.Status.State), "OrderPending",
fmt.Sprintf("Waiting on certificate issuance from order %s/%s", resourceNamespace, expectedOrder.Name))
log.Info("acme Order resource is not in a valid state, waiting...", "state", order.Status.State)
return nil, nil
}
// Build order. If we error here it is a terminating failure.
func buildOrder(cr *v1alpha1.CertificateRequest, csr *x509.CertificateRequest) (*v1alpha1.Order, error) {
spec := v1alpha1.OrderSpec{
CSR: cr.Spec.CSRPEM,
IssuerRef: cr.Spec.IssuerRef,
CommonName: csr.Subject.CommonName,
DNSNames: csr.DNSNames,
}
hash, err := hashOrder(spec)
if err != nil {
return nil, err
}
// truncate certificate name so final name will be <= 63 characters.
// hash (uint32) will be at most 10 digits long, and we account for
// the hyphen.
return &v1alpha1.Order{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("%.52s-%d", cr.Name, hash),
Namespace: cr.Namespace,
Labels: cr.Labels,
OwnerReferences: []metav1.OwnerReference{
*metav1.NewControllerRef(cr, v1alpha1.SchemeGroupVersion.WithKind(v1alpha1.CertificateRequestKind)),
},
},
Spec: spec,
}, nil
}
func hashOrder(orderSpec v1alpha1.OrderSpec) (uint32, error) {
// create a shallow copy of the OrderSpec so we can overwrite the CSR field
orderSpec.CSR = nil
orderSpecBytes, err := json.Marshal(orderSpec)
if err != nil {
return 0, err
}
hashF := fnv.New32()
_, err = hashF.Write(orderSpecBytes)
if err != nil {
return 0, err
}
return hashF.Sum32(), nil
}

View File

@ -0,0 +1,211 @@
/*
Copyright 2019 The Jetstack cert-manager contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package acme
import (
"context"
"crypto/x509"
"errors"
"testing"
"time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
coretesting "k8s.io/client-go/testing"
"github.com/jetstack/cert-manager/pkg/apis/certmanager"
"github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1"
cmlisters "github.com/jetstack/cert-manager/pkg/client/listers/certmanager/v1alpha1"
testcr "github.com/jetstack/cert-manager/pkg/controller/certificaterequests/test"
testpkg "github.com/jetstack/cert-manager/pkg/controller/test"
testfake "github.com/jetstack/cert-manager/pkg/controller/test/fake"
"github.com/jetstack/cert-manager/test/unit/gen"
)
func buildOrderMust(t *testing.T, cr *v1alpha1.CertificateRequest,
csr *x509.CertificateRequest) *v1alpha1.Order {
order, err := buildOrder(cr, csr)
if err != nil {
t.Errorf("failed to build order during testing: %s", err)
t.FailNow()
}
return order
}
func TestSign(t *testing.T) {
rsaPK := testcr.GenerateRSAPrivateKey(t)
csr, csrPEM := testcr.GenerateCSR(t, rsaPK)
testCR := gen.CertificateRequest("test-cr",
gen.SetCertificateRequestCSR(csrPEM),
gen.SetCertificateRequestIsCA(true),
gen.SetCertificateRequestDuration(&metav1.Duration{Duration: time.Hour * 24 * 60}),
gen.SetCertificateRequestIssuer(v1alpha1.ObjectReference{
Name: "acme-issuer",
Group: certmanager.GroupName,
Kind: "Issuer",
}),
)
_, rsaPEMCert := testcr.GenerateSelfSignedCertFromCR(t, testCR, rsaPK, time.Hour*24*60)
testOrder := buildOrderMust(t, testCR, csr)
tests := map[string]testT{
"a badly formed CSR should report failure": {
issuer: gen.Issuer("acme-issuer"),
certificateRequest: gen.CertificateRequestFrom(testCR,
gen.SetCertificateRequestCSR([]byte("a bad csr")),
),
builder: &testpkg.Builder{
KubeObjects: []runtime.Object{},
CertManagerObjects: []runtime.Object{},
ExpectedEvents: []string{
"Warning ErrorParsingCSR Failed to decode CSR in spec: error decoding certificate request PEM block",
},
CheckFn: testcr.MustNoResponse,
},
expectedErr: false,
},
//TODO: Think of a creative way to get `buildOrder` to fail :thinking_face:
"if order doesn't exist then attempt to create one": {
issuer: gen.Issuer("acme-issuer"),
certificateRequest: testCR,
builder: &testpkg.Builder{
CertManagerObjects: []runtime.Object{},
ExpectedActions: []testpkg.Action{
testpkg.NewAction(coretesting.NewCreateAction(
v1alpha1.SchemeGroupVersion.WithResource("orders"),
gen.DefaultTestNamespace,
testOrder,
)),
},
ExpectedEvents: []string{
`Normal OrderPending Waiting on certificate issuance from order default-unit-test-ns/test-cr-3958469914: order is currently pending: ""`,
},
CheckFn: testcr.MustNoResponse,
},
expectedErr: false,
},
"if we fail to get the order resource then we should report pending": {
issuer: gen.Issuer("acme-issuer"),
certificateRequest: testCR,
builder: &testpkg.Builder{
ExpectedEvents: []string{
`Normal ErrorGettingOrder Failed to get order resource default-unit-test-ns/test-cr-3958469914: this is a network error`,
},
CheckFn: testcr.MustNoResponse,
},
expectedErr: true,
FakeOrderLister: &testfake.FakeOrderLister{
OrdersFn: func(namespace string) cmlisters.OrderNamespaceLister {
return &testfake.FakeOrderNamespaceLister{
GetFn: func(name string) (ret *v1alpha1.Order, err error) {
return nil, errors.New("this is a network error")
},
}
},
},
},
"if the order resource is in a failed state then we should report failure": {
issuer: gen.Issuer("acme-issuer"),
certificateRequest: testCR,
builder: &testpkg.Builder{
ExpectedEvents: []string{
`Warning OrderFailed Failed to resolve order resource default-unit-test-ns/test-cr-3958469914: order is in failure state "invalid"`,
},
CertManagerObjects: []runtime.Object{gen.OrderFrom(testOrder,
gen.SetOrderState(v1alpha1.Invalid),
)},
CheckFn: testcr.MustNoResponse,
},
expectedErr: false,
},
"if the order is in a non failure state or valid, then report pending": {
issuer: gen.Issuer("acme-issuer"),
certificateRequest: testCR,
builder: &testpkg.Builder{
ExpectedEvents: []string{
`Normal OrderPending Waiting on certificate issuance from order default-unit-test-ns/test-cr-3958469914: order is currently pending: ""`,
},
CertManagerObjects: []runtime.Object{gen.OrderFrom(testOrder,
gen.SetOrderState(""),
)},
CheckFn: testcr.MustNoResponse,
},
expectedErr: false,
},
"if the order is in Valid state then return the certificate as response": {
issuer: gen.Issuer("acme-issuer"),
certificateRequest: testCR,
builder: &testpkg.Builder{
ExpectedEvents: []string{},
CertManagerObjects: []runtime.Object{gen.OrderFrom(testOrder,
gen.SetOrderState(v1alpha1.Valid),
gen.SetOrderCertificate(rsaPEMCert),
)},
CheckFn: testcr.NoPrivateKeyFieldsSetCheck(nil),
},
expectedErr: false,
},
}
for name, test := range tests {
t.Run(name, func(t *testing.T) {
runTest(t, test)
})
}
}
type testT struct {
builder *testpkg.Builder
certificateRequest *v1alpha1.CertificateRequest
issuer v1alpha1.GenericIssuer
checkFn func(*testpkg.Builder, ...interface{})
expectedErr bool
FakeOrderLister *testfake.FakeOrderLister
}
func runTest(t *testing.T, test testT) {
test.builder.T = t
test.builder.Start()
defer test.builder.Stop()
a := NewACME(test.builder.Context)
test.builder.Sync()
if test.FakeOrderLister != nil {
a.orderLister = test.FakeOrderLister
}
resp, err := a.Sign(context.Background(), test.certificateRequest, test.issuer)
if err != nil && !test.expectedErr {
t.Errorf("expected to not get an error, but got: %v", err)
}
if err == nil && test.expectedErr {
t.Errorf("expected to get an error but did not get one")
}
test.builder.CheckAndFinish(resp, err)
}

View File

@ -69,6 +69,11 @@ type Controller struct {
issuerLister cmlisters.IssuerLister
clusterIssuerLister cmlisters.ClusterIssuerLister
// Extra informers that should be watched by this certificate request
// controller instance. These resources can be owned by certificate requests
// that we resolve.
extraInformers []cache.SharedIndexInformer
// Issuer to call sign function
issuer Issuer
@ -78,7 +83,7 @@ type Controller struct {
reporter *util.Reporter
}
func New(issuerType string, issuer Issuer) *Controller {
func New(issuerType string, issuer Issuer, extraInformers ...cache.SharedIndexInformer) *Controller {
return &Controller{
issuerType: issuerType,
issuer: issuer,
@ -103,10 +108,17 @@ func (c *Controller) Register(ctx *controllerpkg.Context) (workqueue.RateLimitin
// build a list of InformerSynced functions that will be returned by the Register method.
// the controller will only begin processing items once all of these informers have synced.
mustSync := []cache.InformerSynced{
// Ensure we also catch all extra informers for this certificate controller instance
var extraInformersMustSync []cache.InformerSynced
for _, i := range c.extraInformers {
extraInformersMustSync = append(extraInformersMustSync, i.HasSynced)
}
mustSync := append([]cache.InformerSynced{
certificateRequestInformer.Informer().HasSynced,
issuerInformer.Informer().HasSynced,
}
}, extraInformersMustSync...)
// if scoped to a single namespace
// if we are running in non-namespaced mode (i.e. --namespace=""), we also
@ -124,6 +136,14 @@ func (c *Controller) Register(ctx *controllerpkg.Context) (workqueue.RateLimitin
// register handler functions
certificateRequestInformer.Informer().AddEventHandler(&controllerpkg.QueuingEventHandler{Queue: c.queue})
issuerInformer.Informer().AddEventHandler(&controllerpkg.BlockingEventHandler{WorkFunc: c.handleGenericIssuer})
// Ensure we catch extra informers that are owned by certificate requests
for _, i := range c.extraInformers {
i.AddEventHandler(&controllerpkg.BlockingEventHandler{
WorkFunc: controllerpkg.HandleOwnedResourceNamespacedFunc(c.log, c.queue, certificateRequestGvk, certificateRequestGetter(c.certificateRequestLister)),
})
}
// instantiate metrics interface with default metrics implementation
c.metrics = metrics.Default
@ -165,3 +185,9 @@ func (c *Controller) ProcessItem(ctx context.Context, key string) error {
ctx = logf.NewContext(ctx, logf.WithResource(log, cr))
return c.Sync(ctx, cr)
}
func certificateRequestGetter(lister cmlisters.CertificateRequestLister) func(namespace, name string) (interface{}, error) {
return func(namespace, name string) (interface{}, error) {
return lister.CertificateRequests(namespace).Get(name)
}
}

View File

@ -7,7 +7,9 @@ go_library(
visibility = ["//visibility:public"],
deps = [
"//pkg/apis/certmanager/v1alpha1:go_default_library",
"//pkg/controller/test:go_default_library",
"//pkg/issuer:go_default_library",
"//pkg/util/pki:go_default_library",
],
)

View File

@ -34,6 +34,10 @@ import (
"github.com/jetstack/cert-manager/pkg/util/pki"
)
var (
certificateRequestGvk = v1alpha1.SchemeGroupVersion.WithKind("CertificateRequest")
)
func (c *Controller) Sync(ctx context.Context, cr *v1alpha1.CertificateRequest) (err error) {
c.metrics.IncrementSyncCallCount(ControllerName)

View File

@ -40,7 +40,10 @@ filegroup(
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
srcs = [
":package-srcs",
"//pkg/controller/test/fake:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,27 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["orderlister.go"],
importpath = "github.com/jetstack/cert-manager/pkg/controller/test/fake",
visibility = ["//visibility:public"],
deps = [
"//pkg/apis/certmanager/v1alpha1:go_default_library",
"//pkg/client/listers/certmanager/v1alpha1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/labels: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"],
)

View File

@ -0,0 +1,73 @@
/*
Copyright 2019 The Jetstack cert-manager contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package fake
import (
"k8s.io/apimachinery/pkg/labels"
"github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1"
cmlisters "github.com/jetstack/cert-manager/pkg/client/listers/certmanager/v1alpha1"
)
var _ cmlisters.OrderLister = &FakeOrderLister{}
var _ cmlisters.OrderNamespaceLister = &FakeOrderNamespaceLister{}
type FakeOrderLister struct {
ListFn func(selector labels.Selector) (ret []*v1alpha1.Order, err error)
OrdersFn func(namespace string) cmlisters.OrderNamespaceLister
}
type FakeOrderNamespaceLister struct {
ListFn func(selector labels.Selector) (ret []*v1alpha1.Order, err error)
GetFn func(name string) (ret *v1alpha1.Order, err error)
}
func NewFakeOrderLister() *FakeOrderLister {
return &FakeOrderLister{
ListFn: func(selector labels.Selector) (ret []*v1alpha1.Order, err error) {
return nil, nil
},
OrdersFn: func(namespace string) cmlisters.OrderNamespaceLister {
return nil
},
}
}
func NewFakeOrderNamespaceLister() *FakeOrderNamespaceLister {
return &FakeOrderNamespaceLister{
ListFn: func(selector labels.Selector) (ret []*v1alpha1.Order, err error) {
return nil, nil
},
GetFn: func(name string) (ret *v1alpha1.Order, err error) {
return nil, nil
},
}
}
func (f *FakeOrderLister) List(selector labels.Selector) (ret []*v1alpha1.Order, err error) {
return f.ListFn(selector)
}
func (f *FakeOrderLister) Orders(namespace string) cmlisters.OrderNamespaceLister {
return f.OrdersFn(namespace)
}
func (f *FakeOrderNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.Order, err error) {
return f.ListFn(selector)
}
func (f *FakeOrderNamespaceLister) Get(name string) (*v1alpha1.Order, error) {
return f.GetFn(name)
}