Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Status conditions for Claim and Composite #146

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ on:

env:
# Common versions
GO_VERSION: '1.21.3'
GOLANGCI_VERSION: 'v1.54.2'
GO_VERSION: '1.23.3'
GOLANGCI_VERSION: 'v1.62.0'
DOCKER_BUILDX_VERSION: 'v0.11.2'

# These environment variables are important to the Crossplane CLI install.sh
Expand Down
41 changes: 41 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,47 @@ spec:

For more information, see the example in [recursive](example/recursive).

## Setting Conditions on the Claim and Composite

Starting with Crossplane 1.17, Composition authors can set custom Conditions on the
Composite and the Claim.

Add a `ClaimConditions` to your template to set Conditions:

```yaml
apiVersion: meta.gotemplating.fn.crossplane.io/v1alpha1
kind: ClaimConditions
conditions:
# Guide to ClaimConditions fields:
# Type of the condition, e.g. DatabaseReady.
# 'Healthy', 'Ready' and 'Synced' are reserved for use by Crossplane and this function will raise an error if used
# - type:
# Status of the condition. String of "True"/"False"/"Unknown"
# status:
# Machine-readable PascalCase reason, for example "ErrorProvisioning"
# reason:
# Optional Target. Publish Condition only to the Composite, or the Composite and the Claim (CompositeAndClaim).
# Defaults to Composite
# target:
# Optional message:
# message:
- type: TestCondition
status: "False"
reason: InstallFail
message: "failed to install"
target: CompositeAndClaim
- type: ConditionTrue
status: "True"
reason: TrueCondition
message: we are true
target: Composite
- type: DatabaseReady
status: "True"
reason: Ready
message: Database is ready
target: CompositeAndClaim
```

## Additional functions

| Name | Description |
Expand Down
88 changes: 88 additions & 0 deletions claimconditions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package main

import (
xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
"github.com/crossplane/function-sdk-go/errors"
fnv1 "github.com/crossplane/function-sdk-go/proto/v1"
"github.com/crossplane/function-sdk-go/response"
corev1 "k8s.io/api/core/v1"
)

// A CompositionTarget is the target of a composition event or condition.
type CompositionTarget string

// A TargetedCondition represents a condition produced by the composition
// process. It can target either the XR only, or both the XR and the claim.
type TargetedCondition struct {
xpv1.Condition `json:",inline"`
Target CompositionTarget `json:"target"`
}

// Composition event and condition targets.
const (
CompositionTargetComposite CompositionTarget = "Composite"
CompositionTargetCompositeAndClaim CompositionTarget = "CompositeAndClaim"
)

// UpdateClaimConditions updates Conditions in the Claim and Composite
func UpdateClaimConditions(rsp *fnv1.RunFunctionResponse, conditions ...TargetedCondition) error {
if rsp == nil {
return nil
}
for _, c := range conditions {
if xpv1.IsSystemConditionType(xpv1.ConditionType(c.Type)) {
response.Fatal(rsp, errors.Errorf("cannot set ClaimCondition type: %s is a reserved Crossplane Condition", c.Type))
return errors.New("error updating response")
}
co := transformCondition(c)
UpdateResponseWithCondition(rsp, co)
}
return nil
}

// transformCondition converts a TargetedCondition to be compatible with the Protobuf SDK
func transformCondition(tc TargetedCondition) *fnv1.Condition {
c := &fnv1.Condition{
Type: string(tc.Condition.Type),
Reason: string(tc.Condition.Reason),
Target: transformTarget(tc.Target),
}

switch tc.Condition.Status {
case corev1.ConditionTrue:
c.Status = fnv1.Status_STATUS_CONDITION_TRUE
case corev1.ConditionFalse:
c.Status = fnv1.Status_STATUS_CONDITION_FALSE
case corev1.ConditionUnknown:
fallthrough
default:
c.Status = fnv1.Status_STATUS_CONDITION_UNKNOWN
}

if tc.Message != "" {
c.Message = &tc.Message
}
return c
}

// transformTarget converts the input into a target Go SDK Enum
// Default to TARGET_COMPOSITE
func transformTarget(ct CompositionTarget) *fnv1.Target {
if ct == CompositionTargetCompositeAndClaim {
return fnv1.Target_TARGET_COMPOSITE_AND_CLAIM.Enum().Enum()
}
return fnv1.Target_TARGET_COMPOSITE.Enum()
}

// UpdateResponseWithCondition updates the RunFunctionResponse with a Condition
func UpdateResponseWithCondition(rsp *fnv1.RunFunctionResponse, c *fnv1.Condition) {
if rsp == nil {
return
}
if rsp.GetConditions() == nil {
rsp.Conditions = make([]*fnv1.Condition, 0, 1)
}
if c != nil {
rsp.Conditions = append(rsp.GetConditions(), c)
}
}
Loading