mirror of
https://github.com/rancher/norman.git
synced 2025-09-16 15:21:33 +00:00
More initial dev
This commit is contained in:
184
clientbase/object_client.go
Normal file
184
clientbase/object_client.go
Normal file
@@ -0,0 +1,184 @@
|
||||
package clientbase
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
type ObjectFactory interface {
|
||||
Object() runtime.Object
|
||||
List() runtime.Object
|
||||
}
|
||||
|
||||
type ObjectClient struct {
|
||||
restClient rest.Interface
|
||||
resource *metav1.APIResource
|
||||
gvk schema.GroupVersionKind
|
||||
ns string
|
||||
Factory ObjectFactory
|
||||
}
|
||||
|
||||
func NewObjectClient(namespace string, config rest.Config, apiResource *metav1.APIResource, gvk schema.GroupVersionKind, factory ObjectFactory) (*ObjectClient, error) {
|
||||
if config.NegotiatedSerializer == nil {
|
||||
configConfig := dynamic.ContentConfig()
|
||||
config.NegotiatedSerializer = configConfig.NegotiatedSerializer
|
||||
}
|
||||
|
||||
restClient, err := rest.UnversionedRESTClientFor(&config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ObjectClient{
|
||||
restClient: restClient,
|
||||
resource: apiResource,
|
||||
gvk: gvk,
|
||||
ns: namespace,
|
||||
Factory: factory,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (p *ObjectClient) Create(o runtime.Object) (runtime.Object, error) {
|
||||
ns := p.ns
|
||||
if obj, ok := o.(metav1.Object); ok && obj.GetNamespace() != "" {
|
||||
ns = obj.GetNamespace()
|
||||
}
|
||||
result := p.Factory.Object()
|
||||
err := p.restClient.Post().
|
||||
Prefix("apis", p.gvk.Group, p.gvk.Version).
|
||||
NamespaceIfScoped(ns, p.resource.Namespaced).
|
||||
Resource(p.resource.Name).
|
||||
Body(o).
|
||||
Do().
|
||||
Into(result)
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (p *ObjectClient) Get(name string, opts metav1.GetOptions) (runtime.Object, error) {
|
||||
result := p.Factory.Object()
|
||||
err := p.restClient.Get().
|
||||
Prefix("apis", p.gvk.Group, p.gvk.Version).
|
||||
NamespaceIfScoped(p.ns, p.resource.Namespaced).
|
||||
Resource(p.resource.Name).
|
||||
VersionedParams(&opts, dynamic.VersionedParameterEncoderWithV1Fallback).
|
||||
Name(name).
|
||||
Do().
|
||||
Into(result)
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (p *ObjectClient) Update(name string, o runtime.Object) (runtime.Object, error) {
|
||||
ns := p.ns
|
||||
if obj, ok := o.(metav1.Object); ok && obj.GetNamespace() != "" {
|
||||
ns = obj.GetNamespace()
|
||||
}
|
||||
result := p.Factory.Object()
|
||||
if len(name) == 0 {
|
||||
return result, errors.New("object missing name")
|
||||
}
|
||||
err := p.restClient.Put().
|
||||
Prefix("apis", p.gvk.Group, p.gvk.Version).
|
||||
NamespaceIfScoped(ns, p.resource.Namespaced).
|
||||
Resource(p.resource.Name).
|
||||
Name(name).
|
||||
Body(o).
|
||||
Do().
|
||||
Into(result)
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (p *ObjectClient) Delete(name string, opts *metav1.DeleteOptions) error {
|
||||
return p.restClient.Delete().
|
||||
Prefix("apis", p.gvk.Group, p.gvk.Version).
|
||||
NamespaceIfScoped(p.ns, p.resource.Namespaced).
|
||||
Resource(p.resource.Name).
|
||||
Name(name).
|
||||
Body(opts).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
func (p *ObjectClient) List(opts metav1.ListOptions) (runtime.Object, error) {
|
||||
result := p.Factory.List()
|
||||
return result, p.restClient.Get().
|
||||
Prefix("apis", p.gvk.Group, p.gvk.Version).
|
||||
NamespaceIfScoped(p.ns, p.resource.Namespaced).
|
||||
Resource(p.resource.Name).
|
||||
VersionedParams(&opts, dynamic.VersionedParameterEncoderWithV1Fallback).
|
||||
Do().
|
||||
Into(result)
|
||||
}
|
||||
|
||||
func (p *ObjectClient) Watch(opts metav1.ListOptions) (watch.Interface, error) {
|
||||
r, err := p.restClient.Get().
|
||||
Prefix("apis", p.gvk.Group, p.gvk.Version).
|
||||
Prefix("watch").
|
||||
Namespace(p.ns).
|
||||
NamespaceIfScoped(p.ns, p.resource.Namespaced).
|
||||
Resource(p.resource.Name).
|
||||
VersionedParams(&opts, dynamic.VersionedParameterEncoderWithV1Fallback).
|
||||
Stream()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return watch.NewStreamWatcher(&dynamicDecoder{
|
||||
factory: p.Factory,
|
||||
dec: json.NewDecoder(r),
|
||||
close: r.Close,
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (p *ObjectClient) DeleteCollection(deleteOptions *metav1.DeleteOptions, listOptions metav1.ListOptions) error {
|
||||
return p.restClient.Delete().
|
||||
Prefix("apis", p.gvk.Group, p.gvk.Version).
|
||||
NamespaceIfScoped(p.ns, p.resource.Namespaced).
|
||||
Resource(p.resource.Name).
|
||||
VersionedParams(&listOptions, dynamic.VersionedParameterEncoderWithV1Fallback).
|
||||
Body(deleteOptions).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
type dynamicDecoder struct {
|
||||
factory ObjectFactory
|
||||
dec *json.Decoder
|
||||
close func() error
|
||||
}
|
||||
|
||||
func (d *dynamicDecoder) Close() {
|
||||
d.close()
|
||||
}
|
||||
|
||||
func (d *dynamicDecoder) Decode() (action watch.EventType, object runtime.Object, err error) {
|
||||
e := dynamicEvent{
|
||||
Object: holder{
|
||||
factory: d.factory,
|
||||
},
|
||||
}
|
||||
if err := d.dec.Decode(&e); err != nil {
|
||||
return watch.Error, nil, err
|
||||
}
|
||||
return e.Type, e.Object.obj, nil
|
||||
}
|
||||
|
||||
type dynamicEvent struct {
|
||||
Type watch.EventType
|
||||
Object holder
|
||||
}
|
||||
|
||||
type holder struct {
|
||||
factory ObjectFactory
|
||||
obj runtime.Object
|
||||
}
|
||||
|
||||
func (h *holder) UnmarshalJSON(b []byte) error {
|
||||
h.obj = h.factory.Object()
|
||||
return json.Unmarshal(b, h.obj)
|
||||
}
|
Reference in New Issue
Block a user