1
16
17 package apiclient
18
19 import (
20 "context"
21 "encoding/json"
22 "fmt"
23
24 "github.com/pkg/errors"
25
26 apierrors "k8s.io/apimachinery/pkg/api/errors"
27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28 "k8s.io/apimachinery/pkg/runtime"
29 "k8s.io/client-go/dynamic"
30 clientset "k8s.io/client-go/kubernetes"
31 clientsetscheme "k8s.io/client-go/kubernetes/scheme"
32 "k8s.io/client-go/rest"
33 core "k8s.io/client-go/testing"
34 "k8s.io/client-go/tools/clientcmd"
35 )
36
37
38 type ClientBackedDryRunGetter struct {
39 client clientset.Interface
40 dynamicClient dynamic.Interface
41 }
42
43
44 var _ DryRunGetter = &ClientBackedDryRunGetter{}
45
46
47 func NewClientBackedDryRunGetter(config *rest.Config) (*ClientBackedDryRunGetter, error) {
48 client, err := clientset.NewForConfig(config)
49 if err != nil {
50 return nil, err
51 }
52 dynamicClient, err := dynamic.NewForConfig(config)
53 if err != nil {
54 return nil, err
55 }
56
57 return &ClientBackedDryRunGetter{
58 client: client,
59 dynamicClient: dynamicClient,
60 }, nil
61 }
62
63
64 func NewClientBackedDryRunGetterFromKubeconfig(file string) (*ClientBackedDryRunGetter, error) {
65 config, err := clientcmd.LoadFromFile(file)
66 if err != nil {
67 return nil, errors.Wrap(err, "failed to load kubeconfig")
68 }
69 clientConfig, err := clientcmd.NewDefaultClientConfig(*config, &clientcmd.ConfigOverrides{}).ClientConfig()
70 if err != nil {
71 return nil, errors.Wrap(err, "failed to create API client configuration from kubeconfig")
72 }
73 return NewClientBackedDryRunGetter(clientConfig)
74 }
75
76
77 func (clg *ClientBackedDryRunGetter) HandleGetAction(action core.GetAction) (bool, runtime.Object, error) {
78 unstructuredObj, err := clg.dynamicClient.Resource(action.GetResource()).Namespace(action.GetNamespace()).Get(context.TODO(), action.GetName(), metav1.GetOptions{})
79 if err != nil {
80
81 printIfNotExists(err)
82 return true, nil, err
83 }
84 newObj, err := decodeUnstructuredIntoAPIObject(action, unstructuredObj)
85 if err != nil {
86 fmt.Printf("error after decode: %v %v\n", unstructuredObj, err)
87 return true, nil, err
88 }
89 return true, newObj, err
90 }
91
92
93 func (clg *ClientBackedDryRunGetter) HandleListAction(action core.ListAction) (bool, runtime.Object, error) {
94 listOpts := metav1.ListOptions{
95 LabelSelector: action.GetListRestrictions().Labels.String(),
96 FieldSelector: action.GetListRestrictions().Fields.String(),
97 }
98
99 unstructuredList, err := clg.dynamicClient.Resource(action.GetResource()).Namespace(action.GetNamespace()).List(context.TODO(), listOpts)
100 if err != nil {
101 return true, nil, err
102 }
103 newObj, err := decodeUnstructuredIntoAPIObject(action, unstructuredList)
104 if err != nil {
105 fmt.Printf("error after decode: %v %v\n", unstructuredList, err)
106 return true, nil, err
107 }
108 return true, newObj, err
109 }
110
111
112 func (clg *ClientBackedDryRunGetter) Client() clientset.Interface {
113 return clg.client
114 }
115
116
117
118 func decodeUnstructuredIntoAPIObject(action core.Action, unstructuredObj runtime.Unstructured) (runtime.Object, error) {
119 objBytes, err := json.Marshal(unstructuredObj)
120 if err != nil {
121 return nil, err
122 }
123 newObj, err := runtime.Decode(clientsetscheme.Codecs.UniversalDecoder(action.GetResource().GroupVersion()), objBytes)
124 if err != nil {
125 return nil, err
126 }
127 return newObj, nil
128 }
129
130 func printIfNotExists(err error) {
131 if apierrors.IsNotFound(err) {
132 fmt.Println("[dryrun] The GET request didn't yield any result, the API Server returned a NotFound error.")
133 }
134 }
135
View as plain text