6
6
"errors"
7
7
"fmt"
8
8
"gopkg.in/yaml.v3"
9
+ v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
9
10
"regexp"
10
11
11
12
"github.com/graphql-go/graphql"
@@ -23,19 +24,24 @@ import (
23
24
24
25
type Provider interface {
25
26
CrudProvider
27
+ CustomQueriesProvider
26
28
CommonResolver () graphql.FieldResolveFn
27
29
SanitizeGroupName (string ) string
28
30
}
29
31
30
32
type CrudProvider interface {
31
- ListItems (gvk schema.GroupVersionKind ) graphql.FieldResolveFn
32
- GetItem (gvk schema.GroupVersionKind ) graphql.FieldResolveFn
33
- GetItemAsYAML (gvk schema.GroupVersionKind ) graphql.FieldResolveFn
34
- CreateItem (gvk schema.GroupVersionKind ) graphql.FieldResolveFn
35
- UpdateItem (gvk schema.GroupVersionKind ) graphql.FieldResolveFn
36
- DeleteItem (gvk schema.GroupVersionKind ) graphql.FieldResolveFn
37
- SubscribeItem (gvk schema.GroupVersionKind ) graphql.FieldResolveFn
38
- SubscribeItems (gvk schema.GroupVersionKind ) graphql.FieldResolveFn
33
+ ListItems (gvk schema.GroupVersionKind , scope v1.ResourceScope ) graphql.FieldResolveFn
34
+ GetItem (gvk schema.GroupVersionKind , scope v1.ResourceScope ) graphql.FieldResolveFn
35
+ GetItemAsYAML (gvk schema.GroupVersionKind , scope v1.ResourceScope ) graphql.FieldResolveFn
36
+ CreateItem (gvk schema.GroupVersionKind , scope v1.ResourceScope ) graphql.FieldResolveFn
37
+ UpdateItem (gvk schema.GroupVersionKind , scope v1.ResourceScope ) graphql.FieldResolveFn
38
+ DeleteItem (gvk schema.GroupVersionKind , scope v1.ResourceScope ) graphql.FieldResolveFn
39
+ SubscribeItem (gvk schema.GroupVersionKind , scope v1.ResourceScope ) graphql.FieldResolveFn
40
+ SubscribeItems (gvk schema.GroupVersionKind , scope v1.ResourceScope ) graphql.FieldResolveFn
41
+ }
42
+
43
+ type CustomQueriesProvider interface {
44
+ TypeByCategory (m map [string ][]TypeByCategory ) graphql.FieldResolveFn
39
45
}
40
46
41
47
type Service struct {
@@ -54,7 +60,7 @@ func New(log *logger.Logger, runtimeClient client.WithWatch) *Service {
54
60
}
55
61
56
62
// ListItems returns a GraphQL CommonResolver function that lists Kubernetes resources of the given GroupVersionKind.
57
- func (r * Service ) ListItems (gvk schema.GroupVersionKind ) graphql.FieldResolveFn {
63
+ func (r * Service ) ListItems (gvk schema.GroupVersionKind , scope v1. ResourceScope ) graphql.FieldResolveFn {
58
64
return func (p graphql.ResolveParams ) (interface {}, error ) {
59
65
ctx , span := otel .Tracer ("" ).Start (p .Context , "ListItems" , trace .WithAttributes (attribute .String ("kind" , gvk .Kind )))
60
66
defer span .End ()
@@ -88,9 +94,14 @@ func (r *Service) ListItems(gvk schema.GroupVersionKind) graphql.FieldResolveFn
88
94
opts = append (opts , client.MatchingLabelsSelector {Selector : selector })
89
95
}
90
96
91
- // Handle namespace argument
92
- if namespace , ok := p .Args [NamespaceArg ].(string ); ok && namespace != "" {
93
- opts = append (opts , client .InNamespace (namespace ))
97
+ if isResourceNamespaceScoped (scope ) {
98
+ namespace , err := getStringArg (p .Args , NamespaceArg , false )
99
+ if err != nil {
100
+ return nil , err
101
+ }
102
+ if namespace != "" {
103
+ opts = append (opts , client .InNamespace (namespace ))
104
+ }
94
105
}
95
106
96
107
if err = r .runtimeClient .List (ctx , list , opts ... ); err != nil {
@@ -108,7 +119,7 @@ func (r *Service) ListItems(gvk schema.GroupVersionKind) graphql.FieldResolveFn
108
119
}
109
120
110
121
// GetItem returns a GraphQL CommonResolver function that retrieves a single Kubernetes resource of the given GroupVersionKind.
111
- func (r * Service ) GetItem (gvk schema.GroupVersionKind ) graphql.FieldResolveFn {
122
+ func (r * Service ) GetItem (gvk schema.GroupVersionKind , scope v1. ResourceScope ) graphql.FieldResolveFn {
112
123
return func (p graphql.ResolveParams ) (interface {}, error ) {
113
124
ctx , span := otel .Tracer ("" ).Start (p .Context , "GetItem" , trace .WithAttributes (attribute .String ("kind" , gvk .Kind )))
114
125
defer span .End ()
@@ -128,7 +139,7 @@ func (r *Service) GetItem(gvk schema.GroupVersionKind) graphql.FieldResolveFn {
128
139
}
129
140
130
141
// Retrieve required arguments
131
- name , namespace , err := getRequiredNameAndNamespaceArgs (p .Args )
142
+ name , err := getStringArg (p .Args , NameArg , true )
132
143
if err != nil {
133
144
return nil , err
134
145
}
@@ -137,26 +148,36 @@ func (r *Service) GetItem(gvk schema.GroupVersionKind) graphql.FieldResolveFn {
137
148
obj := & unstructured.Unstructured {}
138
149
obj .SetGroupVersionKind (gvk )
139
150
151
+ key := client.ObjectKey {
152
+ Name : name ,
153
+ }
154
+
155
+ if isResourceNamespaceScoped (scope ) {
156
+ namespace , err := getStringArg (p .Args , NamespaceArg , true )
157
+ if err != nil {
158
+ return nil , err
159
+ }
160
+
161
+ key .Namespace = namespace
162
+ }
163
+
140
164
// Get the object using the runtime client
141
- if err = r .runtimeClient .Get (ctx , client.ObjectKey {
142
- Namespace : namespace ,
143
- Name : name ,
144
- }, obj ); err != nil {
145
- log .Error ().Err (err ).Str ("name" , name ).Str ("namespace" , namespace ).Msg ("Unable to get object" )
165
+ if err = r .runtimeClient .Get (ctx , key , obj ); err != nil {
166
+ log .Error ().Err (err ).Str ("name" , name ).Str ("scope" , string (scope )).Msg ("Unable to get object" )
146
167
return nil , err
147
168
}
148
169
149
170
return obj .Object , nil
150
171
}
151
172
}
152
173
153
- func (r * Service ) GetItemAsYAML (gvk schema.GroupVersionKind ) graphql.FieldResolveFn {
174
+ func (r * Service ) GetItemAsYAML (gvk schema.GroupVersionKind , scope v1. ResourceScope ) graphql.FieldResolveFn {
154
175
return func (p graphql.ResolveParams ) (interface {}, error ) {
155
176
var span trace.Span
156
177
p .Context , span = otel .Tracer ("" ).Start (p .Context , "GetItemAsYAML" , trace .WithAttributes (attribute .String ("kind" , gvk .Kind )))
157
178
defer span .End ()
158
179
159
- out , err := r .GetItem (gvk )(p )
180
+ out , err := r .GetItem (gvk , scope )(p )
160
181
if err != nil {
161
182
return "" , err
162
183
}
@@ -170,7 +191,7 @@ func (r *Service) GetItemAsYAML(gvk schema.GroupVersionKind) graphql.FieldResolv
170
191
}
171
192
}
172
193
173
- func (r * Service ) CreateItem (gvk schema.GroupVersionKind ) graphql.FieldResolveFn {
194
+ func (r * Service ) CreateItem (gvk schema.GroupVersionKind , scope v1. ResourceScope ) graphql.FieldResolveFn {
174
195
return func (p graphql.ResolveParams ) (interface {}, error ) {
175
196
ctx , span := otel .Tracer ("" ).Start (p .Context , "CreateItem" , trace .WithAttributes (attribute .String ("kind" , gvk .Kind )))
176
197
defer span .End ()
@@ -179,14 +200,20 @@ func (r *Service) CreateItem(gvk schema.GroupVersionKind) graphql.FieldResolveFn
179
200
180
201
log := r .log .With ().Str ("operation" , "create" ).Str ("kind" , gvk .Kind ).Logger ()
181
202
182
- namespace := p .Args [NamespaceArg ].(string )
183
203
objectInput := p .Args ["object" ].(map [string ]interface {})
184
204
185
205
obj := & unstructured.Unstructured {
186
206
Object : objectInput ,
187
207
}
188
208
obj .SetGroupVersionKind (gvk )
189
- obj .SetNamespace (namespace )
209
+
210
+ if isResourceNamespaceScoped (scope ) {
211
+ namespace , err := getStringArg (p .Args , NamespaceArg , true )
212
+ if err != nil {
213
+ return nil , err
214
+ }
215
+ obj .SetNamespace (namespace )
216
+ }
190
217
191
218
if obj .GetName () == "" {
192
219
return nil , errors .New ("object metadata.name is required" )
@@ -201,7 +228,7 @@ func (r *Service) CreateItem(gvk schema.GroupVersionKind) graphql.FieldResolveFn
201
228
}
202
229
}
203
230
204
- func (r * Service ) UpdateItem (gvk schema.GroupVersionKind ) graphql.FieldResolveFn {
231
+ func (r * Service ) UpdateItem (gvk schema.GroupVersionKind , scope v1. ResourceScope ) graphql.FieldResolveFn {
205
232
return func (p graphql.ResolveParams ) (interface {}, error ) {
206
233
ctx , span := otel .Tracer ("" ).Start (p .Context , "UpdateItem" , trace .WithAttributes (attribute .String ("kind" , gvk .Kind )))
207
234
defer span .End ()
@@ -210,7 +237,7 @@ func (r *Service) UpdateItem(gvk schema.GroupVersionKind) graphql.FieldResolveFn
210
237
211
238
log := r .log .With ().Str ("operation" , "update" ).Str ("kind" , gvk .Kind ).Logger ()
212
239
213
- name , namespace , err := getRequiredNameAndNamespaceArgs (p .Args )
240
+ name , err := getStringArg (p .Args , NameArg , true )
214
241
if err != nil {
215
242
return nil , err
216
243
}
@@ -226,8 +253,17 @@ func (r *Service) UpdateItem(gvk schema.GroupVersionKind) graphql.FieldResolveFn
226
253
existingObj := & unstructured.Unstructured {}
227
254
existingObj .SetGroupVersionKind (gvk )
228
255
256
+ key := client.ObjectKey {Name : name }
257
+ if isResourceNamespaceScoped (scope ) {
258
+ namespace , err := getStringArg (p .Args , NamespaceArg , true )
259
+ if err != nil {
260
+ return nil , err
261
+ }
262
+ key .Namespace = namespace
263
+ }
264
+
229
265
// Fetch the existing object from the cluster
230
- err = r .runtimeClient .Get (ctx , client. ObjectKey { Namespace : namespace , Name : name } , existingObj )
266
+ err = r .runtimeClient .Get (ctx , key , existingObj )
231
267
if err != nil {
232
268
log .Error ().Err (err ).Msg ("Failed to get existing object" )
233
269
return nil , err
@@ -245,7 +281,7 @@ func (r *Service) UpdateItem(gvk schema.GroupVersionKind) graphql.FieldResolveFn
245
281
}
246
282
247
283
// DeleteItem returns a CommonResolver function for deleting a resource.
248
- func (r * Service ) DeleteItem (gvk schema.GroupVersionKind ) graphql.FieldResolveFn {
284
+ func (r * Service ) DeleteItem (gvk schema.GroupVersionKind , scope v1. ResourceScope ) graphql.FieldResolveFn {
249
285
return func (p graphql.ResolveParams ) (interface {}, error ) {
250
286
ctx , span := otel .Tracer ("" ).Start (p .Context , "DeleteItem" , trace .WithAttributes (attribute .String ("kind" , gvk .Kind )))
251
287
defer span .End ()
@@ -254,16 +290,23 @@ func (r *Service) DeleteItem(gvk schema.GroupVersionKind) graphql.FieldResolveFn
254
290
255
291
log := r .log .With ().Str ("operation" , "delete" ).Str ("kind" , gvk .Kind ).Logger ()
256
292
257
- name , namespace , err := getRequiredNameAndNamespaceArgs (p .Args )
293
+ name , err := getStringArg (p .Args , NameArg , true )
258
294
if err != nil {
259
295
return nil , err
260
296
}
261
297
262
298
obj := & unstructured.Unstructured {}
263
299
obj .SetGroupVersionKind (gvk )
264
- obj .SetNamespace (namespace )
265
300
obj .SetName (name )
266
301
302
+ if isResourceNamespaceScoped (scope ) {
303
+ namespace , err := getStringArg (p .Args , NamespaceArg , true )
304
+ if err != nil {
305
+ return nil , err
306
+ }
307
+ obj .SetNamespace (namespace )
308
+ }
309
+
267
310
if err := r .runtimeClient .Delete (ctx , obj ); err != nil {
268
311
log .Error ().Err (err ).Msg ("Failed to delete object" )
269
312
return nil , err
0 commit comments