Skip to content

Commit 66f94a2

Browse files
committed
Dynamic 'servicePrincipalRef` implementation
* Tests * Implementation * Examples Signed-off-by: Yury Tsarev <[email protected]>
1 parent d271aef commit 66f94a2

File tree

10 files changed

+440
-1
lines changed

10 files changed

+440
-1
lines changed

example/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,13 @@ Get details of specified service principals:
9595
```shell
9696
crossplane render xr.yaml service-principal-example.yaml functions.yaml --function-credentials=./secrets/azure-creds.yaml -rc
9797
```
98+
99+
Dynamic `servicePrinicpalsRef` variations:
100+
101+
```shell
102+
crossplane render xr.yaml service-principal-example-status-ref.yaml functions.yaml --function-credentials=./secrets/azure-creds.yaml -rc
103+
```
104+
105+
```shell
106+
crossplane render xr.yaml service-principal-example-context-ref.yaml functions.yaml --function-credentials=./secrets/azure-creds.yaml -rc --extra-resources=envconfig.yaml
107+
```

example/envconfig.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,5 @@ data:
99
- test-fn-msgraph
1010
users:
1111
12+
servicePrincipalNames:
13+
- yury-upbound-oidc-provider
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
apiVersion: apiextensions.crossplane.io/v1
2+
kind: Composition
3+
metadata:
4+
name: service-principal-example-context-ref
5+
spec:
6+
compositeTypeRef:
7+
apiVersion: example.crossplane.io/v1
8+
kind: XR
9+
mode: Pipeline
10+
pipeline:
11+
- step: environmentConfigs
12+
functionRef:
13+
name: crossplane-contrib-function-environment-configs
14+
input:
15+
apiVersion: environmentconfigs.fn.crossplane.io/v1beta1
16+
kind: Input
17+
spec:
18+
environmentConfigs:
19+
- type: Reference
20+
ref:
21+
name: example-config
22+
- step: get-service-principal-details
23+
functionRef:
24+
name: function-msgraph
25+
input:
26+
apiVersion: msgraph.fn.crossplane.io/v1alpha1
27+
kind: Input
28+
queryType: ServicePrincipalDetails
29+
servicePrincipalsRef: context.[apiextensions.crossplane.io/environment].servicePrincipalNames
30+
target: "status.servicePrincipals"
31+
skipQueryWhenTargetHasData: true
32+
credentials:
33+
- name: azure-creds
34+
source: Secret
35+
secretRef:
36+
namespace: upbound-system
37+
name: azure-account-creds
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
apiVersion: apiextensions.crossplane.io/v1
2+
kind: Composition
3+
metadata:
4+
name: service-principal-example-status-ref
5+
annotations:
6+
# Important: This function requires an Azure AD app registration with Microsoft Graph API permissions:
7+
# - Application.Read.All
8+
# - Directory.Read.All
9+
spec:
10+
compositeTypeRef:
11+
apiVersion: example.crossplane.io/v1
12+
kind: XR
13+
mode: Pipeline
14+
pipeline:
15+
- step: get-service-principal-details
16+
functionRef:
17+
name: function-msgraph
18+
input:
19+
apiVersion: msgraph.fn.crossplane.io/v1alpha1
20+
kind: Input
21+
queryType: ServicePrincipalDetails
22+
servicePrincipalsRef: status.servicePrincipalNames
23+
target: "status.servicePrincipals"
24+
skipQueryWhenTargetHasData: true
25+
credentials:
26+
- name: azure-creds
27+
source: Secret
28+
secretRef:
29+
namespace: upbound-system
30+
name: azure-account-creds

example/xr.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@ status:
1111
- test-fn-msgraph
1212
users:
1313
14+
servicePrincipalNames:
15+
- yury-upbound-oidc-provider

fn.go

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -887,7 +887,7 @@ func (f *Function) validateAndPrepareInput(_ context.Context, req *fnv1.RunFunct
887887
return true
888888
}
889889

890-
// processReferences handles resolving references like groupRef, groupsRef, and usersRef
890+
// processReferences handles resolving references like groupRef, groupsRef, usersRef, and servicePrincipalsRef
891891
func (f *Function) processReferences(req *fnv1.RunFunctionRequest, in *v1beta1.Input, rsp *fnv1.RunFunctionResponse) bool {
892892
// Process references based on query type
893893
switch in.QueryType {
@@ -897,6 +897,8 @@ func (f *Function) processReferences(req *fnv1.RunFunctionRequest, in *v1beta1.I
897897
return f.processGroupsRef(req, in, rsp)
898898
case "UserValidation":
899899
return f.processUsersRef(req, in, rsp)
900+
case "ServicePrincipalDetails":
901+
return f.processServicePrincipalsRef(req, in, rsp)
900902
}
901903
return true
902904
}
@@ -949,6 +951,22 @@ func (f *Function) processUsersRef(req *fnv1.RunFunctionRequest, in *v1beta1.Inp
949951
return true
950952
}
951953

954+
// processServicePrincipalsRef handles resolving the servicePrincipalsRef reference for ServicePrincipalDetails query type
955+
func (f *Function) processServicePrincipalsRef(req *fnv1.RunFunctionRequest, in *v1beta1.Input, rsp *fnv1.RunFunctionResponse) bool {
956+
if in.ServicePrincipalsRef == nil || *in.ServicePrincipalsRef == "" {
957+
return true
958+
}
959+
960+
spNames, err := f.resolveServicePrincipalsRef(req, in.ServicePrincipalsRef)
961+
if err != nil {
962+
response.Fatal(rsp, err)
963+
return false
964+
}
965+
in.ServicePrincipals = spNames
966+
f.log.Info("Resolved ServicePrincipalsRef to service principals", "spCount", len(spNames), "servicePrincipalsRef", *in.ServicePrincipalsRef)
967+
return true
968+
}
969+
952970
// executeAndProcessQuery executes the query and processes the results
953971
func (f *Function) executeAndProcessQuery(ctx context.Context, req *fnv1.RunFunctionRequest, in *v1beta1.Input, azureCreds map[string]string, rsp *fnv1.RunFunctionResponse) bool {
954972
// Execute the query
@@ -1114,6 +1132,11 @@ func (f *Function) resolveUsersRef(req *fnv1.RunFunctionRequest, usersRef *strin
11141132
return f.resolveStringArrayRef(req, usersRef, "usersRef")
11151133
}
11161134

1135+
// resolveServicePrincipalsRef resolves a list of service principal names from a reference in status or context
1136+
func (f *Function) resolveServicePrincipalsRef(req *fnv1.RunFunctionRequest, servicePrincipalsRef *string) ([]*string, error) {
1137+
return f.resolveStringArrayRef(req, servicePrincipalsRef, "servicePrincipalsRef")
1138+
}
1139+
11171140
// extractStringArrayFromMap extracts a string array from a map using nested key
11181141
func (f *Function) extractStringArrayFromMap(dataMap map[string]interface{}, field, refKey string) ([]*string, error) {
11191142
parts, err := ParseNestedKey(field)

0 commit comments

Comments
 (0)