@@ -11,10 +11,21 @@ import (
11
11
"os"
12
12
"strings"
13
13
14
+ rawyaml "gopkg.in/yaml.v3"
15
+
14
16
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
15
17
)
16
18
17
- func (u * UnstructuredClient ) Call (ctx context.Context , cli * http.Client , path string , opts * RequestConfiguration ) (any , error ) {
19
+ type Response struct {
20
+ ResponseBody any
21
+ statusCode int
22
+ }
23
+
24
+ func (r * Response ) IsPending () bool {
25
+ return r .statusCode == http .StatusProcessing || r .statusCode == http .StatusContinue || r .statusCode == http .StatusAccepted
26
+ }
27
+
28
+ func (u * UnstructuredClient ) Call (ctx context.Context , cli * http.Client , path string , opts * RequestConfiguration ) (* Response , error ) {
18
29
uri := buildPath (u .Server , path , opts .Parameters , opts .Query )
19
30
pathItem , ok := u .DocScheme .Model .Paths .PathItems .Get (path )
20
31
if ! ok {
@@ -129,58 +140,67 @@ func (u *UnstructuredClient) Call(ctx context.Context, cli *http.Client, path st
129
140
return nil , fmt .Errorf ("error handling response: %w" , err )
130
141
}
131
142
132
- val , ok := response .(map [string ]interface {})
133
- if ! ok {
134
- return nil , fmt .Errorf ("unexpected response type: %T" , response )
135
- }
136
- return & val , nil
143
+ return & Response {
144
+ ResponseBody : response ,
145
+ statusCode : resp .StatusCode ,
146
+ }, nil
137
147
}
138
148
139
- func (u * UnstructuredClient ) FindBy (ctx context.Context , cli * http.Client , path string , opts * RequestConfiguration ) (any , error ) {
140
- list , err := u .Call (ctx , cli , path , opts )
149
+ // It support both list and single item responses
150
+ func (u * UnstructuredClient ) FindBy (ctx context.Context , cli * http.Client , path string , opts * RequestConfiguration ) (* Response , error ) {
151
+ response , err := u .Call (ctx , cli , path , opts )
141
152
if err != nil {
142
153
return nil , err
143
154
}
144
- if list == nil {
155
+ if response == nil {
145
156
return nil , nil
146
157
}
147
158
148
- var li map [ string ] interface {}
159
+ list := response . ResponseBody
149
160
150
- if _ , ok := list .([]interface {}); ! ok {
161
+ var li map [string ]interface {}
162
+ if _ , ok := list .([]interface {}); ok {
151
163
li = map [string ]interface {}{
152
164
"items" : list ,
153
165
}
154
- }
155
-
156
- if _ , ok := list .(map [string ]interface {}); ! ok {
157
- return nil , fmt .Errorf ("unexpected response type: %T" , list )
166
+ } else {
167
+ li , ok = list .(map [string ]interface {})
168
+ if ! ok {
169
+ return nil , fmt .Errorf ("unexpected response type: %T" , list )
170
+ }
158
171
}
159
172
160
173
for _ , v := range li {
161
- if v , ok := v .([]interface {}); ok {
162
- if len (v ) > 0 {
163
- for _ , item := range v {
164
- if item , ok := item .(map [string ]interface {}); ok {
165
- for _ , ide := range u .IdentifierFields {
166
- idepath := strings .Split (ide , "." ) // split the identifier field by '.'
167
- responseValue , _ , err := unstructured .NestedString (item , idepath ... )
168
- if err != nil {
169
- val , _ , err := unstructured .NestedFieldCopy (item , idepath ... )
170
- if err != nil {
171
- return nil , fmt .Errorf ("error getting nested field: %w" , err )
172
- }
173
- responseValue = fmt .Sprintf ("%v" , val )
174
- }
175
- ok , err = u .isInSpecFields (ide , responseValue )
174
+ if vli , ok := v .([]interface {}); ok {
175
+ if len (vli ) > 0 {
176
+ for _ , item := range vli {
177
+ itMap , ok := item .(map [string ]interface {})
178
+ if ! ok {
179
+ continue // skip this item if it's not a map
180
+ }
181
+
182
+ for _ , ide := range u .IdentifierFields {
183
+ idepath := strings .Split (ide , "." ) // split the identifier field by '.'
184
+ responseValue , _ , err := unstructured .NestedString (itMap , idepath ... )
185
+ if err != nil {
186
+ val , _ , err := unstructured .NestedFieldNoCopy (itMap , idepath ... )
176
187
if err != nil {
177
- return nil , err
178
- }
179
- if ok {
180
- return & item , nil
188
+ return nil , fmt .Errorf ("error getting nested field: %w" , err )
181
189
}
190
+ responseValue = fmt .Sprintf ("%v" , val )
191
+ }
192
+ ok , err = u .isInSpecFields (ide , responseValue )
193
+ if err != nil {
194
+ return nil , err
195
+ }
196
+ if ok {
197
+ return & Response {
198
+ ResponseBody : itMap ,
199
+ statusCode : response .statusCode ,
200
+ }, nil
182
201
}
183
202
}
203
+
184
204
}
185
205
}
186
206
break
@@ -192,7 +212,22 @@ func (u *UnstructuredClient) FindBy(ctx context.Context, cli *http.Client, path
192
212
}
193
213
}
194
214
195
- // buildPath constructs the URL path with the given parameters and query.
215
+ func jsonToYAML (jsonData []byte ) ([]byte , error ) {
216
+ // First unmarshal JSON into a generic interface
217
+ var obj interface {}
218
+ if err := json .Unmarshal (jsonData , & obj ); err != nil {
219
+ return nil , err
220
+ }
221
+
222
+ // Then marshal to YAML
223
+ yamlData , err := rawyaml .Marshal (obj )
224
+ if err != nil {
225
+ return nil , err
226
+ }
227
+
228
+ return yamlData , nil
229
+ }
230
+
196
231
// response should be a pointer to the object where the response will be unmarshalled.
197
232
func handleResponse (rc io.ReadCloser , response any ) error {
198
233
if rc == nil {
@@ -206,7 +241,17 @@ func handleResponse(rc io.ReadCloser, response any) error {
206
241
if len (data ) == 0 {
207
242
return nil
208
243
}
209
- return json .Unmarshal (data , & response )
244
+
245
+ yamlData , err := jsonToYAML (data )
246
+ if err != nil {
247
+ return fmt .Errorf ("error converting JSON to YAML: %w" , err )
248
+ }
249
+
250
+ err = rawyaml .Unmarshal (yamlData , response )
251
+ if err != nil {
252
+ return fmt .Errorf ("error unmarshalling YAML response: %w" , err )
253
+ }
254
+ return nil
210
255
}
211
256
212
257
type debuggingRoundTripper struct {
0 commit comments