Skip to content

Commit e64181e

Browse files
authored
Merge pull request #6 from UpboundCare/query-source
Add implementation for QueryRef from XR status
2 parents 922ef1b + 86bcd87 commit e64181e

File tree

4 files changed

+223
-8
lines changed

4 files changed

+223
-8
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
apiVersion: apiextensions.crossplane.io/v1
2+
kind: Composition
3+
metadata:
4+
name: function-azresourcegraph
5+
spec:
6+
compositeTypeRef:
7+
apiVersion: example.crossplane.io/v1
8+
kind: XR
9+
mode: Pipeline
10+
pipeline:
11+
- step: query-azresourcegraph
12+
functionRef:
13+
name: function-azresourcegraph
14+
input:
15+
apiVersion: azresourcegraph.fn.crossplane.io/v1alpha1
16+
kind: Input
17+
queryRef: "status.azResourceGraphQuery"
18+
target: "context.azResourceGraphQueryResult"
19+
credentials:
20+
- name: azure-creds
21+
source: Secret
22+
secretRef:
23+
namespace: upbound-system
24+
name: azure-account-creds

example/xr-with-status.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Replace this with your XR!
2+
apiVersion: example.crossplane.io/v1
3+
kind: XR
4+
metadata:
5+
name: example-xr
6+
spec: {}
7+
status:
8+
azResourceGraphQuery: Resources| count

fn.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,21 @@ func (f *Function) RunFunction(ctx context.Context, req *fnv1.RunFunctionRequest
7474
switch {
7575
case in.QueryRef == nil:
7676
case strings.HasPrefix(*in.QueryRef, "status."):
77+
// The composite resource that actually exists.
78+
oxr, err := request.GetObservedCompositeResource(req)
79+
if err != nil {
80+
response.Fatal(rsp, errors.Wrap(err, "cannot get observed composite resource"))
81+
return rsp, nil
82+
}
83+
xrStatus := make(map[string]interface{})
84+
err = oxr.Resource.GetValueInto("status", &xrStatus)
85+
if err != nil {
86+
response.Fatal(rsp, errors.Wrap(err, "cannot get XR status"))
87+
return rsp, nil
88+
}
89+
if queryFromXRStatus, ok := GetNestedContextKey(xrStatus, strings.TrimPrefix(*in.QueryRef, "status.")); ok {
90+
in.Query = queryFromXRStatus
91+
}
7792
case strings.HasPrefix(*in.QueryRef, "context."):
7893
functionContext := req.GetContext().AsMap()
7994
if queryFromContext, ok := GetNestedContextKey(functionContext, strings.TrimPrefix(*in.QueryRef, "context.")); ok {
@@ -84,6 +99,12 @@ func (f *Function) RunFunction(ctx context.Context, req *fnv1.RunFunctionRequest
8499
return rsp, nil
85100
}
86101

102+
if in.Query == "" {
103+
response.Fatal(rsp, errors.New("Query is empty"))
104+
f.log.Info("FAILURE: ", "query is empty", in.Query)
105+
return rsp, nil
106+
}
107+
87108
results, err := f.azureQuery.azQuery(ctx, azureCreds, in)
88109
if err != nil {
89110
response.Fatal(rsp, err)

fn_test.go

Lines changed: 170 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -153,14 +153,14 @@ func TestRunFunction(t *testing.T) {
153153
Desired: &fnv1.State{
154154
Composite: &fnv1.Resource{
155155
Resource: resource.MustStructJSON(`{
156-
"apiVersion": "example.org/v1",
157-
"kind": "XR",
158-
"status": {
159-
"azResourceGraphQueryResult":
160-
{
161-
"resource": "mock-resource"
162-
}
163-
}}`),
156+
"apiVersion": "example.org/v1",
157+
"kind": "XR",
158+
"status": {
159+
"azResourceGraphQueryResult":
160+
{
161+
"resource": "mock-resource"
162+
}
163+
}}`),
164164
},
165165
},
166166
},
@@ -454,6 +454,168 @@ func TestRunFunction(t *testing.T) {
454454
},
455455
},
456456
},
457+
"CanGetQueryFromXRStatusKey": {
458+
reason: "The Function should be able to get Query from the XR status field",
459+
args: args{
460+
ctx: context.Background(),
461+
req: &fnv1.RunFunctionRequest{
462+
Meta: &fnv1.RequestMeta{Tag: "hello"},
463+
Input: resource.MustStructJSON(`{
464+
"apiVersion": "azresourcegraph.fn.crossplane.io/v1alpha1",
465+
"kind": "Input",
466+
"queryRef": "status.azResourceGraphQuery",
467+
"target": "context.azResourceGraphQueryResult"
468+
}`),
469+
Observed: &fnv1.State{
470+
Composite: &fnv1.Resource{
471+
Resource: resource.MustStructJSON(`{
472+
"apiVersion": "example.org/v1",
473+
"kind": "XR",
474+
"status": {
475+
"azResourceGraphQuery": "QueryFromXRStatus"
476+
}}`),
477+
},
478+
},
479+
Credentials: map[string]*fnv1.Credentials{
480+
"azure-creds": {
481+
Source: &fnv1.Credentials_CredentialData{CredentialData: creds},
482+
},
483+
},
484+
},
485+
},
486+
want: want{
487+
rsp: &fnv1.RunFunctionResponse{
488+
Meta: &fnv1.ResponseMeta{Tag: "hello", Ttl: durationpb.New(response.DefaultTTL)},
489+
Conditions: []*fnv1.Condition{
490+
{
491+
Type: "FunctionSuccess",
492+
Status: fnv1.Status_STATUS_CONDITION_TRUE,
493+
Reason: "Success",
494+
Target: fnv1.Target_TARGET_COMPOSITE_AND_CLAIM.Enum(),
495+
},
496+
},
497+
Results: []*fnv1.Result{
498+
{
499+
Severity: fnv1.Severity_SEVERITY_NORMAL,
500+
Message: `Query: "QueryFromXRStatus"`,
501+
Target: fnv1.Target_TARGET_COMPOSITE.Enum(),
502+
},
503+
},
504+
Context: resource.MustStructJSON(
505+
`{
506+
"azResourceGraphQueryResult":
507+
{
508+
"resource": "mock-resource"
509+
}
510+
}`,
511+
),
512+
},
513+
},
514+
},
515+
"CanGetQueryFromNestedXRStatusKey": {
516+
reason: "The Function should be able to get Query from the nested XR status field",
517+
args: args{
518+
ctx: context.Background(),
519+
req: &fnv1.RunFunctionRequest{
520+
Meta: &fnv1.RequestMeta{Tag: "hello"},
521+
Input: resource.MustStructJSON(`{
522+
"apiVersion": "azresourcegraph.fn.crossplane.io/v1alpha1",
523+
"kind": "Input",
524+
"queryRef": "status.testKey.azResourceGraphQuery",
525+
"target": "context.azResourceGraphQueryResult"
526+
}`),
527+
Observed: &fnv1.State{
528+
Composite: &fnv1.Resource{
529+
Resource: resource.MustStructJSON(`{
530+
"apiVersion": "example.org/v1",
531+
"kind": "XR",
532+
"status": {
533+
"testKey": {
534+
"azResourceGraphQuery": "QueryFromNestedXRStatus"
535+
}
536+
}}`),
537+
},
538+
},
539+
Credentials: map[string]*fnv1.Credentials{
540+
"azure-creds": {
541+
Source: &fnv1.Credentials_CredentialData{CredentialData: creds},
542+
},
543+
},
544+
},
545+
},
546+
want: want{
547+
rsp: &fnv1.RunFunctionResponse{
548+
Meta: &fnv1.ResponseMeta{Tag: "hello", Ttl: durationpb.New(response.DefaultTTL)},
549+
Conditions: []*fnv1.Condition{
550+
{
551+
Type: "FunctionSuccess",
552+
Status: fnv1.Status_STATUS_CONDITION_TRUE,
553+
Reason: "Success",
554+
Target: fnv1.Target_TARGET_COMPOSITE_AND_CLAIM.Enum(),
555+
},
556+
},
557+
Results: []*fnv1.Result{
558+
{
559+
Severity: fnv1.Severity_SEVERITY_NORMAL,
560+
Message: `Query: "QueryFromNestedXRStatus"`,
561+
Target: fnv1.Target_TARGET_COMPOSITE.Enum(),
562+
},
563+
},
564+
Context: resource.MustStructJSON(
565+
`{
566+
"azResourceGraphQueryResult":
567+
{
568+
"resource": "mock-resource"
569+
}
570+
}`,
571+
),
572+
},
573+
},
574+
},
575+
"FailIfQueryIsEmpty": {
576+
reason: "The Function should fail if Query is empty",
577+
args: args{
578+
ctx: context.Background(),
579+
req: &fnv1.RunFunctionRequest{
580+
Meta: &fnv1.RequestMeta{Tag: "hello"},
581+
Input: resource.MustStructJSON(`{
582+
"apiVersion": "azresourcegraph.fn.crossplane.io/v1alpha1",
583+
"kind": "Input",
584+
"queryRef": "status.nonExistingKey.azResourceGraphQuery",
585+
"target": "context.azResourceGraphQueryResult"
586+
}`),
587+
Observed: &fnv1.State{
588+
Composite: &fnv1.Resource{
589+
Resource: resource.MustStructJSON(`{
590+
"apiVersion": "example.org/v1",
591+
"kind": "XR",
592+
"status": {
593+
"testKey": {
594+
"azResourceGraphQuery": "QueryFromNestedXRStatus"
595+
}
596+
}}`),
597+
},
598+
},
599+
Credentials: map[string]*fnv1.Credentials{
600+
"azure-creds": {
601+
Source: &fnv1.Credentials_CredentialData{CredentialData: creds},
602+
},
603+
},
604+
},
605+
},
606+
want: want{
607+
rsp: &fnv1.RunFunctionResponse{
608+
Meta: &fnv1.ResponseMeta{Tag: "hello", Ttl: durationpb.New(response.DefaultTTL)},
609+
Results: []*fnv1.Result{
610+
{
611+
Severity: fnv1.Severity_SEVERITY_FATAL,
612+
Message: `Query is empty`,
613+
Target: fnv1.Target_TARGET_COMPOSITE.Enum(),
614+
},
615+
},
616+
},
617+
},
618+
},
457619
}
458620

459621
for name, tc := range cases {

0 commit comments

Comments
 (0)