mirror of https://github.com/knative/pkg.git
Add AuthenticatableType duck type (#3056)
* Add AuthenticatableType * Add Resolver for AuthenticatableType * Run gofmt and goimports * Fix linter issues
This commit is contained in:
parent
15e6cdf2f3
commit
339c22b821
|
@ -16,6 +16,21 @@ limitations under the License.
|
|||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"knative.dev/pkg/apis"
|
||||
"knative.dev/pkg/apis/duck/ducktypes"
|
||||
"knative.dev/pkg/kmeta"
|
||||
"knative.dev/pkg/ptr"
|
||||
)
|
||||
|
||||
// +genduck
|
||||
|
||||
// AuthStatus is meant to provide the generated service account name
|
||||
// in the resource status.
|
||||
type AuthStatus struct {
|
||||
|
@ -28,3 +43,81 @@ type AuthStatus struct {
|
|||
// when the component uses multiple identities (e.g. in case of a Parallel).
|
||||
ServiceAccountNames []string `json:"serviceAccountNames,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// AuthenticatableType is a skeleton type wrapping AuthStatus in the manner we expect
|
||||
// resource writers defining compatible resources to embed it. We will
|
||||
// typically use this type to deserialize AuthenticatableType ObjectReferences and
|
||||
// access the AuthenticatableType data. This is not a real resource.
|
||||
type AuthenticatableType struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Status AuthenticatableStatus `json:"status"`
|
||||
}
|
||||
|
||||
type AuthenticatableStatus struct {
|
||||
// Auth contains the service account name for the subscription
|
||||
// +optional
|
||||
Auth *AuthStatus `json:"auth,omitempty"`
|
||||
}
|
||||
|
||||
var (
|
||||
// AuthStatus is a Convertible type.
|
||||
_ apis.Convertible = (*AuthStatus)(nil)
|
||||
|
||||
// Verify AuthenticatableType resources meet duck contracts.
|
||||
_ apis.Listable = (*AuthenticatableType)(nil)
|
||||
_ ducktypes.Populatable = (*AuthenticatableType)(nil)
|
||||
_ kmeta.OwnerRefable = (*AuthenticatableType)(nil)
|
||||
)
|
||||
|
||||
// GetFullType implements duck.Implementable
|
||||
func (*AuthStatus) GetFullType() ducktypes.Populatable {
|
||||
return &AuthenticatableType{}
|
||||
}
|
||||
|
||||
// ConvertTo implements apis.Convertible
|
||||
func (a *AuthStatus) ConvertTo(_ context.Context, to apis.Convertible) error {
|
||||
return fmt.Errorf("v1 is the highest known version, got: %T", to)
|
||||
}
|
||||
|
||||
// ConvertFrom implements apis.Convertible
|
||||
func (a *AuthStatus) ConvertFrom(_ context.Context, from apis.Convertible) error {
|
||||
return fmt.Errorf("v1 is the highest known version, got: %T", from)
|
||||
}
|
||||
|
||||
// Populate implements duck.Populatable
|
||||
func (t *AuthenticatableType) Populate() {
|
||||
t.Status = AuthenticatableStatus{
|
||||
Auth: &AuthStatus{
|
||||
// Populate ALL fields
|
||||
ServiceAccountName: ptr.String("foo"),
|
||||
ServiceAccountNames: []string{
|
||||
"bar",
|
||||
"baz",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetGroupVersionKind implements kmeta.OwnerRefable
|
||||
func (t *AuthenticatableType) GetGroupVersionKind() schema.GroupVersionKind {
|
||||
return t.GroupVersionKind()
|
||||
}
|
||||
|
||||
// GetListType implements apis.Listable
|
||||
func (*AuthenticatableType) GetListType() runtime.Object {
|
||||
return &AuthenticatableTypeList{}
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// AuthenticatableTypeList is a list of AuthenticatableType resources
|
||||
type AuthenticatableTypeList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata"`
|
||||
|
||||
Items []AuthenticatableType `json:"items"`
|
||||
}
|
||||
|
|
|
@ -176,6 +176,87 @@ func (in *AuthStatus) DeepCopy() *AuthStatus {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AuthenticatableStatus) DeepCopyInto(out *AuthenticatableStatus) {
|
||||
*out = *in
|
||||
if in.Auth != nil {
|
||||
in, out := &in.Auth, &out.Auth
|
||||
*out = new(AuthStatus)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthenticatableStatus.
|
||||
func (in *AuthenticatableStatus) DeepCopy() *AuthenticatableStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(AuthenticatableStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AuthenticatableType) DeepCopyInto(out *AuthenticatableType) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthenticatableType.
|
||||
func (in *AuthenticatableType) DeepCopy() *AuthenticatableType {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(AuthenticatableType)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *AuthenticatableType) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AuthenticatableTypeList) DeepCopyInto(out *AuthenticatableTypeList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]AuthenticatableType, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthenticatableTypeList.
|
||||
func (in *AuthenticatableTypeList) DeepCopy() *AuthenticatableTypeList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(AuthenticatableTypeList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *AuthenticatableTypeList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Binding) DeepCopyInto(out *Binding) {
|
||||
*out = *in
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
Copyright 2022 The Knative 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.
|
||||
*/
|
||||
|
||||
// Code generated by injection-gen. DO NOT EDIT.
|
||||
|
||||
package authstatus
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
duck "knative.dev/pkg/apis/duck"
|
||||
v1 "knative.dev/pkg/apis/duck/v1"
|
||||
controller "knative.dev/pkg/controller"
|
||||
injection "knative.dev/pkg/injection"
|
||||
dynamicclient "knative.dev/pkg/injection/clients/dynamicclient"
|
||||
logging "knative.dev/pkg/logging"
|
||||
)
|
||||
|
||||
func init() {
|
||||
injection.Default.RegisterDuck(WithDuck)
|
||||
}
|
||||
|
||||
// Key is used for associating the Informer inside the context.Context.
|
||||
type Key struct{}
|
||||
|
||||
func WithDuck(ctx context.Context) context.Context {
|
||||
dc := dynamicclient.Get(ctx)
|
||||
dif := &duck.CachedInformerFactory{
|
||||
Delegate: &duck.TypedInformerFactory{
|
||||
Client: dc,
|
||||
Type: (&v1.AuthStatus{}).GetFullType(),
|
||||
ResyncPeriod: controller.GetResyncPeriod(ctx),
|
||||
StopChannel: ctx.Done(),
|
||||
},
|
||||
}
|
||||
return context.WithValue(ctx, Key{}, dif)
|
||||
}
|
||||
|
||||
// Get extracts the typed informer from the context.
|
||||
func Get(ctx context.Context) duck.InformerFactory {
|
||||
untyped := ctx.Value(Key{})
|
||||
if untyped == nil {
|
||||
logging.FromContext(ctx).Panic(
|
||||
"Unable to fetch knative.dev/pkg/apis/duck.InformerFactory from context.")
|
||||
}
|
||||
return untyped.(duck.InformerFactory)
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
Copyright 2022 The Knative 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.
|
||||
*/
|
||||
|
||||
// Code generated by injection-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
authstatus "knative.dev/pkg/client/injection/ducks/duck/v1/authstatus"
|
||||
injection "knative.dev/pkg/injection"
|
||||
)
|
||||
|
||||
var Get = authstatus.Get
|
||||
|
||||
func init() {
|
||||
injection.Fake.RegisterDuck(authstatus.WithDuck)
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
Copyright 2024 The Knative 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 resolver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apierrs "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"knative.dev/pkg/client/injection/ducks/duck/v1/authstatus"
|
||||
"knative.dev/pkg/controller"
|
||||
|
||||
pkgapisduck "knative.dev/pkg/apis/duck"
|
||||
duckv1 "knative.dev/pkg/apis/duck/v1"
|
||||
"knative.dev/pkg/tracker"
|
||||
)
|
||||
|
||||
// AuthenticatableResolver resolves ObjectReferences into a AuthenticatableType.
|
||||
type AuthenticatableResolver struct {
|
||||
tracker tracker.Interface
|
||||
listerFactory func(schema.GroupVersionResource) (cache.GenericLister, error)
|
||||
}
|
||||
|
||||
// NewAuthenticatableResolverFromTracker constructs a new AuthenticatableResolver with context and a tracker.
|
||||
func NewAuthenticatableResolverFromTracker(ctx context.Context, t tracker.Interface) *AuthenticatableResolver {
|
||||
ret := &AuthenticatableResolver{
|
||||
tracker: t,
|
||||
}
|
||||
|
||||
informerFactory := &pkgapisduck.CachedInformerFactory{
|
||||
Delegate: &pkgapisduck.EnqueueInformerFactory{
|
||||
Delegate: authstatus.Get(ctx),
|
||||
EventHandler: controller.HandleAll(ret.tracker.OnChanged),
|
||||
},
|
||||
}
|
||||
|
||||
ret.listerFactory = func(gvr schema.GroupVersionResource) (cache.GenericLister, error) {
|
||||
_, l, err := informerFactory.Get(ctx, gvr)
|
||||
return l, err
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// AuthStatusFromObjectReference returns the AuthStatus from an object
|
||||
func (r *AuthenticatableResolver) AuthStatusFromObjectReference(ref *corev1.ObjectReference, parent interface{}) (*duckv1.AuthStatus, error) {
|
||||
if ref == nil {
|
||||
return nil, apierrs.NewBadRequest("ref is nil")
|
||||
}
|
||||
|
||||
authenticatable, err := r.authenticatableFromObjectReference(ref, parent)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get authenticatable %s/%s: %w", ref.Namespace, ref.Name, err)
|
||||
}
|
||||
|
||||
if authenticatable.Status.Auth == nil {
|
||||
return nil, fmt.Errorf(".status.auth is missing in object %s/%s", ref.Namespace, ref.Name)
|
||||
}
|
||||
|
||||
return authenticatable.Status.Auth, nil
|
||||
}
|
||||
|
||||
// authenticatableFromObjectReference resolves an object reference into an AuthenticatableType
|
||||
func (r *AuthenticatableResolver) authenticatableFromObjectReference(ref *corev1.ObjectReference, parent interface{}) (*duckv1.AuthenticatableType, error) {
|
||||
if ref == nil {
|
||||
return nil, apierrs.NewBadRequest("ref is nil")
|
||||
}
|
||||
|
||||
gvr, _ := meta.UnsafeGuessKindToResource(ref.GroupVersionKind())
|
||||
if err := r.tracker.TrackReference(tracker.Reference{
|
||||
APIVersion: ref.APIVersion,
|
||||
Kind: ref.Kind,
|
||||
Namespace: ref.Namespace,
|
||||
Name: ref.Name,
|
||||
}, parent); err != nil {
|
||||
return nil, fmt.Errorf("failed to track reference %s %s/%s: %w", gvr.String(), ref.Namespace, ref.Name, err)
|
||||
}
|
||||
|
||||
lister, err := r.listerFactory(gvr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get lister for %s: %w", gvr.String(), err)
|
||||
}
|
||||
|
||||
obj, err := lister.ByNamespace(ref.Namespace).Get(ref.Name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get object %s/%s: %w", ref.Namespace, ref.Name, err)
|
||||
}
|
||||
|
||||
authenticatable, ok := obj.(*duckv1.AuthenticatableType)
|
||||
if !ok {
|
||||
return nil, apierrs.NewBadRequest(fmt.Sprintf("%s(%T) is not an AuthenticatableType", ref, ref))
|
||||
}
|
||||
|
||||
// Do not modify informer copy.
|
||||
authenticatable = authenticatable.DeepCopy()
|
||||
|
||||
return authenticatable, nil
|
||||
}
|
|
@ -0,0 +1,274 @@
|
|||
/*
|
||||
Copyright 2024 The Knative 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 resolver_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
duckv1 "knative.dev/pkg/apis/duck/v1"
|
||||
fakedynamicclient "knative.dev/pkg/injection/clients/dynamicclient/fake"
|
||||
"knative.dev/pkg/ptr"
|
||||
"knative.dev/pkg/resolver"
|
||||
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
duckv1alpha1 "knative.dev/pkg/apis/duck/v1alpha1"
|
||||
duckv1beta1 "knative.dev/pkg/apis/duck/v1beta1"
|
||||
"knative.dev/pkg/client/injection/ducks/duck/v1/authstatus"
|
||||
"knative.dev/pkg/tracker"
|
||||
)
|
||||
|
||||
const (
|
||||
authenticatableName = "testsource"
|
||||
authenticatableKind = "Source"
|
||||
authenticatableAPIVersion = "duck.knative.dev/v1"
|
||||
authenticatableResource = "sources.duck.knative.dev"
|
||||
|
||||
authenticatable2Name = "test2-source"
|
||||
authenticatable2Kind = "AnotherSource"
|
||||
authenticatable2APIVersion = "duck.knative.dev/v1"
|
||||
authenticatable2Resource = "anothersources.duck.knative.dev"
|
||||
|
||||
unauthenticatableName = "testunauthenticatable"
|
||||
unauthenticatableKind = "KResource"
|
||||
unauthenticatableAPIVersion = "duck.knative.dev/v1alpha1"
|
||||
|
||||
authenticatableServiceAccountName = "my-service-account"
|
||||
authenticatableServiceAccountName1 = "my-service-account-1"
|
||||
authenticatableServiceAccountName2 = "my-service-account-2"
|
||||
authenticatable2ServiceAccountName = "service-account-of-2nd-authenticatable"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Add types to scheme
|
||||
duckv1alpha1.AddToScheme(scheme.Scheme)
|
||||
duckv1beta1.AddToScheme(scheme.Scheme)
|
||||
|
||||
scheme.Scheme.AddKnownTypeWithName(
|
||||
schema.FromAPIVersionAndKind(unauthenticatableAPIVersion, unauthenticatableKind),
|
||||
&unstructured.Unstructured{},
|
||||
)
|
||||
scheme.Scheme.AddKnownTypeWithName(
|
||||
schema.FromAPIVersionAndKind(unauthenticatableAPIVersion, unauthenticatableKind+"List"),
|
||||
&unstructured.UnstructuredList{},
|
||||
)
|
||||
scheme.Scheme.AddKnownTypeWithName(
|
||||
schema.FromAPIVersionAndKind(authenticatableAPIVersion, authenticatableKind),
|
||||
&unstructured.Unstructured{},
|
||||
)
|
||||
scheme.Scheme.AddKnownTypeWithName(
|
||||
schema.FromAPIVersionAndKind(authenticatableAPIVersion, authenticatableKind+"List"),
|
||||
&unstructured.UnstructuredList{},
|
||||
)
|
||||
}
|
||||
|
||||
func TestAuthenticatableResolver_AuthStatusFromObjectReference(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
objects []runtime.Object
|
||||
objectRef *corev1.ObjectReference
|
||||
want *duckv1.AuthStatus
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "nil everything",
|
||||
wantErr: "ref is nil",
|
||||
}, {
|
||||
name: "Valid authenticatable",
|
||||
objects: []runtime.Object{
|
||||
getAuthenticatable(),
|
||||
},
|
||||
objectRef: authenticatableRef(),
|
||||
want: &duckv1.AuthStatus{
|
||||
ServiceAccountName: ptr.String(authenticatableServiceAccountName),
|
||||
},
|
||||
}, {
|
||||
name: "Valid authenticatable in multiple objects",
|
||||
objects: []runtime.Object{
|
||||
getUnauthenticatable(),
|
||||
getAuthenticatable(),
|
||||
getAuthenticatable2(),
|
||||
},
|
||||
objectRef: authenticatable2Ref(),
|
||||
want: &duckv1.AuthStatus{
|
||||
ServiceAccountName: ptr.String(authenticatable2ServiceAccountName),
|
||||
},
|
||||
}, {
|
||||
name: "Valid authenticatable multiple SAs",
|
||||
objects: []runtime.Object{
|
||||
getAuthenticatableWithMultipleSAs(),
|
||||
},
|
||||
objectRef: authenticatableRef(),
|
||||
want: &duckv1.AuthStatus{
|
||||
ServiceAccountNames: []string{
|
||||
authenticatableServiceAccountName1,
|
||||
authenticatableServiceAccountName2,
|
||||
},
|
||||
},
|
||||
}, {
|
||||
name: "Unauthenticatable",
|
||||
objects: []runtime.Object{
|
||||
getUnauthenticatable(),
|
||||
},
|
||||
objectRef: unauthenticatableRef(),
|
||||
wantErr: fmt.Sprintf(".status.auth is missing in object %s/%s", testNS, unauthenticatableName),
|
||||
}, {
|
||||
name: "Authenticatable not found",
|
||||
objects: []runtime.Object{
|
||||
getUnauthenticatable(),
|
||||
},
|
||||
objectRef: authenticatableRef(),
|
||||
wantErr: fmt.Sprintf("failed to get authenticatable %s/%s: failed to get object %s/%s: %s %q not found", testNS, authenticatableName, testNS, authenticatableName, authenticatableResource, authenticatableName),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctx, _ := fakedynamicclient.With(context.Background(), scheme.Scheme, tt.objects...)
|
||||
ctx = authstatus.WithDuck(ctx)
|
||||
r := resolver.NewAuthenticatableResolverFromTracker(ctx, tracker.New(func(types.NamespacedName) {}, 0))
|
||||
|
||||
// Run it twice since this should be idempotent. AuthenticatableResolver should
|
||||
// not modify the cache's copy.
|
||||
_, _ = r.AuthStatusFromObjectReference(tt.objectRef, getAuthenticatable())
|
||||
authStatus, gotErr := r.AuthStatusFromObjectReference(tt.objectRef, getAuthenticatable())
|
||||
|
||||
if gotErr != nil {
|
||||
if tt.wantErr != "" {
|
||||
if got, want := gotErr.Error(), tt.wantErr; got != want {
|
||||
t.Errorf("Unexpected error (-want, +got) =\n%s", cmp.Diff(want, got))
|
||||
}
|
||||
} else {
|
||||
t.Error("Unexpected error:", gotErr)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if got, want := authStatus, tt.want; !cmp.Equal(got, want) {
|
||||
t.Errorf("Unexpected object (-want, +got) =\n%s", cmp.Diff(got, want))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func getAuthenticatable() *unstructured.Unstructured {
|
||||
return &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": authenticatableAPIVersion,
|
||||
"kind": authenticatableKind,
|
||||
"metadata": map[string]interface{}{
|
||||
"namespace": testNS,
|
||||
"name": authenticatableName,
|
||||
},
|
||||
"status": map[string]interface{}{
|
||||
"auth": map[string]interface{}{
|
||||
"serviceAccountName": authenticatableServiceAccountName,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getAuthenticatable2() *unstructured.Unstructured {
|
||||
return &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": authenticatable2APIVersion,
|
||||
"kind": authenticatable2Kind,
|
||||
"metadata": map[string]interface{}{
|
||||
"namespace": testNS,
|
||||
"name": authenticatable2Name,
|
||||
},
|
||||
"status": map[string]interface{}{
|
||||
"auth": map[string]interface{}{
|
||||
"serviceAccountName": authenticatable2ServiceAccountName,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getAuthenticatableWithMultipleSAs() *unstructured.Unstructured {
|
||||
return &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": authenticatableAPIVersion,
|
||||
"kind": authenticatableKind,
|
||||
"metadata": map[string]interface{}{
|
||||
"namespace": testNS,
|
||||
"name": authenticatableName,
|
||||
},
|
||||
"status": map[string]interface{}{
|
||||
"auth": map[string]interface{}{
|
||||
"serviceAccountNames": []interface{}{
|
||||
authenticatableServiceAccountName1,
|
||||
authenticatableServiceAccountName2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getUnauthenticatable() *unstructured.Unstructured {
|
||||
return &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": unauthenticatableAPIVersion,
|
||||
"kind": unauthenticatableKind,
|
||||
"metadata": map[string]interface{}{
|
||||
"namespace": testNS,
|
||||
"name": unauthenticatableName,
|
||||
},
|
||||
"status": map[string]interface{}{
|
||||
"something": map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func authenticatableRef() *corev1.ObjectReference {
|
||||
return &corev1.ObjectReference{
|
||||
Kind: authenticatableKind,
|
||||
Name: authenticatableName,
|
||||
APIVersion: authenticatableAPIVersion,
|
||||
Namespace: testNS,
|
||||
}
|
||||
}
|
||||
|
||||
func authenticatable2Ref() *corev1.ObjectReference {
|
||||
return &corev1.ObjectReference{
|
||||
Kind: authenticatable2Kind,
|
||||
Name: authenticatable2Name,
|
||||
APIVersion: authenticatable2APIVersion,
|
||||
Namespace: testNS,
|
||||
}
|
||||
}
|
||||
|
||||
func unauthenticatableRef() *corev1.ObjectReference {
|
||||
return &corev1.ObjectReference{
|
||||
Kind: unauthenticatableKind,
|
||||
Name: unauthenticatableName,
|
||||
APIVersion: unauthenticatableAPIVersion,
|
||||
Namespace: testNS,
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue