Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,9 @@ The business logic of the controllers can be provided to the libary through the
If it returns a normal error, the controller will retry with backoff until the `Check` function succeeds.
If the error is of type `signer.PermanentError`, the controller will not retry automatically. Instead, an increase in Generation is required to recheck the issuer.

- The `Sign` function is used by the CertificateRequest controller.
- The `Sign` function is used by the CertificateRequest controller.
If it returns a normal error, the `Sign` function will be retried as long as we have not spent more than the configured `MaxRetryDuration` after the certificate request was created.
If the error is of type `signer.IssuerError`, the error is an error that should be set on the issuer instead of the CertificateRequest.
If the error is of type `signer.SetCertificateRequestConditionError`, the controller will, additional to setting the ready condition, also set the specified condition. This can be used in case we have to store some additional state in the status.
If the error is of type `signer.PermanentError`, the controller will not retry automatically. Instead, a new CertificateRequest has to be created.

## Reconciliation loops
Expand Down
59 changes: 37 additions & 22 deletions controllers/certificaterequest_controller_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,11 @@ func TestCertificateRequestControllerIntegrationIssuerInitiallyNotFoundAndNotRea
MaxRetryDuration: time.Minute,
EventSource: kubeutil.NewEventStore(),
Client: mgr.GetClient(),
Sign: func(_ context.Context, cr signer.CertificateRequestObject, _ v1alpha1.Issuer) (signer.PEMBundle, error) {
Sign: func(_ context.Context, cr signer.CertificateRequestObject, _ v1alpha1.Issuer) (signer.PEMBundle, signer.ExtraConditions, error) {
atomic.AddUint64(&counters[extractIdFromNamespace(t, cr.GetNamespace())], 1)
return signer.PEMBundle{
ChainPEM: []byte("cert"),
}, nil
}, signer.ExtraConditions{}, nil
},
EventRecorder: record.NewFakeRecorder(100),
Clock: clock.RealClock{},
Expand Down Expand Up @@ -202,6 +202,11 @@ func TestCertificateRequestControllerIntegrationIssuerInitiallyNotFoundAndNotRea
}
}

type signResults struct {
err error
extraConditions []cmapi.CertificateRequestCondition
}

// TestCertificateRequestControllerIntegrationSetCondition runs the
// CertificateRequestController against a real Kubernetes API server.
func TestCertificateRequestControllerIntegrationSetCondition(t *testing.T) {
Expand All @@ -218,7 +223,7 @@ func TestCertificateRequestControllerIntegrationSetCondition(t *testing.T) {
kubeClients := testresource.KubeClients(t, nil)

counter := uint64(0)
signResult := make(chan error, 10)
signResult := make(chan signResults, 10)
ctx = setupControllersAPIServerAndClient(t, ctx, kubeClients,
func(mgr ctrl.Manager) controllerInterface {
return &CertificateRequestReconciler{
Expand All @@ -229,13 +234,13 @@ func TestCertificateRequestControllerIntegrationSetCondition(t *testing.T) {
MaxRetryDuration: time.Minute,
EventSource: kubeutil.NewEventStore(),
Client: mgr.GetClient(),
Sign: func(ctx context.Context, cr signer.CertificateRequestObject, _ v1alpha1.Issuer) (signer.PEMBundle, error) {
Sign: func(ctx context.Context, cr signer.CertificateRequestObject, _ v1alpha1.Issuer) (signer.PEMBundle, signer.ExtraConditions, error) {
atomic.AddUint64(&counter, 1)
select {
case err := <-signResult:
return signer.PEMBundle{}, err
case res := <-signResult:
return signer.PEMBundle{}, res.extraConditions, res.err
case <-ctx.Done():
return signer.PEMBundle{}, ctx.Err()
return signer.PEMBundle{}, signer.ExtraConditions{}, ctx.Err()
}
},
EventRecorder: record.NewFakeRecorder(100),
Expand Down Expand Up @@ -308,19 +313,24 @@ func TestCertificateRequestControllerIntegrationSetCondition(t *testing.T) {
markIssuerReady(t, ctx, kubeClients.Client, clock.RealClock{}, fieldOwner, issuer)

checkComplete = kubeClients.StartObjectWatch(t, ctx, cr)
signResult <- signer.SetCertificateRequestConditionError{
Err: fmt.Errorf("[err message1]"),
ConditionType: "[condition type]",
Status: cmmeta.ConditionTrue,
Reason: "[reason]",
signResult <- signResults{
err: fmt.Errorf("[err message1]"),
extraConditions: []cmapi.CertificateRequestCondition{
{
Type: "[condition type]",
Status: cmmeta.ConditionTrue,
Reason: "[condition reason]",
Message: "[condition message1]",
},
},
}
err = checkComplete(func(obj runtime.Object) error {
customCondition := cmutil.GetCertificateRequestCondition(obj.(*cmapi.CertificateRequest), "[condition type]")

if (customCondition == nil) ||
(customCondition.Status != cmmeta.ConditionTrue) ||
(customCondition.Reason != "[reason]") ||
(customCondition.Message != "[err message1]") {
(customCondition.Reason != "[condition reason]") ||
(customCondition.Message != "[condition message1]") {
return fmt.Errorf("incorrect custom condition: %v", customCondition)
}

Expand All @@ -329,19 +339,24 @@ func TestCertificateRequestControllerIntegrationSetCondition(t *testing.T) {
require.NoError(t, err)

checkComplete = kubeClients.StartObjectWatch(t, ctx, cr)
signResult <- signer.SetCertificateRequestConditionError{
Err: fmt.Errorf("[err message2]"),
ConditionType: "[condition type]",
Status: cmmeta.ConditionTrue,
Reason: "[reason]",
signResult <- signResults{
err: fmt.Errorf("[err message2]"),
extraConditions: []cmapi.CertificateRequestCondition{
{
Type: "[condition type]",
Status: cmmeta.ConditionTrue,
Reason: "[condition reason]",
Message: "[condition message2]",
},
},
}
err = checkComplete(func(obj runtime.Object) error {
customCondition := cmutil.GetCertificateRequestCondition(obj.(*cmapi.CertificateRequest), "[condition type]")

if (customCondition == nil) ||
(customCondition.Status != cmmeta.ConditionTrue) ||
(customCondition.Reason != "[reason]") ||
(customCondition.Message != "[err message2]") {
(customCondition.Reason != "[condition reason]") ||
(customCondition.Message != "[condition message2]") {
return fmt.Errorf("incorrect custom condition: %v", customCondition)
}

Expand All @@ -350,7 +365,7 @@ func TestCertificateRequestControllerIntegrationSetCondition(t *testing.T) {
require.NoError(t, err)

checkComplete = kubeClients.StartObjectWatch(t, ctx, cr)
signResult <- nil
signResult <- signResults{}
t.Log("Waiting for the controller to marks the CertificateRequest as Ready")
err = checkComplete(func(obj runtime.Object) error {
readyCondition := cmutil.GetCertificateRequestCondition(obj.(*cmapi.CertificateRequest), cmapi.CertificateRequestConditionReady)
Expand Down
Loading