Skip to content

Commit

Permalink
Merge tag 'v1.14.8' into sync-upstream-release-1.14
Browse files Browse the repository at this point in the history
Release v1.14.8
  • Loading branch information
pedjak committed Apr 15, 2024
2 parents d1c6b37 + a3f1bbc commit 399c497
Show file tree
Hide file tree
Showing 26 changed files with 576 additions and 59 deletions.
3 changes: 2 additions & 1 deletion apis/apiextensions/v1/composition_transforms.go
Original file line number Diff line number Diff line change
Expand Up @@ -377,8 +377,9 @@ type StringTransform struct {
// `ToJson` converts any input value into its raw JSON representation.
// `ToSha1`, `ToSha256` and `ToSha512` generate a hash value based on the input
// converted to JSON.
// `ToAdler32` generate a addler32 hash based on the input string.
// +optional
// +kubebuilder:validation:Enum=ToUpper;ToLower;ToBase64;FromBase64;ToJson;ToSha1;ToSha256;ToSha512
// +kubebuilder:validation:Enum=ToUpper;ToLower;ToBase64;FromBase64;ToJson;ToSha1;ToSha256;ToSha512;ToAdler32
Convert *StringConversionType `json:"convert,omitempty"`

// Trim the prefix or suffix from the input
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -379,8 +379,9 @@ type StringTransform struct {
// `ToJson` converts any input value into its raw JSON representation.
// `ToSha1`, `ToSha256` and `ToSha512` generate a hash value based on the input
// converted to JSON.
// `ToAdler32` generate a addler32 hash based on the input string.
// +optional
// +kubebuilder:validation:Enum=ToUpper;ToLower;ToBase64;FromBase64;ToJson;ToSha1;ToSha256;ToSha512
// +kubebuilder:validation:Enum=ToUpper;ToLower;ToBase64;FromBase64;ToJson;ToSha1;ToSha256;ToSha512;ToAdler32
Convert *StringConversionType `json:"convert,omitempty"`

// Trim the prefix or suffix from the input
Expand Down
24 changes: 18 additions & 6 deletions cluster/crds/apiextensions.crossplane.io_compositionrevisions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,8 @@ spec:
any input value into its raw JSON representation.
`ToSha1`, `ToSha256` and `ToSha512` generate
a hash value based on the input converted to
JSON.
JSON. `ToAdler32` generate a addler32 hash based
on the input string.
enum:
- ToUpper
- ToLower
Expand All @@ -437,6 +438,7 @@ spec:
- ToSha1
- ToSha256
- ToSha512
- ToAdler32
type: string
fmt:
description: Format the input using a Go format
Expand Down Expand Up @@ -810,7 +812,8 @@ spec:
any input value into its raw JSON representation.
`ToSha1`, `ToSha256` and `ToSha512` generate
a hash value based on the input converted
to JSON.
to JSON. `ToAdler32` generate a addler32 hash
based on the input string.
enum:
- ToUpper
- ToLower
Expand All @@ -820,6 +823,7 @@ spec:
- ToSha1
- ToSha256
- ToSha512
- ToAdler32
type: string
fmt:
description: Format the input using a Go format
Expand Down Expand Up @@ -1269,7 +1273,8 @@ spec:
any input value into its raw JSON representation.
`ToSha1`, `ToSha256` and `ToSha512` generate
a hash value based on the input converted
to JSON.
to JSON. `ToAdler32` generate a addler32 hash
based on the input string.
enum:
- ToUpper
- ToLower
Expand All @@ -1279,6 +1284,7 @@ spec:
- ToSha1
- ToSha256
- ToSha512
- ToAdler32
type: string
fmt:
description: Format the input using a Go format
Expand Down Expand Up @@ -1886,7 +1892,8 @@ spec:
any input value into its raw JSON representation.
`ToSha1`, `ToSha256` and `ToSha512` generate
a hash value based on the input converted to
JSON.
JSON. `ToAdler32` generate a addler32 hash based
on the input string.
enum:
- ToUpper
- ToLower
Expand All @@ -1896,6 +1903,7 @@ spec:
- ToSha1
- ToSha256
- ToSha512
- ToAdler32
type: string
fmt:
description: Format the input using a Go format
Expand Down Expand Up @@ -2269,7 +2277,8 @@ spec:
any input value into its raw JSON representation.
`ToSha1`, `ToSha256` and `ToSha512` generate
a hash value based on the input converted
to JSON.
to JSON. `ToAdler32` generate a addler32 hash
based on the input string.
enum:
- ToUpper
- ToLower
Expand All @@ -2279,6 +2288,7 @@ spec:
- ToSha1
- ToSha256
- ToSha512
- ToAdler32
type: string
fmt:
description: Format the input using a Go format
Expand Down Expand Up @@ -2728,7 +2738,8 @@ spec:
any input value into its raw JSON representation.
`ToSha1`, `ToSha256` and `ToSha512` generate
a hash value based on the input converted
to JSON.
to JSON. `ToAdler32` generate a addler32 hash
based on the input string.
enum:
- ToUpper
- ToLower
Expand All @@ -2738,6 +2749,7 @@ spec:
- ToSha1
- ToSha256
- ToSha512
- ToAdler32
type: string
fmt:
description: Format the input using a Go format
Expand Down
12 changes: 9 additions & 3 deletions cluster/crds/apiextensions.crossplane.io_compositions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,8 @@ spec:
any input value into its raw JSON representation.
`ToSha1`, `ToSha256` and `ToSha512` generate
a hash value based on the input converted to
JSON.
JSON. `ToAdler32` generate a addler32 hash based
on the input string.
enum:
- ToUpper
- ToLower
Expand All @@ -432,6 +433,7 @@ spec:
- ToSha1
- ToSha256
- ToSha512
- ToAdler32
type: string
fmt:
description: Format the input using a Go format
Expand Down Expand Up @@ -805,7 +807,8 @@ spec:
any input value into its raw JSON representation.
`ToSha1`, `ToSha256` and `ToSha512` generate
a hash value based on the input converted
to JSON.
to JSON. `ToAdler32` generate a addler32 hash
based on the input string.
enum:
- ToUpper
- ToLower
Expand All @@ -815,6 +818,7 @@ spec:
- ToSha1
- ToSha256
- ToSha512
- ToAdler32
type: string
fmt:
description: Format the input using a Go format
Expand Down Expand Up @@ -1264,7 +1268,8 @@ spec:
any input value into its raw JSON representation.
`ToSha1`, `ToSha256` and `ToSha512` generate
a hash value based on the input converted
to JSON.
to JSON. `ToAdler32` generate a addler32 hash
based on the input string.
enum:
- ToUpper
- ToLower
Expand All @@ -1274,6 +1279,7 @@ spec:
- ToSha1
- ToSha256
- ToSha512
- ToAdler32
type: string
fmt:
description: Format the input using a Go format
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ require (
github.com/alecthomas/kong v0.8.1
github.com/bufbuild/buf v1.27.1
github.com/crossplane/crossplane-runtime v1.14.2
github.com/docker/docker v24.0.7+incompatible
github.com/docker/docker v24.0.9+incompatible
github.com/docker/go-connections v0.4.0
github.com/emicklei/dot v1.6.0
github.com/go-git/go-billy/v5 v5.5.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,8 @@ github.com/docker/cli v24.0.6+incompatible h1:fF+XCQCgJjjQNIMjzaSmiKJSCcfcXb3TWT
github.com/docker/cli v24.0.6+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM=
github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v24.0.9+incompatible h1:HPGzNmwfLZWdxHqK9/II92pyi1EpYKsAqcl4G0Of9v0=
github.com/docker/docker v24.0.9+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0=
github.com/docker/docker-credential-helpers v0.8.0 h1:YQFtbBQb4VrpoPxhFuzEBPQ9E16qz5SpHLS+uswaCp8=
github.com/docker/docker-credential-helpers v0.8.0/go.mod h1:UGFXcuoQ5TxPiB54nHOZ32AWRqQdECoh/Mg0AlEYb40=
Expand Down
8 changes: 7 additions & 1 deletion internal/controller/apiextensions/composite/composed.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,14 @@ type ComposedResource struct {
ResourceName ResourceName

// Ready indicates whether this composed resource is ready - i.e. whether
// all of its readiness checks passed.
// all of its readiness checks passed. Setting it to false will cause the
// XR to be marked as not ready.
Ready bool

// Synced indicates whether the composition process was able to sync the
// composed resource with its desired state. Setting it to false will cause
// the XR to be marked as not synced.
Synced bool
}

// ComposedResourceState represents a composed resource (either desired or
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package composite

import (
"context"
"crypto/sha256"
"fmt"
"sort"

Expand Down Expand Up @@ -79,9 +80,9 @@ const (
// resources (XR).
FieldOwnerXR = "apiextensions.crossplane.io/composite"

// FieldOwnerComposed owns the fields this controller mutates on composed
// FieldOwnerComposedPrefix owns the fields this controller mutates on composed
// resources.
FieldOwnerComposed = "apiextensions.crossplane.io/composed"
FieldOwnerComposedPrefix = "apiextensions.crossplane.io/composed"
)

const (
Expand Down Expand Up @@ -372,6 +373,46 @@ func (c *FunctionComposer) Compose(ctx context.Context, xr *composite.Unstructur
return CompositionResult{}, errors.Wrap(err, errApplyXRRefs)
}

// Produce our array of resources to return to the Reconciler. The
// Reconciler uses this array to determine whether the XR is ready.
resources := make([]ComposedResource, 0, len(desired))

// We apply all of our desired resources before we observe them in the loop
// below. This ensures that issues observing and processing one composed
// resource won't block the application of another.
for name, cd := range desired {
// We don't need any crossplane-runtime resource.Applicator style apply
// options here because server-side apply takes care of everything.
// Specifically it will merge rather than replace owner references (e.g.
// for Usages), and will fail if we try to add a controller reference to
// a resource that already has a different one.
// NOTE(phisco): We need to set a field owner unique for each XR here,
// this prevents multiple XRs composing the same resource to be
// continuously alternated as controllers.
if err := c.client.Patch(ctx, cd.Resource, client.Apply, client.ForceOwnership, client.FieldOwner(ComposedFieldOwnerName(xr))); err != nil {
if kerrors.IsInvalid(err) {
// We tried applying an invalid resource, we can't tell whether
// this means the resource will never be valid or it will if we
// run again the composition after some other resource is
// created or updated successfully. So, we emit a warning event
// and move on.
// We mark the resource as not synced, so that once we get to
// decide the XR's Synced condition, we can set it to false if
// any of the resources didn't sync successfully.
events = append(events, event.Warning(reasonCompose, errors.Wrapf(err, errFmtApplyCD, name)))
// NOTE(phisco): here we behave differently w.r.t. the native
// p&t composer, as we respect the readiness reported by
// functions, while there we defaulted to also set ready false
// in case of apply errors.
resources = append(resources, ComposedResource{ResourceName: name, Ready: cd.Ready, Synced: false})
continue
}
return CompositionResult{}, errors.Wrapf(err, errFmtApplyCD, name)
}

resources = append(resources, ComposedResource{ResourceName: name, Ready: cd.Ready, Synced: true})
}

// Our goal here is to patch our XR's status using server-side apply. We
// want the resulting, patched object loaded into uxr. We need to pass in
// only our "fully specified intent" - i.e. only the fields that we actually
Expand All @@ -390,33 +431,41 @@ func (c *FunctionComposer) Compose(ctx context.Context, xr *composite.Unstructur
xr.SetName(n)
xr.SetUID(u)

// NOTE(phisco): Here we are fine using a hardcoded field owner as there is
// no risk of conflict between different XRs.
if err := c.client.Status().Patch(ctx, xr, client.Apply, client.ForceOwnership, client.FieldOwner(FieldOwnerXR)); err != nil {
// Note(phisco): here we are fine with this error being terminal, as
// there is no other resource to apply that might eventually resolve
// this issue.
return CompositionResult{}, errors.Wrap(err, errApplyXRStatus)
}

// Produce our array of resources to return to the Reconciler. The
// Reconciler uses this array to determine whether the XR is ready.
resources := make([]ComposedResource, 0, len(desired))

// We apply all of our desired resources before we observe them in the loop
// below. This ensures that issues observing and processing one composed
// resource won't block the application of another.
for name, cd := range desired {
// We don't need any crossplane-runtime resource.Applicator style apply
// options here because server-side apply takes care of everything.
// Specifically it will merge rather than replace owner references (e.g.
// for Usages), and will fail if we try to add a controller reference to
// a resource that already has a different one.
if err := c.client.Patch(ctx, cd.Resource, client.Apply, client.ForceOwnership, client.FieldOwner(FieldOwnerComposed)); err != nil {
return CompositionResult{}, errors.Wrapf(err, errFmtApplyCD, name)
}

resources = append(resources, ComposedResource{ResourceName: name, Ready: cd.Ready})
}

return CompositionResult{ConnectionDetails: d.GetComposite().GetConnectionDetails(), Composed: resources, Events: events}, nil
}

// ComposedFieldOwnerName generates a unique field owner name
// for a given Crossplane composite resource (XR). This uniqueness is crucial to
// prevent multiple XRs, which compose the same resource, from continuously
// alternating as controllers.
//
// The function generates a deterministic hash based on the XR's name and
// GroupKind (GK), ensuring consistency even during system restores. The hash
// does not include the XR's UID (as it's not deterministic), namespace (XRs
// don't have one), or version (to allow version changes without needing to
// update the field owner name).
//
// We decided to include the GK in the hash to prevent transferring ownership of
// composed resources across XRs with whole new GK, as that should not be
// supported without manual intervention.
//
// Given that field owner names are limited to 128 characters, the function
// truncates the hash to 32 characters. A longer hash was deemed unnecessary.
func ComposedFieldOwnerName(xr *composite.Unstructured) string {
h := sha256.New()
_, _ = h.Write([]byte(xr.GetName() + xr.GroupVersionKind().GroupKind().String()))
return fmt.Sprintf("%s/%x", FieldOwnerComposedPrefix, h.Sum(nil))
}

// An ExistingComposedResourceObserver uses an XR's resource references to load
// any existing composed resources from the API server. It also loads their
// connection details.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -614,8 +614,8 @@ func TestFunctionCompose(t *testing.T) {
want: want{
res: CompositionResult{
Composed: []ComposedResource{
{ResourceName: "desired-resource-a"},
{ResourceName: "observed-resource-a", Ready: true},
{ResourceName: "desired-resource-a", Synced: true},
{ResourceName: "observed-resource-a", Ready: true, Synced: true},
},
ConnectionDetails: managed.ConnectionDetails{
"from": []byte("function-pipeline"),
Expand Down
Loading

0 comments on commit 399c497

Please sign in to comment.