defaultclass: add all policies and remove deprecated default controllers
Signed-off-by: hasheddan <georgedanielmangum@gmail.com>
This commit is contained in:
parent
06c5252917
commit
5c1fdc1caa
|
|
@ -1,130 +0,0 @@
|
|||
/*
|
||||
Copyright 2019 The Crossplane 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 resource
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
|
||||
corev1alpha1 "github.com/crossplaneio/crossplane/apis/core/v1alpha1"
|
||||
"github.com/crossplaneio/crossplane/pkg/logging"
|
||||
"github.com/crossplaneio/crossplane/pkg/meta"
|
||||
)
|
||||
|
||||
const (
|
||||
controllerNameDeprecatedDefaultClass = "deprecateddefaultclass.crossplane.io"
|
||||
deprecatedDefaultClassWait = 1 * time.Minute
|
||||
deprecatedDefaultClassReconcileTimeout = 1 * time.Minute
|
||||
)
|
||||
|
||||
// Error strings
|
||||
const (
|
||||
errFailedListDeprecated = "unable to list default resource classes"
|
||||
errNoDefaultClass = "unable to locate a default resource class for claim kind"
|
||||
errMultipleDefaultClasses = "multiple default classes defined for claim kind"
|
||||
)
|
||||
|
||||
// DeprecatedDefaultClassReconciler reconciles resource claims to the
|
||||
// default resource class for their given kind. Predicates
|
||||
// ensure that only claims with no resource class reference
|
||||
// are reconciled.
|
||||
type DeprecatedDefaultClassReconciler struct {
|
||||
client client.Client
|
||||
newClaim func() Claim
|
||||
options client.MatchingLabels
|
||||
}
|
||||
|
||||
// NewDeprecatedDefaultClassReconciler creates a new DefaultReconciler for the claim kind
|
||||
func NewDeprecatedDefaultClassReconciler(m manager.Manager, of ClaimKind) *DeprecatedDefaultClassReconciler {
|
||||
nc := func() Claim { return MustCreateObject(schema.GroupVersionKind(of), m.GetScheme()).(Claim) }
|
||||
|
||||
// Panic early if we've been asked to reconcile a claim that has
|
||||
// not been registered with our controller manager's scheme.
|
||||
_ = nc()
|
||||
|
||||
gk := strings.ToLower(schema.GroupVersionKind(of).GroupKind().String())
|
||||
|
||||
// Create list options query that will be used to search
|
||||
// for resource class that is default for claim kind.
|
||||
options := client.MatchingLabels{
|
||||
gk + "/default": "true",
|
||||
}
|
||||
return &DeprecatedDefaultClassReconciler{
|
||||
client: m.GetClient(),
|
||||
newClaim: nc,
|
||||
options: options,
|
||||
}
|
||||
}
|
||||
|
||||
// Reconcile reconciles a claim to the default class reference for its kind
|
||||
func (r *DeprecatedDefaultClassReconciler) Reconcile(req reconcile.Request) (reconcile.Result, error) {
|
||||
log.V(logging.Debug).Info("Reconciling", "request", req, "controller", controllerNameDeprecatedDefaultClass)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), deprecatedDefaultClassReconcileTimeout)
|
||||
defer cancel()
|
||||
|
||||
claim := r.newClaim()
|
||||
if err := r.client.Get(ctx, req.NamespacedName, claim); err != nil {
|
||||
// There's no need to requeue if we no longer exist. Otherwise we'll be
|
||||
// requeued implicitly because we return an error.
|
||||
return reconcile.Result{}, errors.Wrap(IgnoreNotFound(err), errGetClaim)
|
||||
}
|
||||
|
||||
// Get resource classes with claim kind as default
|
||||
// NOTE(hasheddan): corev1alpha1 import here prevents checking that
|
||||
// ResourceClass satisfies Class interface. Would be a circular import.
|
||||
classes := &corev1alpha1.ResourceClassList{}
|
||||
if err := r.client.List(ctx, classes, r.options); err != nil {
|
||||
// If this is the first time we encounter no defaults we'll be
|
||||
// requeued implicitly due to the status update. If not, we don't
|
||||
// care to requeue because list parameters will not change.
|
||||
claim.SetConditions(corev1alpha1.ReconcileError(errors.New(errFailedListDeprecated)))
|
||||
return reconcile.Result{}, errors.Wrap(IgnoreNotFound(r.client.Status().Update(ctx, claim)), errUpdateClaimStatus)
|
||||
}
|
||||
|
||||
// Check to see if no defaults defined for claim kind.
|
||||
if len(classes.Items) == 0 {
|
||||
// If this is the first time we encounter no defaults we'll be
|
||||
// requeued implicitly due to the status update. If not, we will requeue
|
||||
// after a time to see if a default class has been created.
|
||||
claim.SetConditions(corev1alpha1.ReconcileError(errors.New(errNoDefaultClass)))
|
||||
return reconcile.Result{RequeueAfter: deprecatedDefaultClassWait}, errors.Wrap(IgnoreNotFound(r.client.Status().Update(ctx, claim)), errUpdateClaimStatus)
|
||||
}
|
||||
|
||||
// Check to see if multiple defaults defined for claim kind.
|
||||
if len(classes.Items) > 1 {
|
||||
// If this is the first time we encounter multiple defaults we'll be
|
||||
// requeued implicitly due to the status update. If not, we will requeue
|
||||
// after a time to see if only one default class exists.
|
||||
claim.SetConditions(corev1alpha1.ReconcileError(errors.New(errMultipleDefaultClasses)))
|
||||
return reconcile.Result{RequeueAfter: deprecatedDefaultClassWait}, errors.Wrap(IgnoreNotFound(r.client.Status().Update(ctx, claim)), errUpdateClaimStatus)
|
||||
}
|
||||
|
||||
// Set class reference on claim to default resource class
|
||||
claim.SetClassReference(meta.ReferenceTo(&classes.Items[0], corev1alpha1.ResourceClassGroupVersionKind))
|
||||
|
||||
// Do not requeue, claim controller will see update and claim
|
||||
// with class reference set will pass predicates.
|
||||
return reconcile.Result{Requeue: false}, errors.Wrap(IgnoreNotFound(r.client.Update(ctx, claim)), errUpdateClaimStatus)
|
||||
}
|
||||
|
|
@ -1,234 +0,0 @@
|
|||
/*
|
||||
Copyright 2019 The Crossplane 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 resource
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
|
||||
corev1alpha1 "github.com/crossplaneio/crossplane/apis/core/v1alpha1"
|
||||
"github.com/crossplaneio/crossplane/pkg/meta"
|
||||
"github.com/crossplaneio/crossplane/pkg/test"
|
||||
)
|
||||
|
||||
var _ reconcile.Reconciler = &DeprecatedDefaultClassReconciler{}
|
||||
|
||||
func TestDeprecatedDefaultClassReconcile(t *testing.T) {
|
||||
type args struct {
|
||||
m manager.Manager
|
||||
of ClaimKind
|
||||
}
|
||||
|
||||
type want struct {
|
||||
result reconcile.Result
|
||||
err error
|
||||
}
|
||||
|
||||
errBoom := errors.New("boom")
|
||||
errUnexpected := errors.New("unexpected object type")
|
||||
class := corev1alpha1.ResourceClass{}
|
||||
class.SetName("default-class")
|
||||
class.SetNamespace("default-namespace")
|
||||
|
||||
cases := map[string]struct {
|
||||
args args
|
||||
want want
|
||||
}{
|
||||
"GetClaimError": {
|
||||
args: args{
|
||||
m: &MockManager{
|
||||
c: &test.MockClient{MockGet: test.NewMockGetFn(errBoom)},
|
||||
s: MockSchemeWith(&MockClaim{}),
|
||||
},
|
||||
of: ClaimKind(MockGVK(&MockClaim{})),
|
||||
},
|
||||
want: want{err: errors.Wrap(errBoom, errGetClaim)},
|
||||
},
|
||||
"ListDefaultClassesError": {
|
||||
args: args{
|
||||
m: &MockManager{
|
||||
c: &test.MockClient{
|
||||
MockGet: test.NewMockGetFn(nil, func(o runtime.Object) error {
|
||||
switch o := o.(type) {
|
||||
case *MockClaim:
|
||||
*o = MockClaim{}
|
||||
return nil
|
||||
default:
|
||||
return errUnexpected
|
||||
}
|
||||
}),
|
||||
MockList: test.NewMockListFn(errBoom),
|
||||
MockStatusUpdate: test.NewMockStatusUpdateFn(nil, func(got runtime.Object) error {
|
||||
want := &MockClaim{}
|
||||
want.SetConditions(corev1alpha1.ReconcileError(errors.New(errFailedListDeprecated)))
|
||||
if diff := cmp.Diff(want, got, test.EquateConditions()); diff != "" {
|
||||
t.Errorf("-want, +got:\n%s", diff)
|
||||
}
|
||||
return nil
|
||||
}),
|
||||
},
|
||||
s: MockSchemeWith(&MockClaim{}),
|
||||
},
|
||||
of: ClaimKind(MockGVK(&MockClaim{})),
|
||||
},
|
||||
want: want{result: reconcile.Result{}},
|
||||
},
|
||||
"NoDefaultClass": {
|
||||
args: args{
|
||||
m: &MockManager{
|
||||
c: &test.MockClient{
|
||||
MockGet: test.NewMockGetFn(nil, func(o runtime.Object) error {
|
||||
switch o := o.(type) {
|
||||
case *MockClaim:
|
||||
*o = MockClaim{}
|
||||
return nil
|
||||
default:
|
||||
return errUnexpected
|
||||
}
|
||||
}),
|
||||
MockList: test.NewMockListFn(nil, func(o runtime.Object) error {
|
||||
switch o := o.(type) {
|
||||
case *corev1alpha1.ResourceClassList:
|
||||
cm := &corev1alpha1.ResourceClassList{}
|
||||
cm.Items = []corev1alpha1.ResourceClass{}
|
||||
*o = *cm
|
||||
return nil
|
||||
default:
|
||||
return errUnexpected
|
||||
}
|
||||
}),
|
||||
MockStatusUpdate: test.NewMockStatusUpdateFn(nil, func(got runtime.Object) error {
|
||||
want := &MockClaim{}
|
||||
want.SetConditions(corev1alpha1.ReconcileError(errors.New(errNoDefaultClass)))
|
||||
if diff := cmp.Diff(want, got, test.EquateConditions()); diff != "" {
|
||||
t.Errorf("-want, +got:\n%s", diff)
|
||||
}
|
||||
return nil
|
||||
}),
|
||||
},
|
||||
s: MockSchemeWith(&MockClaim{}),
|
||||
},
|
||||
of: ClaimKind(MockGVK(&MockClaim{})),
|
||||
},
|
||||
want: want{result: reconcile.Result{RequeueAfter: deprecatedDefaultClassWait}},
|
||||
},
|
||||
"MultipleDefaultClasses": {
|
||||
args: args{
|
||||
m: &MockManager{
|
||||
c: &test.MockClient{
|
||||
MockGet: test.NewMockGetFn(nil, func(o runtime.Object) error {
|
||||
switch o := o.(type) {
|
||||
case *MockClaim:
|
||||
*o = MockClaim{}
|
||||
return nil
|
||||
default:
|
||||
return errUnexpected
|
||||
}
|
||||
}),
|
||||
MockList: test.NewMockListFn(nil, func(o runtime.Object) error {
|
||||
switch o := o.(type) {
|
||||
case *corev1alpha1.ResourceClassList:
|
||||
cm := &corev1alpha1.ResourceClassList{}
|
||||
cm.Items = []corev1alpha1.ResourceClass{
|
||||
{},
|
||||
{},
|
||||
}
|
||||
*o = *cm
|
||||
return nil
|
||||
default:
|
||||
return errUnexpected
|
||||
}
|
||||
}),
|
||||
MockStatusUpdate: test.NewMockStatusUpdateFn(nil, func(got runtime.Object) error {
|
||||
want := &MockClaim{}
|
||||
want.SetConditions(corev1alpha1.ReconcileError(errors.New(errMultipleDefaultClasses)))
|
||||
if diff := cmp.Diff(want, got, test.EquateConditions()); diff != "" {
|
||||
t.Errorf("-want, +got:\n%s", diff)
|
||||
}
|
||||
return nil
|
||||
}),
|
||||
},
|
||||
s: MockSchemeWith(&MockClaim{}),
|
||||
},
|
||||
of: ClaimKind(MockGVK(&MockClaim{})),
|
||||
},
|
||||
want: want{result: reconcile.Result{RequeueAfter: deprecatedDefaultClassWait}},
|
||||
},
|
||||
"Successful": {
|
||||
args: args{
|
||||
m: &MockManager{
|
||||
c: &test.MockClient{
|
||||
MockGet: test.NewMockGetFn(nil, func(o runtime.Object) error {
|
||||
switch o := o.(type) {
|
||||
case *MockClaim:
|
||||
*o = MockClaim{}
|
||||
return nil
|
||||
default:
|
||||
return errUnexpected
|
||||
}
|
||||
}),
|
||||
MockList: test.NewMockListFn(nil, func(o runtime.Object) error {
|
||||
switch o := o.(type) {
|
||||
case *corev1alpha1.ResourceClassList:
|
||||
cm := &corev1alpha1.ResourceClassList{}
|
||||
cm.Items = []corev1alpha1.ResourceClass{
|
||||
class,
|
||||
}
|
||||
*o = *cm
|
||||
return nil
|
||||
default:
|
||||
return errUnexpected
|
||||
}
|
||||
}),
|
||||
MockUpdate: test.NewMockUpdateFn(nil, func(got runtime.Object) error {
|
||||
want := &MockClaim{}
|
||||
want.SetClassReference(meta.ReferenceTo(class.GetObjectMeta(), corev1alpha1.ResourceClassGroupVersionKind))
|
||||
if diff := cmp.Diff(want, got, test.EquateConditions()); diff != "" {
|
||||
t.Errorf("-want, +got:\n%s", diff)
|
||||
}
|
||||
return nil
|
||||
}),
|
||||
},
|
||||
s: MockSchemeWith(&MockClaim{}),
|
||||
},
|
||||
of: ClaimKind(MockGVK(&MockClaim{})),
|
||||
},
|
||||
want: want{result: reconcile.Result{Requeue: false}},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
r := NewDeprecatedDefaultClassReconciler(tc.args.m, tc.args.of)
|
||||
got, err := r.Reconcile(reconcile.Request{})
|
||||
|
||||
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
|
||||
t.Errorf("r.Reconcile(...): -want error, +got error:\n%s", diff)
|
||||
}
|
||||
|
||||
if diff := cmp.Diff(tc.want.result, got); diff != "" {
|
||||
t.Errorf("r.Reconcile(...): -want, +got:\n%s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue