diff --git a/e2e/k8sworkload.yaml b/e2e/k8sworkload.yaml index f849968e..2aabb3dd 100644 --- a/e2e/k8sworkload.yaml +++ b/e2e/k8sworkload.yaml @@ -134,6 +134,8 @@ data: # echo -n 'notakey' | base64 ssh-privatekey: | bm90YWtleSAtbgo= + authorized_keys: | + c3NoLWVkMjU1MTkgQUFBQUMzTnphQzFsWkRJMU5URTVBQUFBSU5SR1RIMzI1ckRVcDEydHBsd3VrSG1SOHl0YkM5VFBaODg2Z0NzdHluUDEK kind: Secret metadata: name: host-publickey-key-custom-field @@ -149,7 +151,8 @@ spec: from: - username: "custom_field" # catch all username_regex_match: true - authorized_keys_data: "c3NoLWVkMjU1MTkgQUFBQUMzTnphQzFsWkRJMU5URTVBQUFBSU5SR1RIMzI1ckRVcDEydHBsd3VrSG1SOHl0YkM5VFBaODg2Z0NzdHluUDEK" + authorized_keys_secret: # use the secret with custom field + name: host-publickey-key-custom-field to: host: host-publickey:2222 username: "user" diff --git a/plugin/kubernetes/apis/sshpiper/v1beta1/types.go b/plugin/kubernetes/apis/sshpiper/v1beta1/types.go index 80ae658d..b9470e03 100644 --- a/plugin/kubernetes/apis/sshpiper/v1beta1/types.go +++ b/plugin/kubernetes/apis/sshpiper/v1beta1/types.go @@ -20,12 +20,13 @@ type PipeSpec struct { } type FromSpec struct { - Username string `json:"username"` - UsernameRegexMatch bool `json:"username_regex_match,omitempty"` - AuthorizedKeysData string `json:"authorized_keys_data,omitempty"` - HtpasswdData string `json:"htpasswd_data,omitempty"` - AuthorizedKeysFile string `json:"authorized_keys_file,omitempty"` - HtpasswdFile string `json:"htpasswd_file,omitempty"` + Username string `json:"username"` + UsernameRegexMatch bool `json:"username_regex_match,omitempty"` + AuthorizedKeysData string `json:"authorized_keys_data,omitempty"` + AuthorizedKeysFile string `json:"authorized_keys_file,omitempty"` + AuthorizedKeysSecret corev1.LocalObjectReference `json:"authorized_keys_secret,omitempty"` + HtpasswdData string `json:"htpasswd_data,omitempty"` + HtpasswdFile string `json:"htpasswd_file,omitempty"` } type ToSpec struct { diff --git a/plugin/kubernetes/apis/sshpiper/v1beta1/zz_generated.deepcopy.go b/plugin/kubernetes/apis/sshpiper/v1beta1/zz_generated.deepcopy.go index eddf8bc9..96f22316 100644 --- a/plugin/kubernetes/apis/sshpiper/v1beta1/zz_generated.deepcopy.go +++ b/plugin/kubernetes/apis/sshpiper/v1beta1/zz_generated.deepcopy.go @@ -12,6 +12,7 @@ import ( // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *FromSpec) DeepCopyInto(out *FromSpec) { *out = *in + out.AuthorizedKeysSecret = in.AuthorizedKeysSecret return } @@ -111,6 +112,7 @@ func (in *PipeSpec) DeepCopy() *PipeSpec { func (in *ToSpec) DeepCopyInto(out *ToSpec) { *out = *in out.PrivateKeySecret = in.PrivateKeySecret + out.PasswordSecret = in.PasswordSecret return } diff --git a/plugin/kubernetes/crd.yaml b/plugin/kubernetes/crd.yaml index 098d9c05..b768b561 100644 --- a/plugin/kubernetes/crd.yaml +++ b/plugin/kubernetes/crd.yaml @@ -36,6 +36,15 @@ spec: type: string authorized_keys_file: type: string + authorized_keys_secret: + description: LocalObjectReference contains enough information + to let you locate the referenced object inside the same namespace. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + type: object username: type: string htpasswd_data: diff --git a/plugin/kubernetes/generated/clientset/versioned/clientset.go b/plugin/kubernetes/generated/clientset/versioned/clientset.go index 965fb79f..e80ddbfc 100644 --- a/plugin/kubernetes/generated/clientset/versioned/clientset.go +++ b/plugin/kubernetes/generated/clientset/versioned/clientset.go @@ -3,8 +3,8 @@ package versioned import ( - "fmt" - "net/http" + fmt "fmt" + http "net/http" sshpiperv1beta1 "github.com/tg123/sshpiper/plugin/kubernetes/generated/clientset/versioned/typed/sshpiper/v1beta1" discovery "k8s.io/client-go/discovery" diff --git a/plugin/kubernetes/generated/clientset/versioned/fake/clientset_generated.go b/plugin/kubernetes/generated/clientset/versioned/fake/clientset_generated.go index d304c5ad..dd6f72d8 100644 --- a/plugin/kubernetes/generated/clientset/versioned/fake/clientset_generated.go +++ b/plugin/kubernetes/generated/clientset/versioned/fake/clientset_generated.go @@ -15,8 +15,12 @@ import ( // NewSimpleClientset returns a clientset that will respond with the provided objects. // It's backed by a very simple object tracker that processes creates, updates and deletions as-is, -// without applying any validations and/or defaults. It shouldn't be considered a replacement +// without applying any field management, validations and/or defaults. It shouldn't be considered a replacement // for a real clientset and is mostly useful in simple unit tests. +// +// DEPRECATED: NewClientset replaces this with support for field management, which significantly improves +// server side apply testing. NewClientset is only available when apply configurations are generated (e.g. +// via --with-applyconfig). func NewSimpleClientset(objects ...runtime.Object) *Clientset { o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) for _, obj := range objects { diff --git a/plugin/kubernetes/generated/clientset/versioned/typed/sshpiper/v1beta1/fake/fake_pipe.go b/plugin/kubernetes/generated/clientset/versioned/typed/sshpiper/v1beta1/fake/fake_pipe.go index d9611698..f1698388 100644 --- a/plugin/kubernetes/generated/clientset/versioned/typed/sshpiper/v1beta1/fake/fake_pipe.go +++ b/plugin/kubernetes/generated/clientset/versioned/typed/sshpiper/v1beta1/fake/fake_pipe.go @@ -3,111 +3,30 @@ package fake import ( - "context" - v1beta1 "github.com/tg123/sshpiper/plugin/kubernetes/apis/sshpiper/v1beta1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - testing "k8s.io/client-go/testing" + sshpiperv1beta1 "github.com/tg123/sshpiper/plugin/kubernetes/generated/clientset/versioned/typed/sshpiper/v1beta1" + gentype "k8s.io/client-go/gentype" ) -// FakePipes implements PipeInterface -type FakePipes struct { +// fakePipes implements PipeInterface +type fakePipes struct { + *gentype.FakeClientWithList[*v1beta1.Pipe, *v1beta1.PipeList] Fake *FakeSshpiperV1beta1 - ns string } -var pipesResource = v1beta1.SchemeGroupVersion.WithResource("pipes") - -var pipesKind = v1beta1.SchemeGroupVersion.WithKind("Pipe") - -// Get takes name of the pipe, and returns the corresponding pipe object, and an error if there is any. -func (c *FakePipes) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.Pipe, err error) { - obj, err := c.Fake. - Invokes(testing.NewGetAction(pipesResource, c.ns, name), &v1beta1.Pipe{}) - - if obj == nil { - return nil, err +func newFakePipes(fake *FakeSshpiperV1beta1, namespace string) sshpiperv1beta1.PipeInterface { + return &fakePipes{ + gentype.NewFakeClientWithList[*v1beta1.Pipe, *v1beta1.PipeList]( + fake.Fake, + namespace, + v1beta1.SchemeGroupVersion.WithResource("pipes"), + v1beta1.SchemeGroupVersion.WithKind("Pipe"), + func() *v1beta1.Pipe { return &v1beta1.Pipe{} }, + func() *v1beta1.PipeList { return &v1beta1.PipeList{} }, + func(dst, src *v1beta1.PipeList) { dst.ListMeta = src.ListMeta }, + func(list *v1beta1.PipeList) []*v1beta1.Pipe { return gentype.ToPointerSlice(list.Items) }, + func(list *v1beta1.PipeList, items []*v1beta1.Pipe) { list.Items = gentype.FromPointerSlice(items) }, + ), + fake, } - return obj.(*v1beta1.Pipe), err -} - -// List takes label and field selectors, and returns the list of Pipes that match those selectors. -func (c *FakePipes) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.PipeList, err error) { - obj, err := c.Fake. - Invokes(testing.NewListAction(pipesResource, pipesKind, c.ns, opts), &v1beta1.PipeList{}) - - if obj == nil { - return nil, err - } - - label, _, _ := testing.ExtractFromListOptions(opts) - if label == nil { - label = labels.Everything() - } - list := &v1beta1.PipeList{ListMeta: obj.(*v1beta1.PipeList).ListMeta} - for _, item := range obj.(*v1beta1.PipeList).Items { - if label.Matches(labels.Set(item.Labels)) { - list.Items = append(list.Items, item) - } - } - return list, err -} - -// Watch returns a watch.Interface that watches the requested pipes. -func (c *FakePipes) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - return c.Fake. - InvokesWatch(testing.NewWatchAction(pipesResource, c.ns, opts)) - -} - -// Create takes the representation of a pipe and creates it. Returns the server's representation of the pipe, and an error, if there is any. -func (c *FakePipes) Create(ctx context.Context, pipe *v1beta1.Pipe, opts v1.CreateOptions) (result *v1beta1.Pipe, err error) { - obj, err := c.Fake. - Invokes(testing.NewCreateAction(pipesResource, c.ns, pipe), &v1beta1.Pipe{}) - - if obj == nil { - return nil, err - } - return obj.(*v1beta1.Pipe), err -} - -// Update takes the representation of a pipe and updates it. Returns the server's representation of the pipe, and an error, if there is any. -func (c *FakePipes) Update(ctx context.Context, pipe *v1beta1.Pipe, opts v1.UpdateOptions) (result *v1beta1.Pipe, err error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateAction(pipesResource, c.ns, pipe), &v1beta1.Pipe{}) - - if obj == nil { - return nil, err - } - return obj.(*v1beta1.Pipe), err -} - -// Delete takes name of the pipe and deletes it. Returns an error if one occurs. -func (c *FakePipes) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - _, err := c.Fake. - Invokes(testing.NewDeleteActionWithOptions(pipesResource, c.ns, name, opts), &v1beta1.Pipe{}) - - return err -} - -// DeleteCollection deletes a collection of objects. -func (c *FakePipes) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(pipesResource, c.ns, listOpts) - - _, err := c.Fake.Invokes(action, &v1beta1.PipeList{}) - return err -} - -// Patch applies the patch and returns the patched pipe. -func (c *FakePipes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.Pipe, err error) { - obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(pipesResource, c.ns, name, pt, data, subresources...), &v1beta1.Pipe{}) - - if obj == nil { - return nil, err - } - return obj.(*v1beta1.Pipe), err } diff --git a/plugin/kubernetes/generated/clientset/versioned/typed/sshpiper/v1beta1/fake/fake_sshpiper_client.go b/plugin/kubernetes/generated/clientset/versioned/typed/sshpiper/v1beta1/fake/fake_sshpiper_client.go index f168f664..8b90bf6c 100644 --- a/plugin/kubernetes/generated/clientset/versioned/typed/sshpiper/v1beta1/fake/fake_sshpiper_client.go +++ b/plugin/kubernetes/generated/clientset/versioned/typed/sshpiper/v1beta1/fake/fake_sshpiper_client.go @@ -13,7 +13,7 @@ type FakeSshpiperV1beta1 struct { } func (c *FakeSshpiperV1beta1) Pipes(namespace string) v1beta1.PipeInterface { - return &FakePipes{c, namespace} + return newFakePipes(c, namespace) } // RESTClient returns a RESTClient that is used to communicate diff --git a/plugin/kubernetes/generated/clientset/versioned/typed/sshpiper/v1beta1/pipe.go b/plugin/kubernetes/generated/clientset/versioned/typed/sshpiper/v1beta1/pipe.go index 3c801e96..86a383d7 100644 --- a/plugin/kubernetes/generated/clientset/versioned/typed/sshpiper/v1beta1/pipe.go +++ b/plugin/kubernetes/generated/clientset/versioned/typed/sshpiper/v1beta1/pipe.go @@ -3,15 +3,14 @@ package v1beta1 import ( - "context" - "time" + context "context" - v1beta1 "github.com/tg123/sshpiper/plugin/kubernetes/apis/sshpiper/v1beta1" + sshpiperv1beta1 "github.com/tg123/sshpiper/plugin/kubernetes/apis/sshpiper/v1beta1" scheme "github.com/tg123/sshpiper/plugin/kubernetes/generated/clientset/versioned/scheme" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" + gentype "k8s.io/client-go/gentype" ) // PipesGetter has a method to return a PipeInterface. @@ -22,141 +21,32 @@ type PipesGetter interface { // PipeInterface has methods to work with Pipe resources. type PipeInterface interface { - Create(ctx context.Context, pipe *v1beta1.Pipe, opts v1.CreateOptions) (*v1beta1.Pipe, error) - Update(ctx context.Context, pipe *v1beta1.Pipe, opts v1.UpdateOptions) (*v1beta1.Pipe, error) + Create(ctx context.Context, pipe *sshpiperv1beta1.Pipe, opts v1.CreateOptions) (*sshpiperv1beta1.Pipe, error) + Update(ctx context.Context, pipe *sshpiperv1beta1.Pipe, opts v1.UpdateOptions) (*sshpiperv1beta1.Pipe, error) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error - Get(ctx context.Context, name string, opts v1.GetOptions) (*v1beta1.Pipe, error) - List(ctx context.Context, opts v1.ListOptions) (*v1beta1.PipeList, error) + Get(ctx context.Context, name string, opts v1.GetOptions) (*sshpiperv1beta1.Pipe, error) + List(ctx context.Context, opts v1.ListOptions) (*sshpiperv1beta1.PipeList, error) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) - Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.Pipe, err error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *sshpiperv1beta1.Pipe, err error) PipeExpansion } // pipes implements PipeInterface type pipes struct { - client rest.Interface - ns string + *gentype.ClientWithList[*sshpiperv1beta1.Pipe, *sshpiperv1beta1.PipeList] } // newPipes returns a Pipes func newPipes(c *SshpiperV1beta1Client, namespace string) *pipes { return &pipes{ - client: c.RESTClient(), - ns: namespace, + gentype.NewClientWithList[*sshpiperv1beta1.Pipe, *sshpiperv1beta1.PipeList]( + "pipes", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *sshpiperv1beta1.Pipe { return &sshpiperv1beta1.Pipe{} }, + func() *sshpiperv1beta1.PipeList { return &sshpiperv1beta1.PipeList{} }, + ), } } - -// Get takes name of the pipe, and returns the corresponding pipe object, and an error if there is any. -func (c *pipes) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.Pipe, err error) { - result = &v1beta1.Pipe{} - err = c.client.Get(). - Namespace(c.ns). - Resource("pipes"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of Pipes that match those selectors. -func (c *pipes) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.PipeList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1beta1.PipeList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("pipes"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested pipes. -func (c *pipes) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("pipes"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a pipe and creates it. Returns the server's representation of the pipe, and an error, if there is any. -func (c *pipes) Create(ctx context.Context, pipe *v1beta1.Pipe, opts v1.CreateOptions) (result *v1beta1.Pipe, err error) { - result = &v1beta1.Pipe{} - err = c.client.Post(). - Namespace(c.ns). - Resource("pipes"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(pipe). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a pipe and updates it. Returns the server's representation of the pipe, and an error, if there is any. -func (c *pipes) Update(ctx context.Context, pipe *v1beta1.Pipe, opts v1.UpdateOptions) (result *v1beta1.Pipe, err error) { - result = &v1beta1.Pipe{} - err = c.client.Put(). - Namespace(c.ns). - Resource("pipes"). - Name(pipe.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(pipe). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the pipe and deletes it. Returns an error if one occurs. -func (c *pipes) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("pipes"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *pipes) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("pipes"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched pipe. -func (c *pipes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.Pipe, err error) { - result = &v1beta1.Pipe{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("pipes"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/plugin/kubernetes/generated/clientset/versioned/typed/sshpiper/v1beta1/sshpiper_client.go b/plugin/kubernetes/generated/clientset/versioned/typed/sshpiper/v1beta1/sshpiper_client.go index 360b9bac..8832a7b5 100644 --- a/plugin/kubernetes/generated/clientset/versioned/typed/sshpiper/v1beta1/sshpiper_client.go +++ b/plugin/kubernetes/generated/clientset/versioned/typed/sshpiper/v1beta1/sshpiper_client.go @@ -3,10 +3,10 @@ package v1beta1 import ( - "net/http" + http "net/http" - v1beta1 "github.com/tg123/sshpiper/plugin/kubernetes/apis/sshpiper/v1beta1" - "github.com/tg123/sshpiper/plugin/kubernetes/generated/clientset/versioned/scheme" + sshpiperv1beta1 "github.com/tg123/sshpiper/plugin/kubernetes/apis/sshpiper/v1beta1" + scheme "github.com/tg123/sshpiper/plugin/kubernetes/generated/clientset/versioned/scheme" rest "k8s.io/client-go/rest" ) @@ -69,10 +69,10 @@ func New(c rest.Interface) *SshpiperV1beta1Client { } func setConfigDefaults(config *rest.Config) error { - gv := v1beta1.SchemeGroupVersion + gv := sshpiperv1beta1.SchemeGroupVersion config.GroupVersion = &gv config.APIPath = "/apis" - config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() + config.NegotiatedSerializer = rest.CodecFactoryForGeneratedClient(scheme.Scheme, scheme.Codecs).WithoutConversion() if config.UserAgent == "" { config.UserAgent = rest.DefaultKubernetesUserAgent() diff --git a/plugin/kubernetes/generated/informers/externalversions/factory.go b/plugin/kubernetes/generated/informers/externalversions/factory.go new file mode 100644 index 00000000..b63b44ea --- /dev/null +++ b/plugin/kubernetes/generated/informers/externalversions/factory.go @@ -0,0 +1,246 @@ +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + reflect "reflect" + sync "sync" + time "time" + + versioned "github.com/tg123/sshpiper/plugin/kubernetes/generated/clientset/versioned" + internalinterfaces "github.com/tg123/sshpiper/plugin/kubernetes/generated/informers/externalversions/internalinterfaces" + sshpiper "github.com/tg123/sshpiper/plugin/kubernetes/generated/informers/externalversions/sshpiper" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" +) + +// SharedInformerOption defines the functional option type for SharedInformerFactory. +type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory + +type sharedInformerFactory struct { + client versioned.Interface + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc + lock sync.Mutex + defaultResync time.Duration + customResync map[reflect.Type]time.Duration + transform cache.TransformFunc + + informers map[reflect.Type]cache.SharedIndexInformer + // startedInformers is used for tracking which informers have been started. + // This allows Start() to be called multiple times safely. + startedInformers map[reflect.Type]bool + // wg tracks how many goroutines were started. + wg sync.WaitGroup + // shuttingDown is true when Shutdown has been called. It may still be running + // because it needs to wait for goroutines. + shuttingDown bool +} + +// WithCustomResyncConfig sets a custom resync period for the specified informer types. +func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + for k, v := range resyncConfig { + factory.customResync[reflect.TypeOf(k)] = v + } + return factory + } +} + +// WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory. +func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.tweakListOptions = tweakListOptions + return factory + } +} + +// WithNamespace limits the SharedInformerFactory to the specified namespace. +func WithNamespace(namespace string) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.namespace = namespace + return factory + } +} + +// WithTransform sets a transform on all informers. +func WithTransform(transform cache.TransformFunc) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.transform = transform + return factory + } +} + +// NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces. +func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync) +} + +// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory. +// Listers obtained via this SharedInformerFactory will be subject to the same filters +// as specified here. +// Deprecated: Please use NewSharedInformerFactoryWithOptions instead +func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions)) +} + +// NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options. +func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory { + factory := &sharedInformerFactory{ + client: client, + namespace: v1.NamespaceAll, + defaultResync: defaultResync, + informers: make(map[reflect.Type]cache.SharedIndexInformer), + startedInformers: make(map[reflect.Type]bool), + customResync: make(map[reflect.Type]time.Duration), + } + + // Apply all options + for _, opt := range options { + factory = opt(factory) + } + + return factory +} + +func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { + f.lock.Lock() + defer f.lock.Unlock() + + if f.shuttingDown { + return + } + + for informerType, informer := range f.informers { + if !f.startedInformers[informerType] { + f.wg.Add(1) + // We need a new variable in each loop iteration, + // otherwise the goroutine would use the loop variable + // and that keeps changing. + informer := informer + go func() { + defer f.wg.Done() + informer.Run(stopCh) + }() + f.startedInformers[informerType] = true + } + } +} + +func (f *sharedInformerFactory) Shutdown() { + f.lock.Lock() + f.shuttingDown = true + f.lock.Unlock() + + // Will return immediately if there is nothing to wait for. + f.wg.Wait() +} + +func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { + informers := func() map[reflect.Type]cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informers := map[reflect.Type]cache.SharedIndexInformer{} + for informerType, informer := range f.informers { + if f.startedInformers[informerType] { + informers[informerType] = informer + } + } + return informers + }() + + res := map[reflect.Type]bool{} + for informType, informer := range informers { + res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced) + } + return res +} + +// InformerFor returns the SharedIndexInformer for obj using an internal +// client. +func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informerType := reflect.TypeOf(obj) + informer, exists := f.informers[informerType] + if exists { + return informer + } + + resyncPeriod, exists := f.customResync[informerType] + if !exists { + resyncPeriod = f.defaultResync + } + + informer = newFunc(f.client, resyncPeriod) + informer.SetTransform(f.transform) + f.informers[informerType] = informer + + return informer +} + +// SharedInformerFactory provides shared informers for resources in all known +// API group versions. +// +// It is typically used like this: +// +// ctx, cancel := context.Background() +// defer cancel() +// factory := NewSharedInformerFactory(client, resyncPeriod) +// defer factory.WaitForStop() // Returns immediately if nothing was started. +// genericInformer := factory.ForResource(resource) +// typedInformer := factory.SomeAPIGroup().V1().SomeType() +// factory.Start(ctx.Done()) // Start processing these informers. +// synced := factory.WaitForCacheSync(ctx.Done()) +// for v, ok := range synced { +// if !ok { +// fmt.Fprintf(os.Stderr, "caches failed to sync: %v", v) +// return +// } +// } +// +// // Creating informers can also be created after Start, but then +// // Start must be called again: +// anotherGenericInformer := factory.ForResource(resource) +// factory.Start(ctx.Done()) +type SharedInformerFactory interface { + internalinterfaces.SharedInformerFactory + + // Start initializes all requested informers. They are handled in goroutines + // which run until the stop channel gets closed. + // Warning: Start does not block. When run in a go-routine, it will race with a later WaitForCacheSync. + Start(stopCh <-chan struct{}) + + // Shutdown marks a factory as shutting down. At that point no new + // informers can be started anymore and Start will return without + // doing anything. + // + // In addition, Shutdown blocks until all goroutines have terminated. For that + // to happen, the close channel(s) that they were started with must be closed, + // either before Shutdown gets called or while it is waiting. + // + // Shutdown may be called multiple times, even concurrently. All such calls will + // block until all goroutines have terminated. + Shutdown() + + // WaitForCacheSync blocks until all started informers' caches were synced + // or the stop channel gets closed. + WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool + + // ForResource gives generic access to a shared informer of the matching type. + ForResource(resource schema.GroupVersionResource) (GenericInformer, error) + + // InformerFor returns the SharedIndexInformer for obj using an internal + // client. + InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer + + Sshpiper() sshpiper.Interface +} + +func (f *sharedInformerFactory) Sshpiper() sshpiper.Interface { + return sshpiper.New(f, f.namespace, f.tweakListOptions) +} diff --git a/plugin/kubernetes/generated/informers/externalversions/generic.go b/plugin/kubernetes/generated/informers/externalversions/generic.go new file mode 100644 index 00000000..c696e85a --- /dev/null +++ b/plugin/kubernetes/generated/informers/externalversions/generic.go @@ -0,0 +1,46 @@ +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + fmt "fmt" + + v1beta1 "github.com/tg123/sshpiper/plugin/kubernetes/apis/sshpiper/v1beta1" + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" +) + +// GenericInformer is type of SharedIndexInformer which will locate and delegate to other +// sharedInformers based on type +type GenericInformer interface { + Informer() cache.SharedIndexInformer + Lister() cache.GenericLister +} + +type genericInformer struct { + informer cache.SharedIndexInformer + resource schema.GroupResource +} + +// Informer returns the SharedIndexInformer. +func (f *genericInformer) Informer() cache.SharedIndexInformer { + return f.informer +} + +// Lister returns the GenericLister. +func (f *genericInformer) Lister() cache.GenericLister { + return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource) +} + +// ForResource gives generic access to a shared informer of the matching type +// TODO extend this to unknown resources with a client pool +func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { + switch resource { + // Group=sshpiper, Version=v1beta1 + case v1beta1.SchemeGroupVersion.WithResource("pipes"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Sshpiper().V1beta1().Pipes().Informer()}, nil + + } + + return nil, fmt.Errorf("no informer found for %v", resource) +} diff --git a/plugin/kubernetes/generated/informers/externalversions/internalinterfaces/factory_interfaces.go b/plugin/kubernetes/generated/informers/externalversions/internalinterfaces/factory_interfaces.go new file mode 100644 index 00000000..8599fb27 --- /dev/null +++ b/plugin/kubernetes/generated/informers/externalversions/internalinterfaces/factory_interfaces.go @@ -0,0 +1,24 @@ +// Code generated by informer-gen. DO NOT EDIT. + +package internalinterfaces + +import ( + time "time" + + versioned "github.com/tg123/sshpiper/plugin/kubernetes/generated/clientset/versioned" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + cache "k8s.io/client-go/tools/cache" +) + +// NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer. +type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer + +// SharedInformerFactory a small interface to allow for adding an informer without an import cycle +type SharedInformerFactory interface { + Start(stopCh <-chan struct{}) + InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer +} + +// TweakListOptionsFunc is a function that transforms a v1.ListOptions. +type TweakListOptionsFunc func(*v1.ListOptions) diff --git a/plugin/kubernetes/generated/informers/externalversions/sshpiper/interface.go b/plugin/kubernetes/generated/informers/externalversions/sshpiper/interface.go new file mode 100644 index 00000000..80789c52 --- /dev/null +++ b/plugin/kubernetes/generated/informers/externalversions/sshpiper/interface.go @@ -0,0 +1,30 @@ +// Code generated by informer-gen. DO NOT EDIT. + +package sshpiper + +import ( + internalinterfaces "github.com/tg123/sshpiper/plugin/kubernetes/generated/informers/externalversions/internalinterfaces" + v1beta1 "github.com/tg123/sshpiper/plugin/kubernetes/generated/informers/externalversions/sshpiper/v1beta1" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1beta1 provides access to shared informers for resources in V1beta1. + V1beta1() v1beta1.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1beta1 returns a new v1beta1.Interface. +func (g *group) V1beta1() v1beta1.Interface { + return v1beta1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/plugin/kubernetes/generated/informers/externalversions/sshpiper/v1beta1/interface.go b/plugin/kubernetes/generated/informers/externalversions/sshpiper/v1beta1/interface.go new file mode 100644 index 00000000..f963ac8a --- /dev/null +++ b/plugin/kubernetes/generated/informers/externalversions/sshpiper/v1beta1/interface.go @@ -0,0 +1,29 @@ +// Code generated by informer-gen. DO NOT EDIT. + +package v1beta1 + +import ( + internalinterfaces "github.com/tg123/sshpiper/plugin/kubernetes/generated/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // Pipes returns a PipeInformer. + Pipes() PipeInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// Pipes returns a PipeInformer. +func (v *version) Pipes() PipeInformer { + return &pipeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/plugin/kubernetes/generated/informers/externalversions/sshpiper/v1beta1/pipe.go b/plugin/kubernetes/generated/informers/externalversions/sshpiper/v1beta1/pipe.go new file mode 100644 index 00000000..0e2cd353 --- /dev/null +++ b/plugin/kubernetes/generated/informers/externalversions/sshpiper/v1beta1/pipe.go @@ -0,0 +1,74 @@ +// Code generated by informer-gen. DO NOT EDIT. + +package v1beta1 + +import ( + context "context" + time "time" + + apissshpiperv1beta1 "github.com/tg123/sshpiper/plugin/kubernetes/apis/sshpiper/v1beta1" + versioned "github.com/tg123/sshpiper/plugin/kubernetes/generated/clientset/versioned" + internalinterfaces "github.com/tg123/sshpiper/plugin/kubernetes/generated/informers/externalversions/internalinterfaces" + sshpiperv1beta1 "github.com/tg123/sshpiper/plugin/kubernetes/generated/listers/sshpiper/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// PipeInformer provides access to a shared informer and lister for +// Pipes. +type PipeInformer interface { + Informer() cache.SharedIndexInformer + Lister() sshpiperv1beta1.PipeLister +} + +type pipeInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewPipeInformer constructs a new informer for Pipe type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewPipeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredPipeInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredPipeInformer constructs a new informer for Pipe type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredPipeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.SshpiperV1beta1().Pipes(namespace).List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.SshpiperV1beta1().Pipes(namespace).Watch(context.TODO(), options) + }, + }, + &apissshpiperv1beta1.Pipe{}, + resyncPeriod, + indexers, + ) +} + +func (f *pipeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredPipeInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *pipeInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&apissshpiperv1beta1.Pipe{}, f.defaultInformer) +} + +func (f *pipeInformer) Lister() sshpiperv1beta1.PipeLister { + return sshpiperv1beta1.NewPipeLister(f.Informer().GetIndexer()) +} diff --git a/plugin/kubernetes/generated/listers/sshpiper/v1beta1/pipe.go b/plugin/kubernetes/generated/listers/sshpiper/v1beta1/pipe.go index 94f786cd..996cb0d7 100644 --- a/plugin/kubernetes/generated/listers/sshpiper/v1beta1/pipe.go +++ b/plugin/kubernetes/generated/listers/sshpiper/v1beta1/pipe.go @@ -3,10 +3,10 @@ package v1beta1 import ( - v1beta1 "github.com/tg123/sshpiper/plugin/kubernetes/apis/sshpiper/v1beta1" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/tools/cache" + sshpiperv1beta1 "github.com/tg123/sshpiper/plugin/kubernetes/apis/sshpiper/v1beta1" + labels "k8s.io/apimachinery/pkg/labels" + listers "k8s.io/client-go/listers" + cache "k8s.io/client-go/tools/cache" ) // PipeLister helps list Pipes. @@ -14,7 +14,7 @@ import ( type PipeLister interface { // List lists all Pipes in the indexer. // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1beta1.Pipe, err error) + List(selector labels.Selector) (ret []*sshpiperv1beta1.Pipe, err error) // Pipes returns an object that can list and get Pipes. Pipes(namespace string) PipeNamespaceLister PipeListerExpansion @@ -22,25 +22,17 @@ type PipeLister interface { // pipeLister implements the PipeLister interface. type pipeLister struct { - indexer cache.Indexer + listers.ResourceIndexer[*sshpiperv1beta1.Pipe] } // NewPipeLister returns a new PipeLister. func NewPipeLister(indexer cache.Indexer) PipeLister { - return &pipeLister{indexer: indexer} -} - -// List lists all Pipes in the indexer. -func (s *pipeLister) List(selector labels.Selector) (ret []*v1beta1.Pipe, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1beta1.Pipe)) - }) - return ret, err + return &pipeLister{listers.New[*sshpiperv1beta1.Pipe](indexer, sshpiperv1beta1.Resource("pipe"))} } // Pipes returns an object that can list and get Pipes. func (s *pipeLister) Pipes(namespace string) PipeNamespaceLister { - return pipeNamespaceLister{indexer: s.indexer, namespace: namespace} + return pipeNamespaceLister{listers.NewNamespaced[*sshpiperv1beta1.Pipe](s.ResourceIndexer, namespace)} } // PipeNamespaceLister helps list and get Pipes. @@ -48,36 +40,15 @@ func (s *pipeLister) Pipes(namespace string) PipeNamespaceLister { type PipeNamespaceLister interface { // List lists all Pipes in the indexer for a given namespace. // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1beta1.Pipe, err error) + List(selector labels.Selector) (ret []*sshpiperv1beta1.Pipe, err error) // Get retrieves the Pipe from the indexer for a given namespace and name. // Objects returned here must be treated as read-only. - Get(name string) (*v1beta1.Pipe, error) + Get(name string) (*sshpiperv1beta1.Pipe, error) PipeNamespaceListerExpansion } // pipeNamespaceLister implements the PipeNamespaceLister // interface. type pipeNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all Pipes in the indexer for a given namespace. -func (s pipeNamespaceLister) List(selector labels.Selector) (ret []*v1beta1.Pipe, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1beta1.Pipe)) - }) - return ret, err -} - -// Get retrieves the Pipe from the indexer for a given namespace and name. -func (s pipeNamespaceLister) Get(name string) (*v1beta1.Pipe, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1beta1.Resource("pipe"), name) - } - return obj.(*v1beta1.Pipe), nil + listers.ResourceIndexer[*sshpiperv1beta1.Pipe] } diff --git a/plugin/kubernetes/skel.go b/plugin/kubernetes/skel.go index e47e3d14..30d93507 100644 --- a/plugin/kubernetes/skel.go +++ b/plugin/kubernetes/skel.go @@ -64,7 +64,7 @@ func (s *skelpipeWrapper) From() []skel.SkelPipeFrom { to: &s.pipe.Spec.To, } - if f.AuthorizedKeysData != "" || f.AuthorizedKeysFile != "" { + if f.AuthorizedKeysData != "" || f.AuthorizedKeysFile != "" || f.AuthorizedKeysSecret.Name != "" { froms = append(froms, &skelpipePublicKeyWrapper{ skelpipeFromWrapper: *w, }) @@ -171,6 +171,26 @@ func (s *skelpipePublicKeyWrapper) AuthorizedKeys(conn libplugin.ConnMetadata) ( return nil, err } + if s.from.AuthorizedKeysSecret.Name != "" { + log.Debugf("mapping to %v authorized keys using secret %v", s.pipe.Spec.To.Host, s.from.AuthorizedKeysSecret.Name) + anno := s.pipe.GetAnnotations() + + secret, err := s.plugin.k8sclient.Secrets(s.pipe.Namespace).Get(context.Background(), s.from.AuthorizedKeysSecret.Name, metav1.GetOptions{}) + if err != nil { + return nil, err + } + + for _, k := range []string{anno["sshpiper.com/authorizedkeys_field_name"], anno["authorizedkeys_field_name"], "authorized_keys", "authorizedkeys", "ssh-authorizedkeys"} { + data := secret.Data[k] + if data != nil { + log.Debugf("found authorized keys in secret %v/%v", s.from.AuthorizedKeysSecret.Name, k) + byteSlices = append(byteSlices, data) + break + } + } + + } + return bytes.Join(byteSlices, []byte("\n")), nil } @@ -189,7 +209,7 @@ func (s *skelpipeToPrivateKeyWrapper) PrivateKey(conn libplugin.ConnMetadata) ([ var publicKey []byte var privateKey []byte - for _, k := range []string{anno["privatekey_field_name"], "ssh-privatekey", "privatekey"} { + for _, k := range []string{anno["sshpiper.com/privatekey_field_name"], anno["privatekey_field_name"], "ssh-privatekey", "privatekey"} { data := secret.Data[k] if data != nil { log.Debugf("found private key in secret %v/%v", s.to.PrivateKeySecret.Name, k) @@ -198,8 +218,8 @@ func (s *skelpipeToPrivateKeyWrapper) PrivateKey(conn libplugin.ConnMetadata) ([ } } - if anno["no_ca_publickey"] != "true" { - for _, k := range []string{anno["publickey_field_name"], "ssh-publickey-cert", "publickey-cert", "ssh-publickey", "publickey"} { + if anno["no_ca_publickey"] != "true" && anno["sshpiper.com/no_ca_publickey"] != "true" { + for _, k := range []string{anno["sshpiper.com/publickey_field_name"], anno["publickey_field_name"], "ssh-publickey-cert", "publickey-cert", "ssh-publickey", "publickey"} { data := secret.Data[k] if data != nil { log.Debugf("found publickey key cert in secret %v/%v", s.to.PrivateKeySecret.Name, k) diff --git a/plugin/kubernetes/update-codegen.sh b/plugin/kubernetes/update-codegen.sh index 86d3ca53..b38b60a2 100755 --- a/plugin/kubernetes/update-codegen.sh +++ b/plugin/kubernetes/update-codegen.sh @@ -9,18 +9,22 @@ go mod vendor SCRIPT_ROOT=$(dirname "${BASH_SOURCE[0]}") REPO_ROOT=$(realpath "${SCRIPT_ROOT}/../../") CODEGEN_PKG=${REPO_ROOT}/vendor/k8s.io/code-generator +THIS_PKG="github.com/tg123/sshpiper/plugin/kubernetes" -# generate the code with: -# --output-base because this script should also be able to run inside the vendor dir of -# k8s.io/kubernetes. The output-base is needed for the generators to output into the vendor dir -# instead of the $GOPATH directly. For normal projects this can be dropped. -# generators deepcopy,client,informer,lister -chmod +x "${CODEGEN_PKG}"/kube_codegen.sh -"${CODEGEN_PKG}"/kube_codegen.sh \ - "deepcopy,client,lister" \ - github.com/tg123/sshpiper/plugin/kubernetes/generated \ - github.com/tg123/sshpiper/plugin/kubernetes/apis \ - sshpiper:v1beta1 \ - --go-header-file /dev/null \ - --trim-path-prefix github.com/tg123/sshpiper/plugin/kubernetes/ - +source "${CODEGEN_PKG}/kube_codegen.sh" + + +kube::codegen::gen_helpers \ + --boilerplate /dev/null \ + "${SCRIPT_ROOT}" + +kube::codegen::gen_register \ + --boilerplate /dev/null \ + "${SCRIPT_ROOT}" + +kube::codegen::gen_client \ + --with-watch \ + --output-dir "${SCRIPT_ROOT}/generated" \ + --output-pkg "${THIS_PKG}/generated" \ + --boilerplate /dev/null \ + "${SCRIPT_ROOT}/apis" \ No newline at end of file